1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 3 /* 4 * Xen para-virtual sound device 5 * 6 * Copyright (C) 2016-2018 EPAM Systems Inc. 7 * 8 * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> 9 */ 10 11 #include <linux/platform_device.h> 12 13 #include <sound/core.h> 14 #include <sound/pcm.h> 15 #include <sound/pcm_params.h> 16 17 #include <xen/xenbus.h> 18 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" 24 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; 29 int index; 30 31 bool is_open; 32 struct snd_pcm_hardware pcm_hw; 33 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. */ 37 atomic_t hw_ptr; 38 /* Modulo of the number of processed frames - for period detection. */ 39 u32 out_frames; 40 }; 41 42 struct xen_snd_front_pcm_instance_info { 43 struct xen_snd_front_card_info *card_info; 44 struct snd_pcm *pcm; 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; 50 }; 51 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; 58 }; 59 60 struct alsa_sndif_sample_format { 61 u8 sndif; 62 snd_pcm_format_t alsa; 63 }; 64 65 struct alsa_sndif_hw_param { 66 u8 sndif; 67 snd_pcm_hw_param_t alsa; 68 }; 69 70 static const struct alsa_sndif_sample_format ALSA_SNDIF_FORMATS[] = { 71 { 72 .sndif = XENSND_PCM_FORMAT_U8, 73 .alsa = SNDRV_PCM_FORMAT_U8 74 }, 75 { 76 .sndif = XENSND_PCM_FORMAT_S8, 77 .alsa = SNDRV_PCM_FORMAT_S8 78 }, 79 { 80 .sndif = XENSND_PCM_FORMAT_U16_LE, 81 .alsa = SNDRV_PCM_FORMAT_U16_LE 82 }, 83 { 84 .sndif = XENSND_PCM_FORMAT_U16_BE, 85 .alsa = SNDRV_PCM_FORMAT_U16_BE 86 }, 87 { 88 .sndif = XENSND_PCM_FORMAT_S16_LE, 89 .alsa = SNDRV_PCM_FORMAT_S16_LE 90 }, 91 { 92 .sndif = XENSND_PCM_FORMAT_S16_BE, 93 .alsa = SNDRV_PCM_FORMAT_S16_BE 94 }, 95 { 96 .sndif = XENSND_PCM_FORMAT_U24_LE, 97 .alsa = SNDRV_PCM_FORMAT_U24_LE 98 }, 99 { 100 .sndif = XENSND_PCM_FORMAT_U24_BE, 101 .alsa = SNDRV_PCM_FORMAT_U24_BE 102 }, 103 { 104 .sndif = XENSND_PCM_FORMAT_S24_LE, 105 .alsa = SNDRV_PCM_FORMAT_S24_LE 106 }, 107 { 108 .sndif = XENSND_PCM_FORMAT_S24_BE, 109 .alsa = SNDRV_PCM_FORMAT_S24_BE 110 }, 111 { 112 .sndif = XENSND_PCM_FORMAT_U32_LE, 113 .alsa = SNDRV_PCM_FORMAT_U32_LE 114 }, 115 { 116 .sndif = XENSND_PCM_FORMAT_U32_BE, 117 .alsa = SNDRV_PCM_FORMAT_U32_BE 118 }, 119 { 120 .sndif = XENSND_PCM_FORMAT_S32_LE, 121 .alsa = SNDRV_PCM_FORMAT_S32_LE 122 }, 123 { 124 .sndif = XENSND_PCM_FORMAT_S32_BE, 125 .alsa = SNDRV_PCM_FORMAT_S32_BE 126 }, 127 { 128 .sndif = XENSND_PCM_FORMAT_A_LAW, 129 .alsa = SNDRV_PCM_FORMAT_A_LAW 130 }, 131 { 132 .sndif = XENSND_PCM_FORMAT_MU_LAW, 133 .alsa = SNDRV_PCM_FORMAT_MU_LAW 134 }, 135 { 136 .sndif = XENSND_PCM_FORMAT_F32_LE, 137 .alsa = SNDRV_PCM_FORMAT_FLOAT_LE 138 }, 139 { 140 .sndif = XENSND_PCM_FORMAT_F32_BE, 141 .alsa = SNDRV_PCM_FORMAT_FLOAT_BE 142 }, 143 { 144 .sndif = XENSND_PCM_FORMAT_F64_LE, 145 .alsa = SNDRV_PCM_FORMAT_FLOAT64_LE 146 }, 147 { 148 .sndif = XENSND_PCM_FORMAT_F64_BE, 149 .alsa = SNDRV_PCM_FORMAT_FLOAT64_BE 150 }, 151 { 152 .sndif = XENSND_PCM_FORMAT_IEC958_SUBFRAME_LE, 153 .alsa = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE 154 }, 155 { 156 .sndif = XENSND_PCM_FORMAT_IEC958_SUBFRAME_BE, 157 .alsa = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE 158 }, 159 { 160 .sndif = XENSND_PCM_FORMAT_IMA_ADPCM, 161 .alsa = SNDRV_PCM_FORMAT_IMA_ADPCM 162 }, 163 { 164 .sndif = XENSND_PCM_FORMAT_MPEG, 165 .alsa = SNDRV_PCM_FORMAT_MPEG 166 }, 167 { 168 .sndif = XENSND_PCM_FORMAT_GSM, 169 .alsa = SNDRV_PCM_FORMAT_GSM 170 }, 171 }; 172 173 static int to_sndif_format(snd_pcm_format_t format) 174 { 175 int i; 176 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; 180 181 return -EINVAL; 182 } 183 184 static u64 to_sndif_formats_mask(u64 alsa_formats) 185 { 186 u64 mask; 187 int i; 188 189 mask = 0; 190 for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++) 191 if (1 << ALSA_SNDIF_FORMATS[i].alsa & alsa_formats) 192 mask |= 1 << ALSA_SNDIF_FORMATS[i].sndif; 193 194 return mask; 195 } 196 197 static u64 to_alsa_formats_mask(u64 sndif_formats) 198 { 199 u64 mask; 200 int i; 201 202 mask = 0; 203 for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++) 204 if (1 << ALSA_SNDIF_FORMATS[i].sndif & sndif_formats) 205 mask |= 1 << ALSA_SNDIF_FORMATS[i].alsa; 206 207 return mask; 208 } 209 210 static void stream_clear(struct xen_snd_front_pcm_stream_info *stream) 211 { 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); 218 } 219 220 static void stream_free(struct xen_snd_front_pcm_stream_info *stream) 221 { 222 xen_snd_front_shbuf_free(&stream->sh_buf); 223 stream_clear(stream); 224 } 225 226 static struct xen_snd_front_pcm_stream_info * 227 stream_get(struct snd_pcm_substream *substream) 228 { 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; 232 233 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 234 stream = &pcm_instance->streams_pb[substream->number]; 235 else 236 stream = &pcm_instance->streams_cap[substream->number]; 237 238 return stream; 239 } 240 241 static int alsa_hw_rule(struct snd_pcm_hw_params *params, 242 struct snd_pcm_hw_rule *rule) 243 { 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; 262 u64 sndif_formats; 263 int changed, ret; 264 265 /* Collect all the values we need for the query. */ 266 267 req.formats = to_sndif_formats_mask((u64)formats->bits[0] | 268 (u64)(formats->bits[1]) << 32); 269 270 req.rates.min = rates->min; 271 req.rates.max = rates->max; 272 273 req.channels.min = channels->min; 274 req.channels.max = channels->max; 275 276 req.buffer.min = buffer->min; 277 req.buffer.max = buffer->max; 278 279 req.period.min = period->min; 280 req.period.max = period->max; 281 282 ret = xen_snd_front_stream_query_hw_param(&stream->evt_pair->req, 283 &req, &resp); 284 if (ret < 0) { 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"); 288 return ret; 289 } 290 291 /* Refine HW parameters after the query. */ 292 changed = 0; 293 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); 299 if (ret < 0) 300 return ret; 301 changed |= ret; 302 303 interval.openmin = 0; 304 interval.openmax = 0; 305 interval.integer = 1; 306 307 interval.min = resp.rates.min; 308 interval.max = resp.rates.max; 309 ret = snd_interval_refine(rates, &interval); 310 if (ret < 0) 311 return ret; 312 changed |= ret; 313 314 interval.min = resp.channels.min; 315 interval.max = resp.channels.max; 316 ret = snd_interval_refine(channels, &interval); 317 if (ret < 0) 318 return ret; 319 changed |= ret; 320 321 interval.min = resp.buffer.min; 322 interval.max = resp.buffer.max; 323 ret = snd_interval_refine(buffer, &interval); 324 if (ret < 0) 325 return ret; 326 changed |= ret; 327 328 interval.min = resp.period.min; 329 interval.max = resp.period.max; 330 ret = snd_interval_refine(period, &interval); 331 if (ret < 0) 332 return ret; 333 changed |= ret; 334 335 return changed; 336 } 337 338 static int alsa_open(struct snd_pcm_substream *substream) 339 { 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; 347 int ret; 348 349 /* 350 * Return our HW properties: override defaults with those configured 351 * via XenStore. 352 */ 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; 362 363 stream->evt_pair = &front_info->evt_pairs[stream->index]; 364 365 stream->front_info = front_info; 366 367 stream->evt_pair->evt.u.evt.substream = substream; 368 369 stream_clear(stream); 370 371 xen_snd_front_evtchnl_pair_set_connected(stream->evt_pair, true); 372 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); 376 if (ret) { 377 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_FORMAT\n"); 378 return ret; 379 } 380 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); 384 if (ret) { 385 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_RATE\n"); 386 return ret; 387 } 388 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); 392 if (ret) { 393 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_CHANNELS\n"); 394 return ret; 395 } 396 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); 400 if (ret) { 401 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_PERIOD_SIZE\n"); 402 return ret; 403 } 404 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); 408 if (ret) { 409 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_BUFFER_SIZE\n"); 410 return ret; 411 } 412 413 return 0; 414 } 415 416 static int alsa_close(struct snd_pcm_substream *substream) 417 { 418 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 419 420 xen_snd_front_evtchnl_pair_set_connected(stream->evt_pair, false); 421 return 0; 422 } 423 424 static int alsa_hw_params(struct snd_pcm_substream *substream, 425 struct snd_pcm_hw_params *params) 426 { 427 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 428 int ret; 429 430 /* 431 * This callback may be called multiple times, 432 * so free the previously allocated shared buffer if any. 433 */ 434 stream_free(stream); 435 436 ret = xen_snd_front_shbuf_alloc(stream->front_info->xb_dev, 437 &stream->sh_buf, 438 params_buffer_bytes(params)); 439 if (ret < 0) { 440 stream_free(stream); 441 dev_err(&stream->front_info->xb_dev->dev, 442 "Failed to allocate buffers for stream with index %d\n", 443 stream->index); 444 return ret; 445 } 446 447 return 0; 448 } 449 450 static int alsa_hw_free(struct snd_pcm_substream *substream) 451 { 452 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 453 int ret; 454 455 ret = xen_snd_front_stream_close(&stream->evt_pair->req); 456 stream_free(stream); 457 return ret; 458 } 459 460 static int alsa_prepare(struct snd_pcm_substream *substream) 461 { 462 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 463 464 if (!stream->is_open) { 465 struct snd_pcm_runtime *runtime = substream->runtime; 466 u8 sndif_format; 467 int ret; 468 469 ret = to_sndif_format(runtime->format); 470 if (ret < 0) { 471 dev_err(&stream->front_info->xb_dev->dev, 472 "Unsupported sample format: %d\n", 473 runtime->format); 474 return ret; 475 } 476 sndif_format = ret; 477 478 ret = xen_snd_front_stream_prepare(&stream->evt_pair->req, 479 &stream->sh_buf, 480 sndif_format, 481 runtime->channels, 482 runtime->rate, 483 snd_pcm_lib_buffer_bytes(substream), 484 snd_pcm_lib_period_bytes(substream)); 485 if (ret < 0) 486 return ret; 487 488 stream->is_open = true; 489 } 490 491 return 0; 492 } 493 494 static int alsa_trigger(struct snd_pcm_substream *substream, int cmd) 495 { 496 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 497 int type; 498 499 switch (cmd) { 500 case SNDRV_PCM_TRIGGER_START: 501 type = XENSND_OP_TRIGGER_START; 502 break; 503 504 case SNDRV_PCM_TRIGGER_RESUME: 505 type = XENSND_OP_TRIGGER_RESUME; 506 break; 507 508 case SNDRV_PCM_TRIGGER_STOP: 509 type = XENSND_OP_TRIGGER_STOP; 510 break; 511 512 case SNDRV_PCM_TRIGGER_SUSPEND: 513 type = XENSND_OP_TRIGGER_PAUSE; 514 break; 515 516 default: 517 return -EINVAL; 518 } 519 520 return xen_snd_front_stream_trigger(&stream->evt_pair->req, type); 521 } 522 523 void xen_snd_front_alsa_handle_cur_pos(struct xen_snd_front_evtchnl *evtchnl, 524 u64 pos_bytes) 525 { 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; 529 530 cur_frame = bytes_to_frames(substream->runtime, pos_bytes); 531 532 delta = cur_frame - stream->be_cur_frame; 533 stream->be_cur_frame = cur_frame; 534 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); 538 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); 543 } 544 } 545 546 static snd_pcm_uframes_t alsa_pointer(struct snd_pcm_substream *substream) 547 { 548 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 549 550 return (snd_pcm_uframes_t)atomic_read(&stream->hw_ptr); 551 } 552 553 static int alsa_pb_copy_user(struct snd_pcm_substream *substream, 554 int channel, unsigned long pos, void __user *src, 555 unsigned long count) 556 { 557 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 558 559 if (unlikely(pos + count > stream->sh_buf.buffer_sz)) 560 return -EINVAL; 561 562 if (copy_from_user(stream->sh_buf.buffer + pos, src, count)) 563 return -EFAULT; 564 565 return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); 566 } 567 568 static int alsa_pb_copy_kernel(struct snd_pcm_substream *substream, 569 int channel, unsigned long pos, void *src, 570 unsigned long count) 571 { 572 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 573 574 if (unlikely(pos + count > stream->sh_buf.buffer_sz)) 575 return -EINVAL; 576 577 memcpy(stream->sh_buf.buffer + pos, src, count); 578 579 return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); 580 } 581 582 static int alsa_cap_copy_user(struct snd_pcm_substream *substream, 583 int channel, unsigned long pos, void __user *dst, 584 unsigned long count) 585 { 586 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 587 int ret; 588 589 if (unlikely(pos + count > stream->sh_buf.buffer_sz)) 590 return -EINVAL; 591 592 ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count); 593 if (ret < 0) 594 return ret; 595 596 return copy_to_user(dst, stream->sh_buf.buffer + pos, count) ? 597 -EFAULT : 0; 598 } 599 600 static int alsa_cap_copy_kernel(struct snd_pcm_substream *substream, 601 int channel, unsigned long pos, void *dst, 602 unsigned long count) 603 { 604 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 605 int ret; 606 607 if (unlikely(pos + count > stream->sh_buf.buffer_sz)) 608 return -EINVAL; 609 610 ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count); 611 if (ret < 0) 612 return ret; 613 614 memcpy(dst, stream->sh_buf.buffer + pos, count); 615 616 return 0; 617 } 618 619 static int alsa_pb_fill_silence(struct snd_pcm_substream *substream, 620 int channel, unsigned long pos, 621 unsigned long count) 622 { 623 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 624 625 if (unlikely(pos + count > stream->sh_buf.buffer_sz)) 626 return -EINVAL; 627 628 memset(stream->sh_buf.buffer + pos, 0, count); 629 630 return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); 631 } 632 633 /* 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. 638 */ 639 640 static struct snd_pcm_ops snd_drv_alsa_playback_ops = { 641 .open = alsa_open, 642 .close = alsa_close, 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, 652 }; 653 654 static struct snd_pcm_ops snd_drv_alsa_capture_ops = { 655 .open = alsa_open, 656 .close = alsa_close, 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, 665 }; 666 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) 670 { 671 struct snd_pcm *pcm; 672 int ret, i; 673 674 dev_dbg(&card_info->front_info->xb_dev->dev, 675 "New PCM device \"%s\" with id %d playback %d capture %d", 676 instance_cfg->name, 677 instance_cfg->device_id, 678 instance_cfg->num_streams_pb, 679 instance_cfg->num_streams_cap); 680 681 pcm_instance_info->card_info = card_info; 682 683 pcm_instance_info->pcm_hw = instance_cfg->pcm_hw; 684 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), 690 GFP_KERNEL); 691 if (!pcm_instance_info->streams_pb) 692 return -ENOMEM; 693 } 694 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), 700 GFP_KERNEL); 701 if (!pcm_instance_info->streams_cap) 702 return -ENOMEM; 703 } 704 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; 709 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; 715 } 716 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; 722 } 723 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, 728 &pcm); 729 if (ret < 0) 730 return ret; 731 732 pcm->private_data = pcm_instance_info; 733 pcm->info_flags = 0; 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)); 737 738 if (instance_cfg->num_streams_pb) 739 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 740 &snd_drv_alsa_playback_ops); 741 742 if (instance_cfg->num_streams_cap) 743 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 744 &snd_drv_alsa_capture_ops); 745 746 pcm_instance_info->pcm = pcm; 747 return 0; 748 } 749 750 int xen_snd_front_alsa_init(struct xen_snd_front_info *front_info) 751 { 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; 756 int ret, i; 757 758 dev_dbg(dev, "Creating virtual sound card\n"); 759 760 ret = snd_card_new(dev, 0, XENSND_DRIVER_NAME, THIS_MODULE, 761 sizeof(struct xen_snd_front_card_info), &card); 762 if (ret < 0) 763 return ret; 764 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), 772 GFP_KERNEL); 773 if (!card_info->pcm_instances) { 774 ret = -ENOMEM; 775 goto fail; 776 } 777 778 card_info->num_pcm_instances = cfg->num_pcm_instances; 779 card_info->pcm_hw = cfg->pcm_hw; 780 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]); 784 if (ret < 0) 785 goto fail; 786 } 787 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)); 791 792 ret = snd_card_register(card); 793 if (ret < 0) 794 goto fail; 795 796 return 0; 797 798 fail: 799 snd_card_free(card); 800 return ret; 801 } 802 803 void xen_snd_front_alsa_fini(struct xen_snd_front_info *front_info) 804 { 805 struct xen_snd_front_card_info *card_info; 806 struct snd_card *card; 807 808 card_info = front_info->card_info; 809 if (!card_info) 810 return; 811 812 card = card_info->card; 813 if (!card) 814 return; 815 816 dev_dbg(&front_info->xb_dev->dev, "Removing virtual sound card %d\n", 817 card->number); 818 snd_card_free(card); 819 820 /* Card_info will be freed when destroying front_info->xb_dev->dev. */ 821 card_info->card = NULL; 822 } 823