brintos

brintos / linux-shallow public Read only

0
0
Text · 11.0 KiB · a5d6326 Raw
415 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2#include <linux/module.h>3#include <linux/virtio.h>4#include <linux/virtio_config.h>5#include <linux/input.h>6#include <linux/slab.h>7 8#include <uapi/linux/virtio_ids.h>9#include <uapi/linux/virtio_input.h>10#include <linux/input/mt.h>11 12struct virtio_input {13	struct virtio_device       *vdev;14	struct input_dev           *idev;15	char                       name[64];16	char                       serial[64];17	char                       phys[64];18	struct virtqueue           *evt, *sts;19	struct virtio_input_event  evts[64];20	spinlock_t                 lock;21	bool                       ready;22};23 24static void virtinput_queue_evtbuf(struct virtio_input *vi,25				   struct virtio_input_event *evtbuf)26{27	struct scatterlist sg[1];28 29	sg_init_one(sg, evtbuf, sizeof(*evtbuf));30	virtqueue_add_inbuf(vi->evt, sg, 1, evtbuf, GFP_ATOMIC);31}32 33static void virtinput_recv_events(struct virtqueue *vq)34{35	struct virtio_input *vi = vq->vdev->priv;36	struct virtio_input_event *event;37	unsigned long flags;38	unsigned int len;39 40	spin_lock_irqsave(&vi->lock, flags);41	if (vi->ready) {42		while ((event = virtqueue_get_buf(vi->evt, &len)) != NULL) {43			spin_unlock_irqrestore(&vi->lock, flags);44			input_event(vi->idev,45				    le16_to_cpu(event->type),46				    le16_to_cpu(event->code),47				    le32_to_cpu(event->value));48			spin_lock_irqsave(&vi->lock, flags);49			virtinput_queue_evtbuf(vi, event);50		}51		virtqueue_kick(vq);52	}53	spin_unlock_irqrestore(&vi->lock, flags);54}55 56/*57 * On error we are losing the status update, which isn't critical as58 * this is typically used for stuff like keyboard leds.59 */60static int virtinput_send_status(struct virtio_input *vi,61				 u16 type, u16 code, s32 value)62{63	struct virtio_input_event *stsbuf;64	struct scatterlist sg[1];65	unsigned long flags;66	int rc;67 68	/*69	 * Since 29cc309d8bf1 (HID: hid-multitouch: forward MSC_TIMESTAMP),70	 * EV_MSC/MSC_TIMESTAMP is added to each before EV_SYN event.71	 * EV_MSC is configured as INPUT_PASS_TO_ALL.72	 * In case of touch device:73	 *   BE pass EV_MSC/MSC_TIMESTAMP to FE on receiving event from evdev.74	 *   FE pass EV_MSC/MSC_TIMESTAMP back to BE.75	 *   BE writes EV_MSC/MSC_TIMESTAMP to evdev due to INPUT_PASS_TO_ALL.76	 *   BE receives extra EV_MSC/MSC_TIMESTAMP and pass to FE.77	 *   >>> Each new frame becomes larger and larger.78	 * Disable EV_MSC/MSC_TIMESTAMP forwarding for MT.79	 */80	if (vi->idev->mt && type == EV_MSC && code == MSC_TIMESTAMP)81		return 0;82 83	stsbuf = kzalloc(sizeof(*stsbuf), GFP_ATOMIC);84	if (!stsbuf)85		return -ENOMEM;86 87	stsbuf->type  = cpu_to_le16(type);88	stsbuf->code  = cpu_to_le16(code);89	stsbuf->value = cpu_to_le32(value);90	sg_init_one(sg, stsbuf, sizeof(*stsbuf));91 92	spin_lock_irqsave(&vi->lock, flags);93	if (vi->ready) {94		rc = virtqueue_add_outbuf(vi->sts, sg, 1, stsbuf, GFP_ATOMIC);95		virtqueue_kick(vi->sts);96	} else {97		rc = -ENODEV;98	}99	spin_unlock_irqrestore(&vi->lock, flags);100 101	if (rc != 0)102		kfree(stsbuf);103	return rc;104}105 106static void virtinput_recv_status(struct virtqueue *vq)107{108	struct virtio_input *vi = vq->vdev->priv;109	struct virtio_input_event *stsbuf;110	unsigned long flags;111	unsigned int len;112 113	spin_lock_irqsave(&vi->lock, flags);114	while ((stsbuf = virtqueue_get_buf(vi->sts, &len)) != NULL)115		kfree(stsbuf);116	spin_unlock_irqrestore(&vi->lock, flags);117}118 119static int virtinput_status(struct input_dev *idev, unsigned int type,120			    unsigned int code, int value)121{122	struct virtio_input *vi = input_get_drvdata(idev);123 124	return virtinput_send_status(vi, type, code, value);125}126 127static u8 virtinput_cfg_select(struct virtio_input *vi,128			       u8 select, u8 subsel)129{130	u8 size;131 132	virtio_cwrite_le(vi->vdev, struct virtio_input_config, select, &select);133	virtio_cwrite_le(vi->vdev, struct virtio_input_config, subsel, &subsel);134	virtio_cread_le(vi->vdev, struct virtio_input_config, size, &size);135	return size;136}137 138static void virtinput_cfg_bits(struct virtio_input *vi, int select, int subsel,139			       unsigned long *bits, unsigned int bitcount)140{141	unsigned int bit;142	u8 *virtio_bits;143	u8 bytes;144 145	bytes = virtinput_cfg_select(vi, select, subsel);146	if (!bytes)147		return;148	if (bitcount > bytes * 8)149		bitcount = bytes * 8;150 151	/*152	 * Bitmap in virtio config space is a simple stream of bytes,153	 * with the first byte carrying bits 0-7, second bits 8-15 and154	 * so on.155	 */156	virtio_bits = kzalloc(bytes, GFP_KERNEL);157	if (!virtio_bits)158		return;159	virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config,160					      u.bitmap),161			   virtio_bits, bytes);162	for (bit = 0; bit < bitcount; bit++) {163		if (virtio_bits[bit / 8] & (1 << (bit % 8)))164			__set_bit(bit, bits);165	}166	kfree(virtio_bits);167 168	if (select == VIRTIO_INPUT_CFG_EV_BITS)169		__set_bit(subsel, vi->idev->evbit);170}171 172static void virtinput_cfg_abs(struct virtio_input *vi, int abs)173{174	u32 mi, ma, re, fu, fl;175 176	virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ABS_INFO, abs);177	virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.min, &mi);178	virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.max, &ma);179	virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.res, &re);180	virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.fuzz, &fu);181	virtio_cread_le(vi->vdev, struct virtio_input_config, u.abs.flat, &fl);182	input_set_abs_params(vi->idev, abs, mi, ma, fu, fl);183	input_abs_set_res(vi->idev, abs, re);184}185 186static int virtinput_init_vqs(struct virtio_input *vi)187{188	struct virtqueue_info vqs_info[] = {189		{ "events", virtinput_recv_events },190		{ "status", virtinput_recv_status },191	};192	struct virtqueue *vqs[2];193	int err;194 195	err = virtio_find_vqs(vi->vdev, 2, vqs, vqs_info, NULL);196	if (err)197		return err;198	vi->evt = vqs[0];199	vi->sts = vqs[1];200 201	return 0;202}203 204static void virtinput_fill_evt(struct virtio_input *vi)205{206	unsigned long flags;207	int i, size;208 209	spin_lock_irqsave(&vi->lock, flags);210	size = virtqueue_get_vring_size(vi->evt);211	if (size > ARRAY_SIZE(vi->evts))212		size = ARRAY_SIZE(vi->evts);213	for (i = 0; i < size; i++)214		virtinput_queue_evtbuf(vi, &vi->evts[i]);215	virtqueue_kick(vi->evt);216	spin_unlock_irqrestore(&vi->lock, flags);217}218 219static int virtinput_probe(struct virtio_device *vdev)220{221	struct virtio_input *vi;222	unsigned long flags;223	size_t size;224	int abs, err, nslots;225 226	if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1))227		return -ENODEV;228 229	vi = kzalloc(sizeof(*vi), GFP_KERNEL);230	if (!vi)231		return -ENOMEM;232 233	vdev->priv = vi;234	vi->vdev = vdev;235	spin_lock_init(&vi->lock);236 237	err = virtinput_init_vqs(vi);238	if (err)239		goto err_init_vq;240 241	vi->idev = input_allocate_device();242	if (!vi->idev) {243		err = -ENOMEM;244		goto err_input_alloc;245	}246	input_set_drvdata(vi->idev, vi);247 248	size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_NAME, 0);249	virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config,250					      u.string),251			   vi->name, min(size, sizeof(vi->name)));252	size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_SERIAL, 0);253	virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config,254					      u.string),255			   vi->serial, min(size, sizeof(vi->serial)));256	snprintf(vi->phys, sizeof(vi->phys),257		 "virtio%d/input0", vdev->index);258	vi->idev->name = vi->name;259	vi->idev->phys = vi->phys;260	vi->idev->uniq = vi->serial;261 262	size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_DEVIDS, 0);263	if (size >= sizeof(struct virtio_input_devids)) {264		virtio_cread_le(vi->vdev, struct virtio_input_config,265				u.ids.bustype, &vi->idev->id.bustype);266		virtio_cread_le(vi->vdev, struct virtio_input_config,267				u.ids.vendor, &vi->idev->id.vendor);268		virtio_cread_le(vi->vdev, struct virtio_input_config,269				u.ids.product, &vi->idev->id.product);270		virtio_cread_le(vi->vdev, struct virtio_input_config,271				u.ids.version, &vi->idev->id.version);272	} else {273		vi->idev->id.bustype = BUS_VIRTUAL;274	}275 276	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_PROP_BITS, 0,277			   vi->idev->propbit, INPUT_PROP_CNT);278	size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REP);279	if (size)280		__set_bit(EV_REP, vi->idev->evbit);281 282	vi->idev->dev.parent = &vdev->dev;283	vi->idev->event = virtinput_status;284 285	/* device -> kernel */286	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY,287			   vi->idev->keybit, KEY_CNT);288	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REL,289			   vi->idev->relbit, REL_CNT);290	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS,291			   vi->idev->absbit, ABS_CNT);292	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_MSC,293			   vi->idev->mscbit, MSC_CNT);294	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SW,295			   vi->idev->swbit,  SW_CNT);296 297	/* kernel -> device */298	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_LED,299			   vi->idev->ledbit, LED_CNT);300	virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SND,301			   vi->idev->sndbit, SND_CNT);302 303	if (test_bit(EV_ABS, vi->idev->evbit)) {304		for (abs = 0; abs < ABS_CNT; abs++) {305			if (!test_bit(abs, vi->idev->absbit))306				continue;307			virtinput_cfg_abs(vi, abs);308		}309 310		if (test_bit(ABS_MT_SLOT, vi->idev->absbit)) {311			nslots = input_abs_get_max(vi->idev, ABS_MT_SLOT) + 1;312			err = input_mt_init_slots(vi->idev, nslots, 0);313			if (err)314				goto err_mt_init_slots;315		}316	}317 318	virtio_device_ready(vdev);319	vi->ready = true;320	err = input_register_device(vi->idev);321	if (err)322		goto err_input_register;323 324	virtinput_fill_evt(vi);325	return 0;326 327err_input_register:328	spin_lock_irqsave(&vi->lock, flags);329	vi->ready = false;330	spin_unlock_irqrestore(&vi->lock, flags);331err_mt_init_slots:332	input_free_device(vi->idev);333err_input_alloc:334	vdev->config->del_vqs(vdev);335err_init_vq:336	kfree(vi);337	return err;338}339 340static void virtinput_remove(struct virtio_device *vdev)341{342	struct virtio_input *vi = vdev->priv;343	void *buf;344	unsigned long flags;345 346	spin_lock_irqsave(&vi->lock, flags);347	vi->ready = false;348	spin_unlock_irqrestore(&vi->lock, flags);349 350	input_unregister_device(vi->idev);351	virtio_reset_device(vdev);352	while ((buf = virtqueue_detach_unused_buf(vi->sts)) != NULL)353		kfree(buf);354	vdev->config->del_vqs(vdev);355	kfree(vi);356}357 358#ifdef CONFIG_PM_SLEEP359static int virtinput_freeze(struct virtio_device *vdev)360{361	struct virtio_input *vi = vdev->priv;362	unsigned long flags;363 364	spin_lock_irqsave(&vi->lock, flags);365	vi->ready = false;366	spin_unlock_irqrestore(&vi->lock, flags);367 368	vdev->config->del_vqs(vdev);369	return 0;370}371 372static int virtinput_restore(struct virtio_device *vdev)373{374	struct virtio_input *vi = vdev->priv;375	int err;376 377	err = virtinput_init_vqs(vi);378	if (err)379		return err;380 381	virtio_device_ready(vdev);382	vi->ready = true;383	virtinput_fill_evt(vi);384	return 0;385}386#endif387 388static unsigned int features[] = {389	/* none */390};391static const struct virtio_device_id id_table[] = {392	{ VIRTIO_ID_INPUT, VIRTIO_DEV_ANY_ID },393	{ 0 },394};395 396static struct virtio_driver virtio_input_driver = {397	.driver.name         = KBUILD_MODNAME,398	.feature_table       = features,399	.feature_table_size  = ARRAY_SIZE(features),400	.id_table            = id_table,401	.probe               = virtinput_probe,402	.remove              = virtinput_remove,403#ifdef CONFIG_PM_SLEEP404	.freeze	             = virtinput_freeze,405	.restore             = virtinput_restore,406#endif407};408 409module_virtio_driver(virtio_input_driver);410MODULE_DEVICE_TABLE(virtio, id_table);411 412MODULE_LICENSE("GPL");413MODULE_DESCRIPTION("Virtio input device driver");414MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");415