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 sndif_format = to_sndif_format(runtime->format); 470 if (sndif_format < 0) { 471 dev_err(&stream->front_info->xb_dev->dev, 472 "Unsupported sample format: %d\n", 473 runtime->format); 474 return sndif_format; 475 } 476 477 ret = xen_snd_front_stream_prepare(&stream->evt_pair->req, 478 &stream->sh_buf, 479 sndif_format, 480 runtime->channels, 481 runtime->rate, 482 snd_pcm_lib_buffer_bytes(substream), 483 snd_pcm_lib_period_bytes(substream)); 484 if (ret < 0) 485 return ret; 486 487 stream->is_open = true; 488 } 489 490 return 0; 491 } 492 493 static int alsa_trigger(struct snd_pcm_substream *substream, int cmd) 494 { 495 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 496 int type; 497 498 switch (cmd) { 499 case SNDRV_PCM_TRIGGER_START: 500 type = XENSND_OP_TRIGGER_START; 501 break; 502 503 case SNDRV_PCM_TRIGGER_RESUME: 504 type = XENSND_OP_TRIGGER_RESUME; 505 break; 506 507 case SNDRV_PCM_TRIGGER_STOP: 508 type = XENSND_OP_TRIGGER_STOP; 509 break; 510 511 case SNDRV_PCM_TRIGGER_SUSPEND: 512 type = XENSND_OP_TRIGGER_PAUSE; 513 break; 514 515 default: 516 return -EINVAL; 517 } 518 519 return xen_snd_front_stream_trigger(&stream->evt_pair->req, type); 520 } 521 522 void xen_snd_front_alsa_handle_cur_pos(struct xen_snd_front_evtchnl *evtchnl, 523 u64 pos_bytes) 524 { 525 struct snd_pcm_substream *substream = evtchnl->u.evt.substream; 526 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 527 snd_pcm_uframes_t delta, new_hw_ptr, cur_frame; 528 529 cur_frame = bytes_to_frames(substream->runtime, pos_bytes); 530 531 delta = cur_frame - stream->be_cur_frame; 532 stream->be_cur_frame = cur_frame; 533 534 new_hw_ptr = (snd_pcm_uframes_t)atomic_read(&stream->hw_ptr); 535 new_hw_ptr = (new_hw_ptr + delta) % substream->runtime->buffer_size; 536 atomic_set(&stream->hw_ptr, (int)new_hw_ptr); 537 538 stream->out_frames += delta; 539 if (stream->out_frames > substream->runtime->period_size) { 540 stream->out_frames %= substream->runtime->period_size; 541 snd_pcm_period_elapsed(substream); 542 } 543 } 544 545 static snd_pcm_uframes_t alsa_pointer(struct snd_pcm_substream *substream) 546 { 547 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 548 549 return (snd_pcm_uframes_t)atomic_read(&stream->hw_ptr); 550 } 551 552 static int alsa_pb_copy_user(struct snd_pcm_substream *substream, 553 int channel, unsigned long pos, void __user *src, 554 unsigned long count) 555 { 556 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 557 558 if (unlikely(pos + count > stream->sh_buf.buffer_sz)) 559 return -EINVAL; 560 561 if (copy_from_user(stream->sh_buf.buffer + pos, src, count)) 562 return -EFAULT; 563 564 return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); 565 } 566 567 static int alsa_pb_copy_kernel(struct snd_pcm_substream *substream, 568 int channel, unsigned long pos, void *src, 569 unsigned long count) 570 { 571 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 572 573 if (unlikely(pos + count > stream->sh_buf.buffer_sz)) 574 return -EINVAL; 575 576 memcpy(stream->sh_buf.buffer + pos, src, count); 577 578 return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); 579 } 580 581 static int alsa_cap_copy_user(struct snd_pcm_substream *substream, 582 int channel, unsigned long pos, void __user *dst, 583 unsigned long count) 584 { 585 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 586 int ret; 587 588 if (unlikely(pos + count > stream->sh_buf.buffer_sz)) 589 return -EINVAL; 590 591 ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count); 592 if (ret < 0) 593 return ret; 594 595 return copy_to_user(dst, stream->sh_buf.buffer + pos, count) ? 596 -EFAULT : 0; 597 } 598 599 static int alsa_cap_copy_kernel(struct snd_pcm_substream *substream, 600 int channel, unsigned long pos, void *dst, 601 unsigned long count) 602 { 603 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 604 int ret; 605 606 if (unlikely(pos + count > stream->sh_buf.buffer_sz)) 607 return -EINVAL; 608 609 ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count); 610 if (ret < 0) 611 return ret; 612 613 memcpy(dst, stream->sh_buf.buffer + pos, count); 614 615 return 0; 616 } 617 618 static int alsa_pb_fill_silence(struct snd_pcm_substream *substream, 619 int channel, unsigned long pos, 620 unsigned long count) 621 { 622 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 623 624 if (unlikely(pos + count > stream->sh_buf.buffer_sz)) 625 return -EINVAL; 626 627 memset(stream->sh_buf.buffer + pos, 0, count); 628 629 return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); 630 } 631 632 /* 633 * FIXME: The mmaped data transfer is asynchronous and there is no 634 * ack signal from user-space when it is done. This is the 635 * reason it is not implemented in the PV driver as we do need 636 * to know when the buffer can be transferred to the backend. 637 */ 638 639 static struct snd_pcm_ops snd_drv_alsa_playback_ops = { 640 .open = alsa_open, 641 .close = alsa_close, 642 .ioctl = snd_pcm_lib_ioctl, 643 .hw_params = alsa_hw_params, 644 .hw_free = alsa_hw_free, 645 .prepare = alsa_prepare, 646 .trigger = alsa_trigger, 647 .pointer = alsa_pointer, 648 .copy_user = alsa_pb_copy_user, 649 .copy_kernel = alsa_pb_copy_kernel, 650 .fill_silence = alsa_pb_fill_silence, 651 }; 652 653 static struct snd_pcm_ops snd_drv_alsa_capture_ops = { 654 .open = alsa_open, 655 .close = alsa_close, 656 .ioctl = snd_pcm_lib_ioctl, 657 .hw_params = alsa_hw_params, 658 .hw_free = alsa_hw_free, 659 .prepare = alsa_prepare, 660 .trigger = alsa_trigger, 661 .pointer = alsa_pointer, 662 .copy_user = alsa_cap_copy_user, 663 .copy_kernel = alsa_cap_copy_kernel, 664 }; 665 666 static int new_pcm_instance(struct xen_snd_front_card_info *card_info, 667 struct xen_front_cfg_pcm_instance *instance_cfg, 668 struct xen_snd_front_pcm_instance_info *pcm_instance_info) 669 { 670 struct snd_pcm *pcm; 671 int ret, i; 672 673 dev_dbg(&card_info->front_info->xb_dev->dev, 674 "New PCM device \"%s\" with id %d playback %d capture %d", 675 instance_cfg->name, 676 instance_cfg->device_id, 677 instance_cfg->num_streams_pb, 678 instance_cfg->num_streams_cap); 679 680 pcm_instance_info->card_info = card_info; 681 682 pcm_instance_info->pcm_hw = instance_cfg->pcm_hw; 683 684 if (instance_cfg->num_streams_pb) { 685 pcm_instance_info->streams_pb = 686 devm_kcalloc(&card_info->card->card_dev, 687 instance_cfg->num_streams_pb, 688 sizeof(struct xen_snd_front_pcm_stream_info), 689 GFP_KERNEL); 690 if (!pcm_instance_info->streams_pb) 691 return -ENOMEM; 692 } 693 694 if (instance_cfg->num_streams_cap) { 695 pcm_instance_info->streams_cap = 696 devm_kcalloc(&card_info->card->card_dev, 697 instance_cfg->num_streams_cap, 698 sizeof(struct xen_snd_front_pcm_stream_info), 699 GFP_KERNEL); 700 if (!pcm_instance_info->streams_cap) 701 return -ENOMEM; 702 } 703 704 pcm_instance_info->num_pcm_streams_pb = 705 instance_cfg->num_streams_pb; 706 pcm_instance_info->num_pcm_streams_cap = 707 instance_cfg->num_streams_cap; 708 709 for (i = 0; i < pcm_instance_info->num_pcm_streams_pb; i++) { 710 pcm_instance_info->streams_pb[i].pcm_hw = 711 instance_cfg->streams_pb[i].pcm_hw; 712 pcm_instance_info->streams_pb[i].index = 713 instance_cfg->streams_pb[i].index; 714 } 715 716 for (i = 0; i < pcm_instance_info->num_pcm_streams_cap; i++) { 717 pcm_instance_info->streams_cap[i].pcm_hw = 718 instance_cfg->streams_cap[i].pcm_hw; 719 pcm_instance_info->streams_cap[i].index = 720 instance_cfg->streams_cap[i].index; 721 } 722 723 ret = snd_pcm_new(card_info->card, instance_cfg->name, 724 instance_cfg->device_id, 725 instance_cfg->num_streams_pb, 726 instance_cfg->num_streams_cap, 727 &pcm); 728 if (ret < 0) 729 return ret; 730 731 pcm->private_data = pcm_instance_info; 732 pcm->info_flags = 0; 733 /* we want to handle all PCM operations in non-atomic context */ 734 pcm->nonatomic = true; 735 strncpy(pcm->name, "Virtual card PCM", sizeof(pcm->name)); 736 737 if (instance_cfg->num_streams_pb) 738 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 739 &snd_drv_alsa_playback_ops); 740 741 if (instance_cfg->num_streams_cap) 742 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 743 &snd_drv_alsa_capture_ops); 744 745 pcm_instance_info->pcm = pcm; 746 return 0; 747 } 748 749 int xen_snd_front_alsa_init(struct xen_snd_front_info *front_info) 750 { 751 struct device *dev = &front_info->xb_dev->dev; 752 struct xen_front_cfg_card *cfg = &front_info->cfg; 753 struct xen_snd_front_card_info *card_info; 754 struct snd_card *card; 755 int ret, i; 756 757 dev_dbg(dev, "Creating virtual sound card\n"); 758 759 ret = snd_card_new(dev, 0, XENSND_DRIVER_NAME, THIS_MODULE, 760 sizeof(struct xen_snd_front_card_info), &card); 761 if (ret < 0) 762 return ret; 763 764 card_info = card->private_data; 765 card_info->front_info = front_info; 766 front_info->card_info = card_info; 767 card_info->card = card; 768 card_info->pcm_instances = 769 devm_kcalloc(dev, cfg->num_pcm_instances, 770 sizeof(struct xen_snd_front_pcm_instance_info), 771 GFP_KERNEL); 772 if (!card_info->pcm_instances) { 773 ret = -ENOMEM; 774 goto fail; 775 } 776 777 card_info->num_pcm_instances = cfg->num_pcm_instances; 778 card_info->pcm_hw = cfg->pcm_hw; 779 780 for (i = 0; i < cfg->num_pcm_instances; i++) { 781 ret = new_pcm_instance(card_info, &cfg->pcm_instances[i], 782 &card_info->pcm_instances[i]); 783 if (ret < 0) 784 goto fail; 785 } 786 787 strncpy(card->driver, XENSND_DRIVER_NAME, sizeof(card->driver)); 788 strncpy(card->shortname, cfg->name_short, sizeof(card->shortname)); 789 strncpy(card->longname, cfg->name_long, sizeof(card->longname)); 790 791 ret = snd_card_register(card); 792 if (ret < 0) 793 goto fail; 794 795 return 0; 796 797 fail: 798 snd_card_free(card); 799 return ret; 800 } 801 802 void xen_snd_front_alsa_fini(struct xen_snd_front_info *front_info) 803 { 804 struct xen_snd_front_card_info *card_info; 805 struct snd_card *card; 806 807 card_info = front_info->card_info; 808 if (!card_info) 809 return; 810 811 card = card_info->card; 812 if (!card) 813 return; 814 815 dev_dbg(&front_info->xb_dev->dev, "Removing virtual sound card %d\n", 816 card->number); 817 snd_card_free(card); 818 819 /* Card_info will be freed when destroying front_info->xb_dev->dev. */ 820 card_info->card = NULL; 821 } 822