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>
18 #include <xen/xen-front-pgdir-shbuf.h>
20 #include "xen_snd_front.h"
21 #include "xen_snd_front_alsa.h"
22 #include "xen_snd_front_cfg.h"
23 #include "xen_snd_front_evtchnl.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
;
29 /* This is the shared buffer with its backing storage. */
30 struct xen_front_pgdir_shbuf shbuf
;
39 struct snd_pcm_hardware pcm_hw
;
41 /* Number of processed frames as reported by the backend. */
42 snd_pcm_uframes_t be_cur_frame
;
43 /* Current HW pointer to be reported via .period callback. */
45 /* Modulo of the number of processed frames - for period detection. */
49 struct xen_snd_front_pcm_instance_info
{
50 struct xen_snd_front_card_info
*card_info
;
52 struct snd_pcm_hardware pcm_hw
;
53 int num_pcm_streams_pb
;
54 struct xen_snd_front_pcm_stream_info
*streams_pb
;
55 int num_pcm_streams_cap
;
56 struct xen_snd_front_pcm_stream_info
*streams_cap
;
59 struct xen_snd_front_card_info
{
60 struct xen_snd_front_info
*front_info
;
61 struct snd_card
*card
;
62 struct snd_pcm_hardware pcm_hw
;
63 int num_pcm_instances
;
64 struct xen_snd_front_pcm_instance_info
*pcm_instances
;
67 struct alsa_sndif_sample_format
{
69 snd_pcm_format_t alsa
;
72 struct alsa_sndif_hw_param
{
74 snd_pcm_hw_param_t alsa
;
77 static const struct alsa_sndif_sample_format ALSA_SNDIF_FORMATS
[] = {
79 .sndif
= XENSND_PCM_FORMAT_U8
,
80 .alsa
= SNDRV_PCM_FORMAT_U8
83 .sndif
= XENSND_PCM_FORMAT_S8
,
84 .alsa
= SNDRV_PCM_FORMAT_S8
87 .sndif
= XENSND_PCM_FORMAT_U16_LE
,
88 .alsa
= SNDRV_PCM_FORMAT_U16_LE
91 .sndif
= XENSND_PCM_FORMAT_U16_BE
,
92 .alsa
= SNDRV_PCM_FORMAT_U16_BE
95 .sndif
= XENSND_PCM_FORMAT_S16_LE
,
96 .alsa
= SNDRV_PCM_FORMAT_S16_LE
99 .sndif
= XENSND_PCM_FORMAT_S16_BE
,
100 .alsa
= SNDRV_PCM_FORMAT_S16_BE
103 .sndif
= XENSND_PCM_FORMAT_U24_LE
,
104 .alsa
= SNDRV_PCM_FORMAT_U24_LE
107 .sndif
= XENSND_PCM_FORMAT_U24_BE
,
108 .alsa
= SNDRV_PCM_FORMAT_U24_BE
111 .sndif
= XENSND_PCM_FORMAT_S24_LE
,
112 .alsa
= SNDRV_PCM_FORMAT_S24_LE
115 .sndif
= XENSND_PCM_FORMAT_S24_BE
,
116 .alsa
= SNDRV_PCM_FORMAT_S24_BE
119 .sndif
= XENSND_PCM_FORMAT_U32_LE
,
120 .alsa
= SNDRV_PCM_FORMAT_U32_LE
123 .sndif
= XENSND_PCM_FORMAT_U32_BE
,
124 .alsa
= SNDRV_PCM_FORMAT_U32_BE
127 .sndif
= XENSND_PCM_FORMAT_S32_LE
,
128 .alsa
= SNDRV_PCM_FORMAT_S32_LE
131 .sndif
= XENSND_PCM_FORMAT_S32_BE
,
132 .alsa
= SNDRV_PCM_FORMAT_S32_BE
135 .sndif
= XENSND_PCM_FORMAT_A_LAW
,
136 .alsa
= SNDRV_PCM_FORMAT_A_LAW
139 .sndif
= XENSND_PCM_FORMAT_MU_LAW
,
140 .alsa
= SNDRV_PCM_FORMAT_MU_LAW
143 .sndif
= XENSND_PCM_FORMAT_F32_LE
,
144 .alsa
= SNDRV_PCM_FORMAT_FLOAT_LE
147 .sndif
= XENSND_PCM_FORMAT_F32_BE
,
148 .alsa
= SNDRV_PCM_FORMAT_FLOAT_BE
151 .sndif
= XENSND_PCM_FORMAT_F64_LE
,
152 .alsa
= SNDRV_PCM_FORMAT_FLOAT64_LE
155 .sndif
= XENSND_PCM_FORMAT_F64_BE
,
156 .alsa
= SNDRV_PCM_FORMAT_FLOAT64_BE
159 .sndif
= XENSND_PCM_FORMAT_IEC958_SUBFRAME_LE
,
160 .alsa
= SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE
163 .sndif
= XENSND_PCM_FORMAT_IEC958_SUBFRAME_BE
,
164 .alsa
= SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE
167 .sndif
= XENSND_PCM_FORMAT_IMA_ADPCM
,
168 .alsa
= SNDRV_PCM_FORMAT_IMA_ADPCM
171 .sndif
= XENSND_PCM_FORMAT_MPEG
,
172 .alsa
= SNDRV_PCM_FORMAT_MPEG
175 .sndif
= XENSND_PCM_FORMAT_GSM
,
176 .alsa
= SNDRV_PCM_FORMAT_GSM
180 static int to_sndif_format(snd_pcm_format_t format
)
184 for (i
= 0; i
< ARRAY_SIZE(ALSA_SNDIF_FORMATS
); i
++)
185 if (ALSA_SNDIF_FORMATS
[i
].alsa
== format
)
186 return ALSA_SNDIF_FORMATS
[i
].sndif
;
191 static u64
to_sndif_formats_mask(u64 alsa_formats
)
197 for (i
= 0; i
< ARRAY_SIZE(ALSA_SNDIF_FORMATS
); i
++)
198 if (pcm_format_to_bits(ALSA_SNDIF_FORMATS
[i
].alsa
) & alsa_formats
)
199 mask
|= 1 << ALSA_SNDIF_FORMATS
[i
].sndif
;
204 static u64
to_alsa_formats_mask(u64 sndif_formats
)
210 for (i
= 0; i
< ARRAY_SIZE(ALSA_SNDIF_FORMATS
); i
++)
211 if (1 << ALSA_SNDIF_FORMATS
[i
].sndif
& sndif_formats
)
212 mask
|= pcm_format_to_bits(ALSA_SNDIF_FORMATS
[i
].alsa
);
217 static void stream_clear(struct xen_snd_front_pcm_stream_info
*stream
)
219 stream
->is_open
= false;
220 stream
->be_cur_frame
= 0;
221 stream
->out_frames
= 0;
222 atomic_set(&stream
->hw_ptr
, 0);
223 xen_snd_front_evtchnl_pair_clear(stream
->evt_pair
);
224 memset(&stream
->shbuf
, 0, sizeof(stream
->shbuf
));
225 stream
->buffer
= NULL
;
226 stream
->buffer_sz
= 0;
227 stream
->pages
= NULL
;
228 stream
->num_pages
= 0;
231 static void stream_free(struct xen_snd_front_pcm_stream_info
*stream
)
233 xen_front_pgdir_shbuf_unmap(&stream
->shbuf
);
234 xen_front_pgdir_shbuf_free(&stream
->shbuf
);
236 free_pages_exact(stream
->buffer
, stream
->buffer_sz
);
237 kfree(stream
->pages
);
238 stream_clear(stream
);
241 static struct xen_snd_front_pcm_stream_info
*
242 stream_get(struct snd_pcm_substream
*substream
)
244 struct xen_snd_front_pcm_instance_info
*pcm_instance
=
245 snd_pcm_substream_chip(substream
);
246 struct xen_snd_front_pcm_stream_info
*stream
;
248 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
249 stream
= &pcm_instance
->streams_pb
[substream
->number
];
251 stream
= &pcm_instance
->streams_cap
[substream
->number
];
256 static int alsa_hw_rule(struct snd_pcm_hw_params
*params
,
257 struct snd_pcm_hw_rule
*rule
)
259 struct xen_snd_front_pcm_stream_info
*stream
= rule
->private;
260 struct device
*dev
= &stream
->front_info
->xb_dev
->dev
;
261 struct snd_mask
*formats
=
262 hw_param_mask(params
, SNDRV_PCM_HW_PARAM_FORMAT
);
263 struct snd_interval
*rates
=
264 hw_param_interval(params
, SNDRV_PCM_HW_PARAM_RATE
);
265 struct snd_interval
*channels
=
266 hw_param_interval(params
, SNDRV_PCM_HW_PARAM_CHANNELS
);
267 struct snd_interval
*period
=
268 hw_param_interval(params
,
269 SNDRV_PCM_HW_PARAM_PERIOD_SIZE
);
270 struct snd_interval
*buffer
=
271 hw_param_interval(params
,
272 SNDRV_PCM_HW_PARAM_BUFFER_SIZE
);
273 struct xensnd_query_hw_param req
;
274 struct xensnd_query_hw_param resp
;
275 struct snd_interval interval
;
276 struct snd_mask mask
;
280 /* Collect all the values we need for the query. */
282 req
.formats
= to_sndif_formats_mask((u64
)formats
->bits
[0] |
283 (u64
)(formats
->bits
[1]) << 32);
285 req
.rates
.min
= rates
->min
;
286 req
.rates
.max
= rates
->max
;
288 req
.channels
.min
= channels
->min
;
289 req
.channels
.max
= channels
->max
;
291 req
.buffer
.min
= buffer
->min
;
292 req
.buffer
.max
= buffer
->max
;
294 req
.period
.min
= period
->min
;
295 req
.period
.max
= period
->max
;
297 ret
= xen_snd_front_stream_query_hw_param(&stream
->evt_pair
->req
,
300 /* Check if this is due to backend communication error. */
301 if (ret
== -EIO
|| ret
== -ETIMEDOUT
)
302 dev_err(dev
, "Failed to query ALSA HW parameters\n");
306 /* Refine HW parameters after the query. */
309 sndif_formats
= to_alsa_formats_mask(resp
.formats
);
310 snd_mask_none(&mask
);
311 mask
.bits
[0] = (u32
)sndif_formats
;
312 mask
.bits
[1] = (u32
)(sndif_formats
>> 32);
313 ret
= snd_mask_refine(formats
, &mask
);
318 interval
.openmin
= 0;
319 interval
.openmax
= 0;
320 interval
.integer
= 1;
322 interval
.min
= resp
.rates
.min
;
323 interval
.max
= resp
.rates
.max
;
324 ret
= snd_interval_refine(rates
, &interval
);
329 interval
.min
= resp
.channels
.min
;
330 interval
.max
= resp
.channels
.max
;
331 ret
= snd_interval_refine(channels
, &interval
);
336 interval
.min
= resp
.buffer
.min
;
337 interval
.max
= resp
.buffer
.max
;
338 ret
= snd_interval_refine(buffer
, &interval
);
343 interval
.min
= resp
.period
.min
;
344 interval
.max
= resp
.period
.max
;
345 ret
= snd_interval_refine(period
, &interval
);
353 static int alsa_open(struct snd_pcm_substream
*substream
)
355 struct xen_snd_front_pcm_instance_info
*pcm_instance
=
356 snd_pcm_substream_chip(substream
);
357 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
358 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
359 struct xen_snd_front_info
*front_info
=
360 pcm_instance
->card_info
->front_info
;
361 struct device
*dev
= &front_info
->xb_dev
->dev
;
365 * Return our HW properties: override defaults with those configured
368 runtime
->hw
= stream
->pcm_hw
;
369 runtime
->hw
.info
&= ~(SNDRV_PCM_INFO_MMAP
|
370 SNDRV_PCM_INFO_MMAP_VALID
|
371 SNDRV_PCM_INFO_DOUBLE
|
372 SNDRV_PCM_INFO_BATCH
|
373 SNDRV_PCM_INFO_NONINTERLEAVED
|
374 SNDRV_PCM_INFO_RESUME
|
375 SNDRV_PCM_INFO_PAUSE
);
376 runtime
->hw
.info
|= SNDRV_PCM_INFO_INTERLEAVED
;
378 stream
->evt_pair
= &front_info
->evt_pairs
[stream
->index
];
380 stream
->front_info
= front_info
;
382 stream
->evt_pair
->evt
.u
.evt
.substream
= substream
;
384 stream_clear(stream
);
386 xen_snd_front_evtchnl_pair_set_connected(stream
->evt_pair
, true);
388 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_FORMAT
,
389 alsa_hw_rule
, stream
,
390 SNDRV_PCM_HW_PARAM_FORMAT
, -1);
392 dev_err(dev
, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_FORMAT\n");
396 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_RATE
,
397 alsa_hw_rule
, stream
,
398 SNDRV_PCM_HW_PARAM_RATE
, -1);
400 dev_err(dev
, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_RATE\n");
404 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_CHANNELS
,
405 alsa_hw_rule
, stream
,
406 SNDRV_PCM_HW_PARAM_CHANNELS
, -1);
408 dev_err(dev
, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_CHANNELS\n");
412 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE
,
413 alsa_hw_rule
, stream
,
414 SNDRV_PCM_HW_PARAM_PERIOD_SIZE
, -1);
416 dev_err(dev
, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_PERIOD_SIZE\n");
420 ret
= snd_pcm_hw_rule_add(runtime
, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE
,
421 alsa_hw_rule
, stream
,
422 SNDRV_PCM_HW_PARAM_BUFFER_SIZE
, -1);
424 dev_err(dev
, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_BUFFER_SIZE\n");
431 static int alsa_close(struct snd_pcm_substream
*substream
)
433 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
435 xen_snd_front_evtchnl_pair_set_connected(stream
->evt_pair
, false);
439 static int shbuf_setup_backstore(struct xen_snd_front_pcm_stream_info
*stream
,
444 stream
->buffer
= alloc_pages_exact(stream
->buffer_sz
, GFP_KERNEL
);
448 stream
->buffer_sz
= buffer_sz
;
449 stream
->num_pages
= DIV_ROUND_UP(stream
->buffer_sz
, PAGE_SIZE
);
450 stream
->pages
= kcalloc(stream
->num_pages
, sizeof(struct page
*),
455 for (i
= 0; i
< stream
->num_pages
; i
++)
456 stream
->pages
[i
] = virt_to_page(stream
->buffer
+ i
* PAGE_SIZE
);
461 static int alsa_hw_params(struct snd_pcm_substream
*substream
,
462 struct snd_pcm_hw_params
*params
)
464 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
465 struct xen_snd_front_info
*front_info
= stream
->front_info
;
466 struct xen_front_pgdir_shbuf_cfg buf_cfg
;
470 * This callback may be called multiple times,
471 * so free the previously allocated shared buffer if any.
474 ret
= shbuf_setup_backstore(stream
, params_buffer_bytes(params
));
478 memset(&buf_cfg
, 0, sizeof(buf_cfg
));
479 buf_cfg
.xb_dev
= front_info
->xb_dev
;
480 buf_cfg
.pgdir
= &stream
->shbuf
;
481 buf_cfg
.num_pages
= stream
->num_pages
;
482 buf_cfg
.pages
= stream
->pages
;
484 ret
= xen_front_pgdir_shbuf_alloc(&buf_cfg
);
488 ret
= xen_front_pgdir_shbuf_map(&stream
->shbuf
);
496 dev_err(&front_info
->xb_dev
->dev
,
497 "Failed to allocate buffers for stream with index %d\n",
502 static int alsa_hw_free(struct snd_pcm_substream
*substream
)
504 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
507 ret
= xen_snd_front_stream_close(&stream
->evt_pair
->req
);
512 static int alsa_prepare(struct snd_pcm_substream
*substream
)
514 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
516 if (!stream
->is_open
) {
517 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
521 ret
= to_sndif_format(runtime
->format
);
523 dev_err(&stream
->front_info
->xb_dev
->dev
,
524 "Unsupported sample format: %d\n",
530 ret
= xen_snd_front_stream_prepare(&stream
->evt_pair
->req
,
535 snd_pcm_lib_buffer_bytes(substream
),
536 snd_pcm_lib_period_bytes(substream
));
540 stream
->is_open
= true;
546 static int alsa_trigger(struct snd_pcm_substream
*substream
, int cmd
)
548 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
552 case SNDRV_PCM_TRIGGER_START
:
553 type
= XENSND_OP_TRIGGER_START
;
556 case SNDRV_PCM_TRIGGER_RESUME
:
557 type
= XENSND_OP_TRIGGER_RESUME
;
560 case SNDRV_PCM_TRIGGER_STOP
:
561 type
= XENSND_OP_TRIGGER_STOP
;
564 case SNDRV_PCM_TRIGGER_SUSPEND
:
565 type
= XENSND_OP_TRIGGER_PAUSE
;
572 return xen_snd_front_stream_trigger(&stream
->evt_pair
->req
, type
);
575 void xen_snd_front_alsa_handle_cur_pos(struct xen_snd_front_evtchnl
*evtchnl
,
578 struct snd_pcm_substream
*substream
= evtchnl
->u
.evt
.substream
;
579 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
580 snd_pcm_uframes_t delta
, new_hw_ptr
, cur_frame
;
582 cur_frame
= bytes_to_frames(substream
->runtime
, pos_bytes
);
584 delta
= cur_frame
- stream
->be_cur_frame
;
585 stream
->be_cur_frame
= cur_frame
;
587 new_hw_ptr
= (snd_pcm_uframes_t
)atomic_read(&stream
->hw_ptr
);
588 new_hw_ptr
= (new_hw_ptr
+ delta
) % substream
->runtime
->buffer_size
;
589 atomic_set(&stream
->hw_ptr
, (int)new_hw_ptr
);
591 stream
->out_frames
+= delta
;
592 if (stream
->out_frames
> substream
->runtime
->period_size
) {
593 stream
->out_frames
%= substream
->runtime
->period_size
;
594 snd_pcm_period_elapsed(substream
);
598 static snd_pcm_uframes_t
alsa_pointer(struct snd_pcm_substream
*substream
)
600 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
602 return (snd_pcm_uframes_t
)atomic_read(&stream
->hw_ptr
);
605 static int alsa_pb_copy_user(struct snd_pcm_substream
*substream
,
606 int channel
, unsigned long pos
, void __user
*src
,
609 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
611 if (unlikely(pos
+ count
> stream
->buffer_sz
))
614 if (copy_from_user(stream
->buffer
+ pos
, src
, count
))
617 return xen_snd_front_stream_write(&stream
->evt_pair
->req
, pos
, count
);
620 static int alsa_pb_copy_kernel(struct snd_pcm_substream
*substream
,
621 int channel
, unsigned long pos
, void *src
,
624 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
626 if (unlikely(pos
+ count
> stream
->buffer_sz
))
629 memcpy(stream
->buffer
+ pos
, src
, count
);
631 return xen_snd_front_stream_write(&stream
->evt_pair
->req
, pos
, count
);
634 static int alsa_cap_copy_user(struct snd_pcm_substream
*substream
,
635 int channel
, unsigned long pos
, void __user
*dst
,
638 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
641 if (unlikely(pos
+ count
> stream
->buffer_sz
))
644 ret
= xen_snd_front_stream_read(&stream
->evt_pair
->req
, pos
, count
);
648 return copy_to_user(dst
, stream
->buffer
+ pos
, count
) ?
652 static int alsa_cap_copy_kernel(struct snd_pcm_substream
*substream
,
653 int channel
, unsigned long pos
, void *dst
,
656 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
659 if (unlikely(pos
+ count
> stream
->buffer_sz
))
662 ret
= xen_snd_front_stream_read(&stream
->evt_pair
->req
, pos
, count
);
666 memcpy(dst
, stream
->buffer
+ pos
, count
);
671 static int alsa_pb_fill_silence(struct snd_pcm_substream
*substream
,
672 int channel
, unsigned long pos
,
675 struct xen_snd_front_pcm_stream_info
*stream
= stream_get(substream
);
677 if (unlikely(pos
+ count
> stream
->buffer_sz
))
680 memset(stream
->buffer
+ pos
, 0, count
);
682 return xen_snd_front_stream_write(&stream
->evt_pair
->req
, pos
, count
);
686 * FIXME: The mmaped data transfer is asynchronous and there is no
687 * ack signal from user-space when it is done. This is the
688 * reason it is not implemented in the PV driver as we do need
689 * to know when the buffer can be transferred to the backend.
692 static const struct snd_pcm_ops snd_drv_alsa_playback_ops
= {
695 .ioctl
= snd_pcm_lib_ioctl
,
696 .hw_params
= alsa_hw_params
,
697 .hw_free
= alsa_hw_free
,
698 .prepare
= alsa_prepare
,
699 .trigger
= alsa_trigger
,
700 .pointer
= alsa_pointer
,
701 .copy_user
= alsa_pb_copy_user
,
702 .copy_kernel
= alsa_pb_copy_kernel
,
703 .fill_silence
= alsa_pb_fill_silence
,
706 static const struct snd_pcm_ops snd_drv_alsa_capture_ops
= {
709 .ioctl
= snd_pcm_lib_ioctl
,
710 .hw_params
= alsa_hw_params
,
711 .hw_free
= alsa_hw_free
,
712 .prepare
= alsa_prepare
,
713 .trigger
= alsa_trigger
,
714 .pointer
= alsa_pointer
,
715 .copy_user
= alsa_cap_copy_user
,
716 .copy_kernel
= alsa_cap_copy_kernel
,
719 static int new_pcm_instance(struct xen_snd_front_card_info
*card_info
,
720 struct xen_front_cfg_pcm_instance
*instance_cfg
,
721 struct xen_snd_front_pcm_instance_info
*pcm_instance_info
)
726 dev_dbg(&card_info
->front_info
->xb_dev
->dev
,
727 "New PCM device \"%s\" with id %d playback %d capture %d",
729 instance_cfg
->device_id
,
730 instance_cfg
->num_streams_pb
,
731 instance_cfg
->num_streams_cap
);
733 pcm_instance_info
->card_info
= card_info
;
735 pcm_instance_info
->pcm_hw
= instance_cfg
->pcm_hw
;
737 if (instance_cfg
->num_streams_pb
) {
738 pcm_instance_info
->streams_pb
=
739 devm_kcalloc(&card_info
->card
->card_dev
,
740 instance_cfg
->num_streams_pb
,
741 sizeof(struct xen_snd_front_pcm_stream_info
),
743 if (!pcm_instance_info
->streams_pb
)
747 if (instance_cfg
->num_streams_cap
) {
748 pcm_instance_info
->streams_cap
=
749 devm_kcalloc(&card_info
->card
->card_dev
,
750 instance_cfg
->num_streams_cap
,
751 sizeof(struct xen_snd_front_pcm_stream_info
),
753 if (!pcm_instance_info
->streams_cap
)
757 pcm_instance_info
->num_pcm_streams_pb
=
758 instance_cfg
->num_streams_pb
;
759 pcm_instance_info
->num_pcm_streams_cap
=
760 instance_cfg
->num_streams_cap
;
762 for (i
= 0; i
< pcm_instance_info
->num_pcm_streams_pb
; i
++) {
763 pcm_instance_info
->streams_pb
[i
].pcm_hw
=
764 instance_cfg
->streams_pb
[i
].pcm_hw
;
765 pcm_instance_info
->streams_pb
[i
].index
=
766 instance_cfg
->streams_pb
[i
].index
;
769 for (i
= 0; i
< pcm_instance_info
->num_pcm_streams_cap
; i
++) {
770 pcm_instance_info
->streams_cap
[i
].pcm_hw
=
771 instance_cfg
->streams_cap
[i
].pcm_hw
;
772 pcm_instance_info
->streams_cap
[i
].index
=
773 instance_cfg
->streams_cap
[i
].index
;
776 ret
= snd_pcm_new(card_info
->card
, instance_cfg
->name
,
777 instance_cfg
->device_id
,
778 instance_cfg
->num_streams_pb
,
779 instance_cfg
->num_streams_cap
,
784 pcm
->private_data
= pcm_instance_info
;
786 /* we want to handle all PCM operations in non-atomic context */
787 pcm
->nonatomic
= true;
788 strncpy(pcm
->name
, "Virtual card PCM", sizeof(pcm
->name
));
790 if (instance_cfg
->num_streams_pb
)
791 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_PLAYBACK
,
792 &snd_drv_alsa_playback_ops
);
794 if (instance_cfg
->num_streams_cap
)
795 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
,
796 &snd_drv_alsa_capture_ops
);
798 pcm_instance_info
->pcm
= pcm
;
802 int xen_snd_front_alsa_init(struct xen_snd_front_info
*front_info
)
804 struct device
*dev
= &front_info
->xb_dev
->dev
;
805 struct xen_front_cfg_card
*cfg
= &front_info
->cfg
;
806 struct xen_snd_front_card_info
*card_info
;
807 struct snd_card
*card
;
810 dev_dbg(dev
, "Creating virtual sound card\n");
812 ret
= snd_card_new(dev
, 0, XENSND_DRIVER_NAME
, THIS_MODULE
,
813 sizeof(struct xen_snd_front_card_info
), &card
);
817 card_info
= card
->private_data
;
818 card_info
->front_info
= front_info
;
819 front_info
->card_info
= card_info
;
820 card_info
->card
= card
;
821 card_info
->pcm_instances
=
822 devm_kcalloc(dev
, cfg
->num_pcm_instances
,
823 sizeof(struct xen_snd_front_pcm_instance_info
),
825 if (!card_info
->pcm_instances
) {
830 card_info
->num_pcm_instances
= cfg
->num_pcm_instances
;
831 card_info
->pcm_hw
= cfg
->pcm_hw
;
833 for (i
= 0; i
< cfg
->num_pcm_instances
; i
++) {
834 ret
= new_pcm_instance(card_info
, &cfg
->pcm_instances
[i
],
835 &card_info
->pcm_instances
[i
]);
840 strncpy(card
->driver
, XENSND_DRIVER_NAME
, sizeof(card
->driver
));
841 strncpy(card
->shortname
, cfg
->name_short
, sizeof(card
->shortname
));
842 strncpy(card
->longname
, cfg
->name_long
, sizeof(card
->longname
));
844 ret
= snd_card_register(card
);
855 void xen_snd_front_alsa_fini(struct xen_snd_front_info
*front_info
)
857 struct xen_snd_front_card_info
*card_info
;
858 struct snd_card
*card
;
860 card_info
= front_info
->card_info
;
864 card
= card_info
->card
;
868 dev_dbg(&front_info
->xb_dev
->dev
, "Removing virtual sound card %d\n",
872 /* Card_info will be freed when destroying front_info->xb_dev->dev. */
873 card_info
->card
= NULL
;