virtio_card.c (10337B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * virtio-snd: Virtio sound device 4 * Copyright (C) 2021 OpenSynergy GmbH 5 */ 6#include <linux/module.h> 7#include <linux/moduleparam.h> 8#include <linux/virtio_config.h> 9#include <sound/initval.h> 10#include <uapi/linux/virtio_ids.h> 11 12#include "virtio_card.h" 13 14u32 virtsnd_msg_timeout_ms = MSEC_PER_SEC; 15module_param_named(msg_timeout_ms, virtsnd_msg_timeout_ms, uint, 0644); 16MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds"); 17 18static void virtsnd_remove(struct virtio_device *vdev); 19 20/** 21 * virtsnd_event_send() - Add an event to the event queue. 22 * @vqueue: Underlying event virtqueue. 23 * @event: Event. 24 * @notify: Indicates whether or not to send a notification to the device. 25 * @gfp: Kernel flags for memory allocation. 26 * 27 * Context: Any context. 28 */ 29static void virtsnd_event_send(struct virtqueue *vqueue, 30 struct virtio_snd_event *event, bool notify, 31 gfp_t gfp) 32{ 33 struct scatterlist sg; 34 struct scatterlist *psgs[1] = { &sg }; 35 36 /* reset event content */ 37 memset(event, 0, sizeof(*event)); 38 39 sg_init_one(&sg, event, sizeof(*event)); 40 41 if (virtqueue_add_sgs(vqueue, psgs, 0, 1, event, gfp) || !notify) 42 return; 43 44 if (virtqueue_kick_prepare(vqueue)) 45 virtqueue_notify(vqueue); 46} 47 48/** 49 * virtsnd_event_dispatch() - Dispatch an event from the device side. 50 * @snd: VirtIO sound device. 51 * @event: VirtIO sound event. 52 * 53 * Context: Any context. 54 */ 55static void virtsnd_event_dispatch(struct virtio_snd *snd, 56 struct virtio_snd_event *event) 57{ 58 switch (le32_to_cpu(event->hdr.code)) { 59 case VIRTIO_SND_EVT_JACK_CONNECTED: 60 case VIRTIO_SND_EVT_JACK_DISCONNECTED: 61 virtsnd_jack_event(snd, event); 62 break; 63 case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED: 64 case VIRTIO_SND_EVT_PCM_XRUN: 65 virtsnd_pcm_event(snd, event); 66 break; 67 } 68} 69 70/** 71 * virtsnd_event_notify_cb() - Dispatch all reported events from the event queue. 72 * @vqueue: Underlying event virtqueue. 73 * 74 * This callback function is called upon a vring interrupt request from the 75 * device. 76 * 77 * Context: Interrupt context. 78 */ 79static void virtsnd_event_notify_cb(struct virtqueue *vqueue) 80{ 81 struct virtio_snd *snd = vqueue->vdev->priv; 82 struct virtio_snd_queue *queue = virtsnd_event_queue(snd); 83 struct virtio_snd_event *event; 84 u32 length; 85 unsigned long flags; 86 87 spin_lock_irqsave(&queue->lock, flags); 88 do { 89 virtqueue_disable_cb(vqueue); 90 while ((event = virtqueue_get_buf(vqueue, &length))) { 91 virtsnd_event_dispatch(snd, event); 92 virtsnd_event_send(vqueue, event, true, GFP_ATOMIC); 93 } 94 if (unlikely(virtqueue_is_broken(vqueue))) 95 break; 96 } while (!virtqueue_enable_cb(vqueue)); 97 spin_unlock_irqrestore(&queue->lock, flags); 98} 99 100/** 101 * virtsnd_find_vqs() - Enumerate and initialize all virtqueues. 102 * @snd: VirtIO sound device. 103 * 104 * After calling this function, the event queue is disabled. 105 * 106 * Context: Any context. 107 * Return: 0 on success, -errno on failure. 108 */ 109static int virtsnd_find_vqs(struct virtio_snd *snd) 110{ 111 struct virtio_device *vdev = snd->vdev; 112 static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = { 113 [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb, 114 [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb, 115 [VIRTIO_SND_VQ_TX] = virtsnd_pcm_tx_notify_cb, 116 [VIRTIO_SND_VQ_RX] = virtsnd_pcm_rx_notify_cb 117 }; 118 static const char *names[VIRTIO_SND_VQ_MAX] = { 119 [VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl", 120 [VIRTIO_SND_VQ_EVENT] = "virtsnd-event", 121 [VIRTIO_SND_VQ_TX] = "virtsnd-tx", 122 [VIRTIO_SND_VQ_RX] = "virtsnd-rx" 123 }; 124 struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 }; 125 unsigned int i; 126 unsigned int n; 127 int rc; 128 129 rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, callbacks, names, 130 NULL); 131 if (rc) { 132 dev_err(&vdev->dev, "failed to initialize virtqueues\n"); 133 return rc; 134 } 135 136 for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i) 137 snd->queues[i].vqueue = vqs[i]; 138 139 /* Allocate events and populate the event queue */ 140 virtqueue_disable_cb(vqs[VIRTIO_SND_VQ_EVENT]); 141 142 n = virtqueue_get_vring_size(vqs[VIRTIO_SND_VQ_EVENT]); 143 144 snd->event_msgs = kmalloc_array(n, sizeof(*snd->event_msgs), 145 GFP_KERNEL); 146 if (!snd->event_msgs) 147 return -ENOMEM; 148 149 for (i = 0; i < n; ++i) 150 virtsnd_event_send(vqs[VIRTIO_SND_VQ_EVENT], 151 &snd->event_msgs[i], false, GFP_KERNEL); 152 153 return 0; 154} 155 156/** 157 * virtsnd_enable_event_vq() - Enable the event virtqueue. 158 * @snd: VirtIO sound device. 159 * 160 * Context: Any context. 161 */ 162static void virtsnd_enable_event_vq(struct virtio_snd *snd) 163{ 164 struct virtio_snd_queue *queue = virtsnd_event_queue(snd); 165 166 if (!virtqueue_enable_cb(queue->vqueue)) 167 virtsnd_event_notify_cb(queue->vqueue); 168} 169 170/** 171 * virtsnd_disable_event_vq() - Disable the event virtqueue. 172 * @snd: VirtIO sound device. 173 * 174 * Context: Any context. 175 */ 176static void virtsnd_disable_event_vq(struct virtio_snd *snd) 177{ 178 struct virtio_snd_queue *queue = virtsnd_event_queue(snd); 179 struct virtio_snd_event *event; 180 u32 length; 181 unsigned long flags; 182 183 if (queue->vqueue) { 184 spin_lock_irqsave(&queue->lock, flags); 185 virtqueue_disable_cb(queue->vqueue); 186 while ((event = virtqueue_get_buf(queue->vqueue, &length))) 187 virtsnd_event_dispatch(snd, event); 188 spin_unlock_irqrestore(&queue->lock, flags); 189 } 190} 191 192/** 193 * virtsnd_build_devs() - Read configuration and build ALSA devices. 194 * @snd: VirtIO sound device. 195 * 196 * Context: Any context that permits to sleep. 197 * Return: 0 on success, -errno on failure. 198 */ 199static int virtsnd_build_devs(struct virtio_snd *snd) 200{ 201 struct virtio_device *vdev = snd->vdev; 202 struct device *dev = &vdev->dev; 203 int rc; 204 205 rc = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, 206 THIS_MODULE, 0, &snd->card); 207 if (rc < 0) 208 return rc; 209 210 snd->card->private_data = snd; 211 212 strscpy(snd->card->driver, VIRTIO_SND_CARD_DRIVER, 213 sizeof(snd->card->driver)); 214 strscpy(snd->card->shortname, VIRTIO_SND_CARD_NAME, 215 sizeof(snd->card->shortname)); 216 if (dev->parent->bus) 217 snprintf(snd->card->longname, sizeof(snd->card->longname), 218 VIRTIO_SND_CARD_NAME " at %s/%s/%s", 219 dev->parent->bus->name, dev_name(dev->parent), 220 dev_name(dev)); 221 else 222 snprintf(snd->card->longname, sizeof(snd->card->longname), 223 VIRTIO_SND_CARD_NAME " at %s/%s", 224 dev_name(dev->parent), dev_name(dev)); 225 226 rc = virtsnd_jack_parse_cfg(snd); 227 if (rc) 228 return rc; 229 230 rc = virtsnd_pcm_parse_cfg(snd); 231 if (rc) 232 return rc; 233 234 rc = virtsnd_chmap_parse_cfg(snd); 235 if (rc) 236 return rc; 237 238 if (snd->njacks) { 239 rc = virtsnd_jack_build_devs(snd); 240 if (rc) 241 return rc; 242 } 243 244 if (snd->nsubstreams) { 245 rc = virtsnd_pcm_build_devs(snd); 246 if (rc) 247 return rc; 248 } 249 250 if (snd->nchmaps) { 251 rc = virtsnd_chmap_build_devs(snd); 252 if (rc) 253 return rc; 254 } 255 256 return snd_card_register(snd->card); 257} 258 259/** 260 * virtsnd_validate() - Validate if the device can be started. 261 * @vdev: VirtIO parent device. 262 * 263 * Context: Any context. 264 * Return: 0 on success, -EINVAL on failure. 265 */ 266static int virtsnd_validate(struct virtio_device *vdev) 267{ 268 if (!vdev->config->get) { 269 dev_err(&vdev->dev, "configuration access disabled\n"); 270 return -EINVAL; 271 } 272 273 if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { 274 dev_err(&vdev->dev, 275 "device does not comply with spec version 1.x\n"); 276 return -EINVAL; 277 } 278 279 if (!virtsnd_msg_timeout_ms) { 280 dev_err(&vdev->dev, "msg_timeout_ms value cannot be zero\n"); 281 return -EINVAL; 282 } 283 284 if (virtsnd_pcm_validate(vdev)) 285 return -EINVAL; 286 287 return 0; 288} 289 290/** 291 * virtsnd_probe() - Create and initialize the device. 292 * @vdev: VirtIO parent device. 293 * 294 * Context: Any context that permits to sleep. 295 * Return: 0 on success, -errno on failure. 296 */ 297static int virtsnd_probe(struct virtio_device *vdev) 298{ 299 struct virtio_snd *snd; 300 unsigned int i; 301 int rc; 302 303 snd = devm_kzalloc(&vdev->dev, sizeof(*snd), GFP_KERNEL); 304 if (!snd) 305 return -ENOMEM; 306 307 snd->vdev = vdev; 308 INIT_LIST_HEAD(&snd->ctl_msgs); 309 INIT_LIST_HEAD(&snd->pcm_list); 310 311 vdev->priv = snd; 312 313 for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i) 314 spin_lock_init(&snd->queues[i].lock); 315 316 rc = virtsnd_find_vqs(snd); 317 if (rc) 318 goto on_exit; 319 320 virtio_device_ready(vdev); 321 322 rc = virtsnd_build_devs(snd); 323 if (rc) 324 goto on_exit; 325 326 virtsnd_enable_event_vq(snd); 327 328on_exit: 329 if (rc) 330 virtsnd_remove(vdev); 331 332 return rc; 333} 334 335/** 336 * virtsnd_remove() - Remove VirtIO and ALSA devices. 337 * @vdev: VirtIO parent device. 338 * 339 * Context: Any context that permits to sleep. 340 */ 341static void virtsnd_remove(struct virtio_device *vdev) 342{ 343 struct virtio_snd *snd = vdev->priv; 344 unsigned int i; 345 346 virtsnd_disable_event_vq(snd); 347 virtsnd_ctl_msg_cancel_all(snd); 348 349 if (snd->card) 350 snd_card_free(snd->card); 351 352 vdev->config->del_vqs(vdev); 353 virtio_reset_device(vdev); 354 355 for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) { 356 struct virtio_pcm_substream *vss = &snd->substreams[i]; 357 358 cancel_work_sync(&vss->elapsed_period); 359 virtsnd_pcm_msg_free(vss); 360 } 361 362 kfree(snd->event_msgs); 363} 364 365#ifdef CONFIG_PM_SLEEP 366/** 367 * virtsnd_freeze() - Suspend device. 368 * @vdev: VirtIO parent device. 369 * 370 * Context: Any context. 371 * Return: 0 on success, -errno on failure. 372 */ 373static int virtsnd_freeze(struct virtio_device *vdev) 374{ 375 struct virtio_snd *snd = vdev->priv; 376 unsigned int i; 377 378 virtsnd_disable_event_vq(snd); 379 virtsnd_ctl_msg_cancel_all(snd); 380 381 vdev->config->del_vqs(vdev); 382 virtio_reset_device(vdev); 383 384 for (i = 0; i < snd->nsubstreams; ++i) 385 cancel_work_sync(&snd->substreams[i].elapsed_period); 386 387 kfree(snd->event_msgs); 388 snd->event_msgs = NULL; 389 390 return 0; 391} 392 393/** 394 * virtsnd_restore() - Resume device. 395 * @vdev: VirtIO parent device. 396 * 397 * Context: Any context. 398 * Return: 0 on success, -errno on failure. 399 */ 400static int virtsnd_restore(struct virtio_device *vdev) 401{ 402 struct virtio_snd *snd = vdev->priv; 403 int rc; 404 405 rc = virtsnd_find_vqs(snd); 406 if (rc) 407 return rc; 408 409 virtio_device_ready(vdev); 410 411 virtsnd_enable_event_vq(snd); 412 413 return 0; 414} 415#endif /* CONFIG_PM_SLEEP */ 416 417static const struct virtio_device_id id_table[] = { 418 { VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID }, 419 { 0 }, 420}; 421 422static struct virtio_driver virtsnd_driver = { 423 .driver.name = KBUILD_MODNAME, 424 .driver.owner = THIS_MODULE, 425 .id_table = id_table, 426 .validate = virtsnd_validate, 427 .probe = virtsnd_probe, 428 .remove = virtsnd_remove, 429#ifdef CONFIG_PM_SLEEP 430 .freeze = virtsnd_freeze, 431 .restore = virtsnd_restore, 432#endif 433}; 434 435module_virtio_driver(virtsnd_driver); 436 437MODULE_DEVICE_TABLE(virtio, id_table); 438MODULE_DESCRIPTION("Virtio sound card driver"); 439MODULE_LICENSE("GPL");