xref: /openbmc/linux/drivers/hid/uhid.c (revision 1c5d4221)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21ccd7a2aSDavid Herrmann /*
31ccd7a2aSDavid Herrmann  * User-space I/O driver support for HID subsystem
41ccd7a2aSDavid Herrmann  * Copyright (c) 2012 David Herrmann
51ccd7a2aSDavid Herrmann  */
61ccd7a2aSDavid Herrmann 
71ccd7a2aSDavid Herrmann /*
81ccd7a2aSDavid Herrmann  */
91ccd7a2aSDavid Herrmann 
101ccd7a2aSDavid Herrmann #include <linux/atomic.h>
11befde022SDmitry Torokhov #include <linux/compat.h>
128c01db76SEric Biggers #include <linux/cred.h>
131ccd7a2aSDavid Herrmann #include <linux/device.h>
141ccd7a2aSDavid Herrmann #include <linux/fs.h>
151ccd7a2aSDavid Herrmann #include <linux/hid.h>
161ccd7a2aSDavid Herrmann #include <linux/input.h>
171ccd7a2aSDavid Herrmann #include <linux/miscdevice.h>
181ccd7a2aSDavid Herrmann #include <linux/module.h>
191ccd7a2aSDavid Herrmann #include <linux/mutex.h>
201ccd7a2aSDavid Herrmann #include <linux/poll.h>
211ccd7a2aSDavid Herrmann #include <linux/sched.h>
221ccd7a2aSDavid Herrmann #include <linux/spinlock.h>
231ccd7a2aSDavid Herrmann #include <linux/uhid.h>
241ccd7a2aSDavid Herrmann #include <linux/wait.h>
251ccd7a2aSDavid Herrmann 
261ccd7a2aSDavid Herrmann #define UHID_NAME	"uhid"
27ace3d861SDavid Herrmann #define UHID_BUFSIZE	32
28ace3d861SDavid Herrmann 
29ace3d861SDavid Herrmann struct uhid_device {
30d937ae5fSDavid Herrmann 	struct mutex devlock;
314ea5763fSJann Horn 
324ea5763fSJann Horn 	/* This flag tracks whether the HID device is usable for commands from
334ea5763fSJann Horn 	 * userspace. The flag is already set before hid_add_device(), which
344ea5763fSJann Horn 	 * runs in workqueue context, to allow hid_add_device() to communicate
354ea5763fSJann Horn 	 * with userspace.
364ea5763fSJann Horn 	 * However, if hid_add_device() fails, the flag is cleared without
374ea5763fSJann Horn 	 * holding devlock.
384ea5763fSJann Horn 	 * We guarantee that if @running changes from true to false while you're
394ea5763fSJann Horn 	 * holding @devlock, it's still fine to access @hid.
404ea5763fSJann Horn 	 */
41d365c6cfSDavid Herrmann 	bool running;
42d365c6cfSDavid Herrmann 
43d365c6cfSDavid Herrmann 	__u8 *rd_data;
44d365c6cfSDavid Herrmann 	uint rd_size;
45d365c6cfSDavid Herrmann 
464ea5763fSJann Horn 	/* When this is NULL, userspace may use UHID_CREATE/UHID_CREATE2. */
47ace3d861SDavid Herrmann 	struct hid_device *hid;
486664ef72SDavid Herrmann 	struct uhid_event input_buf;
49ace3d861SDavid Herrmann 
50ace3d861SDavid Herrmann 	wait_queue_head_t waitq;
51ace3d861SDavid Herrmann 	spinlock_t qlock;
52ace3d861SDavid Herrmann 	__u8 head;
53ace3d861SDavid Herrmann 	__u8 tail;
54ace3d861SDavid Herrmann 	struct uhid_event *outq[UHID_BUFSIZE];
55fcfcf0deSDavid Herrmann 
568cad5b01SDavid Herrmann 	/* blocking GET_REPORT support; state changes protected by qlock */
57fcfcf0deSDavid Herrmann 	struct mutex report_lock;
58fcfcf0deSDavid Herrmann 	wait_queue_head_t report_wait;
595942b849SDavid Herrmann 	bool report_running;
608cad5b01SDavid Herrmann 	u32 report_id;
6111c22155SDavid Herrmann 	u32 report_type;
62fcfcf0deSDavid Herrmann 	struct uhid_event report_buf;
6367f8ecc5SRoderick Colenbrander 	struct work_struct worker;
64ace3d861SDavid Herrmann };
651ccd7a2aSDavid Herrmann 
661ccd7a2aSDavid Herrmann static struct miscdevice uhid_misc;
671ccd7a2aSDavid Herrmann 
uhid_device_add_worker(struct work_struct * work)6867f8ecc5SRoderick Colenbrander static void uhid_device_add_worker(struct work_struct *work)
6967f8ecc5SRoderick Colenbrander {
7067f8ecc5SRoderick Colenbrander 	struct uhid_device *uhid = container_of(work, struct uhid_device, worker);
7167f8ecc5SRoderick Colenbrander 	int ret;
7267f8ecc5SRoderick Colenbrander 
7367f8ecc5SRoderick Colenbrander 	ret = hid_add_device(uhid->hid);
7467f8ecc5SRoderick Colenbrander 	if (ret) {
7567f8ecc5SRoderick Colenbrander 		hid_err(uhid->hid, "Cannot register HID device: error %d\n", ret);
7667f8ecc5SRoderick Colenbrander 
774ea5763fSJann Horn 		/* We used to call hid_destroy_device() here, but that's really
784ea5763fSJann Horn 		 * messy to get right because we have to coordinate with
794ea5763fSJann Horn 		 * concurrent writes from userspace that might be in the middle
804ea5763fSJann Horn 		 * of using uhid->hid.
814ea5763fSJann Horn 		 * Just leave uhid->hid as-is for now, and clean it up when
824ea5763fSJann Horn 		 * userspace tries to close or reinitialize the uhid instance.
834ea5763fSJann Horn 		 *
844ea5763fSJann Horn 		 * However, we do have to clear the ->running flag and do a
854ea5763fSJann Horn 		 * wakeup to make sure userspace knows that the device is gone.
864ea5763fSJann Horn 		 */
87c8e7ff41SJann Horn 		WRITE_ONCE(uhid->running, false);
884ea5763fSJann Horn 		wake_up_interruptible(&uhid->report_wait);
8967f8ecc5SRoderick Colenbrander 	}
9067f8ecc5SRoderick Colenbrander }
9167f8ecc5SRoderick Colenbrander 
uhid_queue(struct uhid_device * uhid,struct uhid_event * ev)92ace3d861SDavid Herrmann static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev)
93ace3d861SDavid Herrmann {
94ace3d861SDavid Herrmann 	__u8 newhead;
95ace3d861SDavid Herrmann 
96ace3d861SDavid Herrmann 	newhead = (uhid->head + 1) % UHID_BUFSIZE;
97ace3d861SDavid Herrmann 
98ace3d861SDavid Herrmann 	if (newhead != uhid->tail) {
99ace3d861SDavid Herrmann 		uhid->outq[uhid->head] = ev;
100ace3d861SDavid Herrmann 		uhid->head = newhead;
101ace3d861SDavid Herrmann 		wake_up_interruptible(&uhid->waitq);
102ace3d861SDavid Herrmann 	} else {
103ace3d861SDavid Herrmann 		hid_warn(uhid->hid, "Output queue is full\n");
104ace3d861SDavid Herrmann 		kfree(ev);
105ace3d861SDavid Herrmann 	}
106ace3d861SDavid Herrmann }
107ace3d861SDavid Herrmann 
uhid_queue_event(struct uhid_device * uhid,__u32 event)108ace3d861SDavid Herrmann static int uhid_queue_event(struct uhid_device *uhid, __u32 event)
109ace3d861SDavid Herrmann {
110ace3d861SDavid Herrmann 	unsigned long flags;
111ace3d861SDavid Herrmann 	struct uhid_event *ev;
112ace3d861SDavid Herrmann 
113ace3d861SDavid Herrmann 	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
114ace3d861SDavid Herrmann 	if (!ev)
115ace3d861SDavid Herrmann 		return -ENOMEM;
116ace3d861SDavid Herrmann 
117ace3d861SDavid Herrmann 	ev->type = event;
118ace3d861SDavid Herrmann 
119ace3d861SDavid Herrmann 	spin_lock_irqsave(&uhid->qlock, flags);
120ace3d861SDavid Herrmann 	uhid_queue(uhid, ev);
121ace3d861SDavid Herrmann 	spin_unlock_irqrestore(&uhid->qlock, flags);
122ace3d861SDavid Herrmann 
123ace3d861SDavid Herrmann 	return 0;
124ace3d861SDavid Herrmann }
125ace3d861SDavid Herrmann 
uhid_hid_start(struct hid_device * hid)126d365c6cfSDavid Herrmann static int uhid_hid_start(struct hid_device *hid)
127d365c6cfSDavid Herrmann {
128ec4b7deaSDavid Herrmann 	struct uhid_device *uhid = hid->driver_data;
129c2b2f16cSDavid Herrmann 	struct uhid_event *ev;
130c2b2f16cSDavid Herrmann 	unsigned long flags;
131ec4b7deaSDavid Herrmann 
132c2b2f16cSDavid Herrmann 	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
133c2b2f16cSDavid Herrmann 	if (!ev)
134c2b2f16cSDavid Herrmann 		return -ENOMEM;
135c2b2f16cSDavid Herrmann 
136c2b2f16cSDavid Herrmann 	ev->type = UHID_START;
137c2b2f16cSDavid Herrmann 
138c2b2f16cSDavid Herrmann 	if (hid->report_enum[HID_FEATURE_REPORT].numbered)
139c2b2f16cSDavid Herrmann 		ev->u.start.dev_flags |= UHID_DEV_NUMBERED_FEATURE_REPORTS;
140c2b2f16cSDavid Herrmann 	if (hid->report_enum[HID_OUTPUT_REPORT].numbered)
141c2b2f16cSDavid Herrmann 		ev->u.start.dev_flags |= UHID_DEV_NUMBERED_OUTPUT_REPORTS;
142c2b2f16cSDavid Herrmann 	if (hid->report_enum[HID_INPUT_REPORT].numbered)
143c2b2f16cSDavid Herrmann 		ev->u.start.dev_flags |= UHID_DEV_NUMBERED_INPUT_REPORTS;
144c2b2f16cSDavid Herrmann 
145c2b2f16cSDavid Herrmann 	spin_lock_irqsave(&uhid->qlock, flags);
146c2b2f16cSDavid Herrmann 	uhid_queue(uhid, ev);
147c2b2f16cSDavid Herrmann 	spin_unlock_irqrestore(&uhid->qlock, flags);
148c2b2f16cSDavid Herrmann 
149c2b2f16cSDavid Herrmann 	return 0;
150d365c6cfSDavid Herrmann }
151d365c6cfSDavid Herrmann 
uhid_hid_stop(struct hid_device * hid)152d365c6cfSDavid Herrmann static void uhid_hid_stop(struct hid_device *hid)
153d365c6cfSDavid Herrmann {
154ec4b7deaSDavid Herrmann 	struct uhid_device *uhid = hid->driver_data;
155ec4b7deaSDavid Herrmann 
156ec4b7deaSDavid Herrmann 	hid->claimed = 0;
157ec4b7deaSDavid Herrmann 	uhid_queue_event(uhid, UHID_STOP);
158d365c6cfSDavid Herrmann }
159d365c6cfSDavid Herrmann 
uhid_hid_open(struct hid_device * hid)160d365c6cfSDavid Herrmann static int uhid_hid_open(struct hid_device *hid)
161d365c6cfSDavid Herrmann {
162e7191474SDavid Herrmann 	struct uhid_device *uhid = hid->driver_data;
163e7191474SDavid Herrmann 
164e7191474SDavid Herrmann 	return uhid_queue_event(uhid, UHID_OPEN);
165d365c6cfSDavid Herrmann }
166d365c6cfSDavid Herrmann 
uhid_hid_close(struct hid_device * hid)167d365c6cfSDavid Herrmann static void uhid_hid_close(struct hid_device *hid)
168d365c6cfSDavid Herrmann {
169e7191474SDavid Herrmann 	struct uhid_device *uhid = hid->driver_data;
170e7191474SDavid Herrmann 
171e7191474SDavid Herrmann 	uhid_queue_event(uhid, UHID_CLOSE);
172d365c6cfSDavid Herrmann }
173d365c6cfSDavid Herrmann 
uhid_hid_parse(struct hid_device * hid)174d365c6cfSDavid Herrmann static int uhid_hid_parse(struct hid_device *hid)
175d365c6cfSDavid Herrmann {
176037c061bSDavid Herrmann 	struct uhid_device *uhid = hid->driver_data;
177037c061bSDavid Herrmann 
178037c061bSDavid Herrmann 	return hid_parse_report(hid, uhid->rd_data, uhid->rd_size);
179d365c6cfSDavid Herrmann }
180d365c6cfSDavid Herrmann 
18111c22155SDavid Herrmann /* must be called with report_lock held */
__uhid_report_queue_and_wait(struct uhid_device * uhid,struct uhid_event * ev,__u32 * report_id)18211c22155SDavid Herrmann static int __uhid_report_queue_and_wait(struct uhid_device *uhid,
18311c22155SDavid Herrmann 					struct uhid_event *ev,
18411c22155SDavid Herrmann 					__u32 *report_id)
185289a7162SJiri Kosina {
186289a7162SJiri Kosina 	unsigned long flags;
187289a7162SJiri Kosina 	int ret;
188289a7162SJiri Kosina 
189289a7162SJiri Kosina 	spin_lock_irqsave(&uhid->qlock, flags);
19011c22155SDavid Herrmann 	*report_id = ++uhid->report_id;
1918493eccaSBenjamin Tissoires 	uhid->report_type = ev->type + 1;
1925942b849SDavid Herrmann 	uhid->report_running = true;
193289a7162SJiri Kosina 	uhid_queue(uhid, ev);
194289a7162SJiri Kosina 	spin_unlock_irqrestore(&uhid->qlock, flags);
195289a7162SJiri Kosina 
196289a7162SJiri Kosina 	ret = wait_event_interruptible_timeout(uhid->report_wait,
197c8e7ff41SJann Horn 				!uhid->report_running || !READ_ONCE(uhid->running),
1980e0d7520SDavid Herrmann 				5 * HZ);
199c8e7ff41SJann Horn 	if (!ret || !READ_ONCE(uhid->running) || uhid->report_running)
200289a7162SJiri Kosina 		ret = -EIO;
20111c22155SDavid Herrmann 	else if (ret < 0)
202289a7162SJiri Kosina 		ret = -ERESTARTSYS;
20311c22155SDavid Herrmann 	else
204289a7162SJiri Kosina 		ret = 0;
205289a7162SJiri Kosina 
2065942b849SDavid Herrmann 	uhid->report_running = false;
207289a7162SJiri Kosina 
20811c22155SDavid Herrmann 	return ret;
20911c22155SDavid Herrmann }
21011c22155SDavid Herrmann 
uhid_report_wake_up(struct uhid_device * uhid,u32 id,const struct uhid_event * ev)21111c22155SDavid Herrmann static void uhid_report_wake_up(struct uhid_device *uhid, u32 id,
21211c22155SDavid Herrmann 				const struct uhid_event *ev)
21311c22155SDavid Herrmann {
21411c22155SDavid Herrmann 	unsigned long flags;
21511c22155SDavid Herrmann 
21611c22155SDavid Herrmann 	spin_lock_irqsave(&uhid->qlock, flags);
21711c22155SDavid Herrmann 
21811c22155SDavid Herrmann 	/* id for old report; drop it silently */
21911c22155SDavid Herrmann 	if (uhid->report_type != ev->type || uhid->report_id != id)
22011c22155SDavid Herrmann 		goto unlock;
22111c22155SDavid Herrmann 	if (!uhid->report_running)
22211c22155SDavid Herrmann 		goto unlock;
22311c22155SDavid Herrmann 
22411c22155SDavid Herrmann 	memcpy(&uhid->report_buf, ev, sizeof(*ev));
22511c22155SDavid Herrmann 	uhid->report_running = false;
22611c22155SDavid Herrmann 	wake_up_interruptible(&uhid->report_wait);
22711c22155SDavid Herrmann 
22811c22155SDavid Herrmann unlock:
22911c22155SDavid Herrmann 	spin_unlock_irqrestore(&uhid->qlock, flags);
23011c22155SDavid Herrmann }
23111c22155SDavid Herrmann 
uhid_hid_get_report(struct hid_device * hid,unsigned char rnum,u8 * buf,size_t count,u8 rtype)23211c22155SDavid Herrmann static int uhid_hid_get_report(struct hid_device *hid, unsigned char rnum,
23311c22155SDavid Herrmann 			       u8 *buf, size_t count, u8 rtype)
23411c22155SDavid Herrmann {
23511c22155SDavid Herrmann 	struct uhid_device *uhid = hid->driver_data;
23611c22155SDavid Herrmann 	struct uhid_get_report_reply_req *req;
23711c22155SDavid Herrmann 	struct uhid_event *ev;
23811c22155SDavid Herrmann 	int ret;
23911c22155SDavid Herrmann 
240c8e7ff41SJann Horn 	if (!READ_ONCE(uhid->running))
24111c22155SDavid Herrmann 		return -EIO;
24211c22155SDavid Herrmann 
24311c22155SDavid Herrmann 	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
24411c22155SDavid Herrmann 	if (!ev)
24511c22155SDavid Herrmann 		return -ENOMEM;
24611c22155SDavid Herrmann 
24711c22155SDavid Herrmann 	ev->type = UHID_GET_REPORT;
24811c22155SDavid Herrmann 	ev->u.get_report.rnum = rnum;
24911c22155SDavid Herrmann 	ev->u.get_report.rtype = rtype;
25011c22155SDavid Herrmann 
25111c22155SDavid Herrmann 	ret = mutex_lock_interruptible(&uhid->report_lock);
25211c22155SDavid Herrmann 	if (ret) {
25311c22155SDavid Herrmann 		kfree(ev);
25411c22155SDavid Herrmann 		return ret;
25511c22155SDavid Herrmann 	}
25611c22155SDavid Herrmann 
25711c22155SDavid Herrmann 	/* this _always_ takes ownership of @ev */
25811c22155SDavid Herrmann 	ret = __uhid_report_queue_and_wait(uhid, ev, &ev->u.get_report.id);
25911c22155SDavid Herrmann 	if (ret)
26011c22155SDavid Herrmann 		goto unlock;
26111c22155SDavid Herrmann 
26211c22155SDavid Herrmann 	req = &uhid->report_buf.u.get_report_reply;
26311c22155SDavid Herrmann 	if (req->err) {
26411c22155SDavid Herrmann 		ret = -EIO;
26511c22155SDavid Herrmann 	} else {
26611c22155SDavid Herrmann 		ret = min3(count, (size_t)req->size, (size_t)UHID_DATA_MAX);
26711c22155SDavid Herrmann 		memcpy(buf, req->data, ret);
26811c22155SDavid Herrmann 	}
26911c22155SDavid Herrmann 
270289a7162SJiri Kosina unlock:
271289a7162SJiri Kosina 	mutex_unlock(&uhid->report_lock);
27211c22155SDavid Herrmann 	return ret;
27311c22155SDavid Herrmann }
27411c22155SDavid Herrmann 
uhid_hid_set_report(struct hid_device * hid,unsigned char rnum,const u8 * buf,size_t count,u8 rtype)27511c22155SDavid Herrmann static int uhid_hid_set_report(struct hid_device *hid, unsigned char rnum,
27611c22155SDavid Herrmann 			       const u8 *buf, size_t count, u8 rtype)
27711c22155SDavid Herrmann {
27811c22155SDavid Herrmann 	struct uhid_device *uhid = hid->driver_data;
27911c22155SDavid Herrmann 	struct uhid_event *ev;
28011c22155SDavid Herrmann 	int ret;
28111c22155SDavid Herrmann 
282c8e7ff41SJann Horn 	if (!READ_ONCE(uhid->running) || count > UHID_DATA_MAX)
28311c22155SDavid Herrmann 		return -EIO;
28411c22155SDavid Herrmann 
28511c22155SDavid Herrmann 	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
28611c22155SDavid Herrmann 	if (!ev)
28711c22155SDavid Herrmann 		return -ENOMEM;
28811c22155SDavid Herrmann 
28911c22155SDavid Herrmann 	ev->type = UHID_SET_REPORT;
29011c22155SDavid Herrmann 	ev->u.set_report.rnum = rnum;
29111c22155SDavid Herrmann 	ev->u.set_report.rtype = rtype;
29211c22155SDavid Herrmann 	ev->u.set_report.size = count;
29311c22155SDavid Herrmann 	memcpy(ev->u.set_report.data, buf, count);
29411c22155SDavid Herrmann 
29511c22155SDavid Herrmann 	ret = mutex_lock_interruptible(&uhid->report_lock);
29611c22155SDavid Herrmann 	if (ret) {
29711c22155SDavid Herrmann 		kfree(ev);
29811c22155SDavid Herrmann 		return ret;
29911c22155SDavid Herrmann 	}
30011c22155SDavid Herrmann 
30111c22155SDavid Herrmann 	/* this _always_ takes ownership of @ev */
30211c22155SDavid Herrmann 	ret = __uhid_report_queue_and_wait(uhid, ev, &ev->u.set_report.id);
30311c22155SDavid Herrmann 	if (ret)
30411c22155SDavid Herrmann 		goto unlock;
30511c22155SDavid Herrmann 
30611c22155SDavid Herrmann 	if (uhid->report_buf.u.set_report_reply.err)
30711c22155SDavid Herrmann 		ret = -EIO;
30811c22155SDavid Herrmann 	else
30911c22155SDavid Herrmann 		ret = count;
31011c22155SDavid Herrmann 
31111c22155SDavid Herrmann unlock:
31211c22155SDavid Herrmann 	mutex_unlock(&uhid->report_lock);
31311c22155SDavid Herrmann 	return ret;
314289a7162SJiri Kosina }
315289a7162SJiri Kosina 
uhid_hid_raw_request(struct hid_device * hid,unsigned char reportnum,__u8 * buf,size_t len,unsigned char rtype,int reqtype)3167c4003bcSDavid Herrmann static int uhid_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
3177c4003bcSDavid Herrmann 				__u8 *buf, size_t len, unsigned char rtype,
3187c4003bcSDavid Herrmann 				int reqtype)
3197c4003bcSDavid Herrmann {
32011c22155SDavid Herrmann 	u8 u_rtype;
32111c22155SDavid Herrmann 
32211c22155SDavid Herrmann 	switch (rtype) {
32311c22155SDavid Herrmann 	case HID_FEATURE_REPORT:
32411c22155SDavid Herrmann 		u_rtype = UHID_FEATURE_REPORT;
32511c22155SDavid Herrmann 		break;
32611c22155SDavid Herrmann 	case HID_OUTPUT_REPORT:
32711c22155SDavid Herrmann 		u_rtype = UHID_OUTPUT_REPORT;
32811c22155SDavid Herrmann 		break;
32911c22155SDavid Herrmann 	case HID_INPUT_REPORT:
33011c22155SDavid Herrmann 		u_rtype = UHID_INPUT_REPORT;
33111c22155SDavid Herrmann 		break;
33211c22155SDavid Herrmann 	default:
33311c22155SDavid Herrmann 		return -EINVAL;
33411c22155SDavid Herrmann 	}
33511c22155SDavid Herrmann 
3367c4003bcSDavid Herrmann 	switch (reqtype) {
3377c4003bcSDavid Herrmann 	case HID_REQ_GET_REPORT:
33811c22155SDavid Herrmann 		return uhid_hid_get_report(hid, reportnum, buf, len, u_rtype);
3397c4003bcSDavid Herrmann 	case HID_REQ_SET_REPORT:
34011c22155SDavid Herrmann 		return uhid_hid_set_report(hid, reportnum, buf, len, u_rtype);
3417c4003bcSDavid Herrmann 	default:
3427c4003bcSDavid Herrmann 		return -EIO;
3437c4003bcSDavid Herrmann 	}
3447c4003bcSDavid Herrmann }
3457c4003bcSDavid Herrmann 
uhid_hid_output_raw(struct hid_device * hid,__u8 * buf,size_t count,unsigned char report_type)346d365c6cfSDavid Herrmann static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
347d365c6cfSDavid Herrmann 			       unsigned char report_type)
348d365c6cfSDavid Herrmann {
3493b3baa82SDavid Herrmann 	struct uhid_device *uhid = hid->driver_data;
3503b3baa82SDavid Herrmann 	__u8 rtype;
3513b3baa82SDavid Herrmann 	unsigned long flags;
3523b3baa82SDavid Herrmann 	struct uhid_event *ev;
3533b3baa82SDavid Herrmann 
3543b3baa82SDavid Herrmann 	switch (report_type) {
3553b3baa82SDavid Herrmann 	case HID_FEATURE_REPORT:
3563b3baa82SDavid Herrmann 		rtype = UHID_FEATURE_REPORT;
3573b3baa82SDavid Herrmann 		break;
3583b3baa82SDavid Herrmann 	case HID_OUTPUT_REPORT:
3593b3baa82SDavid Herrmann 		rtype = UHID_OUTPUT_REPORT;
3603b3baa82SDavid Herrmann 		break;
3613b3baa82SDavid Herrmann 	default:
3623b3baa82SDavid Herrmann 		return -EINVAL;
3633b3baa82SDavid Herrmann 	}
3643b3baa82SDavid Herrmann 
3653b3baa82SDavid Herrmann 	if (count < 1 || count > UHID_DATA_MAX)
3663b3baa82SDavid Herrmann 		return -EINVAL;
3673b3baa82SDavid Herrmann 
3683b3baa82SDavid Herrmann 	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
3693b3baa82SDavid Herrmann 	if (!ev)
3703b3baa82SDavid Herrmann 		return -ENOMEM;
3713b3baa82SDavid Herrmann 
3723b3baa82SDavid Herrmann 	ev->type = UHID_OUTPUT;
3733b3baa82SDavid Herrmann 	ev->u.output.size = count;
3743b3baa82SDavid Herrmann 	ev->u.output.rtype = rtype;
3753b3baa82SDavid Herrmann 	memcpy(ev->u.output.data, buf, count);
3763b3baa82SDavid Herrmann 
3773b3baa82SDavid Herrmann 	spin_lock_irqsave(&uhid->qlock, flags);
3783b3baa82SDavid Herrmann 	uhid_queue(uhid, ev);
3793b3baa82SDavid Herrmann 	spin_unlock_irqrestore(&uhid->qlock, flags);
3803b3baa82SDavid Herrmann 
3813b3baa82SDavid Herrmann 	return count;
382d365c6cfSDavid Herrmann }
383d365c6cfSDavid Herrmann 
uhid_hid_output_report(struct hid_device * hid,__u8 * buf,size_t count)384596cfdd8SFrank Praznik static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf,
385596cfdd8SFrank Praznik 				  size_t count)
386596cfdd8SFrank Praznik {
38741abfb36SBenjamin Tissoires 	return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT);
388596cfdd8SFrank Praznik }
389596cfdd8SFrank Praznik 
39052d22534SThomas Weißschuh static const struct hid_ll_driver uhid_hid_driver = {
391d365c6cfSDavid Herrmann 	.start = uhid_hid_start,
392d365c6cfSDavid Herrmann 	.stop = uhid_hid_stop,
393d365c6cfSDavid Herrmann 	.open = uhid_hid_open,
394d365c6cfSDavid Herrmann 	.close = uhid_hid_close,
395d365c6cfSDavid Herrmann 	.parse = uhid_hid_parse,
3967c4003bcSDavid Herrmann 	.raw_request = uhid_hid_raw_request,
397596cfdd8SFrank Praznik 	.output_report = uhid_hid_output_report,
398*1c5d4221SLee Jones 	.max_buffer_size = UHID_DATA_MAX,
399d365c6cfSDavid Herrmann };
400d365c6cfSDavid Herrmann 
401befde022SDmitry Torokhov #ifdef CONFIG_COMPAT
402befde022SDmitry Torokhov 
403befde022SDmitry Torokhov /* Apparently we haven't stepped on these rakes enough times yet. */
404befde022SDmitry Torokhov struct uhid_create_req_compat {
405befde022SDmitry Torokhov 	__u8 name[128];
406befde022SDmitry Torokhov 	__u8 phys[64];
407befde022SDmitry Torokhov 	__u8 uniq[64];
408befde022SDmitry Torokhov 
409befde022SDmitry Torokhov 	compat_uptr_t rd_data;
410befde022SDmitry Torokhov 	__u16 rd_size;
411befde022SDmitry Torokhov 
412befde022SDmitry Torokhov 	__u16 bus;
413befde022SDmitry Torokhov 	__u32 vendor;
414befde022SDmitry Torokhov 	__u32 product;
415befde022SDmitry Torokhov 	__u32 version;
416befde022SDmitry Torokhov 	__u32 country;
417befde022SDmitry Torokhov } __attribute__((__packed__));
418befde022SDmitry Torokhov 
uhid_event_from_user(const char __user * buffer,size_t len,struct uhid_event * event)419befde022SDmitry Torokhov static int uhid_event_from_user(const char __user *buffer, size_t len,
420befde022SDmitry Torokhov 				struct uhid_event *event)
421befde022SDmitry Torokhov {
4227365abbaSAndy Lutomirski 	if (in_compat_syscall()) {
423befde022SDmitry Torokhov 		u32 type;
424befde022SDmitry Torokhov 
425befde022SDmitry Torokhov 		if (get_user(type, buffer))
426befde022SDmitry Torokhov 			return -EFAULT;
427befde022SDmitry Torokhov 
428befde022SDmitry Torokhov 		if (type == UHID_CREATE) {
429befde022SDmitry Torokhov 			/*
430befde022SDmitry Torokhov 			 * This is our messed up request with compat pointer.
431befde022SDmitry Torokhov 			 * It is largish (more than 256 bytes) so we better
432befde022SDmitry Torokhov 			 * allocate it from the heap.
433befde022SDmitry Torokhov 			 */
434befde022SDmitry Torokhov 			struct uhid_create_req_compat *compat;
435befde022SDmitry Torokhov 
43680897aa7SDavid Herrmann 			compat = kzalloc(sizeof(*compat), GFP_KERNEL);
437befde022SDmitry Torokhov 			if (!compat)
438befde022SDmitry Torokhov 				return -ENOMEM;
439befde022SDmitry Torokhov 
440befde022SDmitry Torokhov 			buffer += sizeof(type);
441befde022SDmitry Torokhov 			len -= sizeof(type);
442befde022SDmitry Torokhov 			if (copy_from_user(compat, buffer,
443befde022SDmitry Torokhov 					   min(len, sizeof(*compat)))) {
444befde022SDmitry Torokhov 				kfree(compat);
445befde022SDmitry Torokhov 				return -EFAULT;
446befde022SDmitry Torokhov 			}
447befde022SDmitry Torokhov 
448befde022SDmitry Torokhov 			/* Shuffle the data over to proper structure */
449befde022SDmitry Torokhov 			event->type = type;
450befde022SDmitry Torokhov 
451befde022SDmitry Torokhov 			memcpy(event->u.create.name, compat->name,
452befde022SDmitry Torokhov 				sizeof(compat->name));
453befde022SDmitry Torokhov 			memcpy(event->u.create.phys, compat->phys,
454befde022SDmitry Torokhov 				sizeof(compat->phys));
455befde022SDmitry Torokhov 			memcpy(event->u.create.uniq, compat->uniq,
456befde022SDmitry Torokhov 				sizeof(compat->uniq));
457befde022SDmitry Torokhov 
458befde022SDmitry Torokhov 			event->u.create.rd_data = compat_ptr(compat->rd_data);
459befde022SDmitry Torokhov 			event->u.create.rd_size = compat->rd_size;
460befde022SDmitry Torokhov 
461befde022SDmitry Torokhov 			event->u.create.bus = compat->bus;
462befde022SDmitry Torokhov 			event->u.create.vendor = compat->vendor;
463befde022SDmitry Torokhov 			event->u.create.product = compat->product;
464befde022SDmitry Torokhov 			event->u.create.version = compat->version;
465befde022SDmitry Torokhov 			event->u.create.country = compat->country;
466befde022SDmitry Torokhov 
467befde022SDmitry Torokhov 			kfree(compat);
468befde022SDmitry Torokhov 			return 0;
469befde022SDmitry Torokhov 		}
470befde022SDmitry Torokhov 		/* All others can be copied directly */
471befde022SDmitry Torokhov 	}
472befde022SDmitry Torokhov 
473befde022SDmitry Torokhov 	if (copy_from_user(event, buffer, min(len, sizeof(*event))))
474befde022SDmitry Torokhov 		return -EFAULT;
475befde022SDmitry Torokhov 
476befde022SDmitry Torokhov 	return 0;
477befde022SDmitry Torokhov }
478befde022SDmitry Torokhov #else
uhid_event_from_user(const char __user * buffer,size_t len,struct uhid_event * event)479befde022SDmitry Torokhov static int uhid_event_from_user(const char __user *buffer, size_t len,
480befde022SDmitry Torokhov 				struct uhid_event *event)
481befde022SDmitry Torokhov {
482befde022SDmitry Torokhov 	if (copy_from_user(event, buffer, min(len, sizeof(*event))))
483befde022SDmitry Torokhov 		return -EFAULT;
484befde022SDmitry Torokhov 
485befde022SDmitry Torokhov 	return 0;
486befde022SDmitry Torokhov }
487befde022SDmitry Torokhov #endif
488befde022SDmitry Torokhov 
uhid_dev_create2(struct uhid_device * uhid,const struct uhid_event * ev)4894522643aSPetri Gynther static int uhid_dev_create2(struct uhid_device *uhid,
4904522643aSPetri Gynther 			    const struct uhid_event *ev)
4914522643aSPetri Gynther {
4924522643aSPetri Gynther 	struct hid_device *hid;
49325be7fe2SDavid Herrmann 	size_t rd_size, len;
49441c4a464SDavid Herrmann 	void *rd_data;
4954522643aSPetri Gynther 	int ret;
4964522643aSPetri Gynther 
4974ea5763fSJann Horn 	if (uhid->hid)
4984522643aSPetri Gynther 		return -EALREADY;
4994522643aSPetri Gynther 
50041c4a464SDavid Herrmann 	rd_size = ev->u.create2.rd_size;
50141c4a464SDavid Herrmann 	if (rd_size <= 0 || rd_size > HID_MAX_DESCRIPTOR_SIZE)
5024522643aSPetri Gynther 		return -EINVAL;
5034522643aSPetri Gynther 
50441c4a464SDavid Herrmann 	rd_data = kmemdup(ev->u.create2.rd_data, rd_size, GFP_KERNEL);
50541c4a464SDavid Herrmann 	if (!rd_data)
5064522643aSPetri Gynther 		return -ENOMEM;
5074522643aSPetri Gynther 
50841c4a464SDavid Herrmann 	uhid->rd_size = rd_size;
50941c4a464SDavid Herrmann 	uhid->rd_data = rd_data;
51041c4a464SDavid Herrmann 
5114522643aSPetri Gynther 	hid = hid_allocate_device();
5124522643aSPetri Gynther 	if (IS_ERR(hid)) {
5134522643aSPetri Gynther 		ret = PTR_ERR(hid);
5144522643aSPetri Gynther 		goto err_free;
5154522643aSPetri Gynther 	}
5164522643aSPetri Gynther 
5174d26d1d1SDavid Herrmann 	/* @hid is zero-initialized, strncpy() is correct, strlcpy() not */
5184d26d1d1SDavid Herrmann 	len = min(sizeof(hid->name), sizeof(ev->u.create2.name)) - 1;
5194d26d1d1SDavid Herrmann 	strncpy(hid->name, ev->u.create2.name, len);
5204d26d1d1SDavid Herrmann 	len = min(sizeof(hid->phys), sizeof(ev->u.create2.phys)) - 1;
5214d26d1d1SDavid Herrmann 	strncpy(hid->phys, ev->u.create2.phys, len);
5224d26d1d1SDavid Herrmann 	len = min(sizeof(hid->uniq), sizeof(ev->u.create2.uniq)) - 1;
5234d26d1d1SDavid Herrmann 	strncpy(hid->uniq, ev->u.create2.uniq, len);
5244522643aSPetri Gynther 
5254522643aSPetri Gynther 	hid->ll_driver = &uhid_hid_driver;
5264522643aSPetri Gynther 	hid->bus = ev->u.create2.bus;
5274522643aSPetri Gynther 	hid->vendor = ev->u.create2.vendor;
5284522643aSPetri Gynther 	hid->product = ev->u.create2.product;
5294522643aSPetri Gynther 	hid->version = ev->u.create2.version;
5304522643aSPetri Gynther 	hid->country = ev->u.create2.country;
5314522643aSPetri Gynther 	hid->driver_data = uhid;
5324522643aSPetri Gynther 	hid->dev.parent = uhid_misc.this_device;
5334522643aSPetri Gynther 
5344522643aSPetri Gynther 	uhid->hid = hid;
5354522643aSPetri Gynther 	uhid->running = true;
5364522643aSPetri Gynther 
53767f8ecc5SRoderick Colenbrander 	/* Adding of a HID device is done through a worker, to allow HID drivers
53867f8ecc5SRoderick Colenbrander 	 * which use feature requests during .probe to work, without they would
53967f8ecc5SRoderick Colenbrander 	 * be blocked on devlock, which is held by uhid_char_write.
54067f8ecc5SRoderick Colenbrander 	 */
54167f8ecc5SRoderick Colenbrander 	schedule_work(&uhid->worker);
5424522643aSPetri Gynther 
5434522643aSPetri Gynther 	return 0;
5444522643aSPetri Gynther 
5454522643aSPetri Gynther err_free:
5464522643aSPetri Gynther 	kfree(uhid->rd_data);
54741c4a464SDavid Herrmann 	uhid->rd_data = NULL;
54841c4a464SDavid Herrmann 	uhid->rd_size = 0;
5494522643aSPetri Gynther 	return ret;
5504522643aSPetri Gynther }
5514522643aSPetri Gynther 
uhid_dev_create(struct uhid_device * uhid,struct uhid_event * ev)55256c47754SDavid Herrmann static int uhid_dev_create(struct uhid_device *uhid,
55356c47754SDavid Herrmann 			   struct uhid_event *ev)
55456c47754SDavid Herrmann {
55556c47754SDavid Herrmann 	struct uhid_create_req orig;
55656c47754SDavid Herrmann 
55756c47754SDavid Herrmann 	orig = ev->u.create;
55856c47754SDavid Herrmann 
55956c47754SDavid Herrmann 	if (orig.rd_size <= 0 || orig.rd_size > HID_MAX_DESCRIPTOR_SIZE)
56056c47754SDavid Herrmann 		return -EINVAL;
56156c47754SDavid Herrmann 	if (copy_from_user(&ev->u.create2.rd_data, orig.rd_data, orig.rd_size))
56256c47754SDavid Herrmann 		return -EFAULT;
56356c47754SDavid Herrmann 
56456c47754SDavid Herrmann 	memcpy(ev->u.create2.name, orig.name, sizeof(orig.name));
56556c47754SDavid Herrmann 	memcpy(ev->u.create2.phys, orig.phys, sizeof(orig.phys));
56656c47754SDavid Herrmann 	memcpy(ev->u.create2.uniq, orig.uniq, sizeof(orig.uniq));
56756c47754SDavid Herrmann 	ev->u.create2.rd_size = orig.rd_size;
56856c47754SDavid Herrmann 	ev->u.create2.bus = orig.bus;
56956c47754SDavid Herrmann 	ev->u.create2.vendor = orig.vendor;
57056c47754SDavid Herrmann 	ev->u.create2.product = orig.product;
57156c47754SDavid Herrmann 	ev->u.create2.version = orig.version;
57256c47754SDavid Herrmann 	ev->u.create2.country = orig.country;
57356c47754SDavid Herrmann 
57456c47754SDavid Herrmann 	return uhid_dev_create2(uhid, ev);
57556c47754SDavid Herrmann }
57656c47754SDavid Herrmann 
uhid_dev_destroy(struct uhid_device * uhid)577d365c6cfSDavid Herrmann static int uhid_dev_destroy(struct uhid_device *uhid)
578d365c6cfSDavid Herrmann {
5794ea5763fSJann Horn 	if (!uhid->hid)
580d365c6cfSDavid Herrmann 		return -EINVAL;
581d365c6cfSDavid Herrmann 
582c8e7ff41SJann Horn 	WRITE_ONCE(uhid->running, false);
583fcfcf0deSDavid Herrmann 	wake_up_interruptible(&uhid->report_wait);
584d365c6cfSDavid Herrmann 
58567f8ecc5SRoderick Colenbrander 	cancel_work_sync(&uhid->worker);
58667f8ecc5SRoderick Colenbrander 
587d365c6cfSDavid Herrmann 	hid_destroy_device(uhid->hid);
5884ea5763fSJann Horn 	uhid->hid = NULL;
589d365c6cfSDavid Herrmann 	kfree(uhid->rd_data);
590d365c6cfSDavid Herrmann 
591d365c6cfSDavid Herrmann 	return 0;
592d365c6cfSDavid Herrmann }
593d365c6cfSDavid Herrmann 
uhid_dev_input(struct uhid_device * uhid,struct uhid_event * ev)5945e87a36aSDavid Herrmann static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
5955e87a36aSDavid Herrmann {
596c8e7ff41SJann Horn 	if (!READ_ONCE(uhid->running))
5975e87a36aSDavid Herrmann 		return -EINVAL;
5985e87a36aSDavid Herrmann 
5995e87a36aSDavid Herrmann 	hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
6005e87a36aSDavid Herrmann 			 min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
6015e87a36aSDavid Herrmann 
6025e87a36aSDavid Herrmann 	return 0;
6035e87a36aSDavid Herrmann }
6045e87a36aSDavid Herrmann 
uhid_dev_input2(struct uhid_device * uhid,struct uhid_event * ev)6054522643aSPetri Gynther static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
6064522643aSPetri Gynther {
607c8e7ff41SJann Horn 	if (!READ_ONCE(uhid->running))
6084522643aSPetri Gynther 		return -EINVAL;
6094522643aSPetri Gynther 
6104522643aSPetri Gynther 	hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
6114522643aSPetri Gynther 			 min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
6124522643aSPetri Gynther 
6134522643aSPetri Gynther 	return 0;
6144522643aSPetri Gynther }
6154522643aSPetri Gynther 
uhid_dev_get_report_reply(struct uhid_device * uhid,struct uhid_event * ev)616fa71f32bSDavid Herrmann static int uhid_dev_get_report_reply(struct uhid_device *uhid,
617fcfcf0deSDavid Herrmann 				     struct uhid_event *ev)
618fcfcf0deSDavid Herrmann {
619c8e7ff41SJann Horn 	if (!READ_ONCE(uhid->running))
620fcfcf0deSDavid Herrmann 		return -EINVAL;
621fcfcf0deSDavid Herrmann 
62211c22155SDavid Herrmann 	uhid_report_wake_up(uhid, ev->u.get_report_reply.id, ev);
62311c22155SDavid Herrmann 	return 0;
62411c22155SDavid Herrmann }
625fcfcf0deSDavid Herrmann 
uhid_dev_set_report_reply(struct uhid_device * uhid,struct uhid_event * ev)62611c22155SDavid Herrmann static int uhid_dev_set_report_reply(struct uhid_device *uhid,
62711c22155SDavid Herrmann 				     struct uhid_event *ev)
62811c22155SDavid Herrmann {
629c8e7ff41SJann Horn 	if (!READ_ONCE(uhid->running))
63011c22155SDavid Herrmann 		return -EINVAL;
631fcfcf0deSDavid Herrmann 
63211c22155SDavid Herrmann 	uhid_report_wake_up(uhid, ev->u.set_report_reply.id, ev);
633fcfcf0deSDavid Herrmann 	return 0;
634fcfcf0deSDavid Herrmann }
635fcfcf0deSDavid Herrmann 
uhid_char_open(struct inode * inode,struct file * file)6361ccd7a2aSDavid Herrmann static int uhid_char_open(struct inode *inode, struct file *file)
6371ccd7a2aSDavid Herrmann {
638ace3d861SDavid Herrmann 	struct uhid_device *uhid;
639ace3d861SDavid Herrmann 
640ace3d861SDavid Herrmann 	uhid = kzalloc(sizeof(*uhid), GFP_KERNEL);
641ace3d861SDavid Herrmann 	if (!uhid)
642ace3d861SDavid Herrmann 		return -ENOMEM;
643ace3d861SDavid Herrmann 
644d937ae5fSDavid Herrmann 	mutex_init(&uhid->devlock);
645fcfcf0deSDavid Herrmann 	mutex_init(&uhid->report_lock);
646ace3d861SDavid Herrmann 	spin_lock_init(&uhid->qlock);
647ace3d861SDavid Herrmann 	init_waitqueue_head(&uhid->waitq);
648fcfcf0deSDavid Herrmann 	init_waitqueue_head(&uhid->report_wait);
649d365c6cfSDavid Herrmann 	uhid->running = false;
65067f8ecc5SRoderick Colenbrander 	INIT_WORK(&uhid->worker, uhid_device_add_worker);
651ace3d861SDavid Herrmann 
652ace3d861SDavid Herrmann 	file->private_data = uhid;
653c5bf68feSKirill Smelkov 	stream_open(inode, file);
654ace3d861SDavid Herrmann 
6551ccd7a2aSDavid Herrmann 	return 0;
6561ccd7a2aSDavid Herrmann }
6571ccd7a2aSDavid Herrmann 
uhid_char_release(struct inode * inode,struct file * file)6581ccd7a2aSDavid Herrmann static int uhid_char_release(struct inode *inode, struct file *file)
6591ccd7a2aSDavid Herrmann {
660ace3d861SDavid Herrmann 	struct uhid_device *uhid = file->private_data;
661ace3d861SDavid Herrmann 	unsigned int i;
662ace3d861SDavid Herrmann 
663d365c6cfSDavid Herrmann 	uhid_dev_destroy(uhid);
664d365c6cfSDavid Herrmann 
665ace3d861SDavid Herrmann 	for (i = 0; i < UHID_BUFSIZE; ++i)
666ace3d861SDavid Herrmann 		kfree(uhid->outq[i]);
667ace3d861SDavid Herrmann 
668ace3d861SDavid Herrmann 	kfree(uhid);
669ace3d861SDavid Herrmann 
6701ccd7a2aSDavid Herrmann 	return 0;
6711ccd7a2aSDavid Herrmann }
6721ccd7a2aSDavid Herrmann 
uhid_char_read(struct file * file,char __user * buffer,size_t count,loff_t * ppos)6731ccd7a2aSDavid Herrmann static ssize_t uhid_char_read(struct file *file, char __user *buffer,
6741ccd7a2aSDavid Herrmann 				size_t count, loff_t *ppos)
6751ccd7a2aSDavid Herrmann {
676d937ae5fSDavid Herrmann 	struct uhid_device *uhid = file->private_data;
677d937ae5fSDavid Herrmann 	int ret;
678d937ae5fSDavid Herrmann 	unsigned long flags;
679d937ae5fSDavid Herrmann 	size_t len;
680d937ae5fSDavid Herrmann 
681d937ae5fSDavid Herrmann 	/* they need at least the "type" member of uhid_event */
682d937ae5fSDavid Herrmann 	if (count < sizeof(__u32))
683d937ae5fSDavid Herrmann 		return -EINVAL;
684d937ae5fSDavid Herrmann 
685d937ae5fSDavid Herrmann try_again:
686d937ae5fSDavid Herrmann 	if (file->f_flags & O_NONBLOCK) {
687d937ae5fSDavid Herrmann 		if (uhid->head == uhid->tail)
688d937ae5fSDavid Herrmann 			return -EAGAIN;
689d937ae5fSDavid Herrmann 	} else {
690d937ae5fSDavid Herrmann 		ret = wait_event_interruptible(uhid->waitq,
691d937ae5fSDavid Herrmann 						uhid->head != uhid->tail);
692d937ae5fSDavid Herrmann 		if (ret)
693d937ae5fSDavid Herrmann 			return ret;
694d937ae5fSDavid Herrmann 	}
695d937ae5fSDavid Herrmann 
696d937ae5fSDavid Herrmann 	ret = mutex_lock_interruptible(&uhid->devlock);
697d937ae5fSDavid Herrmann 	if (ret)
698d937ae5fSDavid Herrmann 		return ret;
699d937ae5fSDavid Herrmann 
700d937ae5fSDavid Herrmann 	if (uhid->head == uhid->tail) {
701d937ae5fSDavid Herrmann 		mutex_unlock(&uhid->devlock);
702d937ae5fSDavid Herrmann 		goto try_again;
703d937ae5fSDavid Herrmann 	} else {
704d937ae5fSDavid Herrmann 		len = min(count, sizeof(**uhid->outq));
705adefb69bSVinicius Costa Gomes 		if (copy_to_user(buffer, uhid->outq[uhid->tail], len)) {
706d937ae5fSDavid Herrmann 			ret = -EFAULT;
707d937ae5fSDavid Herrmann 		} else {
708d937ae5fSDavid Herrmann 			kfree(uhid->outq[uhid->tail]);
709d937ae5fSDavid Herrmann 			uhid->outq[uhid->tail] = NULL;
710d937ae5fSDavid Herrmann 
711d937ae5fSDavid Herrmann 			spin_lock_irqsave(&uhid->qlock, flags);
712d937ae5fSDavid Herrmann 			uhid->tail = (uhid->tail + 1) % UHID_BUFSIZE;
713d937ae5fSDavid Herrmann 			spin_unlock_irqrestore(&uhid->qlock, flags);
714d937ae5fSDavid Herrmann 		}
715d937ae5fSDavid Herrmann 	}
716d937ae5fSDavid Herrmann 
717d937ae5fSDavid Herrmann 	mutex_unlock(&uhid->devlock);
718d937ae5fSDavid Herrmann 	return ret ? ret : len;
7191ccd7a2aSDavid Herrmann }
7201ccd7a2aSDavid Herrmann 
uhid_char_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)7211ccd7a2aSDavid Herrmann static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
7221ccd7a2aSDavid Herrmann 				size_t count, loff_t *ppos)
7231ccd7a2aSDavid Herrmann {
7246664ef72SDavid Herrmann 	struct uhid_device *uhid = file->private_data;
7256664ef72SDavid Herrmann 	int ret;
7266664ef72SDavid Herrmann 	size_t len;
7276664ef72SDavid Herrmann 
7286664ef72SDavid Herrmann 	/* we need at least the "type" member of uhid_event */
7296664ef72SDavid Herrmann 	if (count < sizeof(__u32))
7306664ef72SDavid Herrmann 		return -EINVAL;
7316664ef72SDavid Herrmann 
7326664ef72SDavid Herrmann 	ret = mutex_lock_interruptible(&uhid->devlock);
7336664ef72SDavid Herrmann 	if (ret)
7346664ef72SDavid Herrmann 		return ret;
7356664ef72SDavid Herrmann 
7366664ef72SDavid Herrmann 	memset(&uhid->input_buf, 0, sizeof(uhid->input_buf));
7376664ef72SDavid Herrmann 	len = min(count, sizeof(uhid->input_buf));
738befde022SDmitry Torokhov 
739befde022SDmitry Torokhov 	ret = uhid_event_from_user(buffer, len, &uhid->input_buf);
740befde022SDmitry Torokhov 	if (ret)
7416664ef72SDavid Herrmann 		goto unlock;
7426664ef72SDavid Herrmann 
7436664ef72SDavid Herrmann 	switch (uhid->input_buf.type) {
744d365c6cfSDavid Herrmann 	case UHID_CREATE:
7458c01db76SEric Biggers 		/*
7468c01db76SEric Biggers 		 * 'struct uhid_create_req' contains a __user pointer which is
7478c01db76SEric Biggers 		 * copied from, so it's unsafe to allow this with elevated
7488c01db76SEric Biggers 		 * privileges (e.g. from a setuid binary) or via kernel_write().
7498c01db76SEric Biggers 		 */
750967747bbSArnd Bergmann 		if (file->f_cred != current_cred()) {
7518c01db76SEric Biggers 			pr_err_once("UHID_CREATE from different security context by process %d (%s), this is not allowed.\n",
7528c01db76SEric Biggers 				    task_tgid_vnr(current), current->comm);
7538c01db76SEric Biggers 			ret = -EACCES;
7548c01db76SEric Biggers 			goto unlock;
7558c01db76SEric Biggers 		}
756d365c6cfSDavid Herrmann 		ret = uhid_dev_create(uhid, &uhid->input_buf);
757d365c6cfSDavid Herrmann 		break;
7584522643aSPetri Gynther 	case UHID_CREATE2:
7594522643aSPetri Gynther 		ret = uhid_dev_create2(uhid, &uhid->input_buf);
7604522643aSPetri Gynther 		break;
761d365c6cfSDavid Herrmann 	case UHID_DESTROY:
762d365c6cfSDavid Herrmann 		ret = uhid_dev_destroy(uhid);
763d365c6cfSDavid Herrmann 		break;
7645e87a36aSDavid Herrmann 	case UHID_INPUT:
7655e87a36aSDavid Herrmann 		ret = uhid_dev_input(uhid, &uhid->input_buf);
7665e87a36aSDavid Herrmann 		break;
7674522643aSPetri Gynther 	case UHID_INPUT2:
7684522643aSPetri Gynther 		ret = uhid_dev_input2(uhid, &uhid->input_buf);
7694522643aSPetri Gynther 		break;
770fa71f32bSDavid Herrmann 	case UHID_GET_REPORT_REPLY:
771fa71f32bSDavid Herrmann 		ret = uhid_dev_get_report_reply(uhid, &uhid->input_buf);
772fcfcf0deSDavid Herrmann 		break;
77311c22155SDavid Herrmann 	case UHID_SET_REPORT_REPLY:
77411c22155SDavid Herrmann 		ret = uhid_dev_set_report_reply(uhid, &uhid->input_buf);
77511c22155SDavid Herrmann 		break;
7766664ef72SDavid Herrmann 	default:
7776664ef72SDavid Herrmann 		ret = -EOPNOTSUPP;
7786664ef72SDavid Herrmann 	}
7796664ef72SDavid Herrmann 
7806664ef72SDavid Herrmann unlock:
7816664ef72SDavid Herrmann 	mutex_unlock(&uhid->devlock);
7826664ef72SDavid Herrmann 
7836664ef72SDavid Herrmann 	/* return "count" not "len" to not confuse the caller */
7846664ef72SDavid Herrmann 	return ret ? ret : count;
7851ccd7a2aSDavid Herrmann }
7861ccd7a2aSDavid Herrmann 
uhid_char_poll(struct file * file,poll_table * wait)787afc9a42bSAl Viro static __poll_t uhid_char_poll(struct file *file, poll_table *wait)
7881ccd7a2aSDavid Herrmann {
7891f9dec1eSDavid Herrmann 	struct uhid_device *uhid = file->private_data;
7909e635c28SJiri Kosina 	__poll_t mask = EPOLLOUT | EPOLLWRNORM; /* uhid is always writable */
7911f9dec1eSDavid Herrmann 
7921f9dec1eSDavid Herrmann 	poll_wait(file, &uhid->waitq, wait);
7931f9dec1eSDavid Herrmann 
7941f9dec1eSDavid Herrmann 	if (uhid->head != uhid->tail)
7959e635c28SJiri Kosina 		mask |= EPOLLIN | EPOLLRDNORM;
7961f9dec1eSDavid Herrmann 
7979e635c28SJiri Kosina 	return mask;
7981ccd7a2aSDavid Herrmann }
7991ccd7a2aSDavid Herrmann 
8001ccd7a2aSDavid Herrmann static const struct file_operations uhid_fops = {
8011ccd7a2aSDavid Herrmann 	.owner		= THIS_MODULE,
8021ccd7a2aSDavid Herrmann 	.open		= uhid_char_open,
8031ccd7a2aSDavid Herrmann 	.release	= uhid_char_release,
8041ccd7a2aSDavid Herrmann 	.read		= uhid_char_read,
8051ccd7a2aSDavid Herrmann 	.write		= uhid_char_write,
8061ccd7a2aSDavid Herrmann 	.poll		= uhid_char_poll,
8071ccd7a2aSDavid Herrmann 	.llseek		= no_llseek,
8081ccd7a2aSDavid Herrmann };
8091ccd7a2aSDavid Herrmann 
8101ccd7a2aSDavid Herrmann static struct miscdevice uhid_misc = {
8111ccd7a2aSDavid Herrmann 	.fops		= &uhid_fops,
81219872d20SDavid Herrmann 	.minor		= UHID_MINOR,
8131ccd7a2aSDavid Herrmann 	.name		= UHID_NAME,
8141ccd7a2aSDavid Herrmann };
815ca75d601SPrasannaKumar Muralidharan module_misc_device(uhid_misc);
8161ccd7a2aSDavid Herrmann 
8171ccd7a2aSDavid Herrmann MODULE_LICENSE("GPL");
8181ccd7a2aSDavid Herrmann MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
8191ccd7a2aSDavid Herrmann MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
82019872d20SDavid Herrmann MODULE_ALIAS_MISCDEV(UHID_MINOR);
82160cbd53eSMarcel Holtmann MODULE_ALIAS("devname:" UHID_NAME);
822