1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * HID raw devices, giving access to raw HID events.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * In comparison to hiddev, this device does not process the
6*4882a593Smuzhiyun * hid events at all (no parsing, no lookups). This lets applications
7*4882a593Smuzhiyun * to work on raw hid events as they want to, and avoids a need to
8*4882a593Smuzhiyun * use a transport-specific userspace libhid/libusb libraries.
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Copyright (c) 2007-2014 Jiri Kosina
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <linux/fs.h>
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun #include <linux/errno.h>
19*4882a593Smuzhiyun #include <linux/kernel.h>
20*4882a593Smuzhiyun #include <linux/init.h>
21*4882a593Smuzhiyun #include <linux/cdev.h>
22*4882a593Smuzhiyun #include <linux/poll.h>
23*4882a593Smuzhiyun #include <linux/device.h>
24*4882a593Smuzhiyun #include <linux/major.h>
25*4882a593Smuzhiyun #include <linux/slab.h>
26*4882a593Smuzhiyun #include <linux/hid.h>
27*4882a593Smuzhiyun #include <linux/mutex.h>
28*4882a593Smuzhiyun #include <linux/sched/signal.h>
29*4882a593Smuzhiyun #include <linux/string.h>
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include <linux/hidraw.h>
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun static int hidraw_major;
34*4882a593Smuzhiyun static struct cdev hidraw_cdev;
35*4882a593Smuzhiyun static struct class *hidraw_class;
36*4882a593Smuzhiyun static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
37*4882a593Smuzhiyun static DEFINE_MUTEX(minors_lock);
38*4882a593Smuzhiyun
hidraw_read(struct file * file,char __user * buffer,size_t count,loff_t * ppos)39*4882a593Smuzhiyun static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun struct hidraw_list *list = file->private_data;
42*4882a593Smuzhiyun int ret = 0, len;
43*4882a593Smuzhiyun DECLARE_WAITQUEUE(wait, current);
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun mutex_lock(&list->read_mutex);
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun while (ret == 0) {
48*4882a593Smuzhiyun if (list->head == list->tail) {
49*4882a593Smuzhiyun add_wait_queue(&list->hidraw->wait, &wait);
50*4882a593Smuzhiyun set_current_state(TASK_INTERRUPTIBLE);
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun while (list->head == list->tail) {
53*4882a593Smuzhiyun if (signal_pending(current)) {
54*4882a593Smuzhiyun ret = -ERESTARTSYS;
55*4882a593Smuzhiyun break;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun if (!list->hidraw->exist) {
58*4882a593Smuzhiyun ret = -EIO;
59*4882a593Smuzhiyun break;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun if (file->f_flags & O_NONBLOCK) {
62*4882a593Smuzhiyun ret = -EAGAIN;
63*4882a593Smuzhiyun break;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun /* allow O_NONBLOCK to work well from other threads */
67*4882a593Smuzhiyun mutex_unlock(&list->read_mutex);
68*4882a593Smuzhiyun schedule();
69*4882a593Smuzhiyun mutex_lock(&list->read_mutex);
70*4882a593Smuzhiyun set_current_state(TASK_INTERRUPTIBLE);
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun set_current_state(TASK_RUNNING);
74*4882a593Smuzhiyun remove_wait_queue(&list->hidraw->wait, &wait);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (ret)
78*4882a593Smuzhiyun goto out;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun len = list->buffer[list->tail].len > count ?
81*4882a593Smuzhiyun count : list->buffer[list->tail].len;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (list->buffer[list->tail].value) {
84*4882a593Smuzhiyun if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
85*4882a593Smuzhiyun ret = -EFAULT;
86*4882a593Smuzhiyun goto out;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun ret = len;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun kfree(list->buffer[list->tail].value);
92*4882a593Smuzhiyun list->buffer[list->tail].value = NULL;
93*4882a593Smuzhiyun list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun out:
96*4882a593Smuzhiyun mutex_unlock(&list->read_mutex);
97*4882a593Smuzhiyun return ret;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /*
101*4882a593Smuzhiyun * The first byte of the report buffer is expected to be a report number.
102*4882a593Smuzhiyun */
hidraw_send_report(struct file * file,const char __user * buffer,size_t count,unsigned char report_type)103*4882a593Smuzhiyun static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun unsigned int minor = iminor(file_inode(file));
106*4882a593Smuzhiyun struct hid_device *dev;
107*4882a593Smuzhiyun __u8 *buf;
108*4882a593Smuzhiyun int ret = 0;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun lockdep_assert_held(&minors_lock);
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
113*4882a593Smuzhiyun ret = -ENODEV;
114*4882a593Smuzhiyun goto out;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun dev = hidraw_table[minor]->hid;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun if (count > HID_MAX_BUFFER_SIZE) {
120*4882a593Smuzhiyun hid_warn(dev, "pid %d passed too large report\n",
121*4882a593Smuzhiyun task_pid_nr(current));
122*4882a593Smuzhiyun ret = -EINVAL;
123*4882a593Smuzhiyun goto out;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun if (count < 2) {
127*4882a593Smuzhiyun hid_warn(dev, "pid %d passed too short report\n",
128*4882a593Smuzhiyun task_pid_nr(current));
129*4882a593Smuzhiyun ret = -EINVAL;
130*4882a593Smuzhiyun goto out;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun buf = memdup_user(buffer, count);
134*4882a593Smuzhiyun if (IS_ERR(buf)) {
135*4882a593Smuzhiyun ret = PTR_ERR(buf);
136*4882a593Smuzhiyun goto out;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if ((report_type == HID_OUTPUT_REPORT) &&
140*4882a593Smuzhiyun !(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) {
141*4882a593Smuzhiyun ret = hid_hw_output_report(dev, buf, count);
142*4882a593Smuzhiyun /*
143*4882a593Smuzhiyun * compatibility with old implementation of USB-HID and I2C-HID:
144*4882a593Smuzhiyun * if the device does not support receiving output reports,
145*4882a593Smuzhiyun * on an interrupt endpoint, fallback to SET_REPORT HID command.
146*4882a593Smuzhiyun */
147*4882a593Smuzhiyun if (ret != -ENOSYS)
148*4882a593Smuzhiyun goto out_free;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun ret = hid_hw_raw_request(dev, buf[0], buf, count, report_type,
152*4882a593Smuzhiyun HID_REQ_SET_REPORT);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun out_free:
155*4882a593Smuzhiyun kfree(buf);
156*4882a593Smuzhiyun out:
157*4882a593Smuzhiyun return ret;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
hidraw_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)160*4882a593Smuzhiyun static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun ssize_t ret;
163*4882a593Smuzhiyun mutex_lock(&minors_lock);
164*4882a593Smuzhiyun ret = hidraw_send_report(file, buffer, count, HID_OUTPUT_REPORT);
165*4882a593Smuzhiyun mutex_unlock(&minors_lock);
166*4882a593Smuzhiyun return ret;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /*
171*4882a593Smuzhiyun * This function performs a Get_Report transfer over the control endpoint
172*4882a593Smuzhiyun * per section 7.2.1 of the HID specification, version 1.1. The first byte
173*4882a593Smuzhiyun * of buffer is the report number to request, or 0x0 if the defice does not
174*4882a593Smuzhiyun * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
175*4882a593Smuzhiyun * or HID_INPUT_REPORT.
176*4882a593Smuzhiyun */
hidraw_get_report(struct file * file,char __user * buffer,size_t count,unsigned char report_type)177*4882a593Smuzhiyun static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun unsigned int minor = iminor(file_inode(file));
180*4882a593Smuzhiyun struct hid_device *dev;
181*4882a593Smuzhiyun __u8 *buf;
182*4882a593Smuzhiyun int ret = 0, len;
183*4882a593Smuzhiyun unsigned char report_number;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun lockdep_assert_held(&minors_lock);
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
188*4882a593Smuzhiyun ret = -ENODEV;
189*4882a593Smuzhiyun goto out;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun dev = hidraw_table[minor]->hid;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun if (!dev->ll_driver->raw_request) {
195*4882a593Smuzhiyun ret = -ENODEV;
196*4882a593Smuzhiyun goto out;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (count > HID_MAX_BUFFER_SIZE) {
200*4882a593Smuzhiyun hid_warn(dev, "pid %d passed too large report\n",
201*4882a593Smuzhiyun task_pid_nr(current));
202*4882a593Smuzhiyun ret = -EINVAL;
203*4882a593Smuzhiyun goto out;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun if (count < 2) {
207*4882a593Smuzhiyun hid_warn(dev, "pid %d passed too short report\n",
208*4882a593Smuzhiyun task_pid_nr(current));
209*4882a593Smuzhiyun ret = -EINVAL;
210*4882a593Smuzhiyun goto out;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun buf = kmalloc(count, GFP_KERNEL);
214*4882a593Smuzhiyun if (!buf) {
215*4882a593Smuzhiyun ret = -ENOMEM;
216*4882a593Smuzhiyun goto out;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /*
220*4882a593Smuzhiyun * Read the first byte from the user. This is the report number,
221*4882a593Smuzhiyun * which is passed to hid_hw_raw_request().
222*4882a593Smuzhiyun */
223*4882a593Smuzhiyun if (copy_from_user(&report_number, buffer, 1)) {
224*4882a593Smuzhiyun ret = -EFAULT;
225*4882a593Smuzhiyun goto out_free;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun ret = hid_hw_raw_request(dev, report_number, buf, count, report_type,
229*4882a593Smuzhiyun HID_REQ_GET_REPORT);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun if (ret < 0)
232*4882a593Smuzhiyun goto out_free;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun len = (ret < count) ? ret : count;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun if (copy_to_user(buffer, buf, len)) {
237*4882a593Smuzhiyun ret = -EFAULT;
238*4882a593Smuzhiyun goto out_free;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun ret = len;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun out_free:
244*4882a593Smuzhiyun kfree(buf);
245*4882a593Smuzhiyun out:
246*4882a593Smuzhiyun return ret;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
hidraw_poll(struct file * file,poll_table * wait)249*4882a593Smuzhiyun static __poll_t hidraw_poll(struct file *file, poll_table *wait)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun struct hidraw_list *list = file->private_data;
252*4882a593Smuzhiyun __poll_t mask = EPOLLOUT | EPOLLWRNORM; /* hidraw is always writable */
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun poll_wait(file, &list->hidraw->wait, wait);
255*4882a593Smuzhiyun if (list->head != list->tail)
256*4882a593Smuzhiyun mask |= EPOLLIN | EPOLLRDNORM;
257*4882a593Smuzhiyun if (!list->hidraw->exist)
258*4882a593Smuzhiyun mask |= EPOLLERR | EPOLLHUP;
259*4882a593Smuzhiyun return mask;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
hidraw_open(struct inode * inode,struct file * file)262*4882a593Smuzhiyun static int hidraw_open(struct inode *inode, struct file *file)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun unsigned int minor = iminor(inode);
265*4882a593Smuzhiyun struct hidraw *dev;
266*4882a593Smuzhiyun struct hidraw_list *list;
267*4882a593Smuzhiyun unsigned long flags;
268*4882a593Smuzhiyun int err = 0;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
271*4882a593Smuzhiyun err = -ENOMEM;
272*4882a593Smuzhiyun goto out;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun mutex_lock(&minors_lock);
276*4882a593Smuzhiyun if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
277*4882a593Smuzhiyun err = -ENODEV;
278*4882a593Smuzhiyun goto out_unlock;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun dev = hidraw_table[minor];
282*4882a593Smuzhiyun if (!dev->open++) {
283*4882a593Smuzhiyun err = hid_hw_power(dev->hid, PM_HINT_FULLON);
284*4882a593Smuzhiyun if (err < 0) {
285*4882a593Smuzhiyun dev->open--;
286*4882a593Smuzhiyun goto out_unlock;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun err = hid_hw_open(dev->hid);
290*4882a593Smuzhiyun if (err < 0) {
291*4882a593Smuzhiyun hid_hw_power(dev->hid, PM_HINT_NORMAL);
292*4882a593Smuzhiyun dev->open--;
293*4882a593Smuzhiyun goto out_unlock;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun list->hidraw = hidraw_table[minor];
298*4882a593Smuzhiyun mutex_init(&list->read_mutex);
299*4882a593Smuzhiyun spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
300*4882a593Smuzhiyun list_add_tail(&list->node, &hidraw_table[minor]->list);
301*4882a593Smuzhiyun spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
302*4882a593Smuzhiyun file->private_data = list;
303*4882a593Smuzhiyun out_unlock:
304*4882a593Smuzhiyun mutex_unlock(&minors_lock);
305*4882a593Smuzhiyun out:
306*4882a593Smuzhiyun if (err < 0)
307*4882a593Smuzhiyun kfree(list);
308*4882a593Smuzhiyun return err;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
hidraw_fasync(int fd,struct file * file,int on)312*4882a593Smuzhiyun static int hidraw_fasync(int fd, struct file *file, int on)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun struct hidraw_list *list = file->private_data;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun return fasync_helper(fd, file, on, &list->fasync);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
drop_ref(struct hidraw * hidraw,int exists_bit)319*4882a593Smuzhiyun static void drop_ref(struct hidraw *hidraw, int exists_bit)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun if (exists_bit) {
322*4882a593Smuzhiyun hidraw->exist = 0;
323*4882a593Smuzhiyun if (hidraw->open) {
324*4882a593Smuzhiyun hid_hw_close(hidraw->hid);
325*4882a593Smuzhiyun wake_up_interruptible(&hidraw->wait);
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun device_destroy(hidraw_class,
328*4882a593Smuzhiyun MKDEV(hidraw_major, hidraw->minor));
329*4882a593Smuzhiyun } else {
330*4882a593Smuzhiyun --hidraw->open;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun if (!hidraw->open) {
333*4882a593Smuzhiyun if (!hidraw->exist) {
334*4882a593Smuzhiyun hidraw_table[hidraw->minor] = NULL;
335*4882a593Smuzhiyun kfree(hidraw);
336*4882a593Smuzhiyun } else {
337*4882a593Smuzhiyun /* close device for last reader */
338*4882a593Smuzhiyun hid_hw_close(hidraw->hid);
339*4882a593Smuzhiyun hid_hw_power(hidraw->hid, PM_HINT_NORMAL);
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
hidraw_release(struct inode * inode,struct file * file)344*4882a593Smuzhiyun static int hidraw_release(struct inode * inode, struct file * file)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun unsigned int minor = iminor(inode);
347*4882a593Smuzhiyun struct hidraw_list *list = file->private_data;
348*4882a593Smuzhiyun unsigned long flags;
349*4882a593Smuzhiyun int i;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun mutex_lock(&minors_lock);
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
354*4882a593Smuzhiyun for (i = list->tail; i < list->head; i++)
355*4882a593Smuzhiyun kfree(list->buffer[i].value);
356*4882a593Smuzhiyun list_del(&list->node);
357*4882a593Smuzhiyun spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
358*4882a593Smuzhiyun kfree(list);
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun drop_ref(hidraw_table[minor], 0);
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun mutex_unlock(&minors_lock);
363*4882a593Smuzhiyun return 0;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
hidraw_ioctl(struct file * file,unsigned int cmd,unsigned long arg)366*4882a593Smuzhiyun static long hidraw_ioctl(struct file *file, unsigned int cmd,
367*4882a593Smuzhiyun unsigned long arg)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun struct inode *inode = file_inode(file);
370*4882a593Smuzhiyun unsigned int minor = iminor(inode);
371*4882a593Smuzhiyun long ret = 0;
372*4882a593Smuzhiyun struct hidraw *dev;
373*4882a593Smuzhiyun void __user *user_arg = (void __user*) arg;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun mutex_lock(&minors_lock);
376*4882a593Smuzhiyun dev = hidraw_table[minor];
377*4882a593Smuzhiyun if (!dev || !dev->exist) {
378*4882a593Smuzhiyun ret = -ENODEV;
379*4882a593Smuzhiyun goto out;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun switch (cmd) {
383*4882a593Smuzhiyun case HIDIOCGRDESCSIZE:
384*4882a593Smuzhiyun if (put_user(dev->hid->rsize, (int __user *)arg))
385*4882a593Smuzhiyun ret = -EFAULT;
386*4882a593Smuzhiyun break;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun case HIDIOCGRDESC:
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun __u32 len;
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun if (get_user(len, (int __user *)arg))
393*4882a593Smuzhiyun ret = -EFAULT;
394*4882a593Smuzhiyun else if (len > HID_MAX_DESCRIPTOR_SIZE - 1)
395*4882a593Smuzhiyun ret = -EINVAL;
396*4882a593Smuzhiyun else if (copy_to_user(user_arg + offsetof(
397*4882a593Smuzhiyun struct hidraw_report_descriptor,
398*4882a593Smuzhiyun value[0]),
399*4882a593Smuzhiyun dev->hid->rdesc,
400*4882a593Smuzhiyun min(dev->hid->rsize, len)))
401*4882a593Smuzhiyun ret = -EFAULT;
402*4882a593Smuzhiyun break;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun case HIDIOCGRAWINFO:
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun struct hidraw_devinfo dinfo;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun dinfo.bustype = dev->hid->bus;
409*4882a593Smuzhiyun dinfo.vendor = dev->hid->vendor;
410*4882a593Smuzhiyun dinfo.product = dev->hid->product;
411*4882a593Smuzhiyun if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
412*4882a593Smuzhiyun ret = -EFAULT;
413*4882a593Smuzhiyun break;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun default:
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun struct hid_device *hid = dev->hid;
418*4882a593Smuzhiyun if (_IOC_TYPE(cmd) != 'H') {
419*4882a593Smuzhiyun ret = -EINVAL;
420*4882a593Smuzhiyun break;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSFEATURE(0))) {
424*4882a593Smuzhiyun int len = _IOC_SIZE(cmd);
425*4882a593Smuzhiyun ret = hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT);
426*4882a593Smuzhiyun break;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGFEATURE(0))) {
429*4882a593Smuzhiyun int len = _IOC_SIZE(cmd);
430*4882a593Smuzhiyun ret = hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT);
431*4882a593Smuzhiyun break;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun /* Begin Read-only ioctls. */
435*4882a593Smuzhiyun if (_IOC_DIR(cmd) != _IOC_READ) {
436*4882a593Smuzhiyun ret = -EINVAL;
437*4882a593Smuzhiyun break;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {
441*4882a593Smuzhiyun int len = strlen(hid->name) + 1;
442*4882a593Smuzhiyun if (len > _IOC_SIZE(cmd))
443*4882a593Smuzhiyun len = _IOC_SIZE(cmd);
444*4882a593Smuzhiyun ret = copy_to_user(user_arg, hid->name, len) ?
445*4882a593Smuzhiyun -EFAULT : len;
446*4882a593Smuzhiyun break;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {
450*4882a593Smuzhiyun int len = strlen(hid->phys) + 1;
451*4882a593Smuzhiyun if (len > _IOC_SIZE(cmd))
452*4882a593Smuzhiyun len = _IOC_SIZE(cmd);
453*4882a593Smuzhiyun ret = copy_to_user(user_arg, hid->phys, len) ?
454*4882a593Smuzhiyun -EFAULT : len;
455*4882a593Smuzhiyun break;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWUNIQ(0))) {
459*4882a593Smuzhiyun int len = strlen(hid->uniq) + 1;
460*4882a593Smuzhiyun if (len > _IOC_SIZE(cmd))
461*4882a593Smuzhiyun len = _IOC_SIZE(cmd);
462*4882a593Smuzhiyun ret = copy_to_user(user_arg, hid->uniq, len) ?
463*4882a593Smuzhiyun -EFAULT : len;
464*4882a593Smuzhiyun break;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun ret = -ENOTTY;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun out:
471*4882a593Smuzhiyun mutex_unlock(&minors_lock);
472*4882a593Smuzhiyun return ret;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun static const struct file_operations hidraw_ops = {
476*4882a593Smuzhiyun .owner = THIS_MODULE,
477*4882a593Smuzhiyun .read = hidraw_read,
478*4882a593Smuzhiyun .write = hidraw_write,
479*4882a593Smuzhiyun .poll = hidraw_poll,
480*4882a593Smuzhiyun .open = hidraw_open,
481*4882a593Smuzhiyun .release = hidraw_release,
482*4882a593Smuzhiyun .unlocked_ioctl = hidraw_ioctl,
483*4882a593Smuzhiyun .fasync = hidraw_fasync,
484*4882a593Smuzhiyun .compat_ioctl = compat_ptr_ioctl,
485*4882a593Smuzhiyun .llseek = noop_llseek,
486*4882a593Smuzhiyun };
487*4882a593Smuzhiyun
hidraw_report_event(struct hid_device * hid,u8 * data,int len)488*4882a593Smuzhiyun int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
489*4882a593Smuzhiyun {
490*4882a593Smuzhiyun struct hidraw *dev = hid->hidraw;
491*4882a593Smuzhiyun struct hidraw_list *list;
492*4882a593Smuzhiyun int ret = 0;
493*4882a593Smuzhiyun unsigned long flags;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun spin_lock_irqsave(&dev->list_lock, flags);
496*4882a593Smuzhiyun list_for_each_entry(list, &dev->list, node) {
497*4882a593Smuzhiyun int new_head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun if (new_head == list->tail)
500*4882a593Smuzhiyun continue;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
503*4882a593Smuzhiyun ret = -ENOMEM;
504*4882a593Smuzhiyun break;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun list->buffer[list->head].len = len;
507*4882a593Smuzhiyun list->head = new_head;
508*4882a593Smuzhiyun kill_fasync(&list->fasync, SIGIO, POLL_IN);
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->list_lock, flags);
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun wake_up_interruptible(&dev->wait);
513*4882a593Smuzhiyun return ret;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hidraw_report_event);
516*4882a593Smuzhiyun
hidraw_connect(struct hid_device * hid)517*4882a593Smuzhiyun int hidraw_connect(struct hid_device *hid)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun int minor, result;
520*4882a593Smuzhiyun struct hidraw *dev;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun /* we accept any HID device, all applications */
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
525*4882a593Smuzhiyun if (!dev)
526*4882a593Smuzhiyun return -ENOMEM;
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun result = -EINVAL;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun mutex_lock(&minors_lock);
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {
533*4882a593Smuzhiyun if (hidraw_table[minor])
534*4882a593Smuzhiyun continue;
535*4882a593Smuzhiyun hidraw_table[minor] = dev;
536*4882a593Smuzhiyun result = 0;
537*4882a593Smuzhiyun break;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun if (result) {
541*4882a593Smuzhiyun mutex_unlock(&minors_lock);
542*4882a593Smuzhiyun kfree(dev);
543*4882a593Smuzhiyun goto out;
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor),
547*4882a593Smuzhiyun NULL, "%s%d", "hidraw", minor);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (IS_ERR(dev->dev)) {
550*4882a593Smuzhiyun hidraw_table[minor] = NULL;
551*4882a593Smuzhiyun mutex_unlock(&minors_lock);
552*4882a593Smuzhiyun result = PTR_ERR(dev->dev);
553*4882a593Smuzhiyun kfree(dev);
554*4882a593Smuzhiyun goto out;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun init_waitqueue_head(&dev->wait);
558*4882a593Smuzhiyun spin_lock_init(&dev->list_lock);
559*4882a593Smuzhiyun INIT_LIST_HEAD(&dev->list);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun dev->hid = hid;
562*4882a593Smuzhiyun dev->minor = minor;
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun dev->exist = 1;
565*4882a593Smuzhiyun hid->hidraw = dev;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun mutex_unlock(&minors_lock);
568*4882a593Smuzhiyun out:
569*4882a593Smuzhiyun return result;
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hidraw_connect);
573*4882a593Smuzhiyun
hidraw_disconnect(struct hid_device * hid)574*4882a593Smuzhiyun void hidraw_disconnect(struct hid_device *hid)
575*4882a593Smuzhiyun {
576*4882a593Smuzhiyun struct hidraw *hidraw = hid->hidraw;
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun mutex_lock(&minors_lock);
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun drop_ref(hidraw, 1);
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun mutex_unlock(&minors_lock);
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hidraw_disconnect);
585*4882a593Smuzhiyun
hidraw_init(void)586*4882a593Smuzhiyun int __init hidraw_init(void)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun int result;
589*4882a593Smuzhiyun dev_t dev_id;
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR,
592*4882a593Smuzhiyun HIDRAW_MAX_DEVICES, "hidraw");
593*4882a593Smuzhiyun if (result < 0) {
594*4882a593Smuzhiyun pr_warn("can't get major number\n");
595*4882a593Smuzhiyun goto out;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun hidraw_major = MAJOR(dev_id);
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun hidraw_class = class_create(THIS_MODULE, "hidraw");
601*4882a593Smuzhiyun if (IS_ERR(hidraw_class)) {
602*4882a593Smuzhiyun result = PTR_ERR(hidraw_class);
603*4882a593Smuzhiyun goto error_cdev;
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun cdev_init(&hidraw_cdev, &hidraw_ops);
607*4882a593Smuzhiyun result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
608*4882a593Smuzhiyun if (result < 0)
609*4882a593Smuzhiyun goto error_class;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun pr_info("raw HID events driver (C) Jiri Kosina\n");
612*4882a593Smuzhiyun out:
613*4882a593Smuzhiyun return result;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun error_class:
616*4882a593Smuzhiyun class_destroy(hidraw_class);
617*4882a593Smuzhiyun error_cdev:
618*4882a593Smuzhiyun unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
619*4882a593Smuzhiyun goto out;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun
hidraw_exit(void)622*4882a593Smuzhiyun void hidraw_exit(void)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun dev_t dev_id = MKDEV(hidraw_major, 0);
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun cdev_del(&hidraw_cdev);
627*4882a593Smuzhiyun class_destroy(hidraw_class);
628*4882a593Smuzhiyun unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun }
631