1*de3a9980SAnton Yakovlev // SPDX-License-Identifier: GPL-2.0+ 2*de3a9980SAnton Yakovlev /* 3*de3a9980SAnton Yakovlev * virtio-snd: Virtio sound device 4*de3a9980SAnton Yakovlev * Copyright (C) 2021 OpenSynergy GmbH 5*de3a9980SAnton Yakovlev */ 6*de3a9980SAnton Yakovlev #include <linux/module.h> 7*de3a9980SAnton Yakovlev #include <linux/moduleparam.h> 8*de3a9980SAnton Yakovlev #include <linux/virtio_config.h> 9*de3a9980SAnton Yakovlev #include <sound/initval.h> 10*de3a9980SAnton Yakovlev #include <uapi/linux/virtio_ids.h> 11*de3a9980SAnton Yakovlev 12*de3a9980SAnton Yakovlev #include "virtio_card.h" 13*de3a9980SAnton Yakovlev 14*de3a9980SAnton Yakovlev static void virtsnd_remove(struct virtio_device *vdev); 15*de3a9980SAnton Yakovlev 16*de3a9980SAnton Yakovlev /** 17*de3a9980SAnton Yakovlev * virtsnd_event_send() - Add an event to the event queue. 18*de3a9980SAnton Yakovlev * @vqueue: Underlying event virtqueue. 19*de3a9980SAnton Yakovlev * @event: Event. 20*de3a9980SAnton Yakovlev * @notify: Indicates whether or not to send a notification to the device. 21*de3a9980SAnton Yakovlev * @gfp: Kernel flags for memory allocation. 22*de3a9980SAnton Yakovlev * 23*de3a9980SAnton Yakovlev * Context: Any context. 24*de3a9980SAnton Yakovlev */ 25*de3a9980SAnton Yakovlev static void virtsnd_event_send(struct virtqueue *vqueue, 26*de3a9980SAnton Yakovlev struct virtio_snd_event *event, bool notify, 27*de3a9980SAnton Yakovlev gfp_t gfp) 28*de3a9980SAnton Yakovlev { 29*de3a9980SAnton Yakovlev struct scatterlist sg; 30*de3a9980SAnton Yakovlev struct scatterlist *psgs[1] = { &sg }; 31*de3a9980SAnton Yakovlev 32*de3a9980SAnton Yakovlev /* reset event content */ 33*de3a9980SAnton Yakovlev memset(event, 0, sizeof(*event)); 34*de3a9980SAnton Yakovlev 35*de3a9980SAnton Yakovlev sg_init_one(&sg, event, sizeof(*event)); 36*de3a9980SAnton Yakovlev 37*de3a9980SAnton Yakovlev if (virtqueue_add_sgs(vqueue, psgs, 0, 1, event, gfp) || !notify) 38*de3a9980SAnton Yakovlev return; 39*de3a9980SAnton Yakovlev 40*de3a9980SAnton Yakovlev if (virtqueue_kick_prepare(vqueue)) 41*de3a9980SAnton Yakovlev virtqueue_notify(vqueue); 42*de3a9980SAnton Yakovlev } 43*de3a9980SAnton Yakovlev 44*de3a9980SAnton Yakovlev /** 45*de3a9980SAnton Yakovlev * virtsnd_event_dispatch() - Dispatch an event from the device side. 46*de3a9980SAnton Yakovlev * @snd: VirtIO sound device. 47*de3a9980SAnton Yakovlev * @event: VirtIO sound event. 48*de3a9980SAnton Yakovlev * 49*de3a9980SAnton Yakovlev * Context: Any context. 50*de3a9980SAnton Yakovlev */ 51*de3a9980SAnton Yakovlev static void virtsnd_event_dispatch(struct virtio_snd *snd, 52*de3a9980SAnton Yakovlev struct virtio_snd_event *event) 53*de3a9980SAnton Yakovlev { 54*de3a9980SAnton Yakovlev } 55*de3a9980SAnton Yakovlev 56*de3a9980SAnton Yakovlev /** 57*de3a9980SAnton Yakovlev * virtsnd_event_notify_cb() - Dispatch all reported events from the event queue. 58*de3a9980SAnton Yakovlev * @vqueue: Underlying event virtqueue. 59*de3a9980SAnton Yakovlev * 60*de3a9980SAnton Yakovlev * This callback function is called upon a vring interrupt request from the 61*de3a9980SAnton Yakovlev * device. 62*de3a9980SAnton Yakovlev * 63*de3a9980SAnton Yakovlev * Context: Interrupt context. 64*de3a9980SAnton Yakovlev */ 65*de3a9980SAnton Yakovlev static void virtsnd_event_notify_cb(struct virtqueue *vqueue) 66*de3a9980SAnton Yakovlev { 67*de3a9980SAnton Yakovlev struct virtio_snd *snd = vqueue->vdev->priv; 68*de3a9980SAnton Yakovlev struct virtio_snd_queue *queue = virtsnd_event_queue(snd); 69*de3a9980SAnton Yakovlev struct virtio_snd_event *event; 70*de3a9980SAnton Yakovlev u32 length; 71*de3a9980SAnton Yakovlev unsigned long flags; 72*de3a9980SAnton Yakovlev 73*de3a9980SAnton Yakovlev spin_lock_irqsave(&queue->lock, flags); 74*de3a9980SAnton Yakovlev do { 75*de3a9980SAnton Yakovlev virtqueue_disable_cb(vqueue); 76*de3a9980SAnton Yakovlev while ((event = virtqueue_get_buf(vqueue, &length))) { 77*de3a9980SAnton Yakovlev virtsnd_event_dispatch(snd, event); 78*de3a9980SAnton Yakovlev virtsnd_event_send(vqueue, event, true, GFP_ATOMIC); 79*de3a9980SAnton Yakovlev } 80*de3a9980SAnton Yakovlev if (unlikely(virtqueue_is_broken(vqueue))) 81*de3a9980SAnton Yakovlev break; 82*de3a9980SAnton Yakovlev } while (!virtqueue_enable_cb(vqueue)); 83*de3a9980SAnton Yakovlev spin_unlock_irqrestore(&queue->lock, flags); 84*de3a9980SAnton Yakovlev } 85*de3a9980SAnton Yakovlev 86*de3a9980SAnton Yakovlev /** 87*de3a9980SAnton Yakovlev * virtsnd_find_vqs() - Enumerate and initialize all virtqueues. 88*de3a9980SAnton Yakovlev * @snd: VirtIO sound device. 89*de3a9980SAnton Yakovlev * 90*de3a9980SAnton Yakovlev * After calling this function, the event queue is disabled. 91*de3a9980SAnton Yakovlev * 92*de3a9980SAnton Yakovlev * Context: Any context. 93*de3a9980SAnton Yakovlev * Return: 0 on success, -errno on failure. 94*de3a9980SAnton Yakovlev */ 95*de3a9980SAnton Yakovlev static int virtsnd_find_vqs(struct virtio_snd *snd) 96*de3a9980SAnton Yakovlev { 97*de3a9980SAnton Yakovlev struct virtio_device *vdev = snd->vdev; 98*de3a9980SAnton Yakovlev static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = { 99*de3a9980SAnton Yakovlev [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb 100*de3a9980SAnton Yakovlev }; 101*de3a9980SAnton Yakovlev static const char *names[VIRTIO_SND_VQ_MAX] = { 102*de3a9980SAnton Yakovlev [VIRTIO_SND_VQ_EVENT] = "virtsnd-event" 103*de3a9980SAnton Yakovlev }; 104*de3a9980SAnton Yakovlev struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 }; 105*de3a9980SAnton Yakovlev unsigned int i; 106*de3a9980SAnton Yakovlev unsigned int n; 107*de3a9980SAnton Yakovlev int rc; 108*de3a9980SAnton Yakovlev 109*de3a9980SAnton Yakovlev rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, callbacks, names, 110*de3a9980SAnton Yakovlev NULL); 111*de3a9980SAnton Yakovlev if (rc) { 112*de3a9980SAnton Yakovlev dev_err(&vdev->dev, "failed to initialize virtqueues\n"); 113*de3a9980SAnton Yakovlev return rc; 114*de3a9980SAnton Yakovlev } 115*de3a9980SAnton Yakovlev 116*de3a9980SAnton Yakovlev for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i) 117*de3a9980SAnton Yakovlev snd->queues[i].vqueue = vqs[i]; 118*de3a9980SAnton Yakovlev 119*de3a9980SAnton Yakovlev /* Allocate events and populate the event queue */ 120*de3a9980SAnton Yakovlev virtqueue_disable_cb(vqs[VIRTIO_SND_VQ_EVENT]); 121*de3a9980SAnton Yakovlev 122*de3a9980SAnton Yakovlev n = virtqueue_get_vring_size(vqs[VIRTIO_SND_VQ_EVENT]); 123*de3a9980SAnton Yakovlev 124*de3a9980SAnton Yakovlev snd->event_msgs = kmalloc_array(n, sizeof(*snd->event_msgs), 125*de3a9980SAnton Yakovlev GFP_KERNEL); 126*de3a9980SAnton Yakovlev if (!snd->event_msgs) 127*de3a9980SAnton Yakovlev return -ENOMEM; 128*de3a9980SAnton Yakovlev 129*de3a9980SAnton Yakovlev for (i = 0; i < n; ++i) 130*de3a9980SAnton Yakovlev virtsnd_event_send(vqs[VIRTIO_SND_VQ_EVENT], 131*de3a9980SAnton Yakovlev &snd->event_msgs[i], false, GFP_KERNEL); 132*de3a9980SAnton Yakovlev 133*de3a9980SAnton Yakovlev return 0; 134*de3a9980SAnton Yakovlev } 135*de3a9980SAnton Yakovlev 136*de3a9980SAnton Yakovlev /** 137*de3a9980SAnton Yakovlev * virtsnd_enable_event_vq() - Enable the event virtqueue. 138*de3a9980SAnton Yakovlev * @snd: VirtIO sound device. 139*de3a9980SAnton Yakovlev * 140*de3a9980SAnton Yakovlev * Context: Any context. 141*de3a9980SAnton Yakovlev */ 142*de3a9980SAnton Yakovlev static void virtsnd_enable_event_vq(struct virtio_snd *snd) 143*de3a9980SAnton Yakovlev { 144*de3a9980SAnton Yakovlev struct virtio_snd_queue *queue = virtsnd_event_queue(snd); 145*de3a9980SAnton Yakovlev 146*de3a9980SAnton Yakovlev if (!virtqueue_enable_cb(queue->vqueue)) 147*de3a9980SAnton Yakovlev virtsnd_event_notify_cb(queue->vqueue); 148*de3a9980SAnton Yakovlev } 149*de3a9980SAnton Yakovlev 150*de3a9980SAnton Yakovlev /** 151*de3a9980SAnton Yakovlev * virtsnd_disable_event_vq() - Disable the event virtqueue. 152*de3a9980SAnton Yakovlev * @snd: VirtIO sound device. 153*de3a9980SAnton Yakovlev * 154*de3a9980SAnton Yakovlev * Context: Any context. 155*de3a9980SAnton Yakovlev */ 156*de3a9980SAnton Yakovlev static void virtsnd_disable_event_vq(struct virtio_snd *snd) 157*de3a9980SAnton Yakovlev { 158*de3a9980SAnton Yakovlev struct virtio_snd_queue *queue = virtsnd_event_queue(snd); 159*de3a9980SAnton Yakovlev struct virtio_snd_event *event; 160*de3a9980SAnton Yakovlev u32 length; 161*de3a9980SAnton Yakovlev unsigned long flags; 162*de3a9980SAnton Yakovlev 163*de3a9980SAnton Yakovlev if (queue->vqueue) { 164*de3a9980SAnton Yakovlev spin_lock_irqsave(&queue->lock, flags); 165*de3a9980SAnton Yakovlev virtqueue_disable_cb(queue->vqueue); 166*de3a9980SAnton Yakovlev while ((event = virtqueue_get_buf(queue->vqueue, &length))) 167*de3a9980SAnton Yakovlev virtsnd_event_dispatch(snd, event); 168*de3a9980SAnton Yakovlev spin_unlock_irqrestore(&queue->lock, flags); 169*de3a9980SAnton Yakovlev } 170*de3a9980SAnton Yakovlev } 171*de3a9980SAnton Yakovlev 172*de3a9980SAnton Yakovlev /** 173*de3a9980SAnton Yakovlev * virtsnd_build_devs() - Read configuration and build ALSA devices. 174*de3a9980SAnton Yakovlev * @snd: VirtIO sound device. 175*de3a9980SAnton Yakovlev * 176*de3a9980SAnton Yakovlev * Context: Any context that permits to sleep. 177*de3a9980SAnton Yakovlev * Return: 0 on success, -errno on failure. 178*de3a9980SAnton Yakovlev */ 179*de3a9980SAnton Yakovlev static int virtsnd_build_devs(struct virtio_snd *snd) 180*de3a9980SAnton Yakovlev { 181*de3a9980SAnton Yakovlev struct virtio_device *vdev = snd->vdev; 182*de3a9980SAnton Yakovlev struct device *dev = &vdev->dev; 183*de3a9980SAnton Yakovlev int rc; 184*de3a9980SAnton Yakovlev 185*de3a9980SAnton Yakovlev rc = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, 186*de3a9980SAnton Yakovlev THIS_MODULE, 0, &snd->card); 187*de3a9980SAnton Yakovlev if (rc < 0) 188*de3a9980SAnton Yakovlev return rc; 189*de3a9980SAnton Yakovlev 190*de3a9980SAnton Yakovlev snd->card->private_data = snd; 191*de3a9980SAnton Yakovlev 192*de3a9980SAnton Yakovlev strscpy(snd->card->driver, VIRTIO_SND_CARD_DRIVER, 193*de3a9980SAnton Yakovlev sizeof(snd->card->driver)); 194*de3a9980SAnton Yakovlev strscpy(snd->card->shortname, VIRTIO_SND_CARD_NAME, 195*de3a9980SAnton Yakovlev sizeof(snd->card->shortname)); 196*de3a9980SAnton Yakovlev if (dev->parent->bus) 197*de3a9980SAnton Yakovlev snprintf(snd->card->longname, sizeof(snd->card->longname), 198*de3a9980SAnton Yakovlev VIRTIO_SND_CARD_NAME " at %s/%s/%s", 199*de3a9980SAnton Yakovlev dev->parent->bus->name, dev_name(dev->parent), 200*de3a9980SAnton Yakovlev dev_name(dev)); 201*de3a9980SAnton Yakovlev else 202*de3a9980SAnton Yakovlev snprintf(snd->card->longname, sizeof(snd->card->longname), 203*de3a9980SAnton Yakovlev VIRTIO_SND_CARD_NAME " at %s/%s", 204*de3a9980SAnton Yakovlev dev_name(dev->parent), dev_name(dev)); 205*de3a9980SAnton Yakovlev 206*de3a9980SAnton Yakovlev return snd_card_register(snd->card); 207*de3a9980SAnton Yakovlev } 208*de3a9980SAnton Yakovlev 209*de3a9980SAnton Yakovlev /** 210*de3a9980SAnton Yakovlev * virtsnd_validate() - Validate if the device can be started. 211*de3a9980SAnton Yakovlev * @vdev: VirtIO parent device. 212*de3a9980SAnton Yakovlev * 213*de3a9980SAnton Yakovlev * Context: Any context. 214*de3a9980SAnton Yakovlev * Return: 0 on success, -EINVAL on failure. 215*de3a9980SAnton Yakovlev */ 216*de3a9980SAnton Yakovlev static int virtsnd_validate(struct virtio_device *vdev) 217*de3a9980SAnton Yakovlev { 218*de3a9980SAnton Yakovlev if (!vdev->config->get) { 219*de3a9980SAnton Yakovlev dev_err(&vdev->dev, "configuration access disabled\n"); 220*de3a9980SAnton Yakovlev return -EINVAL; 221*de3a9980SAnton Yakovlev } 222*de3a9980SAnton Yakovlev 223*de3a9980SAnton Yakovlev if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { 224*de3a9980SAnton Yakovlev dev_err(&vdev->dev, 225*de3a9980SAnton Yakovlev "device does not comply with spec version 1.x\n"); 226*de3a9980SAnton Yakovlev return -EINVAL; 227*de3a9980SAnton Yakovlev } 228*de3a9980SAnton Yakovlev 229*de3a9980SAnton Yakovlev return 0; 230*de3a9980SAnton Yakovlev } 231*de3a9980SAnton Yakovlev 232*de3a9980SAnton Yakovlev /** 233*de3a9980SAnton Yakovlev * virtsnd_probe() - Create and initialize the device. 234*de3a9980SAnton Yakovlev * @vdev: VirtIO parent device. 235*de3a9980SAnton Yakovlev * 236*de3a9980SAnton Yakovlev * Context: Any context that permits to sleep. 237*de3a9980SAnton Yakovlev * Return: 0 on success, -errno on failure. 238*de3a9980SAnton Yakovlev */ 239*de3a9980SAnton Yakovlev static int virtsnd_probe(struct virtio_device *vdev) 240*de3a9980SAnton Yakovlev { 241*de3a9980SAnton Yakovlev struct virtio_snd *snd; 242*de3a9980SAnton Yakovlev unsigned int i; 243*de3a9980SAnton Yakovlev int rc; 244*de3a9980SAnton Yakovlev 245*de3a9980SAnton Yakovlev snd = devm_kzalloc(&vdev->dev, sizeof(*snd), GFP_KERNEL); 246*de3a9980SAnton Yakovlev if (!snd) 247*de3a9980SAnton Yakovlev return -ENOMEM; 248*de3a9980SAnton Yakovlev 249*de3a9980SAnton Yakovlev snd->vdev = vdev; 250*de3a9980SAnton Yakovlev 251*de3a9980SAnton Yakovlev vdev->priv = snd; 252*de3a9980SAnton Yakovlev 253*de3a9980SAnton Yakovlev for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i) 254*de3a9980SAnton Yakovlev spin_lock_init(&snd->queues[i].lock); 255*de3a9980SAnton Yakovlev 256*de3a9980SAnton Yakovlev rc = virtsnd_find_vqs(snd); 257*de3a9980SAnton Yakovlev if (rc) 258*de3a9980SAnton Yakovlev goto on_exit; 259*de3a9980SAnton Yakovlev 260*de3a9980SAnton Yakovlev virtio_device_ready(vdev); 261*de3a9980SAnton Yakovlev 262*de3a9980SAnton Yakovlev rc = virtsnd_build_devs(snd); 263*de3a9980SAnton Yakovlev if (rc) 264*de3a9980SAnton Yakovlev goto on_exit; 265*de3a9980SAnton Yakovlev 266*de3a9980SAnton Yakovlev virtsnd_enable_event_vq(snd); 267*de3a9980SAnton Yakovlev 268*de3a9980SAnton Yakovlev on_exit: 269*de3a9980SAnton Yakovlev if (rc) 270*de3a9980SAnton Yakovlev virtsnd_remove(vdev); 271*de3a9980SAnton Yakovlev 272*de3a9980SAnton Yakovlev return rc; 273*de3a9980SAnton Yakovlev } 274*de3a9980SAnton Yakovlev 275*de3a9980SAnton Yakovlev /** 276*de3a9980SAnton Yakovlev * virtsnd_remove() - Remove VirtIO and ALSA devices. 277*de3a9980SAnton Yakovlev * @vdev: VirtIO parent device. 278*de3a9980SAnton Yakovlev * 279*de3a9980SAnton Yakovlev * Context: Any context that permits to sleep. 280*de3a9980SAnton Yakovlev */ 281*de3a9980SAnton Yakovlev static void virtsnd_remove(struct virtio_device *vdev) 282*de3a9980SAnton Yakovlev { 283*de3a9980SAnton Yakovlev struct virtio_snd *snd = vdev->priv; 284*de3a9980SAnton Yakovlev 285*de3a9980SAnton Yakovlev virtsnd_disable_event_vq(snd); 286*de3a9980SAnton Yakovlev 287*de3a9980SAnton Yakovlev if (snd->card) 288*de3a9980SAnton Yakovlev snd_card_free(snd->card); 289*de3a9980SAnton Yakovlev 290*de3a9980SAnton Yakovlev vdev->config->del_vqs(vdev); 291*de3a9980SAnton Yakovlev vdev->config->reset(vdev); 292*de3a9980SAnton Yakovlev 293*de3a9980SAnton Yakovlev kfree(snd->event_msgs); 294*de3a9980SAnton Yakovlev } 295*de3a9980SAnton Yakovlev 296*de3a9980SAnton Yakovlev static const struct virtio_device_id id_table[] = { 297*de3a9980SAnton Yakovlev { VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID }, 298*de3a9980SAnton Yakovlev { 0 }, 299*de3a9980SAnton Yakovlev }; 300*de3a9980SAnton Yakovlev 301*de3a9980SAnton Yakovlev static struct virtio_driver virtsnd_driver = { 302*de3a9980SAnton Yakovlev .driver.name = KBUILD_MODNAME, 303*de3a9980SAnton Yakovlev .driver.owner = THIS_MODULE, 304*de3a9980SAnton Yakovlev .id_table = id_table, 305*de3a9980SAnton Yakovlev .validate = virtsnd_validate, 306*de3a9980SAnton Yakovlev .probe = virtsnd_probe, 307*de3a9980SAnton Yakovlev .remove = virtsnd_remove, 308*de3a9980SAnton Yakovlev }; 309*de3a9980SAnton Yakovlev 310*de3a9980SAnton Yakovlev static int __init init(void) 311*de3a9980SAnton Yakovlev { 312*de3a9980SAnton Yakovlev return register_virtio_driver(&virtsnd_driver); 313*de3a9980SAnton Yakovlev } 314*de3a9980SAnton Yakovlev module_init(init); 315*de3a9980SAnton Yakovlev 316*de3a9980SAnton Yakovlev static void __exit fini(void) 317*de3a9980SAnton Yakovlev { 318*de3a9980SAnton Yakovlev unregister_virtio_driver(&virtsnd_driver); 319*de3a9980SAnton Yakovlev } 320*de3a9980SAnton Yakovlev module_exit(fini); 321*de3a9980SAnton Yakovlev 322*de3a9980SAnton Yakovlev MODULE_DEVICE_TABLE(virtio, id_table); 323*de3a9980SAnton Yakovlev MODULE_DESCRIPTION("Virtio sound card driver"); 324*de3a9980SAnton Yakovlev MODULE_LICENSE("GPL"); 325