162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <linux/module.h> 362306a36Sopenharmony_ci#include <linux/virtio.h> 462306a36Sopenharmony_ci#include <linux/virtio_config.h> 562306a36Sopenharmony_ci#include <linux/input.h> 662306a36Sopenharmony_ci#include <linux/slab.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <uapi/linux/virtio_ids.h> 962306a36Sopenharmony_ci#include <uapi/linux/virtio_input.h> 1062306a36Sopenharmony_ci#include <linux/input/mt.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistruct virtio_input { 1362306a36Sopenharmony_ci struct virtio_device *vdev; 1462306a36Sopenharmony_ci struct input_dev *idev; 1562306a36Sopenharmony_ci char name[64]; 1662306a36Sopenharmony_ci char serial[64]; 1762306a36Sopenharmony_ci char phys[64]; 1862306a36Sopenharmony_ci struct virtqueue *evt, *sts; 1962306a36Sopenharmony_ci struct virtio_input_event evts[64]; 2062306a36Sopenharmony_ci spinlock_t lock; 2162306a36Sopenharmony_ci bool ready; 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic void virtinput_queue_evtbuf(struct virtio_input *vi, 2562306a36Sopenharmony_ci struct virtio_input_event *evtbuf) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct scatterlist sg[1]; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci sg_init_one(sg, evtbuf, sizeof(*evtbuf)); 3062306a36Sopenharmony_ci virtqueue_add_inbuf(vi->evt, sg, 1, evtbuf, GFP_ATOMIC); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic void virtinput_recv_events(struct virtqueue *vq) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci struct virtio_input *vi = vq->vdev->priv; 3662306a36Sopenharmony_ci struct virtio_input_event *event; 3762306a36Sopenharmony_ci unsigned long flags; 3862306a36Sopenharmony_ci unsigned int len; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci spin_lock_irqsave(&vi->lock, flags); 4162306a36Sopenharmony_ci if (vi->ready) { 4262306a36Sopenharmony_ci while ((event = virtqueue_get_buf(vi->evt, &len)) != NULL) { 4362306a36Sopenharmony_ci spin_unlock_irqrestore(&vi->lock, flags); 4462306a36Sopenharmony_ci input_event(vi->idev, 4562306a36Sopenharmony_ci le16_to_cpu(event->type), 4662306a36Sopenharmony_ci le16_to_cpu(event->code), 4762306a36Sopenharmony_ci le32_to_cpu(event->value)); 4862306a36Sopenharmony_ci spin_lock_irqsave(&vi->lock, flags); 4962306a36Sopenharmony_ci virtinput_queue_evtbuf(vi, event); 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci virtqueue_kick(vq); 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci spin_unlock_irqrestore(&vi->lock, flags); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * On error we are losing the status update, which isn't critical as 5862306a36Sopenharmony_ci * this is typically used for stuff like keyboard leds. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistatic int virtinput_send_status(struct virtio_input *vi, 6162306a36Sopenharmony_ci u16 type, u16 code, s32 value) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct virtio_input_event *stsbuf; 6462306a36Sopenharmony_ci struct scatterlist sg[1]; 6562306a36Sopenharmony_ci unsigned long flags; 6662306a36Sopenharmony_ci int rc; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* 6962306a36Sopenharmony_ci * Since 29cc309d8bf1 (HID: hid-multitouch: forward MSC_TIMESTAMP), 7062306a36Sopenharmony_ci * EV_MSC/MSC_TIMESTAMP is added to each before EV_SYN event. 7162306a36Sopenharmony_ci * EV_MSC is configured as INPUT_PASS_TO_ALL. 7262306a36Sopenharmony_ci * In case of touch device: 7362306a36Sopenharmony_ci * BE pass EV_MSC/MSC_TIMESTAMP to FE on receiving event from evdev. 7462306a36Sopenharmony_ci * FE pass EV_MSC/MSC_TIMESTAMP back to BE. 7562306a36Sopenharmony_ci * BE writes EV_MSC/MSC_TIMESTAMP to evdev due to INPUT_PASS_TO_ALL. 7662306a36Sopenharmony_ci * BE receives extra EV_MSC/MSC_TIMESTAMP and pass to FE. 7762306a36Sopenharmony_ci * >>> Each new frame becomes larger and larger. 7862306a36Sopenharmony_ci * Disable EV_MSC/MSC_TIMESTAMP forwarding for MT. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci if (vi->idev->mt && type == EV_MSC && code == MSC_TIMESTAMP) 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci stsbuf = kzalloc(sizeof(*stsbuf), GFP_ATOMIC); 8462306a36Sopenharmony_ci if (!stsbuf) 8562306a36Sopenharmony_ci return -ENOMEM; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci stsbuf->type = cpu_to_le16(type); 8862306a36Sopenharmony_ci stsbuf->code = cpu_to_le16(code); 8962306a36Sopenharmony_ci stsbuf->value = cpu_to_le32(value); 9062306a36Sopenharmony_ci sg_init_one(sg, stsbuf, sizeof(*stsbuf)); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci spin_lock_irqsave(&vi->lock, flags); 9362306a36Sopenharmony_ci if (vi->ready) { 9462306a36Sopenharmony_ci rc = virtqueue_add_outbuf(vi->sts, sg, 1, stsbuf, GFP_ATOMIC); 9562306a36Sopenharmony_ci virtqueue_kick(vi->sts); 9662306a36Sopenharmony_ci } else { 9762306a36Sopenharmony_ci rc = -ENODEV; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci spin_unlock_irqrestore(&vi->lock, flags); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (rc != 0) 10262306a36Sopenharmony_ci kfree(stsbuf); 10362306a36Sopenharmony_ci return rc; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void virtinput_recv_status(struct virtqueue *vq) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct virtio_input *vi = vq->vdev->priv; 10962306a36Sopenharmony_ci struct virtio_input_event *stsbuf; 11062306a36Sopenharmony_ci unsigned long flags; 11162306a36Sopenharmony_ci unsigned int len; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci spin_lock_irqsave(&vi->lock, flags); 11462306a36Sopenharmony_ci while ((stsbuf = virtqueue_get_buf(vi->sts, &len)) != NULL) 11562306a36Sopenharmony_ci kfree(stsbuf); 11662306a36Sopenharmony_ci spin_unlock_irqrestore(&vi->lock, flags); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int virtinput_status(struct input_dev *idev, unsigned int type, 12062306a36Sopenharmony_ci unsigned int code, int value) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct virtio_input *vi = input_get_drvdata(idev); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return virtinput_send_status(vi, type, code, value); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic u8 virtinput_cfg_select(struct virtio_input *vi, 12862306a36Sopenharmony_ci u8 select, u8 subsel) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci u8 size; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci virtio_cwrite_le(vi->vdev, struct virtio_input_config, select, &select); 13362306a36Sopenharmony_ci virtio_cwrite_le(vi->vdev, struct virtio_input_config, subsel, &subsel); 13462306a36Sopenharmony_ci virtio_cread_le(vi->vdev, struct virtio_input_config, size, &size); 13562306a36Sopenharmony_ci return size; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic void virtinput_cfg_bits(struct virtio_input *vi, int select, int subsel, 13962306a36Sopenharmony_ci unsigned long *bits, unsigned int bitcount) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci unsigned int bit; 14262306a36Sopenharmony_ci u8 *virtio_bits; 14362306a36Sopenharmony_ci u8 bytes; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci bytes = virtinput_cfg_select(vi, select, subsel); 14662306a36Sopenharmony_ci if (!bytes) 14762306a36Sopenharmony_ci return; 14862306a36Sopenharmony_ci if (bitcount > bytes * 8) 14962306a36Sopenharmony_ci bitcount = bytes * 8; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* 15262306a36Sopenharmony_ci * Bitmap in virtio config space is a simple stream of bytes, 15362306a36Sopenharmony_ci * with the first byte carrying bits 0-7, second bits 8-15 and 15462306a36Sopenharmony_ci * so on. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci virtio_bits = kzalloc(bytes, GFP_KERNEL); 15762306a36Sopenharmony_ci if (!virtio_bits) 15862306a36Sopenharmony_ci return; 15962306a36Sopenharmony_ci virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config, 16062306a36Sopenharmony_ci u.bitmap), 16162306a36Sopenharmony_ci virtio_bits, bytes); 16262306a36Sopenharmony_ci for (bit = 0; bit < bitcount; bit++) { 16362306a36Sopenharmony_ci if (virtio_bits[bit / 8] & (1 << (bit % 8))) 16462306a36Sopenharmony_ci __set_bit(bit, bits); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci kfree(virtio_bits); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (select == VIRTIO_INPUT_CFG_EV_BITS) 16962306a36Sopenharmony_ci __set_bit(subsel, vi->idev->evbit); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void virtinput_cfg_abs(struct virtio_input *vi, int abs) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci u32 mi, ma, re, fu, fl; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ABS_INFO, abs); 17762306a36Sopenharmony_ci virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.min, &mi); 17862306a36Sopenharmony_ci virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.max, &ma); 17962306a36Sopenharmony_ci virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.res, &re); 18062306a36Sopenharmony_ci virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.fuzz, &fu); 18162306a36Sopenharmony_ci virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.flat, &fl); 18262306a36Sopenharmony_ci input_set_abs_params(vi->idev, abs, mi, ma, fu, fl); 18362306a36Sopenharmony_ci input_abs_set_res(vi->idev, abs, re); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic int virtinput_init_vqs(struct virtio_input *vi) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct virtqueue *vqs[2]; 18962306a36Sopenharmony_ci vq_callback_t *cbs[] = { virtinput_recv_events, 19062306a36Sopenharmony_ci virtinput_recv_status }; 19162306a36Sopenharmony_ci static const char * const names[] = { "events", "status" }; 19262306a36Sopenharmony_ci int err; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci err = virtio_find_vqs(vi->vdev, 2, vqs, cbs, names, NULL); 19562306a36Sopenharmony_ci if (err) 19662306a36Sopenharmony_ci return err; 19762306a36Sopenharmony_ci vi->evt = vqs[0]; 19862306a36Sopenharmony_ci vi->sts = vqs[1]; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci return 0; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic void virtinput_fill_evt(struct virtio_input *vi) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci unsigned long flags; 20662306a36Sopenharmony_ci int i, size; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci spin_lock_irqsave(&vi->lock, flags); 20962306a36Sopenharmony_ci size = virtqueue_get_vring_size(vi->evt); 21062306a36Sopenharmony_ci if (size > ARRAY_SIZE(vi->evts)) 21162306a36Sopenharmony_ci size = ARRAY_SIZE(vi->evts); 21262306a36Sopenharmony_ci for (i = 0; i < size; i++) 21362306a36Sopenharmony_ci virtinput_queue_evtbuf(vi, &vi->evts[i]); 21462306a36Sopenharmony_ci virtqueue_kick(vi->evt); 21562306a36Sopenharmony_ci spin_unlock_irqrestore(&vi->lock, flags); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int virtinput_probe(struct virtio_device *vdev) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct virtio_input *vi; 22162306a36Sopenharmony_ci unsigned long flags; 22262306a36Sopenharmony_ci size_t size; 22362306a36Sopenharmony_ci int abs, err, nslots; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) 22662306a36Sopenharmony_ci return -ENODEV; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci vi = kzalloc(sizeof(*vi), GFP_KERNEL); 22962306a36Sopenharmony_ci if (!vi) 23062306a36Sopenharmony_ci return -ENOMEM; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci vdev->priv = vi; 23362306a36Sopenharmony_ci vi->vdev = vdev; 23462306a36Sopenharmony_ci spin_lock_init(&vi->lock); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci err = virtinput_init_vqs(vi); 23762306a36Sopenharmony_ci if (err) 23862306a36Sopenharmony_ci goto err_init_vq; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci vi->idev = input_allocate_device(); 24162306a36Sopenharmony_ci if (!vi->idev) { 24262306a36Sopenharmony_ci err = -ENOMEM; 24362306a36Sopenharmony_ci goto err_input_alloc; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci input_set_drvdata(vi->idev, vi); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_NAME, 0); 24862306a36Sopenharmony_ci virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config, 24962306a36Sopenharmony_ci u.string), 25062306a36Sopenharmony_ci vi->name, min(size, sizeof(vi->name))); 25162306a36Sopenharmony_ci size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_SERIAL, 0); 25262306a36Sopenharmony_ci virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config, 25362306a36Sopenharmony_ci u.string), 25462306a36Sopenharmony_ci vi->serial, min(size, sizeof(vi->serial))); 25562306a36Sopenharmony_ci snprintf(vi->phys, sizeof(vi->phys), 25662306a36Sopenharmony_ci "virtio%d/input0", vdev->index); 25762306a36Sopenharmony_ci vi->idev->name = vi->name; 25862306a36Sopenharmony_ci vi->idev->phys = vi->phys; 25962306a36Sopenharmony_ci vi->idev->uniq = vi->serial; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_DEVIDS, 0); 26262306a36Sopenharmony_ci if (size >= sizeof(struct virtio_input_devids)) { 26362306a36Sopenharmony_ci virtio_cread_le(vi->vdev, struct virtio_input_config, 26462306a36Sopenharmony_ci u.ids.bustype, &vi->idev->id.bustype); 26562306a36Sopenharmony_ci virtio_cread_le(vi->vdev, struct virtio_input_config, 26662306a36Sopenharmony_ci u.ids.vendor, &vi->idev->id.vendor); 26762306a36Sopenharmony_ci virtio_cread_le(vi->vdev, struct virtio_input_config, 26862306a36Sopenharmony_ci u.ids.product, &vi->idev->id.product); 26962306a36Sopenharmony_ci virtio_cread_le(vi->vdev, struct virtio_input_config, 27062306a36Sopenharmony_ci u.ids.version, &vi->idev->id.version); 27162306a36Sopenharmony_ci } else { 27262306a36Sopenharmony_ci vi->idev->id.bustype = BUS_VIRTUAL; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_PROP_BITS, 0, 27662306a36Sopenharmony_ci vi->idev->propbit, INPUT_PROP_CNT); 27762306a36Sopenharmony_ci size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REP); 27862306a36Sopenharmony_ci if (size) 27962306a36Sopenharmony_ci __set_bit(EV_REP, vi->idev->evbit); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci vi->idev->dev.parent = &vdev->dev; 28262306a36Sopenharmony_ci vi->idev->event = virtinput_status; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* device -> kernel */ 28562306a36Sopenharmony_ci virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY, 28662306a36Sopenharmony_ci vi->idev->keybit, KEY_CNT); 28762306a36Sopenharmony_ci virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REL, 28862306a36Sopenharmony_ci vi->idev->relbit, REL_CNT); 28962306a36Sopenharmony_ci virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS, 29062306a36Sopenharmony_ci vi->idev->absbit, ABS_CNT); 29162306a36Sopenharmony_ci virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_MSC, 29262306a36Sopenharmony_ci vi->idev->mscbit, MSC_CNT); 29362306a36Sopenharmony_ci virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SW, 29462306a36Sopenharmony_ci vi->idev->swbit, SW_CNT); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* kernel -> device */ 29762306a36Sopenharmony_ci virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_LED, 29862306a36Sopenharmony_ci vi->idev->ledbit, LED_CNT); 29962306a36Sopenharmony_ci virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SND, 30062306a36Sopenharmony_ci vi->idev->sndbit, SND_CNT); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (test_bit(EV_ABS, vi->idev->evbit)) { 30362306a36Sopenharmony_ci for (abs = 0; abs < ABS_CNT; abs++) { 30462306a36Sopenharmony_ci if (!test_bit(abs, vi->idev->absbit)) 30562306a36Sopenharmony_ci continue; 30662306a36Sopenharmony_ci virtinput_cfg_abs(vi, abs); 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (test_bit(ABS_MT_SLOT, vi->idev->absbit)) { 31062306a36Sopenharmony_ci nslots = input_abs_get_max(vi->idev, ABS_MT_SLOT) + 1; 31162306a36Sopenharmony_ci err = input_mt_init_slots(vi->idev, nslots, 0); 31262306a36Sopenharmony_ci if (err) 31362306a36Sopenharmony_ci goto err_mt_init_slots; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci virtio_device_ready(vdev); 31862306a36Sopenharmony_ci vi->ready = true; 31962306a36Sopenharmony_ci err = input_register_device(vi->idev); 32062306a36Sopenharmony_ci if (err) 32162306a36Sopenharmony_ci goto err_input_register; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci virtinput_fill_evt(vi); 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cierr_input_register: 32762306a36Sopenharmony_ci spin_lock_irqsave(&vi->lock, flags); 32862306a36Sopenharmony_ci vi->ready = false; 32962306a36Sopenharmony_ci spin_unlock_irqrestore(&vi->lock, flags); 33062306a36Sopenharmony_cierr_mt_init_slots: 33162306a36Sopenharmony_ci input_free_device(vi->idev); 33262306a36Sopenharmony_cierr_input_alloc: 33362306a36Sopenharmony_ci vdev->config->del_vqs(vdev); 33462306a36Sopenharmony_cierr_init_vq: 33562306a36Sopenharmony_ci kfree(vi); 33662306a36Sopenharmony_ci return err; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic void virtinput_remove(struct virtio_device *vdev) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct virtio_input *vi = vdev->priv; 34262306a36Sopenharmony_ci void *buf; 34362306a36Sopenharmony_ci unsigned long flags; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci spin_lock_irqsave(&vi->lock, flags); 34662306a36Sopenharmony_ci vi->ready = false; 34762306a36Sopenharmony_ci spin_unlock_irqrestore(&vi->lock, flags); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci input_unregister_device(vi->idev); 35062306a36Sopenharmony_ci virtio_reset_device(vdev); 35162306a36Sopenharmony_ci while ((buf = virtqueue_detach_unused_buf(vi->sts)) != NULL) 35262306a36Sopenharmony_ci kfree(buf); 35362306a36Sopenharmony_ci vdev->config->del_vqs(vdev); 35462306a36Sopenharmony_ci kfree(vi); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 35862306a36Sopenharmony_cistatic int virtinput_freeze(struct virtio_device *vdev) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct virtio_input *vi = vdev->priv; 36162306a36Sopenharmony_ci unsigned long flags; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci spin_lock_irqsave(&vi->lock, flags); 36462306a36Sopenharmony_ci vi->ready = false; 36562306a36Sopenharmony_ci spin_unlock_irqrestore(&vi->lock, flags); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci vdev->config->del_vqs(vdev); 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic int virtinput_restore(struct virtio_device *vdev) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct virtio_input *vi = vdev->priv; 37462306a36Sopenharmony_ci int err; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci err = virtinput_init_vqs(vi); 37762306a36Sopenharmony_ci if (err) 37862306a36Sopenharmony_ci return err; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci virtio_device_ready(vdev); 38162306a36Sopenharmony_ci vi->ready = true; 38262306a36Sopenharmony_ci virtinput_fill_evt(vi); 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci#endif 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic unsigned int features[] = { 38862306a36Sopenharmony_ci /* none */ 38962306a36Sopenharmony_ci}; 39062306a36Sopenharmony_cistatic const struct virtio_device_id id_table[] = { 39162306a36Sopenharmony_ci { VIRTIO_ID_INPUT, VIRTIO_DEV_ANY_ID }, 39262306a36Sopenharmony_ci { 0 }, 39362306a36Sopenharmony_ci}; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic struct virtio_driver virtio_input_driver = { 39662306a36Sopenharmony_ci .driver.name = KBUILD_MODNAME, 39762306a36Sopenharmony_ci .driver.owner = THIS_MODULE, 39862306a36Sopenharmony_ci .feature_table = features, 39962306a36Sopenharmony_ci .feature_table_size = ARRAY_SIZE(features), 40062306a36Sopenharmony_ci .id_table = id_table, 40162306a36Sopenharmony_ci .probe = virtinput_probe, 40262306a36Sopenharmony_ci .remove = virtinput_remove, 40362306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 40462306a36Sopenharmony_ci .freeze = virtinput_freeze, 40562306a36Sopenharmony_ci .restore = virtinput_restore, 40662306a36Sopenharmony_ci#endif 40762306a36Sopenharmony_ci}; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cimodule_virtio_driver(virtio_input_driver); 41062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(virtio, id_table); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 41362306a36Sopenharmony_ciMODULE_DESCRIPTION("Virtio input device driver"); 41462306a36Sopenharmony_ciMODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>"); 415