0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/platform_device.h>
0012
0013 #include <sound/core.h>
0014 #include <sound/pcm.h>
0015 #include <sound/pcm_params.h>
0016
0017 #include <xen/xenbus.h>
0018 #include <xen/xen-front-pgdir-shbuf.h>
0019
0020 #include "xen_snd_front.h"
0021 #include "xen_snd_front_alsa.h"
0022 #include "xen_snd_front_cfg.h"
0023 #include "xen_snd_front_evtchnl.h"
0024
0025 struct xen_snd_front_pcm_stream_info {
0026 struct xen_snd_front_info *front_info;
0027 struct xen_snd_front_evtchnl_pair *evt_pair;
0028
0029
0030 struct xen_front_pgdir_shbuf shbuf;
0031 u8 *buffer;
0032 size_t buffer_sz;
0033 int num_pages;
0034 struct page **pages;
0035
0036 int index;
0037
0038 bool is_open;
0039 struct snd_pcm_hardware pcm_hw;
0040
0041
0042 snd_pcm_uframes_t be_cur_frame;
0043
0044 atomic_t hw_ptr;
0045
0046 u32 out_frames;
0047 };
0048
0049 struct xen_snd_front_pcm_instance_info {
0050 struct xen_snd_front_card_info *card_info;
0051 struct snd_pcm *pcm;
0052 struct snd_pcm_hardware pcm_hw;
0053 int num_pcm_streams_pb;
0054 struct xen_snd_front_pcm_stream_info *streams_pb;
0055 int num_pcm_streams_cap;
0056 struct xen_snd_front_pcm_stream_info *streams_cap;
0057 };
0058
0059 struct xen_snd_front_card_info {
0060 struct xen_snd_front_info *front_info;
0061 struct snd_card *card;
0062 struct snd_pcm_hardware pcm_hw;
0063 int num_pcm_instances;
0064 struct xen_snd_front_pcm_instance_info *pcm_instances;
0065 };
0066
0067 struct alsa_sndif_sample_format {
0068 u8 sndif;
0069 snd_pcm_format_t alsa;
0070 };
0071
0072 struct alsa_sndif_hw_param {
0073 u8 sndif;
0074 snd_pcm_hw_param_t alsa;
0075 };
0076
0077 static const struct alsa_sndif_sample_format ALSA_SNDIF_FORMATS[] = {
0078 {
0079 .sndif = XENSND_PCM_FORMAT_U8,
0080 .alsa = SNDRV_PCM_FORMAT_U8
0081 },
0082 {
0083 .sndif = XENSND_PCM_FORMAT_S8,
0084 .alsa = SNDRV_PCM_FORMAT_S8
0085 },
0086 {
0087 .sndif = XENSND_PCM_FORMAT_U16_LE,
0088 .alsa = SNDRV_PCM_FORMAT_U16_LE
0089 },
0090 {
0091 .sndif = XENSND_PCM_FORMAT_U16_BE,
0092 .alsa = SNDRV_PCM_FORMAT_U16_BE
0093 },
0094 {
0095 .sndif = XENSND_PCM_FORMAT_S16_LE,
0096 .alsa = SNDRV_PCM_FORMAT_S16_LE
0097 },
0098 {
0099 .sndif = XENSND_PCM_FORMAT_S16_BE,
0100 .alsa = SNDRV_PCM_FORMAT_S16_BE
0101 },
0102 {
0103 .sndif = XENSND_PCM_FORMAT_U24_LE,
0104 .alsa = SNDRV_PCM_FORMAT_U24_LE
0105 },
0106 {
0107 .sndif = XENSND_PCM_FORMAT_U24_BE,
0108 .alsa = SNDRV_PCM_FORMAT_U24_BE
0109 },
0110 {
0111 .sndif = XENSND_PCM_FORMAT_S24_LE,
0112 .alsa = SNDRV_PCM_FORMAT_S24_LE
0113 },
0114 {
0115 .sndif = XENSND_PCM_FORMAT_S24_BE,
0116 .alsa = SNDRV_PCM_FORMAT_S24_BE
0117 },
0118 {
0119 .sndif = XENSND_PCM_FORMAT_U32_LE,
0120 .alsa = SNDRV_PCM_FORMAT_U32_LE
0121 },
0122 {
0123 .sndif = XENSND_PCM_FORMAT_U32_BE,
0124 .alsa = SNDRV_PCM_FORMAT_U32_BE
0125 },
0126 {
0127 .sndif = XENSND_PCM_FORMAT_S32_LE,
0128 .alsa = SNDRV_PCM_FORMAT_S32_LE
0129 },
0130 {
0131 .sndif = XENSND_PCM_FORMAT_S32_BE,
0132 .alsa = SNDRV_PCM_FORMAT_S32_BE
0133 },
0134 {
0135 .sndif = XENSND_PCM_FORMAT_A_LAW,
0136 .alsa = SNDRV_PCM_FORMAT_A_LAW
0137 },
0138 {
0139 .sndif = XENSND_PCM_FORMAT_MU_LAW,
0140 .alsa = SNDRV_PCM_FORMAT_MU_LAW
0141 },
0142 {
0143 .sndif = XENSND_PCM_FORMAT_F32_LE,
0144 .alsa = SNDRV_PCM_FORMAT_FLOAT_LE
0145 },
0146 {
0147 .sndif = XENSND_PCM_FORMAT_F32_BE,
0148 .alsa = SNDRV_PCM_FORMAT_FLOAT_BE
0149 },
0150 {
0151 .sndif = XENSND_PCM_FORMAT_F64_LE,
0152 .alsa = SNDRV_PCM_FORMAT_FLOAT64_LE
0153 },
0154 {
0155 .sndif = XENSND_PCM_FORMAT_F64_BE,
0156 .alsa = SNDRV_PCM_FORMAT_FLOAT64_BE
0157 },
0158 {
0159 .sndif = XENSND_PCM_FORMAT_IEC958_SUBFRAME_LE,
0160 .alsa = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE
0161 },
0162 {
0163 .sndif = XENSND_PCM_FORMAT_IEC958_SUBFRAME_BE,
0164 .alsa = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE
0165 },
0166 {
0167 .sndif = XENSND_PCM_FORMAT_IMA_ADPCM,
0168 .alsa = SNDRV_PCM_FORMAT_IMA_ADPCM
0169 },
0170 {
0171 .sndif = XENSND_PCM_FORMAT_MPEG,
0172 .alsa = SNDRV_PCM_FORMAT_MPEG
0173 },
0174 {
0175 .sndif = XENSND_PCM_FORMAT_GSM,
0176 .alsa = SNDRV_PCM_FORMAT_GSM
0177 },
0178 };
0179
0180 static int to_sndif_format(snd_pcm_format_t format)
0181 {
0182 int i;
0183
0184 for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++)
0185 if (ALSA_SNDIF_FORMATS[i].alsa == format)
0186 return ALSA_SNDIF_FORMATS[i].sndif;
0187
0188 return -EINVAL;
0189 }
0190
0191 static u64 to_sndif_formats_mask(u64 alsa_formats)
0192 {
0193 u64 mask;
0194 int i;
0195
0196 mask = 0;
0197 for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++)
0198 if (pcm_format_to_bits(ALSA_SNDIF_FORMATS[i].alsa) & alsa_formats)
0199 mask |= BIT_ULL(ALSA_SNDIF_FORMATS[i].sndif);
0200
0201 return mask;
0202 }
0203
0204 static u64 to_alsa_formats_mask(u64 sndif_formats)
0205 {
0206 u64 mask;
0207 int i;
0208
0209 mask = 0;
0210 for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++)
0211 if (BIT_ULL(ALSA_SNDIF_FORMATS[i].sndif) & sndif_formats)
0212 mask |= pcm_format_to_bits(ALSA_SNDIF_FORMATS[i].alsa);
0213
0214 return mask;
0215 }
0216
0217 static void stream_clear(struct xen_snd_front_pcm_stream_info *stream)
0218 {
0219 stream->is_open = false;
0220 stream->be_cur_frame = 0;
0221 stream->out_frames = 0;
0222 atomic_set(&stream->hw_ptr, 0);
0223 xen_snd_front_evtchnl_pair_clear(stream->evt_pair);
0224 memset(&stream->shbuf, 0, sizeof(stream->shbuf));
0225 stream->buffer = NULL;
0226 stream->buffer_sz = 0;
0227 stream->pages = NULL;
0228 stream->num_pages = 0;
0229 }
0230
0231 static void stream_free(struct xen_snd_front_pcm_stream_info *stream)
0232 {
0233 xen_front_pgdir_shbuf_unmap(&stream->shbuf);
0234 xen_front_pgdir_shbuf_free(&stream->shbuf);
0235 if (stream->buffer)
0236 free_pages_exact(stream->buffer, stream->buffer_sz);
0237 kfree(stream->pages);
0238 stream_clear(stream);
0239 }
0240
0241 static struct xen_snd_front_pcm_stream_info *
0242 stream_get(struct snd_pcm_substream *substream)
0243 {
0244 struct xen_snd_front_pcm_instance_info *pcm_instance =
0245 snd_pcm_substream_chip(substream);
0246 struct xen_snd_front_pcm_stream_info *stream;
0247
0248 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0249 stream = &pcm_instance->streams_pb[substream->number];
0250 else
0251 stream = &pcm_instance->streams_cap[substream->number];
0252
0253 return stream;
0254 }
0255
0256 static int alsa_hw_rule(struct snd_pcm_hw_params *params,
0257 struct snd_pcm_hw_rule *rule)
0258 {
0259 struct xen_snd_front_pcm_stream_info *stream = rule->private;
0260 struct device *dev = &stream->front_info->xb_dev->dev;
0261 struct snd_mask *formats =
0262 hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
0263 struct snd_interval *rates =
0264 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
0265 struct snd_interval *channels =
0266 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
0267 struct snd_interval *period =
0268 hw_param_interval(params,
0269 SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
0270 struct snd_interval *buffer =
0271 hw_param_interval(params,
0272 SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
0273 struct xensnd_query_hw_param req;
0274 struct xensnd_query_hw_param resp;
0275 struct snd_interval interval;
0276 struct snd_mask mask;
0277 u64 sndif_formats;
0278 int changed, ret;
0279
0280
0281
0282 req.formats = to_sndif_formats_mask((u64)formats->bits[0] |
0283 (u64)(formats->bits[1]) << 32);
0284
0285 req.rates.min = rates->min;
0286 req.rates.max = rates->max;
0287
0288 req.channels.min = channels->min;
0289 req.channels.max = channels->max;
0290
0291 req.buffer.min = buffer->min;
0292 req.buffer.max = buffer->max;
0293
0294 req.period.min = period->min;
0295 req.period.max = period->max;
0296
0297 ret = xen_snd_front_stream_query_hw_param(&stream->evt_pair->req,
0298 &req, &resp);
0299 if (ret < 0) {
0300
0301 if (ret == -EIO || ret == -ETIMEDOUT)
0302 dev_err(dev, "Failed to query ALSA HW parameters\n");
0303 return ret;
0304 }
0305
0306
0307 changed = 0;
0308
0309 sndif_formats = to_alsa_formats_mask(resp.formats);
0310 snd_mask_none(&mask);
0311 mask.bits[0] = (u32)sndif_formats;
0312 mask.bits[1] = (u32)(sndif_formats >> 32);
0313 ret = snd_mask_refine(formats, &mask);
0314 if (ret < 0)
0315 return ret;
0316 changed |= ret;
0317
0318 interval.openmin = 0;
0319 interval.openmax = 0;
0320 interval.integer = 1;
0321
0322 interval.min = resp.rates.min;
0323 interval.max = resp.rates.max;
0324 ret = snd_interval_refine(rates, &interval);
0325 if (ret < 0)
0326 return ret;
0327 changed |= ret;
0328
0329 interval.min = resp.channels.min;
0330 interval.max = resp.channels.max;
0331 ret = snd_interval_refine(channels, &interval);
0332 if (ret < 0)
0333 return ret;
0334 changed |= ret;
0335
0336 interval.min = resp.buffer.min;
0337 interval.max = resp.buffer.max;
0338 ret = snd_interval_refine(buffer, &interval);
0339 if (ret < 0)
0340 return ret;
0341 changed |= ret;
0342
0343 interval.min = resp.period.min;
0344 interval.max = resp.period.max;
0345 ret = snd_interval_refine(period, &interval);
0346 if (ret < 0)
0347 return ret;
0348 changed |= ret;
0349
0350 return changed;
0351 }
0352
0353 static int alsa_open(struct snd_pcm_substream *substream)
0354 {
0355 struct xen_snd_front_pcm_instance_info *pcm_instance =
0356 snd_pcm_substream_chip(substream);
0357 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0358 struct snd_pcm_runtime *runtime = substream->runtime;
0359 struct xen_snd_front_info *front_info =
0360 pcm_instance->card_info->front_info;
0361 struct device *dev = &front_info->xb_dev->dev;
0362 int ret;
0363
0364
0365
0366
0367
0368 runtime->hw = stream->pcm_hw;
0369 runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
0370 SNDRV_PCM_INFO_MMAP_VALID |
0371 SNDRV_PCM_INFO_DOUBLE |
0372 SNDRV_PCM_INFO_BATCH |
0373 SNDRV_PCM_INFO_NONINTERLEAVED |
0374 SNDRV_PCM_INFO_RESUME |
0375 SNDRV_PCM_INFO_PAUSE);
0376 runtime->hw.info |= SNDRV_PCM_INFO_INTERLEAVED;
0377
0378 stream->evt_pair = &front_info->evt_pairs[stream->index];
0379
0380 stream->front_info = front_info;
0381
0382 stream->evt_pair->evt.u.evt.substream = substream;
0383
0384 stream_clear(stream);
0385
0386 xen_snd_front_evtchnl_pair_set_connected(stream->evt_pair, true);
0387
0388 ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
0389 alsa_hw_rule, stream,
0390 SNDRV_PCM_HW_PARAM_FORMAT, -1);
0391 if (ret) {
0392 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_FORMAT\n");
0393 return ret;
0394 }
0395
0396 ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
0397 alsa_hw_rule, stream,
0398 SNDRV_PCM_HW_PARAM_RATE, -1);
0399 if (ret) {
0400 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_RATE\n");
0401 return ret;
0402 }
0403
0404 ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
0405 alsa_hw_rule, stream,
0406 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
0407 if (ret) {
0408 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_CHANNELS\n");
0409 return ret;
0410 }
0411
0412 ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
0413 alsa_hw_rule, stream,
0414 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
0415 if (ret) {
0416 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_PERIOD_SIZE\n");
0417 return ret;
0418 }
0419
0420 ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
0421 alsa_hw_rule, stream,
0422 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
0423 if (ret) {
0424 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_BUFFER_SIZE\n");
0425 return ret;
0426 }
0427
0428 return 0;
0429 }
0430
0431 static int alsa_close(struct snd_pcm_substream *substream)
0432 {
0433 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0434
0435 xen_snd_front_evtchnl_pair_set_connected(stream->evt_pair, false);
0436 return 0;
0437 }
0438
0439 static int shbuf_setup_backstore(struct xen_snd_front_pcm_stream_info *stream,
0440 size_t buffer_sz)
0441 {
0442 int i;
0443
0444 stream->buffer = alloc_pages_exact(buffer_sz, GFP_KERNEL);
0445 if (!stream->buffer)
0446 return -ENOMEM;
0447
0448 stream->buffer_sz = buffer_sz;
0449 stream->num_pages = DIV_ROUND_UP(stream->buffer_sz, PAGE_SIZE);
0450 stream->pages = kcalloc(stream->num_pages, sizeof(struct page *),
0451 GFP_KERNEL);
0452 if (!stream->pages)
0453 return -ENOMEM;
0454
0455 for (i = 0; i < stream->num_pages; i++)
0456 stream->pages[i] = virt_to_page(stream->buffer + i * PAGE_SIZE);
0457
0458 return 0;
0459 }
0460
0461 static int alsa_hw_params(struct snd_pcm_substream *substream,
0462 struct snd_pcm_hw_params *params)
0463 {
0464 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0465 struct xen_snd_front_info *front_info = stream->front_info;
0466 struct xen_front_pgdir_shbuf_cfg buf_cfg;
0467 int ret;
0468
0469
0470
0471
0472
0473 stream_free(stream);
0474 ret = shbuf_setup_backstore(stream, params_buffer_bytes(params));
0475 if (ret < 0)
0476 goto fail;
0477
0478 memset(&buf_cfg, 0, sizeof(buf_cfg));
0479 buf_cfg.xb_dev = front_info->xb_dev;
0480 buf_cfg.pgdir = &stream->shbuf;
0481 buf_cfg.num_pages = stream->num_pages;
0482 buf_cfg.pages = stream->pages;
0483
0484 ret = xen_front_pgdir_shbuf_alloc(&buf_cfg);
0485 if (ret < 0)
0486 goto fail;
0487
0488 ret = xen_front_pgdir_shbuf_map(&stream->shbuf);
0489 if (ret < 0)
0490 goto fail;
0491
0492 return 0;
0493
0494 fail:
0495 stream_free(stream);
0496 dev_err(&front_info->xb_dev->dev,
0497 "Failed to allocate buffers for stream with index %d\n",
0498 stream->index);
0499 return ret;
0500 }
0501
0502 static int alsa_hw_free(struct snd_pcm_substream *substream)
0503 {
0504 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0505 int ret;
0506
0507 ret = xen_snd_front_stream_close(&stream->evt_pair->req);
0508 stream_free(stream);
0509 return ret;
0510 }
0511
0512 static int alsa_prepare(struct snd_pcm_substream *substream)
0513 {
0514 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0515
0516 if (!stream->is_open) {
0517 struct snd_pcm_runtime *runtime = substream->runtime;
0518 u8 sndif_format;
0519 int ret;
0520
0521 ret = to_sndif_format(runtime->format);
0522 if (ret < 0) {
0523 dev_err(&stream->front_info->xb_dev->dev,
0524 "Unsupported sample format: %d\n",
0525 runtime->format);
0526 return ret;
0527 }
0528 sndif_format = ret;
0529
0530 ret = xen_snd_front_stream_prepare(&stream->evt_pair->req,
0531 &stream->shbuf,
0532 sndif_format,
0533 runtime->channels,
0534 runtime->rate,
0535 snd_pcm_lib_buffer_bytes(substream),
0536 snd_pcm_lib_period_bytes(substream));
0537 if (ret < 0)
0538 return ret;
0539
0540 stream->is_open = true;
0541 }
0542
0543 return 0;
0544 }
0545
0546 static int alsa_trigger(struct snd_pcm_substream *substream, int cmd)
0547 {
0548 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0549 int type;
0550
0551 switch (cmd) {
0552 case SNDRV_PCM_TRIGGER_START:
0553 type = XENSND_OP_TRIGGER_START;
0554 break;
0555
0556 case SNDRV_PCM_TRIGGER_RESUME:
0557 type = XENSND_OP_TRIGGER_RESUME;
0558 break;
0559
0560 case SNDRV_PCM_TRIGGER_STOP:
0561 type = XENSND_OP_TRIGGER_STOP;
0562 break;
0563
0564 case SNDRV_PCM_TRIGGER_SUSPEND:
0565 type = XENSND_OP_TRIGGER_PAUSE;
0566 break;
0567
0568 default:
0569 return -EINVAL;
0570 }
0571
0572 return xen_snd_front_stream_trigger(&stream->evt_pair->req, type);
0573 }
0574
0575 void xen_snd_front_alsa_handle_cur_pos(struct xen_snd_front_evtchnl *evtchnl,
0576 u64 pos_bytes)
0577 {
0578 struct snd_pcm_substream *substream = evtchnl->u.evt.substream;
0579 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0580 snd_pcm_uframes_t delta, new_hw_ptr, cur_frame;
0581
0582 cur_frame = bytes_to_frames(substream->runtime, pos_bytes);
0583
0584 delta = cur_frame - stream->be_cur_frame;
0585 stream->be_cur_frame = cur_frame;
0586
0587 new_hw_ptr = (snd_pcm_uframes_t)atomic_read(&stream->hw_ptr);
0588 new_hw_ptr = (new_hw_ptr + delta) % substream->runtime->buffer_size;
0589 atomic_set(&stream->hw_ptr, (int)new_hw_ptr);
0590
0591 stream->out_frames += delta;
0592 if (stream->out_frames > substream->runtime->period_size) {
0593 stream->out_frames %= substream->runtime->period_size;
0594 snd_pcm_period_elapsed(substream);
0595 }
0596 }
0597
0598 static snd_pcm_uframes_t alsa_pointer(struct snd_pcm_substream *substream)
0599 {
0600 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0601
0602 return (snd_pcm_uframes_t)atomic_read(&stream->hw_ptr);
0603 }
0604
0605 static int alsa_pb_copy_user(struct snd_pcm_substream *substream,
0606 int channel, unsigned long pos, void __user *src,
0607 unsigned long count)
0608 {
0609 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0610
0611 if (unlikely(pos + count > stream->buffer_sz))
0612 return -EINVAL;
0613
0614 if (copy_from_user(stream->buffer + pos, src, count))
0615 return -EFAULT;
0616
0617 return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count);
0618 }
0619
0620 static int alsa_pb_copy_kernel(struct snd_pcm_substream *substream,
0621 int channel, unsigned long pos, void *src,
0622 unsigned long count)
0623 {
0624 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0625
0626 if (unlikely(pos + count > stream->buffer_sz))
0627 return -EINVAL;
0628
0629 memcpy(stream->buffer + pos, src, count);
0630
0631 return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count);
0632 }
0633
0634 static int alsa_cap_copy_user(struct snd_pcm_substream *substream,
0635 int channel, unsigned long pos, void __user *dst,
0636 unsigned long count)
0637 {
0638 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0639 int ret;
0640
0641 if (unlikely(pos + count > stream->buffer_sz))
0642 return -EINVAL;
0643
0644 ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count);
0645 if (ret < 0)
0646 return ret;
0647
0648 return copy_to_user(dst, stream->buffer + pos, count) ?
0649 -EFAULT : 0;
0650 }
0651
0652 static int alsa_cap_copy_kernel(struct snd_pcm_substream *substream,
0653 int channel, unsigned long pos, void *dst,
0654 unsigned long count)
0655 {
0656 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0657 int ret;
0658
0659 if (unlikely(pos + count > stream->buffer_sz))
0660 return -EINVAL;
0661
0662 ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count);
0663 if (ret < 0)
0664 return ret;
0665
0666 memcpy(dst, stream->buffer + pos, count);
0667
0668 return 0;
0669 }
0670
0671 static int alsa_pb_fill_silence(struct snd_pcm_substream *substream,
0672 int channel, unsigned long pos,
0673 unsigned long count)
0674 {
0675 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
0676
0677 if (unlikely(pos + count > stream->buffer_sz))
0678 return -EINVAL;
0679
0680 memset(stream->buffer + pos, 0, count);
0681
0682 return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count);
0683 }
0684
0685
0686
0687
0688
0689
0690
0691
0692 static const struct snd_pcm_ops snd_drv_alsa_playback_ops = {
0693 .open = alsa_open,
0694 .close = alsa_close,
0695 .hw_params = alsa_hw_params,
0696 .hw_free = alsa_hw_free,
0697 .prepare = alsa_prepare,
0698 .trigger = alsa_trigger,
0699 .pointer = alsa_pointer,
0700 .copy_user = alsa_pb_copy_user,
0701 .copy_kernel = alsa_pb_copy_kernel,
0702 .fill_silence = alsa_pb_fill_silence,
0703 };
0704
0705 static const struct snd_pcm_ops snd_drv_alsa_capture_ops = {
0706 .open = alsa_open,
0707 .close = alsa_close,
0708 .hw_params = alsa_hw_params,
0709 .hw_free = alsa_hw_free,
0710 .prepare = alsa_prepare,
0711 .trigger = alsa_trigger,
0712 .pointer = alsa_pointer,
0713 .copy_user = alsa_cap_copy_user,
0714 .copy_kernel = alsa_cap_copy_kernel,
0715 };
0716
0717 static int new_pcm_instance(struct xen_snd_front_card_info *card_info,
0718 struct xen_front_cfg_pcm_instance *instance_cfg,
0719 struct xen_snd_front_pcm_instance_info *pcm_instance_info)
0720 {
0721 struct snd_pcm *pcm;
0722 int ret, i;
0723
0724 dev_dbg(&card_info->front_info->xb_dev->dev,
0725 "New PCM device \"%s\" with id %d playback %d capture %d",
0726 instance_cfg->name,
0727 instance_cfg->device_id,
0728 instance_cfg->num_streams_pb,
0729 instance_cfg->num_streams_cap);
0730
0731 pcm_instance_info->card_info = card_info;
0732
0733 pcm_instance_info->pcm_hw = instance_cfg->pcm_hw;
0734
0735 if (instance_cfg->num_streams_pb) {
0736 pcm_instance_info->streams_pb =
0737 devm_kcalloc(&card_info->card->card_dev,
0738 instance_cfg->num_streams_pb,
0739 sizeof(struct xen_snd_front_pcm_stream_info),
0740 GFP_KERNEL);
0741 if (!pcm_instance_info->streams_pb)
0742 return -ENOMEM;
0743 }
0744
0745 if (instance_cfg->num_streams_cap) {
0746 pcm_instance_info->streams_cap =
0747 devm_kcalloc(&card_info->card->card_dev,
0748 instance_cfg->num_streams_cap,
0749 sizeof(struct xen_snd_front_pcm_stream_info),
0750 GFP_KERNEL);
0751 if (!pcm_instance_info->streams_cap)
0752 return -ENOMEM;
0753 }
0754
0755 pcm_instance_info->num_pcm_streams_pb =
0756 instance_cfg->num_streams_pb;
0757 pcm_instance_info->num_pcm_streams_cap =
0758 instance_cfg->num_streams_cap;
0759
0760 for (i = 0; i < pcm_instance_info->num_pcm_streams_pb; i++) {
0761 pcm_instance_info->streams_pb[i].pcm_hw =
0762 instance_cfg->streams_pb[i].pcm_hw;
0763 pcm_instance_info->streams_pb[i].index =
0764 instance_cfg->streams_pb[i].index;
0765 }
0766
0767 for (i = 0; i < pcm_instance_info->num_pcm_streams_cap; i++) {
0768 pcm_instance_info->streams_cap[i].pcm_hw =
0769 instance_cfg->streams_cap[i].pcm_hw;
0770 pcm_instance_info->streams_cap[i].index =
0771 instance_cfg->streams_cap[i].index;
0772 }
0773
0774 ret = snd_pcm_new(card_info->card, instance_cfg->name,
0775 instance_cfg->device_id,
0776 instance_cfg->num_streams_pb,
0777 instance_cfg->num_streams_cap,
0778 &pcm);
0779 if (ret < 0)
0780 return ret;
0781
0782 pcm->private_data = pcm_instance_info;
0783 pcm->info_flags = 0;
0784
0785 pcm->nonatomic = true;
0786 strncpy(pcm->name, "Virtual card PCM", sizeof(pcm->name));
0787
0788 if (instance_cfg->num_streams_pb)
0789 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
0790 &snd_drv_alsa_playback_ops);
0791
0792 if (instance_cfg->num_streams_cap)
0793 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
0794 &snd_drv_alsa_capture_ops);
0795
0796 pcm_instance_info->pcm = pcm;
0797 return 0;
0798 }
0799
0800 int xen_snd_front_alsa_init(struct xen_snd_front_info *front_info)
0801 {
0802 struct device *dev = &front_info->xb_dev->dev;
0803 struct xen_front_cfg_card *cfg = &front_info->cfg;
0804 struct xen_snd_front_card_info *card_info;
0805 struct snd_card *card;
0806 int ret, i;
0807
0808 dev_dbg(dev, "Creating virtual sound card\n");
0809
0810 ret = snd_card_new(dev, 0, XENSND_DRIVER_NAME, THIS_MODULE,
0811 sizeof(struct xen_snd_front_card_info), &card);
0812 if (ret < 0)
0813 return ret;
0814
0815 card_info = card->private_data;
0816 card_info->front_info = front_info;
0817 front_info->card_info = card_info;
0818 card_info->card = card;
0819 card_info->pcm_instances =
0820 devm_kcalloc(dev, cfg->num_pcm_instances,
0821 sizeof(struct xen_snd_front_pcm_instance_info),
0822 GFP_KERNEL);
0823 if (!card_info->pcm_instances) {
0824 ret = -ENOMEM;
0825 goto fail;
0826 }
0827
0828 card_info->num_pcm_instances = cfg->num_pcm_instances;
0829 card_info->pcm_hw = cfg->pcm_hw;
0830
0831 for (i = 0; i < cfg->num_pcm_instances; i++) {
0832 ret = new_pcm_instance(card_info, &cfg->pcm_instances[i],
0833 &card_info->pcm_instances[i]);
0834 if (ret < 0)
0835 goto fail;
0836 }
0837
0838 strncpy(card->driver, XENSND_DRIVER_NAME, sizeof(card->driver));
0839 strncpy(card->shortname, cfg->name_short, sizeof(card->shortname));
0840 strncpy(card->longname, cfg->name_long, sizeof(card->longname));
0841
0842 ret = snd_card_register(card);
0843 if (ret < 0)
0844 goto fail;
0845
0846 return 0;
0847
0848 fail:
0849 snd_card_free(card);
0850 return ret;
0851 }
0852
0853 void xen_snd_front_alsa_fini(struct xen_snd_front_info *front_info)
0854 {
0855 struct xen_snd_front_card_info *card_info;
0856 struct snd_card *card;
0857
0858 card_info = front_info->card_info;
0859 if (!card_info)
0860 return;
0861
0862 card = card_info->card;
0863 if (!card)
0864 return;
0865
0866 dev_dbg(&front_info->xb_dev->dev, "Removing virtual sound card %d\n",
0867 card->number);
0868 snd_card_free(card);
0869
0870
0871 card_info->card = NULL;
0872 }