···46464747 If unsure, say N48484949+config HIDRAW5050+ bool "/dev/hidraw raw HID device support"5151+ depends on HID5252+ ---help---5353+ Say Y here if you want to support HID devices (from the USB5454+ specification standpoint) that aren't strictly user interface5555+ devices, like monitor controls and Uninterruptable Power Supplies.5656+5757+ This module supports these devices separately using a separate5858+ event interface on /dev/hidraw.5959+6060+ There is also a /dev/hiddev configuration option in the USB HID6161+ configuration menu. In comparison to hiddev, this device does not process6262+ the hid events at all (no parsing, no lookups). This lets applications6363+ to work on raw hid events when they want to, and avoid using transport-specific6464+ userspace libhid/libusb libraries.6565+6666+ If unsure, say Y.6767+4968source "drivers/hid/usbhid/Kconfig"50695170endif # HID_SUPPORT
···3030#include <linux/hid.h>3131#include <linux/hiddev.h>3232#include <linux/hid-debug.h>3333+#include <linux/hidraw.h>33343435/*3536 * Version Information···980979981980 if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)982981 hid->hiddev_report_event(hid, report);982982+ if (hid->claimed & HID_CLAIMED_HIDRAW)983983+ hidraw_report_event(hid, data, size);983984984985 for (n = 0; n < report->maxfield; n++)985986 hid_input_field(hid, report->field[n], data, interrupt);···992989 return 0;993990}994991EXPORT_SYMBOL_GPL(hid_input_report);992992+993993+static int __init hid_init(void)994994+{995995+ return hidraw_init();996996+}997997+998998+static void __exit hid_exit(void)999999+{10001000+ hidraw_exit();10011001+}10021002+10031003+module_init(hid_init);10041004+module_exit(hid_exit);99510059961006MODULE_LICENSE(DRIVER_LICENSE);9971007
+401
drivers/hid/hidraw.c
···11+/*22+ * HID raw devices, giving access to raw HID events.33+ *44+ * In comparison to hiddev, this device does not process the55+ * hid events at all (no parsing, no lookups). This lets applications66+ * to work on raw hid events as they want to, and avoids a need to77+ * use a transport-specific userspace libhid/libusb libraries.88+ *99+ * Copyright (c) 2007 Jiri Kosina1010+ */1111+1212+/*1313+ * This program is free software; you can redistribute it and/or modify it1414+ * under the terms and conditions of the GNU General Public License,1515+ * version 2, as published by the Free Software Foundation.1616+ *1717+ * You should have received a copy of the GNU General Public License along with1818+ * this program; if not, write to the Free Software Foundation, Inc.,1919+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.2020+ */2121+2222+#include <linux/fs.h>2323+#include <linux/module.h>2424+#include <linux/errno.h>2525+#include <linux/kernel.h>2626+#include <linux/init.h>2727+#include <linux/cdev.h>2828+#include <linux/poll.h>2929+#include <linux/device.h>3030+#include <linux/major.h>3131+#include <linux/hid.h>3232+#include <linux/mutex.h>3333+3434+#include <linux/hidraw.h>3535+3636+static int hidraw_major;3737+static struct cdev hidraw_cdev;3838+static struct class *hidraw_class;3939+static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];4040+static DEFINE_SPINLOCK(minors_lock);4141+4242+static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)4343+{4444+ struct hidraw_list *list = file->private_data;4545+ int ret = 0, len;4646+ char *report;4747+ DECLARE_WAITQUEUE(wait, current);4848+4949+ while (ret == 0) {5050+5151+ mutex_lock(&list->read_mutex);5252+5353+ if (list->head == list->tail) {5454+ add_wait_queue(&list->hidraw->wait, &wait);5555+ set_current_state(TASK_INTERRUPTIBLE);5656+5757+ while (list->head == list->tail) {5858+ if (file->f_flags & O_NONBLOCK) {5959+ ret = -EAGAIN;6060+ break;6161+ }6262+ if (signal_pending(current)) {6363+ ret = -ERESTARTSYS;6464+ break;6565+ }6666+ if (!list->hidraw->exist) {6767+ ret = -EIO;6868+ break;6969+ }7070+7171+ /* allow O_NONBLOCK to work well from other threads */7272+ mutex_unlock(&list->read_mutex);7373+ schedule();7474+ mutex_lock(&list->read_mutex);7575+ set_current_state(TASK_INTERRUPTIBLE);7676+ }7777+7878+ set_current_state(TASK_RUNNING);7979+ remove_wait_queue(&list->hidraw->wait, &wait);8080+ }8181+8282+ if (ret)8383+ goto out;8484+8585+ report = list->buffer[list->tail].value;8686+ len = list->buffer[list->tail].len > count ?8787+ count : list->buffer[list->tail].len;8888+8989+ if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {9090+ ret = -EFAULT;9191+ goto out;9292+ }9393+ ret += len;9494+9595+ kfree(list->buffer[list->tail].value);9696+ list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);9797+ }9898+out:9999+ mutex_unlock(&list->read_mutex);100100+ return ret;101101+}102102+103103+/* the first byte is expected to be a report number */104104+static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)105105+{106106+ unsigned int minor = iminor(file->f_path.dentry->d_inode);107107+ struct hid_device *dev = hidraw_table[minor]->hid;108108+ __u8 *buf;109109+ int ret = 0;110110+111111+ if (!dev->hid_output_raw_report)112112+ return -ENODEV;113113+114114+ if (count > HID_MIN_BUFFER_SIZE) {115115+ printk(KERN_WARNING "hidraw: pid %d passed too large report\n",116116+ current->pid);117117+ return -EINVAL;118118+ }119119+120120+ if (count < 2) {121121+ printk(KERN_WARNING "hidraw: pid %d passed too short report\n",122122+ current->pid);123123+ return -EINVAL;124124+ }125125+126126+ buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);127127+ if (!buf)128128+ return -ENOMEM;129129+130130+ if (copy_from_user(buf, buffer, count)) {131131+ ret = -EFAULT;132132+ goto out;133133+ }134134+135135+ ret = dev->hid_output_raw_report(dev, buf, count);136136+out:137137+ kfree(buf);138138+ return ret;139139+}140140+141141+static unsigned int hidraw_poll(struct file *file, poll_table *wait)142142+{143143+ struct hidraw_list *list = file->private_data;144144+145145+ poll_wait(file, &list->hidraw->wait, wait);146146+ if (list->head != list->tail)147147+ return POLLIN | POLLRDNORM;148148+ if (!list->hidraw->exist)149149+ return POLLERR | POLLHUP;150150+ return 0;151151+}152152+153153+static int hidraw_open(struct inode *inode, struct file *file)154154+{155155+ unsigned int minor = iminor(inode);156156+ struct hidraw *dev;157157+ struct hidraw_list *list;158158+ int err = 0;159159+160160+ if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {161161+ err = -ENOMEM;162162+ goto out;163163+ }164164+165165+ spin_lock(&minors_lock);166166+ if (!hidraw_table[minor]) {167167+ printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",168168+ minor);169169+ kfree(list);170170+ err = -ENODEV;171171+ goto out_unlock;172172+ }173173+174174+ list->hidraw = hidraw_table[minor];175175+ mutex_init(&list->read_mutex);176176+ list_add_tail(&list->node, &hidraw_table[minor]->list);177177+ file->private_data = list;178178+179179+ dev = hidraw_table[minor];180180+ if (!dev->open++)181181+ dev->hid->hid_open(dev->hid);182182+183183+out_unlock:184184+ spin_unlock(&minors_lock);185185+out:186186+ return err;187187+188188+}189189+190190+static int hidraw_release(struct inode * inode, struct file * file)191191+{192192+ unsigned int minor = iminor(inode);193193+ struct hidraw *dev;194194+ struct hidraw_list *list = file->private_data;195195+196196+ if (!hidraw_table[minor]) {197197+ printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",198198+ minor);199199+ return -ENODEV;200200+ }201201+202202+ list_del(&list->node);203203+ dev = hidraw_table[minor];204204+ if (!dev->open--) {205205+ if (list->hidraw->exist)206206+ dev->hid->hid_close(dev->hid);207207+ else208208+ kfree(list->hidraw);209209+ }210210+211211+ return 0;212212+}213213+214214+static int hidraw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)215215+{216216+ unsigned int minor = iminor(inode);217217+ struct hidraw *dev = hidraw_table[minor];218218+ void __user *user_arg = (void __user*) arg;219219+220220+ switch (cmd) {221221+ case HIDIOCGRDESCSIZE:222222+ if (put_user(dev->hid->rsize, (int __user *)arg))223223+ return -EFAULT;224224+ return 0;225225+226226+ case HIDIOCGRDESC:227227+ {228228+ __u32 len;229229+230230+ if (get_user(len, (int __user *)arg))231231+ return -EFAULT;232232+ if (copy_to_user(*((__u8 **)(user_arg +233233+ sizeof(__u32))),234234+ dev->hid->rdesc, len))235235+ return -EFAULT;236236+ return 0;237237+ }238238+ case HIDIOCGRAWINFO:239239+ {240240+ struct hidraw_devinfo dinfo;241241+242242+ dinfo.bustype = dev->hid->bus;243243+ dinfo.vendor = dev->hid->vendor;244244+ dinfo.product = dev->hid->product;245245+ if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))246246+ return -EFAULT;247247+248248+ return 0;249249+ }250250+ default:251251+ printk(KERN_EMERG "hidraw: unsupported ioctl() %x\n",252252+ cmd);253253+ }254254+ return -EINVAL;255255+}256256+257257+static const struct file_operations hidraw_ops = {258258+ .owner = THIS_MODULE,259259+ .read = hidraw_read,260260+ .write = hidraw_write,261261+ .poll = hidraw_poll,262262+ .open = hidraw_open,263263+ .release = hidraw_release,264264+ .ioctl = hidraw_ioctl,265265+};266266+267267+void hidraw_report_event(struct hid_device *hid, u8 *data, int len)268268+{269269+ struct hidraw *dev = hid->hidraw;270270+ struct hidraw_list *list;271271+272272+ list_for_each_entry(list, &dev->list, node) {273273+ list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC);274274+ list->buffer[list->head].len = len;275275+ list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);276276+ kill_fasync(&list->fasync, SIGIO, POLL_IN);277277+ }278278+279279+ wake_up_interruptible(&dev->wait);280280+}281281+EXPORT_SYMBOL_GPL(hidraw_report_event);282282+283283+int hidraw_connect(struct hid_device *hid)284284+{285285+ int minor, result;286286+ struct hidraw *dev;287287+288288+ /* TODO currently we accept any HID device. This should later289289+ * probably be fixed to accept only those devices which provide290290+ * non-input applications291291+ */292292+293293+ dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);294294+ if (!dev)295295+ return -ENOMEM;296296+297297+ result = -EINVAL;298298+299299+ spin_lock(&minors_lock);300300+301301+ for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {302302+ if (hidraw_table[minor])303303+ continue;304304+ hidraw_table[minor] = dev;305305+ result = 0;306306+ break;307307+ }308308+309309+ spin_unlock(&minors_lock);310310+311311+ if (result) {312312+ kfree(dev);313313+ goto out;314314+ }315315+316316+ dev->dev = device_create(hidraw_class, NULL, MKDEV(hidraw_major, minor),317317+ "%s%d", "hidraw", minor);318318+319319+ if (IS_ERR(dev->dev)) {320320+ spin_lock(&minors_lock);321321+ hidraw_table[minor] = NULL;322322+ spin_unlock(&minors_lock);323323+ result = PTR_ERR(dev->dev);324324+ kfree(dev);325325+ goto out;326326+ }327327+328328+ init_waitqueue_head(&dev->wait);329329+ INIT_LIST_HEAD(&dev->list);330330+331331+ dev->hid = hid;332332+ dev->minor = minor;333333+334334+ dev->exist = 1;335335+ hid->hidraw = dev;336336+337337+out:338338+ return result;339339+340340+}341341+EXPORT_SYMBOL_GPL(hidraw_connect);342342+343343+void hidraw_disconnect(struct hid_device *hid)344344+{345345+ struct hidraw *hidraw = hid->hidraw;346346+347347+ hidraw->exist = 0;348348+349349+ spin_lock(&minors_lock);350350+ hidraw_table[hidraw->minor] = NULL;351351+ spin_unlock(&minors_lock);352352+353353+ device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));354354+355355+ if (hidraw->open) {356356+ hid->hid_close(hid);357357+ wake_up_interruptible(&hidraw->wait);358358+ } else {359359+ kfree(hidraw);360360+ }361361+}362362+EXPORT_SYMBOL_GPL(hidraw_disconnect);363363+364364+int __init hidraw_init(void)365365+{366366+ int result;367367+ dev_t dev_id;368368+369369+ result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR,370370+ HIDRAW_MAX_DEVICES, "hidraw");371371+372372+ hidraw_major = MAJOR(dev_id);373373+374374+ if (result < 0) {375375+ printk(KERN_WARNING "hidraw: can't get major number\n");376376+ result = 0;377377+ goto out;378378+ }379379+380380+ hidraw_class = class_create(THIS_MODULE, "hidraw");381381+ if (IS_ERR(hidraw_class)) {382382+ result = PTR_ERR(hidraw_class);383383+ unregister_chrdev(hidraw_major, "hidraw");384384+ goto out;385385+ }386386+387387+ cdev_init(&hidraw_cdev, &hidraw_ops);388388+ cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);389389+out:390390+ return result;391391+}392392+393393+void __exit hidraw_exit(void)394394+{395395+ dev_t dev_id = MKDEV(hidraw_major, 0);396396+397397+ cdev_del(&hidraw_cdev);398398+ class_destroy(hidraw_class);399399+ unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);400400+401401+}
+36-2
drivers/hid/usbhid/hid-core.c
···3232#include <linux/hid.h>3333#include <linux/hiddev.h>3434#include <linux/hid-debug.h>3535+#include <linux/hidraw.h>3536#include "usbhid.h"36373738/*···640639 return 0;641640}642641642642+static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count)643643+{644644+ struct usbhid_device *usbhid = hid->driver_data;645645+ struct usb_device *dev = hid_to_usb_dev(hid);646646+ struct usb_interface *intf = usbhid->intf;647647+ struct usb_host_interface *interface = intf->cur_altsetting;648648+ int ret;649649+650650+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),651651+ HID_REQ_SET_REPORT,652652+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,653653+ cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf),654654+ interface->desc.bInterfaceNumber, buf + 1, count - 1,655655+ USB_CTRL_SET_TIMEOUT);656656+657657+ /* count also the report id */658658+ if (ret > 0)659659+ ret++;660660+661661+ return ret;662662+}663663+643664static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)644665{645666 struct usbhid_device *usbhid = hid->driver_data;···905882 hid->hiddev_hid_event = hiddev_hid_event;906883 hid->hiddev_report_event = hiddev_report_event;907884#endif885885+ hid->hid_output_raw_report = usbhid_output_raw_report;908886 return hid;909887910888fail:···944920 hidinput_disconnect(hid);945921 if (hid->claimed & HID_CLAIMED_HIDDEV)946922 hiddev_disconnect(hid);923923+ if (hid->claimed & HID_CLAIMED_HIDRAW)924924+ hidraw_disconnect(hid);947925948926 usb_free_urb(usbhid->urbin);949927 usb_free_urb(usbhid->urbctrl);···978952 hid->claimed |= HID_CLAIMED_INPUT;979953 if (!hiddev_connect(hid))980954 hid->claimed |= HID_CLAIMED_HIDDEV;955955+ if (!hidraw_connect(hid))956956+ hid->claimed |= HID_CLAIMED_HIDRAW;981957982958 usb_set_intfdata(intf, hid);983959984960 if (!hid->claimed) {985985- printk ("HID device not claimed by input or hiddev\n");961961+ printk ("HID device claimed by neither input, hiddev nor hidraw\n");986962 hid_disconnect(intf);987963 return -ENODEV;988964 }···10009721001973 if (hid->claimed & HID_CLAIMED_INPUT)1002974 printk("input");10031003- if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))975975+ if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) ||976976+ hid->claimed & HID_CLAIMED_HIDRAW))1004977 printk(",");1005978 if (hid->claimed & HID_CLAIMED_HIDDEV)1006979 printk("hiddev%d", hid->minor);980980+ if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) &&981981+ (hid->claimed & HID_CLAIMED_HIDRAW))982982+ printk(",");983983+ if (hid->claimed & HID_CLAIMED_HIDRAW)984984+ printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor);10079851008986 c = "Device";1009987 for (i = 0; i < hid->maxcollection; i++) {
+5
include/linux/hid.h
···405405406406#define HID_CLAIMED_INPUT 1407407#define HID_CLAIMED_HIDDEV 2408408+#define HID_CLAIMED_HIDRAW 4408409409410#define HID_CTRL_RUNNING 1410411#define HID_OUT_RUNNING 2···441440442441 struct list_head inputs; /* The list of inputs */443442 void *hiddev; /* The hiddev structure */443443+ void *hidraw;444444 int minor; /* Hiddev minor number */445445446446 wait_queue_head_t wait; /* For sleeping */···462460 void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,463461 struct hid_usage *, __s32);464462 void (*hiddev_report_event) (struct hid_device *, struct hid_report *);463463+464464+ /* handler for raw output data, used by hidraw */465465+ int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t);465466#ifdef CONFIG_USB_HIDINPUT_POWERBOOK466467 unsigned long pb_pressed_fn[NBITS(KEY_MAX)];467468 unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
+86
include/linux/hidraw.h
···11+#ifndef _HIDRAW_H22+#define _HIDRAW_H33+44+/*55+ * Copyright (c) 2007 Jiri Kosina66+ */77+88+/*99+ * This program is free software; you can redistribute it and/or modify it1010+ * under the terms and conditions of the GNU General Public License,1111+ * version 2, as published by the Free Software Foundation.1212+ *1313+ * You should have received a copy of the GNU General Public License along with1414+ * this program; if not, write to the Free Software Foundation, Inc.,1515+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.1616+ */1717+1818+struct hidraw_report_descriptor {1919+ __u32 size;2020+ __u8 *value;2121+};2222+2323+struct hidraw_devinfo {2424+ __u32 bustype;2525+ __s16 vendor;2626+ __s16 product;2727+};2828+2929+/* ioctl interface */3030+#define HIDIOCGRDESCSIZE _IOR('H', 0x01, int)3131+#define HIDIOCGRDESC _IOR('H', 0x02, struct hidraw_report_descriptor)3232+#define HIDIOCGRAWINFO _IOR('H', 0x03, struct hidraw_devinfo)3333+3434+#define HIDRAW_FIRST_MINOR 03535+#define HIDRAW_MAX_DEVICES 643636+/* number of reports to buffer */3737+#define HIDRAW_BUFFER_SIZE 643838+3939+4040+/* kernel-only API declarations */4141+#ifdef __KERNEL__4242+4343+#include <linux/hid.h>4444+4545+struct hidraw {4646+ unsigned int minor;4747+ int exist;4848+ int open;4949+ wait_queue_head_t wait;5050+ struct hid_device *hid;5151+ struct device *dev;5252+ struct list_head list;5353+};5454+5555+struct hidraw_report {5656+ __u8 *value;5757+ int len;5858+};5959+6060+struct hidraw_list {6161+ struct hidraw_report buffer[HIDRAW_BUFFER_SIZE];6262+ int head;6363+ int tail;6464+ struct fasync_struct *fasync;6565+ struct hidraw *hidraw;6666+ struct list_head node;6767+ struct mutex read_mutex;6868+};6969+7070+#ifdef CONFIG_HIDRAW7171+int hidraw_init(void);7272+void hidraw_exit(void);7373+void hidraw_report_event(struct hid_device *, u8 *, int);7474+int hidraw_connect(struct hid_device *);7575+void hidraw_disconnect(struct hid_device *);7676+#else7777+static inline int hidraw_init(void) { return 0; }7878+static inline void hidraw_exit(void) { }7979+static inline void hidraw_report_event(struct hid_device *hid, u8 *data, int len) { }8080+static inline int hidraw_connect(struct hid_device *hid) { return -1; }8181+static inline void hidraw_disconnect(struct hid_device *hid) { }8282+#endif8383+8484+#endif8585+8686+#endif