Lines Matching +full:virtio +full:- +full:device

1 // SPDX-License-Identifier: GPL-2.0+
3 * virtio-snd: Virtio sound device
31 /* Map for converting VirtIO format to ALSA format. */
61 /* Map for converting VirtIO frame rate to ALSA frame rate. */
84 * virtsnd_pcm_build_hw() - Parse substream config and build HW descriptor.
85 * @vss: VirtIO substream.
86 * @info: VirtIO substream information entry.
89 * Return: 0 on success, -EINVAL if configuration is invalid.
94 struct virtio_device *vdev = vss->snd->vdev; in virtsnd_pcm_build_hw()
100 vss->features = le32_to_cpu(info->features); in virtsnd_pcm_build_hw()
103 * TODO: set SNDRV_PCM_INFO_{BATCH,BLOCK_TRANSFER} if device supports in virtsnd_pcm_build_hw()
104 * only message-based transport. in virtsnd_pcm_build_hw()
106 vss->hw.info = in virtsnd_pcm_build_hw()
114 if (!info->channels_min || info->channels_min > info->channels_max) { in virtsnd_pcm_build_hw()
115 dev_err(&vdev->dev, in virtsnd_pcm_build_hw()
117 vss->sid, info->channels_min, info->channels_max); in virtsnd_pcm_build_hw()
118 return -EINVAL; in virtsnd_pcm_build_hw()
121 vss->hw.channels_min = info->channels_min; in virtsnd_pcm_build_hw()
122 vss->hw.channels_max = info->channels_max; in virtsnd_pcm_build_hw()
124 values = le64_to_cpu(info->formats); in virtsnd_pcm_build_hw()
126 vss->hw.formats = 0; in virtsnd_pcm_build_hw()
139 vss->hw.formats |= pcm_format_to_bits(alsa_fmt); in virtsnd_pcm_build_hw()
142 if (!vss->hw.formats) { in virtsnd_pcm_build_hw()
143 dev_err(&vdev->dev, in virtsnd_pcm_build_hw()
145 vss->sid); in virtsnd_pcm_build_hw()
146 return -EINVAL; in virtsnd_pcm_build_hw()
149 values = le64_to_cpu(info->rates); in virtsnd_pcm_build_hw()
151 vss->hw.rates = 0; in virtsnd_pcm_build_hw()
155 if (!vss->hw.rate_min || in virtsnd_pcm_build_hw()
156 vss->hw.rate_min > g_v2a_rate_map[i].rate) in virtsnd_pcm_build_hw()
157 vss->hw.rate_min = g_v2a_rate_map[i].rate; in virtsnd_pcm_build_hw()
159 if (vss->hw.rate_max < g_v2a_rate_map[i].rate) in virtsnd_pcm_build_hw()
160 vss->hw.rate_max = g_v2a_rate_map[i].rate; in virtsnd_pcm_build_hw()
162 vss->hw.rates |= g_v2a_rate_map[i].alsa_bit; in virtsnd_pcm_build_hw()
165 if (!vss->hw.rates) { in virtsnd_pcm_build_hw()
166 dev_err(&vdev->dev, in virtsnd_pcm_build_hw()
168 vss->sid); in virtsnd_pcm_build_hw()
169 return -EINVAL; in virtsnd_pcm_build_hw()
172 vss->hw.periods_min = pcm_periods_min; in virtsnd_pcm_build_hw()
173 vss->hw.periods_max = pcm_periods_max; in virtsnd_pcm_build_hw()
182 vss->hw.buffer_bytes_max = in virtsnd_pcm_build_hw()
183 PAGE_ALIGN(sample_max * vss->hw.channels_max * pcm_buffer_ms * in virtsnd_pcm_build_hw()
184 (vss->hw.rate_max / MSEC_PER_SEC)); in virtsnd_pcm_build_hw()
193 vss->hw.period_bytes_min = in virtsnd_pcm_build_hw()
194 sample_min * vss->hw.channels_min * pcm_period_ms_min * in virtsnd_pcm_build_hw()
195 (vss->hw.rate_min / MSEC_PER_SEC); in virtsnd_pcm_build_hw()
201 vss->hw.period_bytes_max = in virtsnd_pcm_build_hw()
202 sample_max * vss->hw.channels_max * pcm_period_ms_max * in virtsnd_pcm_build_hw()
203 (vss->hw.rate_max / MSEC_PER_SEC); in virtsnd_pcm_build_hw()
209 * virtsnd_pcm_find() - Find the PCM device for the specified node ID.
210 * @snd: VirtIO sound device.
214 * Return: a pointer to the PCM device or ERR_PTR(-ENOENT).
220 list_for_each_entry(vpcm, &snd->pcm_list, list) in virtsnd_pcm_find()
221 if (vpcm->nid == nid) in virtsnd_pcm_find()
224 return ERR_PTR(-ENOENT); in virtsnd_pcm_find()
228 * virtsnd_pcm_find_or_create() - Find or create the PCM device for the
230 * @snd: VirtIO sound device.
234 * Return: a pointer to the PCM device or ERR_PTR(-errno).
238 struct virtio_device *vdev = snd->vdev; in virtsnd_pcm_find_or_create()
245 vpcm = devm_kzalloc(&vdev->dev, sizeof(*vpcm), GFP_KERNEL); in virtsnd_pcm_find_or_create()
247 return ERR_PTR(-ENOMEM); in virtsnd_pcm_find_or_create()
249 vpcm->nid = nid; in virtsnd_pcm_find_or_create()
250 list_add_tail(&vpcm->list, &snd->pcm_list); in virtsnd_pcm_find_or_create()
256 * virtsnd_pcm_validate() - Validate if the device can be started.
257 * @vdev: VirtIO parent device.
260 * Return: 0 on success, -EINVAL on failure.
265 dev_err(&vdev->dev, in virtsnd_pcm_validate()
268 return -EINVAL; in virtsnd_pcm_validate()
272 dev_err(&vdev->dev, in virtsnd_pcm_validate()
275 return -EINVAL; in virtsnd_pcm_validate()
279 dev_err(&vdev->dev, in virtsnd_pcm_validate()
282 return -EINVAL; in virtsnd_pcm_validate()
286 dev_err(&vdev->dev, in virtsnd_pcm_validate()
289 return -EINVAL; in virtsnd_pcm_validate()
296 * virtsnd_pcm_period_elapsed() - Kernel work function to handle the elapsed
302 * devices operate in non-atomic mode.
311 snd_pcm_period_elapsed(vss->substream); in virtsnd_pcm_period_elapsed()
315 * virtsnd_pcm_parse_cfg() - Parse the stream configuration.
316 * @snd: VirtIO sound device.
318 * This function is called during initial device initialization.
321 * Return: 0 on success, -errno on failure.
325 struct virtio_device *vdev = snd->vdev; in virtsnd_pcm_parse_cfg()
331 &snd->nsubstreams); in virtsnd_pcm_parse_cfg()
332 if (!snd->nsubstreams) in virtsnd_pcm_parse_cfg()
335 snd->substreams = devm_kcalloc(&vdev->dev, snd->nsubstreams, in virtsnd_pcm_parse_cfg()
336 sizeof(*snd->substreams), GFP_KERNEL); in virtsnd_pcm_parse_cfg()
337 if (!snd->substreams) in virtsnd_pcm_parse_cfg()
338 return -ENOMEM; in virtsnd_pcm_parse_cfg()
340 info = kcalloc(snd->nsubstreams, sizeof(*info), GFP_KERNEL); in virtsnd_pcm_parse_cfg()
342 return -ENOMEM; in virtsnd_pcm_parse_cfg()
345 snd->nsubstreams, sizeof(*info), info); in virtsnd_pcm_parse_cfg()
349 for (i = 0; i < snd->nsubstreams; ++i) { in virtsnd_pcm_parse_cfg()
350 struct virtio_pcm_substream *vss = &snd->substreams[i]; in virtsnd_pcm_parse_cfg()
353 vss->snd = snd; in virtsnd_pcm_parse_cfg()
354 vss->sid = i; in virtsnd_pcm_parse_cfg()
355 INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed); in virtsnd_pcm_parse_cfg()
356 init_waitqueue_head(&vss->msg_empty); in virtsnd_pcm_parse_cfg()
357 spin_lock_init(&vss->lock); in virtsnd_pcm_parse_cfg()
363 vss->nid = le32_to_cpu(info[i].hdr.hda_fn_nid); in virtsnd_pcm_parse_cfg()
365 vpcm = virtsnd_pcm_find_or_create(snd, vss->nid); in virtsnd_pcm_parse_cfg()
373 vss->direction = SNDRV_PCM_STREAM_PLAYBACK; in virtsnd_pcm_parse_cfg()
376 vss->direction = SNDRV_PCM_STREAM_CAPTURE; in virtsnd_pcm_parse_cfg()
379 dev_err(&vdev->dev, "SID %u: unknown direction (%u)\n", in virtsnd_pcm_parse_cfg()
380 vss->sid, info[i].direction); in virtsnd_pcm_parse_cfg()
381 rc = -EINVAL; in virtsnd_pcm_parse_cfg()
385 vpcm->streams[vss->direction].nsubstreams++; in virtsnd_pcm_parse_cfg()
395 * virtsnd_pcm_build_devs() - Build ALSA PCM devices.
396 * @snd: VirtIO sound device.
399 * Return: 0 on success, -errno on failure.
403 struct virtio_device *vdev = snd->vdev; in virtsnd_pcm_build_devs()
408 list_for_each_entry(vpcm, &snd->pcm_list, list) { in virtsnd_pcm_build_devs()
410 vpcm->streams[SNDRV_PCM_STREAM_PLAYBACK].nsubstreams; in virtsnd_pcm_build_devs()
412 vpcm->streams[SNDRV_PCM_STREAM_CAPTURE].nsubstreams; in virtsnd_pcm_build_devs()
417 rc = snd_pcm_new(snd->card, VIRTIO_SND_CARD_DRIVER, vpcm->nid, in virtsnd_pcm_build_devs()
418 npbs, ncps, &vpcm->pcm); in virtsnd_pcm_build_devs()
420 dev_err(&vdev->dev, "snd_pcm_new[%u] failed: %d\n", in virtsnd_pcm_build_devs()
421 vpcm->nid, rc); in virtsnd_pcm_build_devs()
425 vpcm->pcm->info_flags = 0; in virtsnd_pcm_build_devs()
426 vpcm->pcm->dev_class = SNDRV_PCM_CLASS_GENERIC; in virtsnd_pcm_build_devs()
427 vpcm->pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; in virtsnd_pcm_build_devs()
428 snprintf(vpcm->pcm->name, sizeof(vpcm->pcm->name), in virtsnd_pcm_build_devs()
429 VIRTIO_SND_PCM_NAME " %u", vpcm->pcm->device); in virtsnd_pcm_build_devs()
430 vpcm->pcm->private_data = vpcm; in virtsnd_pcm_build_devs()
431 vpcm->pcm->nonatomic = true; in virtsnd_pcm_build_devs()
433 for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) { in virtsnd_pcm_build_devs()
434 struct virtio_pcm_stream *stream = &vpcm->streams[i]; in virtsnd_pcm_build_devs()
436 if (!stream->nsubstreams) in virtsnd_pcm_build_devs()
439 stream->substreams = in virtsnd_pcm_build_devs()
440 devm_kcalloc(&vdev->dev, stream->nsubstreams, in virtsnd_pcm_build_devs()
441 sizeof(*stream->substreams), in virtsnd_pcm_build_devs()
443 if (!stream->substreams) in virtsnd_pcm_build_devs()
444 return -ENOMEM; in virtsnd_pcm_build_devs()
446 stream->nsubstreams = 0; in virtsnd_pcm_build_devs()
450 for (i = 0; i < snd->nsubstreams; ++i) { in virtsnd_pcm_build_devs()
452 struct virtio_pcm_substream *vss = &snd->substreams[i]; in virtsnd_pcm_build_devs()
454 vpcm = virtsnd_pcm_find(snd, vss->nid); in virtsnd_pcm_build_devs()
458 vs = &vpcm->streams[vss->direction]; in virtsnd_pcm_build_devs()
459 vs->substreams[vs->nsubstreams++] = vss; in virtsnd_pcm_build_devs()
462 list_for_each_entry(vpcm, &snd->pcm_list, list) { in virtsnd_pcm_build_devs()
463 for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) { in virtsnd_pcm_build_devs()
464 struct virtio_pcm_stream *vs = &vpcm->streams[i]; in virtsnd_pcm_build_devs()
465 struct snd_pcm_str *ks = &vpcm->pcm->streams[i]; in virtsnd_pcm_build_devs()
468 if (!vs->nsubstreams) in virtsnd_pcm_build_devs()
471 for (kss = ks->substream; kss; kss = kss->next) in virtsnd_pcm_build_devs()
472 vs->substreams[kss->number]->substream = kss; in virtsnd_pcm_build_devs()
474 snd_pcm_set_ops(vpcm->pcm, i, &virtsnd_pcm_ops); in virtsnd_pcm_build_devs()
477 snd_pcm_set_managed_buffer_all(vpcm->pcm, in virtsnd_pcm_build_devs()
486 * virtsnd_pcm_event() - Handle the PCM device event notification.
487 * @snd: VirtIO sound device.
488 * @event: VirtIO sound event.
495 u32 sid = le32_to_cpu(event->data); in virtsnd_pcm_event()
497 if (sid >= snd->nsubstreams) in virtsnd_pcm_event()
500 vss = &snd->substreams[sid]; in virtsnd_pcm_event()
502 switch (le32_to_cpu(event->hdr.code)) { in virtsnd_pcm_event()
507 spin_lock(&vss->lock); in virtsnd_pcm_event()
508 if (vss->xfer_enabled) in virtsnd_pcm_event()
509 vss->xfer_xrun = true; in virtsnd_pcm_event()
510 spin_unlock(&vss->lock); in virtsnd_pcm_event()