[go: nahoru, domu]

186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina/*
286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina * HID raw devices, giving access to raw HID events.
386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina *
486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina * In comparison to hiddev, this device does not process the
586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina * hid events at all (no parsing, no lookups). This lets applications
686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina * to work on raw hid events as they want to, and avoids a need to
786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina * use a transport-specific userspace libhid/libusb libraries.
886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina *
9618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina *  Copyright (c) 2007-2014 Jiri Kosina
1086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina */
1186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
1286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina/*
1386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina * This program is free software; you can redistribute it and/or modify it
1486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina * under the terms and conditions of the GNU General Public License,
1586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina * version 2, as published by the Free Software Foundation.
1686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina *
1786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina * You should have received a copy of the GNU General Public License along with
1886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina * this program; if not, write to the Free Software Foundation, Inc.,
1986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
2086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina */
2186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
224291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
234291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches
2486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina#include <linux/fs.h>
2586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina#include <linux/module.h>
2686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina#include <linux/errno.h>
2786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina#include <linux/kernel.h>
2886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina#include <linux/init.h>
2986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina#include <linux/cdev.h>
3086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina#include <linux/poll.h>
3186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina#include <linux/device.h>
3286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina#include <linux/major.h>
335a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
3486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina#include <linux/hid.h>
3586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina#include <linux/mutex.h>
36a99bbaf5ee6bad1aca0c88ea65ec6e5373e86184Alexey Dobriyan#include <linux/sched.h>
3786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
3886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina#include <linux/hidraw.h>
3986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
4086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinastatic int hidraw_major;
4186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinastatic struct cdev hidraw_cdev;
4286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinastatic struct class *hidraw_class;
4386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinastatic struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
447d672cd7506165818aacf97fdc448cffc72bde37Oliver Neukumstatic DEFINE_MUTEX(minors_lock);
4586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
4686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinastatic ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
4786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina{
4886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	struct hidraw_list *list = file->private_data;
4986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	int ret = 0, len;
5086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	DECLARE_WAITQUEUE(wait, current);
5186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
52b0e14951ee0f6c29abc64b92ec7075a159ede37cJiri Kosina	mutex_lock(&list->read_mutex);
5386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
54b0e14951ee0f6c29abc64b92ec7075a159ede37cJiri Kosina	while (ret == 0) {
5586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		if (list->head == list->tail) {
5686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			add_wait_queue(&list->hidraw->wait, &wait);
5786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			set_current_state(TASK_INTERRUPTIBLE);
5886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
5986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			while (list->head == list->tail) {
6086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				if (signal_pending(current)) {
6186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina					ret = -ERESTARTSYS;
6286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina					break;
6386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				}
6486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				if (!list->hidraw->exist) {
6586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina					ret = -EIO;
6686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina					break;
6786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				}
687611e8d26d8dd0e5e132b46e905cb579daf9da1eFounder Fang				if (file->f_flags & O_NONBLOCK) {
697611e8d26d8dd0e5e132b46e905cb579daf9da1eFounder Fang					ret = -EAGAIN;
707611e8d26d8dd0e5e132b46e905cb579daf9da1eFounder Fang					break;
717611e8d26d8dd0e5e132b46e905cb579daf9da1eFounder Fang				}
7286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
7386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				/* allow O_NONBLOCK to work well from other threads */
7486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				mutex_unlock(&list->read_mutex);
7586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				schedule();
7686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				mutex_lock(&list->read_mutex);
7786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				set_current_state(TASK_INTERRUPTIBLE);
7886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			}
7986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
8086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			set_current_state(TASK_RUNNING);
8186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			remove_wait_queue(&list->hidraw->wait, &wait);
8286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		}
8386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
8486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		if (ret)
8586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			goto out;
8686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
8786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		len = list->buffer[list->tail].len > count ?
8886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			count : list->buffer[list->tail].len;
8986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
90b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosina		if (list->buffer[list->tail].value) {
91b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosina			if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
92b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosina				ret = -EFAULT;
93b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosina				goto out;
94b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosina			}
95b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosina			ret = len;
9686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		}
9786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
9886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		kfree(list->buffer[list->tail].value);
994c7b417ecb756e85dfc955b0e7a04fd45585533eMatthieu CASTET		list->buffer[list->tail].value = NULL;
10086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
10186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	}
10286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinaout:
10386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	mutex_unlock(&list->read_mutex);
10486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	return ret;
10586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina}
10686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
107618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina/*
108618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina * The first byte of the report buffer is expected to be a report number.
109618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina *
110618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina * This function is to be called with the minors_lock mutex held.
111618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina */
112b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ottstatic ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
11386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina{
114496ad9aa8ef448058e36ca7a787c61f2e63f0f54Al Viro	unsigned int minor = iminor(file_inode(file));
1152e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina	struct hid_device *dev;
11686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	__u8 *buf;
11786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	int ret = 0;
11886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
119212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia	if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
120e42dee9a99a3ecd32b5c027e8f7411fb5bc11eb6Antonio Ospite		ret = -ENODEV;
121e42dee9a99a3ecd32b5c027e8f7411fb5bc11eb6Antonio Ospite		goto out;
122e42dee9a99a3ecd32b5c027e8f7411fb5bc11eb6Antonio Ospite	}
123e42dee9a99a3ecd32b5c027e8f7411fb5bc11eb6Antonio Ospite
1242e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina	dev = hidraw_table[minor]->hid;
1252e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina
12686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
1272b107d629dc0c35de606bb7b010b829cd247a93aJiri Kosina	if (count > HID_MAX_BUFFER_SIZE) {
1284291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_warn(dev, "pid %d passed too large report\n",
1294291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches			 task_pid_nr(current));
1302e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina		ret = -EINVAL;
1312e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina		goto out;
13286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	}
13386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
13486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	if (count < 2) {
1354291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_warn(dev, "pid %d passed too short report\n",
1364291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches			 task_pid_nr(current));
1372e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina		ret = -EINVAL;
1382e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina		goto out;
13986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	}
14086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
14186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
1422e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina	if (!buf) {
1432e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina		ret = -ENOMEM;
1442e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina		goto out;
1452e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina	}
14686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
14786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	if (copy_from_user(buf, buffer, count)) {
14886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		ret = -EFAULT;
1492e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina		goto out_free;
15086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	}
15186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
152e534a9352237e84263cecedff283387b144b3ed8Benjamin Tissoires	if ((report_type == HID_OUTPUT_REPORT) &&
153e534a9352237e84263cecedff283387b144b3ed8Benjamin Tissoires	    !(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) {
1543a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires		ret = hid_hw_output_report(dev, buf, count);
1553a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires		/*
1563a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires		 * compatibility with old implementation of USB-HID and I2C-HID:
1573a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires		 * if the device does not support receiving output reports,
1583a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires		 * on an interrupt endpoint, fallback to SET_REPORT HID command.
1593a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires		 */
1603a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires		if (ret != -ENOSYS)
1613a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires			goto out_free;
1623a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires	}
1633a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires
1643a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires	ret = hid_hw_raw_request(dev, buf[0], buf, count, report_type,
1653a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires				HID_REQ_SET_REPORT);
1663a75b24949a8d34d2014866006e30dc69dd567c8Benjamin Tissoires
1672e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosinaout_free:
16886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	kfree(buf);
1692e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosinaout:
170b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	return ret;
171b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott}
172b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
173b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ottstatic ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
174b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott{
175b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	ssize_t ret;
176b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	mutex_lock(&minors_lock);
177b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	ret = hidraw_send_report(file, buffer, count, HID_OUTPUT_REPORT);
1782e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina	mutex_unlock(&minors_lock);
17986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	return ret;
18086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina}
18186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
182b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
183618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina/*
184618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina * This function performs a Get_Report transfer over the control endpoint
185d2a1cfebe38edc0bbac8f5cfbce062fe3d146d7aJiri Kosina * per section 7.2.1 of the HID specification, version 1.1.  The first byte
186d2a1cfebe38edc0bbac8f5cfbce062fe3d146d7aJiri Kosina * of buffer is the report number to request, or 0x0 if the defice does not
187d2a1cfebe38edc0bbac8f5cfbce062fe3d146d7aJiri Kosina * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
188618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina * or HID_INPUT_REPORT.
189618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina *
190618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina * This function is to be called with the minors_lock mutex held.
191618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina */
192b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ottstatic ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
193b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott{
194496ad9aa8ef448058e36ca7a787c61f2e63f0f54Al Viro	unsigned int minor = iminor(file_inode(file));
195b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	struct hid_device *dev;
196b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	__u8 *buf;
197b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	int ret = 0, len;
198b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	unsigned char report_number;
199b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
200b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	dev = hidraw_table[minor]->hid;
201b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
202cafebc058bf86e63fff5354864781d3de11e41d3Benjamin Tissoires	if (!dev->ll_driver->raw_request) {
203b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		ret = -ENODEV;
204b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		goto out;
205b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	}
206b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
207b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	if (count > HID_MAX_BUFFER_SIZE) {
208b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
209b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott				task_pid_nr(current));
210b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		ret = -EINVAL;
211b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		goto out;
212b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	}
213b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
214b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	if (count < 2) {
215b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
216b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott				task_pid_nr(current));
217b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		ret = -EINVAL;
218b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		goto out;
219b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	}
220b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
221b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
222b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	if (!buf) {
223b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		ret = -ENOMEM;
224b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		goto out;
225b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	}
226b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
227618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina	/*
228618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina	 * Read the first byte from the user. This is the report number,
229cafebc058bf86e63fff5354864781d3de11e41d3Benjamin Tissoires	 * which is passed to hid_hw_raw_request().
230618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina	 */
231b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	if (copy_from_user(&report_number, buffer, 1)) {
232b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		ret = -EFAULT;
233b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		goto out_free;
234b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	}
235b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
236cafebc058bf86e63fff5354864781d3de11e41d3Benjamin Tissoires	ret = hid_hw_raw_request(dev, report_number, buf, count, report_type,
237cafebc058bf86e63fff5354864781d3de11e41d3Benjamin Tissoires				 HID_REQ_GET_REPORT);
238b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
239b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	if (ret < 0)
240b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		goto out_free;
241b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
242b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	len = (ret < count) ? ret : count;
243b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
244b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	if (copy_to_user(buffer, buf, len)) {
245b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		ret = -EFAULT;
246b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott		goto out_free;
247b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	}
248b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
249b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	ret = len;
250b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
251b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ottout_free:
252b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	kfree(buf);
253b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ottout:
254b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott	return ret;
255b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott}
256b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
25786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinastatic unsigned int hidraw_poll(struct file *file, poll_table *wait)
25886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina{
25986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	struct hidraw_list *list = file->private_data;
26086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
26186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	poll_wait(file, &list->hidraw->wait, wait);
26286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	if (list->head != list->tail)
26386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		return POLLIN | POLLRDNORM;
26486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	if (!list->hidraw->exist)
26586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		return POLLERR | POLLHUP;
26686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	return 0;
26786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina}
26886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
26986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinastatic int hidraw_open(struct inode *inode, struct file *file)
27086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina{
27186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	unsigned int minor = iminor(inode);
27286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	struct hidraw *dev;
27386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	struct hidraw_list *list;
274277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	unsigned long flags;
27586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	int err = 0;
27686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
27786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
27886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		err = -ENOMEM;
27986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		goto out;
28086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	}
28186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
2827d672cd7506165818aacf97fdc448cffc72bde37Oliver Neukum	mutex_lock(&minors_lock);
283212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia	if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
28486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		err = -ENODEV;
28586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		goto out_unlock;
28686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	}
28786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
28886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	dev = hidraw_table[minor];
2897d672cd7506165818aacf97fdc448cffc72bde37Oliver Neukum	if (!dev->open++) {
2905bea7660bba973dc5e8e9d92b11fb1dd5b524ebfDmitry Torokhov		err = hid_hw_power(dev->hid, PM_HINT_FULLON);
291f554ff80339b4005856e6a86454d6ea2bb962ee5Amit Nagal		if (err < 0) {
292f554ff80339b4005856e6a86454d6ea2bb962ee5Amit Nagal			dev->open--;
2935bea7660bba973dc5e8e9d92b11fb1dd5b524ebfDmitry Torokhov			goto out_unlock;
294f554ff80339b4005856e6a86454d6ea2bb962ee5Amit Nagal		}
2955bea7660bba973dc5e8e9d92b11fb1dd5b524ebfDmitry Torokhov
2965bea7660bba973dc5e8e9d92b11fb1dd5b524ebfDmitry Torokhov		err = hid_hw_open(dev->hid);
2970361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum		if (err < 0) {
2985bea7660bba973dc5e8e9d92b11fb1dd5b524ebfDmitry Torokhov			hid_hw_power(dev->hid, PM_HINT_NORMAL);
2997d672cd7506165818aacf97fdc448cffc72bde37Oliver Neukum			dev->open--;
300277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng			goto out_unlock;
3010361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum		}
3027d672cd7506165818aacf97fdc448cffc72bde37Oliver Neukum	}
30386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
304277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	list->hidraw = hidraw_table[minor];
305277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	mutex_init(&list->read_mutex);
306277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
307277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	list_add_tail(&list->node, &hidraw_table[minor]->list);
308277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
309277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	file->private_data = list;
31086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinaout_unlock:
3117d672cd7506165818aacf97fdc448cffc72bde37Oliver Neukum	mutex_unlock(&minors_lock);
3127d672cd7506165818aacf97fdc448cffc72bde37Oliver Neukumout:
3131a8962317f494ad858971fc08ba035eff658a5c9Amit Nagal	if (err < 0)
3141a8962317f494ad858971fc08ba035eff658a5c9Amit Nagal		kfree(list);
31586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	return err;
31686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
31786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina}
31886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
319b5531318f18b5054c0e4a82beb560a77d85948d8Andrew Dugganstatic int hidraw_fasync(int fd, struct file *file, int on)
320b5531318f18b5054c0e4a82beb560a77d85948d8Andrew Duggan{
321b5531318f18b5054c0e4a82beb560a77d85948d8Andrew Duggan	struct hidraw_list *list = file->private_data;
322b5531318f18b5054c0e4a82beb560a77d85948d8Andrew Duggan
323b5531318f18b5054c0e4a82beb560a77d85948d8Andrew Duggan	return fasync_helper(fd, file, on, &list->fasync);
324b5531318f18b5054c0e4a82beb560a77d85948d8Andrew Duggan}
325b5531318f18b5054c0e4a82beb560a77d85948d8Andrew Duggan
326212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasiastatic void drop_ref(struct hidraw *hidraw, int exists_bit)
327212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia{
328212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia	if (exists_bit) {
329212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia		hidraw->exist = 0;
3300f5a24c6602063e014ee48892ebf56093241106eManoj Chourasia		if (hidraw->open) {
3310f5a24c6602063e014ee48892ebf56093241106eManoj Chourasia			hid_hw_close(hidraw->hid);
332212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia			wake_up_interruptible(&hidraw->wait);
3330f5a24c6602063e014ee48892ebf56093241106eManoj Chourasia		}
33447587fc098451c2100dc1fb618855fc2e2d937afFernando Luis Vázquez Cao		device_destroy(hidraw_class,
33547587fc098451c2100dc1fb618855fc2e2d937afFernando Luis Vázquez Cao			       MKDEV(hidraw_major, hidraw->minor));
336212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia	} else {
337212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia		--hidraw->open;
338212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia	}
3390f5a24c6602063e014ee48892ebf56093241106eManoj Chourasia	if (!hidraw->open) {
3400f5a24c6602063e014ee48892ebf56093241106eManoj Chourasia		if (!hidraw->exist) {
3410f5a24c6602063e014ee48892ebf56093241106eManoj Chourasia			hidraw_table[hidraw->minor] = NULL;
3420f5a24c6602063e014ee48892ebf56093241106eManoj Chourasia			kfree(hidraw);
3430f5a24c6602063e014ee48892ebf56093241106eManoj Chourasia		} else {
3440f5a24c6602063e014ee48892ebf56093241106eManoj Chourasia			/* close device for last reader */
3450f5a24c6602063e014ee48892ebf56093241106eManoj Chourasia			hid_hw_power(hidraw->hid, PM_HINT_NORMAL);
3460f5a24c6602063e014ee48892ebf56093241106eManoj Chourasia			hid_hw_close(hidraw->hid);
3470f5a24c6602063e014ee48892ebf56093241106eManoj Chourasia		}
348212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia	}
349212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia}
350212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia
35186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinastatic int hidraw_release(struct inode * inode, struct file * file)
35286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina{
35386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	unsigned int minor = iminor(inode);
35486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	struct hidraw_list *list = file->private_data;
355277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	unsigned long flags;
356df0cfd6990347c20ae031f3f34137cba274f1972Jiri Kosina
357df0cfd6990347c20ae031f3f34137cba274f1972Jiri Kosina	mutex_lock(&minors_lock);
35886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
359277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
36086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	list_del(&list->node);
361277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
3624db1c62c9991e62b441672db7f227e722776adc4Jiri Kosina	kfree(list);
363df0cfd6990347c20ae031f3f34137cba274f1972Jiri Kosina
364212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia	drop_ref(hidraw_table[minor], 0);
365212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia
366212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia	mutex_unlock(&minors_lock);
367212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia	return 0;
36886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina}
36986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
370979c407e3b89b606e810fa494ef316896eadbfadAlan Coxstatic long hidraw_ioctl(struct file *file, unsigned int cmd,
371979c407e3b89b606e810fa494ef316896eadbfadAlan Cox							unsigned long arg)
37286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina{
373496ad9aa8ef448058e36ca7a787c61f2e63f0f54Al Viro	struct inode *inode = file_inode(file);
37486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	unsigned int minor = iminor(inode);
375979c407e3b89b606e810fa494ef316896eadbfadAlan Cox	long ret = 0;
3762e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina	struct hidraw *dev;
37786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	void __user *user_arg = (void __user*) arg;
37886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
3792e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina	mutex_lock(&minors_lock);
3802e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina	dev = hidraw_table[minor];
381d20d5ffab92f00188f360c44c791a5ffb988247cAntonio Ospite	if (!dev) {
382d20d5ffab92f00188f360c44c791a5ffb988247cAntonio Ospite		ret = -ENODEV;
383d20d5ffab92f00188f360c44c791a5ffb988247cAntonio Ospite		goto out;
384d20d5ffab92f00188f360c44c791a5ffb988247cAntonio Ospite	}
3852e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina
38686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	switch (cmd) {
38786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		case HIDIOCGRDESCSIZE:
38886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			if (put_user(dev->hid->rsize, (int __user *)arg))
389979c407e3b89b606e810fa494ef316896eadbfadAlan Cox				ret = -EFAULT;
390979c407e3b89b606e810fa494ef316896eadbfadAlan Cox			break;
39186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
39286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		case HIDIOCGRDESC:
39386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			{
39486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				__u32 len;
39586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
39686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				if (get_user(len, (int __user *)arg))
397979c407e3b89b606e810fa494ef316896eadbfadAlan Cox					ret = -EFAULT;
398979c407e3b89b606e810fa494ef316896eadbfadAlan Cox				else if (len > HID_MAX_DESCRIPTOR_SIZE - 1)
399979c407e3b89b606e810fa494ef316896eadbfadAlan Cox					ret = -EINVAL;
400979c407e3b89b606e810fa494ef316896eadbfadAlan Cox				else if (copy_to_user(user_arg + offsetof(
401979c407e3b89b606e810fa494ef316896eadbfadAlan Cox					struct hidraw_report_descriptor,
402979c407e3b89b606e810fa494ef316896eadbfadAlan Cox					value[0]),
403979c407e3b89b606e810fa494ef316896eadbfadAlan Cox					dev->hid->rdesc,
404979c407e3b89b606e810fa494ef316896eadbfadAlan Cox					min(dev->hid->rsize, len)))
405979c407e3b89b606e810fa494ef316896eadbfadAlan Cox					ret = -EFAULT;
406979c407e3b89b606e810fa494ef316896eadbfadAlan Cox				break;
40786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			}
40886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		case HIDIOCGRAWINFO:
40986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			{
41086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				struct hidraw_devinfo dinfo;
41186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
41286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				dinfo.bustype = dev->hid->bus;
41386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				dinfo.vendor = dev->hid->vendor;
41486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				dinfo.product = dev->hid->product;
41586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina				if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
416979c407e3b89b606e810fa494ef316896eadbfadAlan Cox					ret = -EFAULT;
417979c407e3b89b606e810fa494ef316896eadbfadAlan Cox				break;
41886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			}
41986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		default:
4209188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina			{
4219188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina				struct hid_device *hid = dev->hid;
422b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott				if (_IOC_TYPE(cmd) != 'H') {
423b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott					ret = -EINVAL;
424b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott					break;
425b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott				}
426b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
427b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSFEATURE(0))) {
428b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott					int len = _IOC_SIZE(cmd);
429b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott					ret = hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT);
430b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott					break;
431b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott				}
432b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGFEATURE(0))) {
433b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott					int len = _IOC_SIZE(cmd);
434b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott					ret = hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT);
435b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott					break;
436b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott				}
437b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott
438b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott				/* Begin Read-only ioctls. */
439b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott				if (_IOC_DIR(cmd) != _IOC_READ) {
440dfd395aff4cb16d2480b280064bea1b19ededef1Dan Carpenter					ret = -EINVAL;
441dfd395aff4cb16d2480b280064bea1b19ededef1Dan Carpenter					break;
442dfd395aff4cb16d2480b280064bea1b19ededef1Dan Carpenter				}
4439188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina
4449188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {
445dd2ed487fdd78b50549b2ca8418875c0d9f4a30eDaniel Mack					int len = strlen(hid->name) + 1;
4469188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina					if (len > _IOC_SIZE(cmd))
4479188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina						len = _IOC_SIZE(cmd);
448dfd395aff4cb16d2480b280064bea1b19ededef1Dan Carpenter					ret = copy_to_user(user_arg, hid->name, len) ?
4499188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina						-EFAULT : len;
450dfd395aff4cb16d2480b280064bea1b19ededef1Dan Carpenter					break;
4519188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina				}
4529188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina
4539188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {
454dd2ed487fdd78b50549b2ca8418875c0d9f4a30eDaniel Mack					int len = strlen(hid->phys) + 1;
4559188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina					if (len > _IOC_SIZE(cmd))
4569188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina						len = _IOC_SIZE(cmd);
457dfd395aff4cb16d2480b280064bea1b19ededef1Dan Carpenter					ret = copy_to_user(user_arg, hid->phys, len) ?
4589188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina						-EFAULT : len;
459dfd395aff4cb16d2480b280064bea1b19ededef1Dan Carpenter					break;
4609188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina				}
461b4dbde9da8ece42bbe4c70c26bac3b28dd6a3ddbAlan Ott			}
4629188e79ec3fd43a0a605274324aecfb731baa88bJiri Kosina
463dfd395aff4cb16d2480b280064bea1b19ededef1Dan Carpenter		ret = -ENOTTY;
46486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	}
465d20d5ffab92f00188f360c44c791a5ffb988247cAntonio Ospiteout:
4662e57480b2a717916510b0c23b2851398a4cbd958Jiri Kosina	mutex_unlock(&minors_lock);
467979c407e3b89b606e810fa494ef316896eadbfadAlan Cox	return ret;
46886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina}
46986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
47086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinastatic const struct file_operations hidraw_ops = {
47186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	.owner =        THIS_MODULE,
47286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	.read =         hidraw_read,
47386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	.write =        hidraw_write,
47486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	.poll =         hidraw_poll,
47586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	.open =         hidraw_open,
47686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	.release =      hidraw_release,
477979c407e3b89b606e810fa494ef316896eadbfadAlan Cox	.unlocked_ioctl = hidraw_ioctl,
478b5531318f18b5054c0e4a82beb560a77d85948d8Andrew Duggan	.fasync =	hidraw_fasync,
479ae5e49c79c051ea1d5ca91cbd4a0d22189067ba3Alan Ott#ifdef CONFIG_COMPAT
480ae5e49c79c051ea1d5ca91cbd4a0d22189067ba3Alan Ott	.compat_ioctl   = hidraw_ioctl,
481ae5e49c79c051ea1d5ca91cbd4a0d22189067ba3Alan Ott#endif
4826038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann	.llseek =	noop_llseek,
48386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina};
48486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
485b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosinaint hidraw_report_event(struct hid_device *hid, u8 *data, int len)
48686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina{
48786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	struct hidraw *dev = hid->hidraw;
48886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	struct hidraw_list *list;
489b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosina	int ret = 0;
490277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	unsigned long flags;
49186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
492277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	spin_lock_irqsave(&dev->list_lock, flags);
49386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	list_for_each_entry(list, &dev->list, node) {
4944c7b417ecb756e85dfc955b0e7a04fd45585533eMatthieu CASTET		int new_head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
4954c7b417ecb756e85dfc955b0e7a04fd45585533eMatthieu CASTET
4964c7b417ecb756e85dfc955b0e7a04fd45585533eMatthieu CASTET		if (new_head == list->tail)
4974c7b417ecb756e85dfc955b0e7a04fd45585533eMatthieu CASTET			continue;
4984c7b417ecb756e85dfc955b0e7a04fd45585533eMatthieu CASTET
499b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosina		if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
500b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosina			ret = -ENOMEM;
501b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosina			break;
502b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosina		}
50386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		list->buffer[list->head].len = len;
5044c7b417ecb756e85dfc955b0e7a04fd45585533eMatthieu CASTET		list->head = new_head;
50586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		kill_fasync(&list->fasync, SIGIO, POLL_IN);
50686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	}
507277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	spin_unlock_irqrestore(&dev->list_lock, flags);
50886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
50986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	wake_up_interruptible(&dev->wait);
510b6787242f32700377d3da3b8d788ab3928bab849Jiri Kosina	return ret;
51186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina}
51286166b7bcda0bcb53525114fa1c87ac432be478eJiri KosinaEXPORT_SYMBOL_GPL(hidraw_report_event);
51386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
51486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinaint hidraw_connect(struct hid_device *hid)
51586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina{
516709d27c04f4eccbc99d57a5569bce028915a4345Mariusz Kozlowski	int minor, result;
51786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	struct hidraw *dev;
51886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
519618345359ed99a78e63f5cef8a09a8494589ee11Jiri Kosina	/* we accept any HID device, all applications */
52086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
521709d27c04f4eccbc99d57a5569bce028915a4345Mariusz Kozlowski	dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
522709d27c04f4eccbc99d57a5569bce028915a4345Mariusz Kozlowski	if (!dev)
523709d27c04f4eccbc99d57a5569bce028915a4345Mariusz Kozlowski		return -ENOMEM;
524709d27c04f4eccbc99d57a5569bce028915a4345Mariusz Kozlowski
525709d27c04f4eccbc99d57a5569bce028915a4345Mariusz Kozlowski	result = -EINVAL;
52686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
5277d672cd7506165818aacf97fdc448cffc72bde37Oliver Neukum	mutex_lock(&minors_lock);
52886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
52986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {
53086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		if (hidraw_table[minor])
53186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			continue;
53286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		hidraw_table[minor] = dev;
53386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		result = 0;
53486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		break;
53586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	}
53686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
537709d27c04f4eccbc99d57a5569bce028915a4345Mariusz Kozlowski	if (result) {
5387d672cd7506165818aacf97fdc448cffc72bde37Oliver Neukum		mutex_unlock(&minors_lock);
539709d27c04f4eccbc99d57a5569bce028915a4345Mariusz Kozlowski		kfree(dev);
54086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		goto out;
541709d27c04f4eccbc99d57a5569bce028915a4345Mariusz Kozlowski	}
54286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
543aae6c286dad33c7f2c6992b9e310a371f2ae377eJiri Kosina	dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor),
544a9b12619f7b6f19c871437ec24a088787a04b1deGreg Kroah-Hartman				 NULL, "%s%d", "hidraw", minor);
54586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
54686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	if (IS_ERR(dev->dev)) {
54786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		hidraw_table[minor] = NULL;
5487d672cd7506165818aacf97fdc448cffc72bde37Oliver Neukum		mutex_unlock(&minors_lock);
54986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		result = PTR_ERR(dev->dev);
550709d27c04f4eccbc99d57a5569bce028915a4345Mariusz Kozlowski		kfree(dev);
55186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		goto out;
55286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	}
55386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
55486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	init_waitqueue_head(&dev->wait);
555277fe44dd862412ee034470ad1c13a79d24e533bYonghua Zheng	spin_lock_init(&dev->list_lock);
55686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	INIT_LIST_HEAD(&dev->list);
55786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
55886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	dev->hid = hid;
55986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	dev->minor = minor;
56086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
56186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	dev->exist = 1;
56286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	hid->hidraw = dev;
56386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
5648e552e535948fe8612d36a7beaf19519140bc285Yonghua Zheng	mutex_unlock(&minors_lock);
56586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinaout:
56686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	return result;
56786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
56886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina}
56986166b7bcda0bcb53525114fa1c87ac432be478eJiri KosinaEXPORT_SYMBOL_GPL(hidraw_connect);
57086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
57186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinavoid hidraw_disconnect(struct hid_device *hid)
57286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina{
57386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	struct hidraw *hidraw = hid->hidraw;
574df0cfd6990347c20ae031f3f34137cba274f1972Jiri Kosina
575df0cfd6990347c20ae031f3f34137cba274f1972Jiri Kosina	mutex_lock(&minors_lock);
576df0cfd6990347c20ae031f3f34137cba274f1972Jiri Kosina
577212a871a3934beccf43431608c27ed2e05a476ecManoj Chourasia	drop_ref(hidraw, 1);
578df0cfd6990347c20ae031f3f34137cba274f1972Jiri Kosina
579df0cfd6990347c20ae031f3f34137cba274f1972Jiri Kosina	mutex_unlock(&minors_lock);
58086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina}
58186166b7bcda0bcb53525114fa1c87ac432be478eJiri KosinaEXPORT_SYMBOL_GPL(hidraw_disconnect);
58286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
58386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinaint __init hidraw_init(void)
58486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina{
58586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	int result;
58686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	dev_t dev_id;
58786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
58886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR,
58986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina			HIDRAW_MAX_DEVICES, "hidraw");
59086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
59186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	hidraw_major = MAJOR(dev_id);
59286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
59386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	if (result < 0) {
5944291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		pr_warn("can't get major number\n");
59586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		goto out;
59686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	}
59786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
59886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	hidraw_class = class_create(THIS_MODULE, "hidraw");
59986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	if (IS_ERR(hidraw_class)) {
60086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina		result = PTR_ERR(hidraw_class);
601bcb4a75bde3821cecb17a71d287abfd6ef9bd68dAlexey Khoroshilov		goto error_cdev;
60286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	}
60386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
60486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina        cdev_init(&hidraw_cdev, &hidraw_ops);
605bcb4a75bde3821cecb17a71d287abfd6ef9bd68dAlexey Khoroshilov	result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
606bcb4a75bde3821cecb17a71d287abfd6ef9bd68dAlexey Khoroshilov	if (result < 0)
607bcb4a75bde3821cecb17a71d287abfd6ef9bd68dAlexey Khoroshilov		goto error_class;
608bcb4a75bde3821cecb17a71d287abfd6ef9bd68dAlexey Khoroshilov
6090f690ccf56d3166e695ad27fb0936af189250ef1Jiri Kosina	printk(KERN_INFO "hidraw: raw HID events driver (C) Jiri Kosina\n");
61086166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosinaout:
61186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	return result;
612bcb4a75bde3821cecb17a71d287abfd6ef9bd68dAlexey Khoroshilov
613bcb4a75bde3821cecb17a71d287abfd6ef9bd68dAlexey Khoroshiloverror_class:
614bcb4a75bde3821cecb17a71d287abfd6ef9bd68dAlexey Khoroshilov	class_destroy(hidraw_class);
615bcb4a75bde3821cecb17a71d287abfd6ef9bd68dAlexey Khoroshiloverror_cdev:
616bcb4a75bde3821cecb17a71d287abfd6ef9bd68dAlexey Khoroshilov	unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
617bcb4a75bde3821cecb17a71d287abfd6ef9bd68dAlexey Khoroshilov	goto out;
61886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina}
61986166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
620140ae3eb6feb6ae96ba1ff073049beb985ea00e8Jiri Slabyvoid hidraw_exit(void)
62186166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina{
62286166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	dev_t dev_id = MKDEV(hidraw_major, 0);
62386166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
62486166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	cdev_del(&hidraw_cdev);
62586166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	class_destroy(hidraw_class);
62686166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina	unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
62786166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina
62886166b7bcda0bcb53525114fa1c87ac432be478eJiri Kosina}
629