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