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 #include <xen/xen-front-pgdir-shbuf.h> 19 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" 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 29 /* This is the shared buffer with its backing storage. */ 30 struct xen_front_pgdir_shbuf shbuf; 31 u8 *buffer; 32 size_t buffer_sz; 33 int num_pages; 34 struct page **pages; 35 36 int index; 37 38 bool is_open; 39 struct snd_pcm_hardware pcm_hw; 40 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. */ 44 atomic_t hw_ptr; 45 /* Modulo of the number of processed frames - for period detection. */ 46 u32 out_frames; 47 }; 48 49 struct xen_snd_front_pcm_instance_info { 50 struct xen_snd_front_card_info *card_info; 51 struct snd_pcm *pcm; 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; 57 }; 58 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; 65 }; 66 67 struct alsa_sndif_sample_format { 68 u8 sndif; 69 snd_pcm_format_t alsa; 70 }; 71 72 static const struct alsa_sndif_sample_format ALSA_SNDIF_FORMATS[] = { 73 { 74 .sndif = XENSND_PCM_FORMAT_U8, 75 .alsa = SNDRV_PCM_FORMAT_U8 76 }, 77 { 78 .sndif = XENSND_PCM_FORMAT_S8, 79 .alsa = SNDRV_PCM_FORMAT_S8 80 }, 81 { 82 .sndif = XENSND_PCM_FORMAT_U16_LE, 83 .alsa = SNDRV_PCM_FORMAT_U16_LE 84 }, 85 { 86 .sndif = XENSND_PCM_FORMAT_U16_BE, 87 .alsa = SNDRV_PCM_FORMAT_U16_BE 88 }, 89 { 90 .sndif = XENSND_PCM_FORMAT_S16_LE, 91 .alsa = SNDRV_PCM_FORMAT_S16_LE 92 }, 93 { 94 .sndif = XENSND_PCM_FORMAT_S16_BE, 95 .alsa = SNDRV_PCM_FORMAT_S16_BE 96 }, 97 { 98 .sndif = XENSND_PCM_FORMAT_U24_LE, 99 .alsa = SNDRV_PCM_FORMAT_U24_LE 100 }, 101 { 102 .sndif = XENSND_PCM_FORMAT_U24_BE, 103 .alsa = SNDRV_PCM_FORMAT_U24_BE 104 }, 105 { 106 .sndif = XENSND_PCM_FORMAT_S24_LE, 107 .alsa = SNDRV_PCM_FORMAT_S24_LE 108 }, 109 { 110 .sndif = XENSND_PCM_FORMAT_S24_BE, 111 .alsa = SNDRV_PCM_FORMAT_S24_BE 112 }, 113 { 114 .sndif = XENSND_PCM_FORMAT_U32_LE, 115 .alsa = SNDRV_PCM_FORMAT_U32_LE 116 }, 117 { 118 .sndif = XENSND_PCM_FORMAT_U32_BE, 119 .alsa = SNDRV_PCM_FORMAT_U32_BE 120 }, 121 { 122 .sndif = XENSND_PCM_FORMAT_S32_LE, 123 .alsa = SNDRV_PCM_FORMAT_S32_LE 124 }, 125 { 126 .sndif = XENSND_PCM_FORMAT_S32_BE, 127 .alsa = SNDRV_PCM_FORMAT_S32_BE 128 }, 129 { 130 .sndif = XENSND_PCM_FORMAT_A_LAW, 131 .alsa = SNDRV_PCM_FORMAT_A_LAW 132 }, 133 { 134 .sndif = XENSND_PCM_FORMAT_MU_LAW, 135 .alsa = SNDRV_PCM_FORMAT_MU_LAW 136 }, 137 { 138 .sndif = XENSND_PCM_FORMAT_F32_LE, 139 .alsa = SNDRV_PCM_FORMAT_FLOAT_LE 140 }, 141 { 142 .sndif = XENSND_PCM_FORMAT_F32_BE, 143 .alsa = SNDRV_PCM_FORMAT_FLOAT_BE 144 }, 145 { 146 .sndif = XENSND_PCM_FORMAT_F64_LE, 147 .alsa = SNDRV_PCM_FORMAT_FLOAT64_LE 148 }, 149 { 150 .sndif = XENSND_PCM_FORMAT_F64_BE, 151 .alsa = SNDRV_PCM_FORMAT_FLOAT64_BE 152 }, 153 { 154 .sndif = XENSND_PCM_FORMAT_IEC958_SUBFRAME_LE, 155 .alsa = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE 156 }, 157 { 158 .sndif = XENSND_PCM_FORMAT_IEC958_SUBFRAME_BE, 159 .alsa = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE 160 }, 161 { 162 .sndif = XENSND_PCM_FORMAT_IMA_ADPCM, 163 .alsa = SNDRV_PCM_FORMAT_IMA_ADPCM 164 }, 165 { 166 .sndif = XENSND_PCM_FORMAT_MPEG, 167 .alsa = SNDRV_PCM_FORMAT_MPEG 168 }, 169 { 170 .sndif = XENSND_PCM_FORMAT_GSM, 171 .alsa = SNDRV_PCM_FORMAT_GSM 172 }, 173 }; 174 175 static int to_sndif_format(snd_pcm_format_t format) 176 { 177 int i; 178 179 for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++) 180 if (ALSA_SNDIF_FORMATS[i].alsa == format) 181 return ALSA_SNDIF_FORMATS[i].sndif; 182 183 return -EINVAL; 184 } 185 186 static u64 to_sndif_formats_mask(u64 alsa_formats) 187 { 188 u64 mask; 189 int i; 190 191 mask = 0; 192 for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++) 193 if (pcm_format_to_bits(ALSA_SNDIF_FORMATS[i].alsa) & alsa_formats) 194 mask |= BIT_ULL(ALSA_SNDIF_FORMATS[i].sndif); 195 196 return mask; 197 } 198 199 static u64 to_alsa_formats_mask(u64 sndif_formats) 200 { 201 u64 mask; 202 int i; 203 204 mask = 0; 205 for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++) 206 if (BIT_ULL(ALSA_SNDIF_FORMATS[i].sndif) & sndif_formats) 207 mask |= pcm_format_to_bits(ALSA_SNDIF_FORMATS[i].alsa); 208 209 return mask; 210 } 211 212 static void stream_clear(struct xen_snd_front_pcm_stream_info *stream) 213 { 214 stream->is_open = false; 215 stream->be_cur_frame = 0; 216 stream->out_frames = 0; 217 atomic_set(&stream->hw_ptr, 0); 218 xen_snd_front_evtchnl_pair_clear(stream->evt_pair); 219 memset(&stream->shbuf, 0, sizeof(stream->shbuf)); 220 stream->buffer = NULL; 221 stream->buffer_sz = 0; 222 stream->pages = NULL; 223 stream->num_pages = 0; 224 } 225 226 static void stream_free(struct xen_snd_front_pcm_stream_info *stream) 227 { 228 xen_front_pgdir_shbuf_unmap(&stream->shbuf); 229 xen_front_pgdir_shbuf_free(&stream->shbuf); 230 if (stream->buffer) 231 free_pages_exact(stream->buffer, stream->buffer_sz); 232 kfree(stream->pages); 233 stream_clear(stream); 234 } 235 236 static struct xen_snd_front_pcm_stream_info * 237 stream_get(struct snd_pcm_substream *substream) 238 { 239 struct xen_snd_front_pcm_instance_info *pcm_instance = 240 snd_pcm_substream_chip(substream); 241 struct xen_snd_front_pcm_stream_info *stream; 242 243 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 244 stream = &pcm_instance->streams_pb[substream->number]; 245 else 246 stream = &pcm_instance->streams_cap[substream->number]; 247 248 return stream; 249 } 250 251 static int alsa_hw_rule(struct snd_pcm_hw_params *params, 252 struct snd_pcm_hw_rule *rule) 253 { 254 struct xen_snd_front_pcm_stream_info *stream = rule->private; 255 struct device *dev = &stream->front_info->xb_dev->dev; 256 struct snd_mask *formats = 257 hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 258 struct snd_interval *rates = 259 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 260 struct snd_interval *channels = 261 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 262 struct snd_interval *period = 263 hw_param_interval(params, 264 SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 265 struct snd_interval *buffer = 266 hw_param_interval(params, 267 SNDRV_PCM_HW_PARAM_BUFFER_SIZE); 268 struct xensnd_query_hw_param req; 269 struct xensnd_query_hw_param resp; 270 struct snd_interval interval; 271 struct snd_mask mask; 272 u64 sndif_formats; 273 int changed, ret; 274 275 /* Collect all the values we need for the query. */ 276 277 req.formats = to_sndif_formats_mask((u64)formats->bits[0] | 278 (u64)(formats->bits[1]) << 32); 279 280 req.rates.min = rates->min; 281 req.rates.max = rates->max; 282 283 req.channels.min = channels->min; 284 req.channels.max = channels->max; 285 286 req.buffer.min = buffer->min; 287 req.buffer.max = buffer->max; 288 289 req.period.min = period->min; 290 req.period.max = period->max; 291 292 ret = xen_snd_front_stream_query_hw_param(&stream->evt_pair->req, 293 &req, &resp); 294 if (ret < 0) { 295 /* Check if this is due to backend communication error. */ 296 if (ret == -EIO || ret == -ETIMEDOUT) 297 dev_err(dev, "Failed to query ALSA HW parameters\n"); 298 return ret; 299 } 300 301 /* Refine HW parameters after the query. */ 302 changed = 0; 303 304 sndif_formats = to_alsa_formats_mask(resp.formats); 305 snd_mask_none(&mask); 306 mask.bits[0] = (u32)sndif_formats; 307 mask.bits[1] = (u32)(sndif_formats >> 32); 308 ret = snd_mask_refine(formats, &mask); 309 if (ret < 0) 310 return ret; 311 changed |= ret; 312 313 interval.openmin = 0; 314 interval.openmax = 0; 315 interval.integer = 1; 316 317 interval.min = resp.rates.min; 318 interval.max = resp.rates.max; 319 ret = snd_interval_refine(rates, &interval); 320 if (ret < 0) 321 return ret; 322 changed |= ret; 323 324 interval.min = resp.channels.min; 325 interval.max = resp.channels.max; 326 ret = snd_interval_refine(channels, &interval); 327 if (ret < 0) 328 return ret; 329 changed |= ret; 330 331 interval.min = resp.buffer.min; 332 interval.max = resp.buffer.max; 333 ret = snd_interval_refine(buffer, &interval); 334 if (ret < 0) 335 return ret; 336 changed |= ret; 337 338 interval.min = resp.period.min; 339 interval.max = resp.period.max; 340 ret = snd_interval_refine(period, &interval); 341 if (ret < 0) 342 return ret; 343 changed |= ret; 344 345 return changed; 346 } 347 348 static int alsa_open(struct snd_pcm_substream *substream) 349 { 350 struct xen_snd_front_pcm_instance_info *pcm_instance = 351 snd_pcm_substream_chip(substream); 352 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 353 struct snd_pcm_runtime *runtime = substream->runtime; 354 struct xen_snd_front_info *front_info = 355 pcm_instance->card_info->front_info; 356 struct device *dev = &front_info->xb_dev->dev; 357 int ret; 358 359 /* 360 * Return our HW properties: override defaults with those configured 361 * via XenStore. 362 */ 363 runtime->hw = stream->pcm_hw; 364 runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | 365 SNDRV_PCM_INFO_MMAP_VALID | 366 SNDRV_PCM_INFO_DOUBLE | 367 SNDRV_PCM_INFO_BATCH | 368 SNDRV_PCM_INFO_NONINTERLEAVED | 369 SNDRV_PCM_INFO_RESUME | 370 SNDRV_PCM_INFO_PAUSE); 371 runtime->hw.info |= SNDRV_PCM_INFO_INTERLEAVED; 372 373 stream->evt_pair = &front_info->evt_pairs[stream->index]; 374 375 stream->front_info = front_info; 376 377 stream->evt_pair->evt.u.evt.substream = substream; 378 379 stream_clear(stream); 380 381 xen_snd_front_evtchnl_pair_set_connected(stream->evt_pair, true); 382 383 ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, 384 alsa_hw_rule, stream, 385 SNDRV_PCM_HW_PARAM_FORMAT, -1); 386 if (ret) { 387 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_FORMAT\n"); 388 return ret; 389 } 390 391 ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 392 alsa_hw_rule, stream, 393 SNDRV_PCM_HW_PARAM_RATE, -1); 394 if (ret) { 395 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_RATE\n"); 396 return ret; 397 } 398 399 ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 400 alsa_hw_rule, stream, 401 SNDRV_PCM_HW_PARAM_CHANNELS, -1); 402 if (ret) { 403 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_CHANNELS\n"); 404 return ret; 405 } 406 407 ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 408 alsa_hw_rule, stream, 409 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); 410 if (ret) { 411 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_PERIOD_SIZE\n"); 412 return ret; 413 } 414 415 ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 416 alsa_hw_rule, stream, 417 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); 418 if (ret) { 419 dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_BUFFER_SIZE\n"); 420 return ret; 421 } 422 423 return 0; 424 } 425 426 static int alsa_close(struct snd_pcm_substream *substream) 427 { 428 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 429 430 xen_snd_front_evtchnl_pair_set_connected(stream->evt_pair, false); 431 return 0; 432 } 433 434 static int shbuf_setup_backstore(struct xen_snd_front_pcm_stream_info *stream, 435 size_t buffer_sz) 436 { 437 int i; 438 439 stream->buffer = alloc_pages_exact(buffer_sz, GFP_KERNEL); 440 if (!stream->buffer) 441 return -ENOMEM; 442 443 stream->buffer_sz = buffer_sz; 444 stream->num_pages = DIV_ROUND_UP(stream->buffer_sz, PAGE_SIZE); 445 stream->pages = kcalloc(stream->num_pages, sizeof(struct page *), 446 GFP_KERNEL); 447 if (!stream->pages) 448 return -ENOMEM; 449 450 for (i = 0; i < stream->num_pages; i++) 451 stream->pages[i] = virt_to_page(stream->buffer + i * PAGE_SIZE); 452 453 return 0; 454 } 455 456 static int alsa_hw_params(struct snd_pcm_substream *substream, 457 struct snd_pcm_hw_params *params) 458 { 459 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 460 struct xen_snd_front_info *front_info = stream->front_info; 461 struct xen_front_pgdir_shbuf_cfg buf_cfg; 462 int ret; 463 464 /* 465 * This callback may be called multiple times, 466 * so free the previously allocated shared buffer if any. 467 */ 468 stream_free(stream); 469 ret = shbuf_setup_backstore(stream, params_buffer_bytes(params)); 470 if (ret < 0) 471 goto fail; 472 473 memset(&buf_cfg, 0, sizeof(buf_cfg)); 474 buf_cfg.xb_dev = front_info->xb_dev; 475 buf_cfg.pgdir = &stream->shbuf; 476 buf_cfg.num_pages = stream->num_pages; 477 buf_cfg.pages = stream->pages; 478 479 ret = xen_front_pgdir_shbuf_alloc(&buf_cfg); 480 if (ret < 0) 481 goto fail; 482 483 ret = xen_front_pgdir_shbuf_map(&stream->shbuf); 484 if (ret < 0) 485 goto fail; 486 487 return 0; 488 489 fail: 490 stream_free(stream); 491 dev_err(&front_info->xb_dev->dev, 492 "Failed to allocate buffers for stream with index %d\n", 493 stream->index); 494 return ret; 495 } 496 497 static int alsa_hw_free(struct snd_pcm_substream *substream) 498 { 499 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 500 int ret; 501 502 ret = xen_snd_front_stream_close(&stream->evt_pair->req); 503 stream_free(stream); 504 return ret; 505 } 506 507 static int alsa_prepare(struct snd_pcm_substream *substream) 508 { 509 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 510 511 if (!stream->is_open) { 512 struct snd_pcm_runtime *runtime = substream->runtime; 513 u8 sndif_format; 514 int ret; 515 516 ret = to_sndif_format(runtime->format); 517 if (ret < 0) { 518 dev_err(&stream->front_info->xb_dev->dev, 519 "Unsupported sample format: %d\n", 520 runtime->format); 521 return ret; 522 } 523 sndif_format = ret; 524 525 ret = xen_snd_front_stream_prepare(&stream->evt_pair->req, 526 &stream->shbuf, 527 sndif_format, 528 runtime->channels, 529 runtime->rate, 530 snd_pcm_lib_buffer_bytes(substream), 531 snd_pcm_lib_period_bytes(substream)); 532 if (ret < 0) 533 return ret; 534 535 stream->is_open = true; 536 } 537 538 return 0; 539 } 540 541 static int alsa_trigger(struct snd_pcm_substream *substream, int cmd) 542 { 543 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 544 int type; 545 546 switch (cmd) { 547 case SNDRV_PCM_TRIGGER_START: 548 type = XENSND_OP_TRIGGER_START; 549 break; 550 551 case SNDRV_PCM_TRIGGER_RESUME: 552 type = XENSND_OP_TRIGGER_RESUME; 553 break; 554 555 case SNDRV_PCM_TRIGGER_STOP: 556 type = XENSND_OP_TRIGGER_STOP; 557 break; 558 559 case SNDRV_PCM_TRIGGER_SUSPEND: 560 type = XENSND_OP_TRIGGER_PAUSE; 561 break; 562 563 default: 564 return -EINVAL; 565 } 566 567 return xen_snd_front_stream_trigger(&stream->evt_pair->req, type); 568 } 569 570 void xen_snd_front_alsa_handle_cur_pos(struct xen_snd_front_evtchnl *evtchnl, 571 u64 pos_bytes) 572 { 573 struct snd_pcm_substream *substream = evtchnl->u.evt.substream; 574 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 575 snd_pcm_uframes_t delta, new_hw_ptr, cur_frame; 576 577 cur_frame = bytes_to_frames(substream->runtime, pos_bytes); 578 579 delta = cur_frame - stream->be_cur_frame; 580 stream->be_cur_frame = cur_frame; 581 582 new_hw_ptr = (snd_pcm_uframes_t)atomic_read(&stream->hw_ptr); 583 new_hw_ptr = (new_hw_ptr + delta) % substream->runtime->buffer_size; 584 atomic_set(&stream->hw_ptr, (int)new_hw_ptr); 585 586 stream->out_frames += delta; 587 if (stream->out_frames > substream->runtime->period_size) { 588 stream->out_frames %= substream->runtime->period_size; 589 snd_pcm_period_elapsed(substream); 590 } 591 } 592 593 static snd_pcm_uframes_t alsa_pointer(struct snd_pcm_substream *substream) 594 { 595 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 596 597 return (snd_pcm_uframes_t)atomic_read(&stream->hw_ptr); 598 } 599 600 static int alsa_pb_copy(struct snd_pcm_substream *substream, 601 int channel, unsigned long pos, struct iov_iter *src, 602 unsigned long count) 603 { 604 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 605 606 if (unlikely(pos + count > stream->buffer_sz)) 607 return -EINVAL; 608 609 if (copy_from_iter(stream->buffer + pos, count, src) != count) 610 return -EFAULT; 611 612 return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); 613 } 614 615 static int alsa_cap_copy(struct snd_pcm_substream *substream, 616 int channel, unsigned long pos, struct iov_iter *dst, 617 unsigned long count) 618 { 619 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 620 int ret; 621 622 if (unlikely(pos + count > stream->buffer_sz)) 623 return -EINVAL; 624 625 ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count); 626 if (ret < 0) 627 return ret; 628 629 if (copy_to_iter(stream->buffer + pos, count, dst) != count) 630 return -EFAULT; 631 return 0; 632 } 633 634 static int alsa_pb_fill_silence(struct snd_pcm_substream *substream, 635 int channel, unsigned long pos, 636 unsigned long count) 637 { 638 struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); 639 640 if (unlikely(pos + count > stream->buffer_sz)) 641 return -EINVAL; 642 643 memset(stream->buffer + pos, 0, count); 644 645 return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); 646 } 647 648 /* 649 * FIXME: The mmaped data transfer is asynchronous and there is no 650 * ack signal from user-space when it is done. This is the 651 * reason it is not implemented in the PV driver as we do need 652 * to know when the buffer can be transferred to the backend. 653 */ 654 655 static const struct snd_pcm_ops snd_drv_alsa_playback_ops = { 656 .open = alsa_open, 657 .close = alsa_close, 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 = alsa_pb_copy, 664 .fill_silence = alsa_pb_fill_silence, 665 }; 666 667 static const struct snd_pcm_ops snd_drv_alsa_capture_ops = { 668 .open = alsa_open, 669 .close = alsa_close, 670 .hw_params = alsa_hw_params, 671 .hw_free = alsa_hw_free, 672 .prepare = alsa_prepare, 673 .trigger = alsa_trigger, 674 .pointer = alsa_pointer, 675 .copy = alsa_cap_copy, 676 }; 677 678 static int new_pcm_instance(struct xen_snd_front_card_info *card_info, 679 struct xen_front_cfg_pcm_instance *instance_cfg, 680 struct xen_snd_front_pcm_instance_info *pcm_instance_info) 681 { 682 struct snd_pcm *pcm; 683 int ret, i; 684 685 dev_dbg(&card_info->front_info->xb_dev->dev, 686 "New PCM device \"%s\" with id %d playback %d capture %d", 687 instance_cfg->name, 688 instance_cfg->device_id, 689 instance_cfg->num_streams_pb, 690 instance_cfg->num_streams_cap); 691 692 pcm_instance_info->card_info = card_info; 693 694 pcm_instance_info->pcm_hw = instance_cfg->pcm_hw; 695 696 if (instance_cfg->num_streams_pb) { 697 pcm_instance_info->streams_pb = 698 devm_kcalloc(&card_info->card->card_dev, 699 instance_cfg->num_streams_pb, 700 sizeof(struct xen_snd_front_pcm_stream_info), 701 GFP_KERNEL); 702 if (!pcm_instance_info->streams_pb) 703 return -ENOMEM; 704 } 705 706 if (instance_cfg->num_streams_cap) { 707 pcm_instance_info->streams_cap = 708 devm_kcalloc(&card_info->card->card_dev, 709 instance_cfg->num_streams_cap, 710 sizeof(struct xen_snd_front_pcm_stream_info), 711 GFP_KERNEL); 712 if (!pcm_instance_info->streams_cap) 713 return -ENOMEM; 714 } 715 716 pcm_instance_info->num_pcm_streams_pb = 717 instance_cfg->num_streams_pb; 718 pcm_instance_info->num_pcm_streams_cap = 719 instance_cfg->num_streams_cap; 720 721 for (i = 0; i < pcm_instance_info->num_pcm_streams_pb; i++) { 722 pcm_instance_info->streams_pb[i].pcm_hw = 723 instance_cfg->streams_pb[i].pcm_hw; 724 pcm_instance_info->streams_pb[i].index = 725 instance_cfg->streams_pb[i].index; 726 } 727 728 for (i = 0; i < pcm_instance_info->num_pcm_streams_cap; i++) { 729 pcm_instance_info->streams_cap[i].pcm_hw = 730 instance_cfg->streams_cap[i].pcm_hw; 731 pcm_instance_info->streams_cap[i].index = 732 instance_cfg->streams_cap[i].index; 733 } 734 735 ret = snd_pcm_new(card_info->card, instance_cfg->name, 736 instance_cfg->device_id, 737 instance_cfg->num_streams_pb, 738 instance_cfg->num_streams_cap, 739 &pcm); 740 if (ret < 0) 741 return ret; 742 743 pcm->private_data = pcm_instance_info; 744 pcm->info_flags = 0; 745 /* we want to handle all PCM operations in non-atomic context */ 746 pcm->nonatomic = true; 747 strscpy(pcm->name, "Virtual card PCM", sizeof(pcm->name)); 748 749 if (instance_cfg->num_streams_pb) 750 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 751 &snd_drv_alsa_playback_ops); 752 753 if (instance_cfg->num_streams_cap) 754 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 755 &snd_drv_alsa_capture_ops); 756 757 pcm_instance_info->pcm = pcm; 758 return 0; 759 } 760 761 int xen_snd_front_alsa_init(struct xen_snd_front_info *front_info) 762 { 763 struct device *dev = &front_info->xb_dev->dev; 764 struct xen_front_cfg_card *cfg = &front_info->cfg; 765 struct xen_snd_front_card_info *card_info; 766 struct snd_card *card; 767 int ret, i; 768 769 dev_dbg(dev, "Creating virtual sound card\n"); 770 771 ret = snd_card_new(dev, 0, XENSND_DRIVER_NAME, THIS_MODULE, 772 sizeof(struct xen_snd_front_card_info), &card); 773 if (ret < 0) 774 return ret; 775 776 card_info = card->private_data; 777 card_info->front_info = front_info; 778 front_info->card_info = card_info; 779 card_info->card = card; 780 card_info->pcm_instances = 781 devm_kcalloc(dev, cfg->num_pcm_instances, 782 sizeof(struct xen_snd_front_pcm_instance_info), 783 GFP_KERNEL); 784 if (!card_info->pcm_instances) { 785 ret = -ENOMEM; 786 goto fail; 787 } 788 789 card_info->num_pcm_instances = cfg->num_pcm_instances; 790 card_info->pcm_hw = cfg->pcm_hw; 791 792 for (i = 0; i < cfg->num_pcm_instances; i++) { 793 ret = new_pcm_instance(card_info, &cfg->pcm_instances[i], 794 &card_info->pcm_instances[i]); 795 if (ret < 0) 796 goto fail; 797 } 798 799 strscpy(card->driver, XENSND_DRIVER_NAME, sizeof(card->driver)); 800 strscpy(card->shortname, cfg->name_short, sizeof(card->shortname)); 801 strscpy(card->longname, cfg->name_long, sizeof(card->longname)); 802 803 ret = snd_card_register(card); 804 if (ret < 0) 805 goto fail; 806 807 return 0; 808 809 fail: 810 snd_card_free(card); 811 return ret; 812 } 813 814 void xen_snd_front_alsa_fini(struct xen_snd_front_info *front_info) 815 { 816 struct xen_snd_front_card_info *card_info; 817 struct snd_card *card; 818 819 card_info = front_info->card_info; 820 if (!card_info) 821 return; 822 823 card = card_info->card; 824 if (!card) 825 return; 826 827 dev_dbg(&front_info->xb_dev->dev, "Removing virtual sound card %d\n", 828 card->number); 829 snd_card_free(card); 830 831 /* Card_info will be freed when destroying front_info->xb_dev->dev. */ 832 card_info->card = NULL; 833 } 834
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.