1 // SPDX-License-Identifier: GPL-2.0 OR MIT
4 * Xen para-virtual sound device
6 * Copyright (C) 2016-2018 EPAM Systems Inc.
8 * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
11 #include <linux/platform_device.h>
13 #include <sound/core.h>
14 #include <sound/pcm.h>
15 #include <sound/pcm_params.h>
17 #include <xen/xenbus.h>
19 #include "xen_snd_front.h"
20 #include "xen_snd_front_alsa.h"
21 #include "xen_snd_front_cfg.h"
22 #include "xen_snd_front_evtchnl.h"
23 #include "xen_snd_front_shbuf.h"
25 struct xen_snd_front_pcm_stream_info
{
26 struct xen_snd_front_info
*front_info
;
27 struct xen_snd_front_evtchnl_pair
*evt_pair
;
28 struct xen_snd_front_shbuf sh_buf
;
32 struct snd_pcm_hardware pcm_hw
;
34 /* Number of processed frames as reported by the backend. */
35 snd_pcm_uframes_t be_cur_frame
;
36 /* Current HW pointer to be reported via .period callback. */
38 /* Modulo of the number of processed frames - for period detection. */
42 struct xen_snd_front_pcm_instance_info
{
43 struct xen_snd_front_card_info
*card_info
;
45 struct snd_pcm_hardware pcm_hw
;
46 int num_pcm_streams_pb
;
47 struct xen_snd_front_pcm_stream_info
*streams_pb
;
48 int num_pcm_streams_cap
;
49 struct xen_snd_front_pcm_stream_info
*streams_cap
;
52 struct xen_snd_front_card_info
{
53 struct xen_snd_front_info
*front_info
;
54 struct snd_card
*card
;
55 struct snd_pcm_hardware pcm_hw
;
56 int num_pcm_instances
;
57 struct xen_snd_front_pcm_instance_info
*pcm_instances
;
60 struct alsa_sndif_sample_format
{
62 snd_pcm_format_t alsa
;
65 struct alsa_sndif_hw_param
{
67 snd_pcm_hw_param_t alsa
;
70 static const struct alsa_sndif_sample_format ALSA_SNDIF_FORMATS
[] = {
72 .sndif
= XENSND_PCM_FORMAT_U8
,
73 .alsa
= SNDRV_PCM_FORMAT_U8
76 .sndif
= XENSND_PCM_FORMAT_S8
,
77 .alsa
= SNDRV_PCM_FORMAT_S8
80 .sndif
= XENSND_PCM_FORMAT_U16_LE
,
81 .alsa
= SNDRV_PCM_FORMAT_U16_LE
84 .sndif
= XENSND_PCM_FORMAT_U16_BE
,
85 .alsa
= SNDRV_PCM_FORMAT_U16_BE
88 .sndif
= XENSND_PCM_FORMAT_S16_LE
,
89 .alsa
= SNDRV_PCM_FORMAT_S16_LE
92 .sndif
= XENSND_PCM_FORMAT_S16_BE
,
93 .alsa
= SNDRV_PCM_FORMAT_S16_BE
96 .sndif
= XENSND_PCM_FORMAT_U24_LE
,
97 .alsa
= SNDRV_PCM_FORMAT_U24_LE
100 .sndif
= XENSND_PCM_FORMAT_U24_BE
,
101 .alsa
= SNDRV_PCM_FORMAT_U24_BE
104 .sndif
= XENSND_PCM_FORMAT_S24_LE
,
105 .alsa
= SNDRV_PCM_FORMAT_S24_LE
108 .sndif
= XENSND_PCM_FORMAT_S24_BE
,
109 .alsa
= SNDRV_PCM_FORMAT_S24_BE
112 .sndif
= XENSND_PCM_FORMAT_U32_LE
,
113 .alsa
= SNDRV_PCM_FORMAT_U32_LE
116 .sndif
= XENSND_PCM_FORMAT_U32_BE
,
117 .alsa
= SNDRV_PCM_FORMAT_U32_BE
120 .sndif
= XENSND_PCM_FORMAT_S32_LE
,
121 .alsa
= SNDRV_PCM_FORMAT_S32_LE
124 .sndif
= XENSND_PCM_FORMAT_S32_BE
,
125 .alsa
= SNDRV_PCM_FORMAT_S32_BE
128 .sndif
= XENSND_PCM_FORMAT_A_LAW
,
129 .alsa
= SNDRV_PCM_FORMAT_A_LAW
132 .sndif
= XENSND_PCM_FORMAT_MU_LAW
,
133 .alsa
= SNDRV_PCM_FORMAT_MU_LAW
136 .sndif
= XENSND_PCM_FORMAT_F32_LE
,
137 .alsa
= SNDRV_PCM_FORMAT_FLOAT_LE
140 .sndif
= XENSND_PCM_FORMAT_F32_BE
,
141 .alsa
= SNDRV_PCM_FORMAT_FLOAT_BE
144 .sndif
= XENSND_PCM_FORMAT_F64_LE
,
145 .alsa
= SNDRV_PCM_FORMAT_FLOAT64_LE
148 .sndif
= XENSND_PCM_FORMAT_F64_BE
,
149 .alsa
= SNDRV_PCM_FORMAT_FLOAT64_BE
152 .sndif
= XENSND_PCM_FORMAT_IEC958_SUBFRAME_LE
,
153 .alsa
= SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE
156 .sndif
= XENSND_PCM_FORMAT_IEC958_SUBFRAME_BE
,
157 .alsa
= SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE
160 .sndif
= XENSND_PCM_FORMAT_IMA_ADPCM
,
161 .alsa
= SNDRV_PCM_FORMAT_IMA_ADPCM
164 .sndif
= XENSND_PCM_FORMAT_MPEG
,
165 .alsa
= SNDRV_PCM_FORMAT_MPEG
168 .sndif
= XENSND_PCM_FORMAT_GSM
,
169 .alsa
= SNDRV_PCM_FORMAT_GSM
173 static int to_sndif_format(snd_pcm_format_t format
)
177 for (i
= 0; i
< ARRAY_SIZE(ALSA_SNDIF_FORMATS
); i
++)
178 if (ALSA_SNDIF_FORMATS
[i
].alsa
== format
)
179 return ALSA_SNDIF_FORMATS
[i
].sndif
;
184 static u64
to_sndif_formats_mask(u64 alsa_formats
)
190 for (i
= 0; i
< ARRAY_SIZE(ALSA_SNDIF_FORMATS
); i
++)
191 if (pcm_format_to_bits(ALSA_SNDIF_FORMATS
[i
].alsa
) & alsa_formats
)
192 mask
|= 1 << ALSA_SNDIF_FORMATS
[i
].sndif
;
197 static u64
to_alsa_formats_mask(u64 sndif_formats
)
203 for (i
= 0; i
< ARRAY_SIZE(ALSA_SNDIF_FORMATS
); i
++)
204 if (1 << ALSA_SNDIF_FORMATS
[i
].sndif
& sndif_formats
)
205 mask
|= pcm_format_to_bits(ALSA_SNDIF_FORMATS
[i
].alsa
);
210 static void stream_clear(struct xen_snd_front_pcm_stream_info
*stream
)
212 stream
->is_open
= false;
213 stream
->be_cur_frame
= 0;
214 stream
->out_frames
= 0;
215 atomic_set(&stream
->hw_ptr
, 0);
216 xen_snd_front_evtchnl_pair_clear(stream
->evt_pair
);
217 xen_snd_front_shbuf_clear(&stream
->sh_buf
);
220 static void stream_free(struct xen_snd_front_pcm_stream_info
*stream
)
222 xen_snd_front_shbuf_free(&stream
->sh_buf
);
223 stream_clear(stream
);
226 static struct xen_snd_front_pcm_stream_info
*
227 stream_get(struct snd_pcm_substream
*substream
)
229 struct xen_snd_front_pcm_instance_info
*pcm_instance
=
230 snd_pcm_substream_chip(substream
);
231 struct xen_snd_front_pcm_stream_info
*stream
;
233 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
234 stream
= &pcm_instance
->streams_pb
[substream
->number
];
236 stream
= &pcm_instance
->streams_cap
[substream
->number
];
241 static int alsa_hw_rule(struct snd_pcm_hw_params
*params
,
242 struct snd_pcm_hw_rule
*rule
)
244 struct xen_snd_front_pcm_stream_info
*stream
= rule
->private;
245 struct device
*dev
= &stream
->front_info
->xb_dev
->dev
;
246 struct snd_mask
*formats
=
247 hw_param_mask(params
, SNDRV_PCM_HW_PARAM_FORMAT
);
248 struct snd_interval
*rates
=
249 hw_param_interval(params
, SNDRV_PCM_HW_PARAM_RATE
);
250 struct snd_interval
*channels
=
251 hw_param_interval(params
, SNDRV_PCM_HW_PARAM_CHANNELS
);
252 struct snd_interval
*period
=
253 hw_param_interval(params
,
254 SNDRV_PCM_HW_PARAM_PERIOD_SIZE
);
255 struct snd_interval
*buffer
=
256 hw_param_interval(params
,
257 SNDRV_PCM_HW_PARAM_BUFFER_SIZE
);
258 struct xensnd_query_hw_param req
;
259 struct xensnd_query_hw_param resp
;
260 struct snd_interval interval
;
261 struct snd_mask mask
;
265 /* Collect all the values we need for the query. */
267 req
.formats
= to_sndif_formats_mask((u64
)formats
->bits
[0] |
268 (u64
)(formats
->bits
[1]) << 32);
270 req
.rates
.min
= rates
->min
;
271 req
.rates
.max
= rates
->max
;
273 req
.channels
.min
= channels
->min
;
274 req
.channels
.max
= channels
->max
;
276 req
.buffer
.min
= buffer
->min
;
277 req
.buffer
.max
= buffer
->max
;
279 req
.period
.min
= period
->min
;
280 req
.period
.max
= period
->max
;
282 ret
= xen_snd_front_stream_query_hw_param(&stream
->evt_pair
->req
,
285 /* Check if this is due to backend communication error. */
286 if (ret
== -EIO
|| ret
== -ETIMEDOUT
)
287 dev_err(dev
, "Failed to query ALSA HW parameters\n");
291 /* Refine HW parameters after the query. */
294 sndif_formats
= to_alsa_formats_mask(resp
.formats
);
295 snd_mask_none(&mask
);
296 mask
.bits
[0] = (u32
)sndif_formats
;
297 mask
.bits
[1] = (u32
)(sndif_formats
>> 32);
298 ret
= snd_mask_refine(formats
, &mask
);
303 interval
.openmin
= 0;
304 interval
.openmax
= 0;
305 interval
.integer
= 1;
307 interval
.min
= resp
.rates
.min
;
308 interval
.max
= resp
.rates
.max
;
309 ret
= snd_interval_refine(rates
, &interval
);
314 interval
.min
= resp
.channels
.min
;
315 interval
.max
= resp
.channels
.max
;
316 ret
= snd_interval_refine(channels
, &interval
);
321 interval
.min
= resp
.buffer
.min
;
322 interval
.max
= resp
.buffer
.max
;
323 ret
= snd_interval_refine(buffer
, &interval
);
328 interval
.min
= resp
.period
.min
;
329 interval
.max
= resp
.period
.max
;
330 ret
= snd_interval_refine(period
, &interval
);
338 static int alsa_open(struct snd_pcm_substream
*substream
)
340 struct xen_snd_front_pcm_instance_info
*pcm_instance
=
341 snd_pcm_substream_chip(substream
);
342 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
343 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
344 struct xen_snd_front_info
*front_info
=
345 pcm_instance
->card_info
->front_info
;
346 struct device
*dev
= &front_info
->xb_dev
->dev
;
350 * Return our HW properties: override defaults with those configured
353 runtime
->hw
= stream
->pcm_hw
;
354 runtime
->hw
.info
&= ~(SNDRV_PCM_INFO_MMAP
|
355 SNDRV_PCM_INFO_MMAP_VALID
|
356 SNDRV_PCM_INFO_DOUBLE
|
357 SNDRV_PCM_INFO_BATCH
|
358 SNDRV_PCM_INFO_NONINTERLEAVED
|
359 SNDRV_PCM_INFO_RESUME
|
360 SNDRV_PCM_INFO_PAUSE
);
361 runtime
->hw
.info
|= SNDRV_PCM_INFO_INTERLEAVED
;
363 stream
->evt_pair
= &front_info
->evt_pairs
[stream
->index
];
365 stream
->front_info
= front_info
;
367 stream
->evt_pair
->evt
.u
.evt
.substream
= substream
;
369 stream_clear(stream
);
371 xen_snd_front_evtchnl_pair_set_connected(stream
->evt_pair
, true);
373 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_FORMAT
,
374 alsa_hw_rule
, stream
,
375 SNDRV_PCM_HW_PARAM_FORMAT
, -1);
377 dev_err(dev
, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_FORMAT\n");
381 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_RATE
,
382 alsa_hw_rule
, stream
,
383 SNDRV_PCM_HW_PARAM_RATE
, -1);
385 dev_err(dev
, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_RATE\n");
389 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_CHANNELS
,
390 alsa_hw_rule
, stream
,
391 SNDRV_PCM_HW_PARAM_CHANNELS
, -1);
393 dev_err(dev
, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_CHANNELS\n");
397 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE
,
398 alsa_hw_rule
, stream
,
399 SNDRV_PCM_HW_PARAM_PERIOD_SIZE
, -1);
401 dev_err(dev
, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_PERIOD_SIZE\n");
405 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE
,
406 alsa_hw_rule
, stream
,
407 SNDRV_PCM_HW_PARAM_BUFFER_SIZE
, -1);
409 dev_err(dev
, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_BUFFER_SIZE\n");
416 static int alsa_close(struct snd_pcm_substream
*substream
)
418 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
420 xen_snd_front_evtchnl_pair_set_connected(stream
->evt_pair
, false);
424 static int alsa_hw_params(struct snd_pcm_substream
*substream
,
425 struct snd_pcm_hw_params
*params
)
427 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
431 * This callback may be called multiple times,
432 * so free the previously allocated shared buffer if any.
436 ret
= xen_snd_front_shbuf_alloc(stream
->front_info
->xb_dev
,
438 params_buffer_bytes(params
));
441 dev_err(&stream
->front_info
->xb_dev
->dev
,
442 "Failed to allocate buffers for stream with index %d\n",
450 static int alsa_hw_free(struct snd_pcm_substream
*substream
)
452 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
455 ret
= xen_snd_front_stream_close(&stream
->evt_pair
->req
);
460 static int alsa_prepare(struct snd_pcm_substream
*substream
)
462 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
464 if (!stream
->is_open
) {
465 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
469 ret
= to_sndif_format(runtime
->format
);
471 dev_err(&stream
->front_info
->xb_dev
->dev
,
472 "Unsupported sample format: %d\n",
478 ret
= xen_snd_front_stream_prepare(&stream
->evt_pair
->req
,
483 snd_pcm_lib_buffer_bytes(substream
),
484 snd_pcm_lib_period_bytes(substream
));
488 stream
->is_open
= true;
494 static int alsa_trigger(struct snd_pcm_substream
*substream
, int cmd
)
496 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
500 case SNDRV_PCM_TRIGGER_START
:
501 type
= XENSND_OP_TRIGGER_START
;
504 case SNDRV_PCM_TRIGGER_RESUME
:
505 type
= XENSND_OP_TRIGGER_RESUME
;
508 case SNDRV_PCM_TRIGGER_STOP
:
509 type
= XENSND_OP_TRIGGER_STOP
;
512 case SNDRV_PCM_TRIGGER_SUSPEND
:
513 type
= XENSND_OP_TRIGGER_PAUSE
;
520 return xen_snd_front_stream_trigger(&stream
->evt_pair
->req
, type
);
523 void xen_snd_front_alsa_handle_cur_pos(struct xen_snd_front_evtchnl
*evtchnl
,
526 struct snd_pcm_substream
*substream
= evtchnl
->u
.evt
.substream
;
527 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
528 snd_pcm_uframes_t delta
, new_hw_ptr
, cur_frame
;
530 cur_frame
= bytes_to_frames(substream
->runtime
, pos_bytes
);
532 delta
= cur_frame
- stream
->be_cur_frame
;
533 stream
->be_cur_frame
= cur_frame
;
535 new_hw_ptr
= (snd_pcm_uframes_t
)atomic_read(&stream
->hw_ptr
);
536 new_hw_ptr
= (new_hw_ptr
+ delta
) % substream
->runtime
->buffer_size
;
537 atomic_set(&stream
->hw_ptr
, (int)new_hw_ptr
);
539 stream
->out_frames
+= delta
;
540 if (stream
->out_frames
> substream
->runtime
->period_size
) {
541 stream
->out_frames
%= substream
->runtime
->period_size
;
542 snd_pcm_period_elapsed(substream
);
546 static snd_pcm_uframes_t
alsa_pointer(struct snd_pcm_substream
*substream
)
548 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
550 return (snd_pcm_uframes_t
)atomic_read(&stream
->hw_ptr
);
553 static int alsa_pb_copy_user(struct snd_pcm_substream
*substream
,
554 int channel
, unsigned long pos
, void __user
*src
,
557 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
559 if (unlikely(pos
+ count
> stream
->sh_buf
.buffer_sz
))
562 if (copy_from_user(stream
->sh_buf
.buffer
+ pos
, src
, count
))
565 return xen_snd_front_stream_write(&stream
->evt_pair
->req
, pos
, count
);
568 static int alsa_pb_copy_kernel(struct snd_pcm_substream
*substream
,
569 int channel
, unsigned long pos
, void *src
,
572 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
574 if (unlikely(pos
+ count
> stream
->sh_buf
.buffer_sz
))
577 memcpy(stream
->sh_buf
.buffer
+ pos
, src
, count
);
579 return xen_snd_front_stream_write(&stream
->evt_pair
->req
, pos
, count
);
582 static int alsa_cap_copy_user(struct snd_pcm_substream
*substream
,
583 int channel
, unsigned long pos
, void __user
*dst
,
586 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
589 if (unlikely(pos
+ count
> stream
->sh_buf
.buffer_sz
))
592 ret
= xen_snd_front_stream_read(&stream
->evt_pair
->req
, pos
, count
);
596 return copy_to_user(dst
, stream
->sh_buf
.buffer
+ pos
, count
) ?
600 static int alsa_cap_copy_kernel(struct snd_pcm_substream
*substream
,
601 int channel
, unsigned long pos
, void *dst
,
604 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
607 if (unlikely(pos
+ count
> stream
->sh_buf
.buffer_sz
))
610 ret
= xen_snd_front_stream_read(&stream
->evt_pair
->req
, pos
, count
);
614 memcpy(dst
, stream
->sh_buf
.buffer
+ pos
, count
);
619 static int alsa_pb_fill_silence(struct snd_pcm_substream
*substream
,
620 int channel
, unsigned long pos
,
623 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
625 if (unlikely(pos
+ count
> stream
->sh_buf
.buffer_sz
))
628 memset(stream
->sh_buf
.buffer
+ pos
, 0, count
);
630 return xen_snd_front_stream_write(&stream
->evt_pair
->req
, pos
, count
);
634 * FIXME: The mmaped data transfer is asynchronous and there is no
635 * ack signal from user-space when it is done. This is the
636 * reason it is not implemented in the PV driver as we do need
637 * to know when the buffer can be transferred to the backend.
640 static struct snd_pcm_ops snd_drv_alsa_playback_ops
= {
643 .ioctl
= snd_pcm_lib_ioctl
,
644 .hw_params
= alsa_hw_params
,
645 .hw_free
= alsa_hw_free
,
646 .prepare
= alsa_prepare
,
647 .trigger
= alsa_trigger
,
648 .pointer
= alsa_pointer
,
649 .copy_user
= alsa_pb_copy_user
,
650 .copy_kernel
= alsa_pb_copy_kernel
,
651 .fill_silence
= alsa_pb_fill_silence
,
654 static struct snd_pcm_ops snd_drv_alsa_capture_ops
= {
657 .ioctl
= snd_pcm_lib_ioctl
,
658 .hw_params
= alsa_hw_params
,
659 .hw_free
= alsa_hw_free
,
660 .prepare
= alsa_prepare
,
661 .trigger
= alsa_trigger
,
662 .pointer
= alsa_pointer
,
663 .copy_user
= alsa_cap_copy_user
,
664 .copy_kernel
= alsa_cap_copy_kernel
,
667 static int new_pcm_instance(struct xen_snd_front_card_info
*card_info
,
668 struct xen_front_cfg_pcm_instance
*instance_cfg
,
669 struct xen_snd_front_pcm_instance_info
*pcm_instance_info
)
674 dev_dbg(&card_info
->front_info
->xb_dev
->dev
,
675 "New PCM device \"%s\" with id %d playback %d capture %d",
677 instance_cfg
->device_id
,
678 instance_cfg
->num_streams_pb
,
679 instance_cfg
->num_streams_cap
);
681 pcm_instance_info
->card_info
= card_info
;
683 pcm_instance_info
->pcm_hw
= instance_cfg
->pcm_hw
;
685 if (instance_cfg
->num_streams_pb
) {
686 pcm_instance_info
->streams_pb
=
687 devm_kcalloc(&card_info
->card
->card_dev
,
688 instance_cfg
->num_streams_pb
,
689 sizeof(struct xen_snd_front_pcm_stream_info
),
691 if (!pcm_instance_info
->streams_pb
)
695 if (instance_cfg
->num_streams_cap
) {
696 pcm_instance_info
->streams_cap
=
697 devm_kcalloc(&card_info
->card
->card_dev
,
698 instance_cfg
->num_streams_cap
,
699 sizeof(struct xen_snd_front_pcm_stream_info
),
701 if (!pcm_instance_info
->streams_cap
)
705 pcm_instance_info
->num_pcm_streams_pb
=
706 instance_cfg
->num_streams_pb
;
707 pcm_instance_info
->num_pcm_streams_cap
=
708 instance_cfg
->num_streams_cap
;
710 for (i
= 0; i
< pcm_instance_info
->num_pcm_streams_pb
; i
++) {
711 pcm_instance_info
->streams_pb
[i
].pcm_hw
=
712 instance_cfg
->streams_pb
[i
].pcm_hw
;
713 pcm_instance_info
->streams_pb
[i
].index
=
714 instance_cfg
->streams_pb
[i
].index
;
717 for (i
= 0; i
< pcm_instance_info
->num_pcm_streams_cap
; i
++) {
718 pcm_instance_info
->streams_cap
[i
].pcm_hw
=
719 instance_cfg
->streams_cap
[i
].pcm_hw
;
720 pcm_instance_info
->streams_cap
[i
].index
=
721 instance_cfg
->streams_cap
[i
].index
;
724 ret
= snd_pcm_new(card_info
->card
, instance_cfg
->name
,
725 instance_cfg
->device_id
,
726 instance_cfg
->num_streams_pb
,
727 instance_cfg
->num_streams_cap
,
732 pcm
->private_data
= pcm_instance_info
;
734 /* we want to handle all PCM operations in non-atomic context */
735 pcm
->nonatomic
= true;
736 strncpy(pcm
->name
, "Virtual card PCM", sizeof(pcm
->name
));
738 if (instance_cfg
->num_streams_pb
)
739 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_PLAYBACK
,
740 &snd_drv_alsa_playback_ops
);
742 if (instance_cfg
->num_streams_cap
)
743 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
,
744 &snd_drv_alsa_capture_ops
);
746 pcm_instance_info
->pcm
= pcm
;
750 int xen_snd_front_alsa_init(struct xen_snd_front_info
*front_info
)
752 struct device
*dev
= &front_info
->xb_dev
->dev
;
753 struct xen_front_cfg_card
*cfg
= &front_info
->cfg
;
754 struct xen_snd_front_card_info
*card_info
;
755 struct snd_card
*card
;
758 dev_dbg(dev
, "Creating virtual sound card\n");
760 ret
= snd_card_new(dev
, 0, XENSND_DRIVER_NAME
, THIS_MODULE
,
761 sizeof(struct xen_snd_front_card_info
), &card
);
765 card_info
= card
->private_data
;
766 card_info
->front_info
= front_info
;
767 front_info
->card_info
= card_info
;
768 card_info
->card
= card
;
769 card_info
->pcm_instances
=
770 devm_kcalloc(dev
, cfg
->num_pcm_instances
,
771 sizeof(struct xen_snd_front_pcm_instance_info
),
773 if (!card_info
->pcm_instances
) {
778 card_info
->num_pcm_instances
= cfg
->num_pcm_instances
;
779 card_info
->pcm_hw
= cfg
->pcm_hw
;
781 for (i
= 0; i
< cfg
->num_pcm_instances
; i
++) {
782 ret
= new_pcm_instance(card_info
, &cfg
->pcm_instances
[i
],
783 &card_info
->pcm_instances
[i
]);
788 strncpy(card
->driver
, XENSND_DRIVER_NAME
, sizeof(card
->driver
));
789 strncpy(card
->shortname
, cfg
->name_short
, sizeof(card
->shortname
));
790 strncpy(card
->longname
, cfg
->name_long
, sizeof(card
->longname
));
792 ret
= snd_card_register(card
);
803 void xen_snd_front_alsa_fini(struct xen_snd_front_info
*front_info
)
805 struct xen_snd_front_card_info
*card_info
;
806 struct snd_card
*card
;
808 card_info
= front_info
->card_info
;
812 card
= card_info
->card
;
816 dev_dbg(&front_info
->xb_dev
->dev
, "Removing virtual sound card %d\n",
820 /* Card_info will be freed when destroying front_info->xb_dev->dev. */
821 card_info
->card
= NULL
;