11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2001 Paul Stewart 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2001 Vojtech Pavlik 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * HID char devices, giving access to raw HID device events. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should you need to contact me, the author, you can do so either by 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e-mail - mail your message to Paul Stewart <stewart@wetlogic.net> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/poll.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/input.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 34dde5845a529ff753364a6d1aea61180946270bfaJiri Kosina#include <linux/hid.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hiddev.h> 36bb6c8d8fa9b5587eea18078ce0bcf6bb2905789fPhilip Langdale#include <linux/compat.h> 37dde5845a529ff753364a6d1aea61180946270bfaJiri Kosina#include "usbhid.h" 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_DYNAMIC_MINORS 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HIDDEV_MINOR_BASE 0 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HIDDEV_MINORS 256 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HIDDEV_MINOR_BASE 96 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HIDDEV_MINORS 16 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 46affbb8c6e690be2196258e65f3cc92d55b18d9faJiri Kosina#define HIDDEV_BUFFER_SIZE 2048 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct hiddev { 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int exist; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int open; 51079034073faf974973baa0256b029451f6e768adOliver Neukum struct mutex existancelock; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t wait; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hid_device *hid; 54826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov struct list_head list; 55cdcb44e87bedcf5070eece61f89f9373a3810031Jiri Kosina spinlock_t list_lock; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct hiddev_list { 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE]; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int head; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tail; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned flags; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fasync_struct *fasync; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev *hiddev; 65826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov struct list_head node; 66079034073faf974973baa0256b029451f6e768adOliver Neukum struct mutex thread_lock; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find a report, given the report's type and ID. The ID can be specified 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * indirectly by REPORT_ID_FIRST (which returns the first report of the given 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * type) or by (REPORT_ID_NEXT | old_id), which returns the next report of the 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * given type which follows old_id. 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct hid_report * 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 78826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov unsigned int flags = rinfo->report_id & ~HID_REPORT_ID_MASK; 79826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov unsigned int rid = rinfo->report_id & HID_REPORT_ID_MASK; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hid_report_enum *report_enum; 81826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov struct hid_report *report; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *list; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rinfo->report_type < HID_REPORT_TYPE_MIN || 85826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov rinfo->report_type > HID_REPORT_TYPE_MAX) 86826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov return NULL; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds report_enum = hid->report_enum + 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (rinfo->report_type - HID_REPORT_TYPE_MIN); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (flags) { 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: /* Nothing to do -- report_id is already set correctly */ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HID_REPORT_ID_FIRST: 96826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov if (list_empty(&report_enum->report_list)) 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 98826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov 99826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov list = report_enum->report_list.next; 100826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov report = list_entry(list, struct hid_report, list); 101826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov rinfo->report_id = report->id; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10305f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HID_REPORT_ID_NEXT: 105826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov report = report_enum->report_id_hash[rid]; 106826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov if (!report) 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 108826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov 109826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov list = report->list.next; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (list == &report_enum->report_list) 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 112826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov 113826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov report = list_entry(list, struct hid_report, list); 114826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov rinfo->report_id = report->id; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11605f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return report_enum->report_id_hash[rinfo->report_id]; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Perform an exhaustive search of the report table for a usage, given its 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * type and usage id. 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct hid_field * 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref) 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hid_report *report; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hid_report_enum *report_enum; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hid_field *field; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uref->report_type < HID_REPORT_TYPE_MIN || 137826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov uref->report_type > HID_REPORT_TYPE_MAX) 138826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov return NULL; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds report_enum = hid->report_enum + 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (uref->report_type - HID_REPORT_TYPE_MIN); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 143826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov list_for_each_entry(report, &report_enum->report_list, list) { 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < report->maxfield; i++) { 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds field = report->field[i]; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < field->maxusage; j++) { 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (field->usage[j].hid == uref->usage_code) { 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uref->report_id = report->id; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uref->field_index = i; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uref->usage_index = j; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return field; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 155826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov } 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hiddev_send_event(struct hid_device *hid, 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_usage_ref *uref) 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev *hiddev = hid->hiddev; 164826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov struct hiddev_list *list; 165cdcb44e87bedcf5070eece61f89f9373a3810031Jiri Kosina unsigned long flags; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 167cdcb44e87bedcf5070eece61f89f9373a3810031Jiri Kosina spin_lock_irqsave(&hiddev->list_lock, flags); 168826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov list_for_each_entry(list, &hiddev->list, node) { 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uref->field_index != HID_FIELD_INDEX_NONE || 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (list->flags & HIDDEV_FLAG_REPORT) != 0) { 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list->buffer[list->head] = *uref; 17205f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov list->head = (list->head + 1) & 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (HIDDEV_BUFFER_SIZE - 1); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kill_fasync(&list->fasync, SIGIO, POLL_IN); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 177cdcb44e87bedcf5070eece61f89f9373a3810031Jiri Kosina spin_unlock_irqrestore(&hiddev->list_lock, flags); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&hiddev->wait); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is where hid.c calls into hiddev to pass an event that occurred over 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the interrupt pipe 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid hiddev_hid_event(struct hid_device *hid, struct hid_field *field, 1877d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells struct hid_usage *usage, __s32 value) 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned type = field->report_type; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_usage_ref uref; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19205f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov uref.report_type = 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : 19405f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : 195826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0)); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uref.report_id = field->report->id; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uref.field_index = field->index; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uref.usage_index = (usage - field->usage); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uref.usage_code = usage->hid; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uref.value = value; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hiddev_send_event(hid, &uref); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 204229695e51efc4ed5e04ab471c82591d0f432909dJiri KosinaEXPORT_SYMBOL_GPL(hiddev_hid_event); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid hiddev_report_event(struct hid_device *hid, struct hid_report *report) 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned type = report->type; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_usage_ref uref; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&uref, 0, sizeof(uref)); 21205f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov uref.report_type = 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : 21405f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : 215826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0)); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uref.report_id = report->id; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uref.field_index = HID_FIELD_INDEX_NONE; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hiddev_send_event(hid, &uref); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 221aa8de2f038baec993f07ef66fb3e94481d1ec22bJiri Kosina 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fasync file op 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hiddev_fasync(int fd, struct file *file, int on) 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_list *list = file->private_data; 228826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov 22960aa49243d09afc873f082567d2e3c16634ced84Jonathan Corbet return fasync_helper(fd, file, on, &list->fasync); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * release file op 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hiddev_release(struct inode * inode, struct file * file) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_list *list = file->private_data; 239cdcb44e87bedcf5070eece61f89f9373a3810031Jiri Kosina unsigned long flags; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241cdcb44e87bedcf5070eece61f89f9373a3810031Jiri Kosina spin_lock_irqsave(&list->hiddev->list_lock, flags); 242826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov list_del(&list->node); 243cdcb44e87bedcf5070eece61f89f9373a3810031Jiri Kosina spin_unlock_irqrestore(&list->hiddev->list_lock, flags); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2456cb4b040795c555c7ab4b1ba29b0dba2b5a42bebJiri Kosina mutex_lock(&list->hiddev->existancelock); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!--list->hiddev->open) { 2470361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum if (list->hiddev->exist) { 2484916b3a57fc94664677d439b911b8aaf86c7ec23Jiri Kosina usbhid_close(list->hiddev->hid); 2490361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum usbhid_put_power(list->hiddev->hid); 2500361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum } else { 2515c699d7d3f94ee1dd934edea889b32f8279a4e65Dan Carpenter mutex_unlock(&list->hiddev->existancelock); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(list->hiddev); 2535c699d7d3f94ee1dd934edea889b32f8279a4e65Dan Carpenter kfree(list); 2545c699d7d3f94ee1dd934edea889b32f8279a4e65Dan Carpenter return 0; 2550361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum } 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2586cb4b040795c555c7ab4b1ba29b0dba2b5a42bebJiri Kosina mutex_unlock(&list->hiddev->existancelock); 2595c699d7d3f94ee1dd934edea889b32f8279a4e65Dan Carpenter kfree(list); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * open file op 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 267826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhovstatic int hiddev_open(struct inode *inode, struct file *file) 268826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov{ 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_list *list; 270bd25f4dd6972755579d0ea50d1a5ace2e9b00d1aArnd Bergmann struct usb_interface *intf; 2719c9e54a8df0be48aa359744f412377cc55c3b7d2Jiri Kosina struct hid_device *hid; 272bd25f4dd6972755579d0ea50d1a5ace2e9b00d1aArnd Bergmann struct hiddev *hiddev; 273bd25f4dd6972755579d0ea50d1a5ace2e9b00d1aArnd Bergmann int res; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2758fe294caf8c868edd9046251824a0af91991bf43Guillaume Chazarain intf = usbhid_find_interface(iminor(inode)); 276bd25f4dd6972755579d0ea50d1a5ace2e9b00d1aArnd Bergmann if (!intf) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 2789c9e54a8df0be48aa359744f412377cc55c3b7d2Jiri Kosina hid = usb_get_intfdata(intf); 2799c9e54a8df0be48aa359744f412377cc55c3b7d2Jiri Kosina hiddev = hid->hiddev; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281bbdb7dafb5b5a3c0197cbabd5055d8e9c093e3eaOliver Neukum if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 283079034073faf974973baa0256b029451f6e768adOliver Neukum mutex_init(&list->thread_lock); 284bd25f4dd6972755579d0ea50d1a5ace2e9b00d1aArnd Bergmann list->hiddev = hiddev; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file->private_data = list; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 287079034073faf974973baa0256b029451f6e768adOliver Neukum /* 288079034073faf974973baa0256b029451f6e768adOliver Neukum * no need for locking because the USB major number 289079034073faf974973baa0256b029451f6e768adOliver Neukum * is shared which usbcore guards against disconnect 290079034073faf974973baa0256b029451f6e768adOliver Neukum */ 291079034073faf974973baa0256b029451f6e768adOliver Neukum if (list->hiddev->exist) { 292079034073faf974973baa0256b029451f6e768adOliver Neukum if (!list->hiddev->open++) { 293bd25f4dd6972755579d0ea50d1a5ace2e9b00d1aArnd Bergmann res = usbhid_open(hiddev->hid); 294079034073faf974973baa0256b029451f6e768adOliver Neukum if (res < 0) { 295079034073faf974973baa0256b029451f6e768adOliver Neukum res = -EIO; 296079034073faf974973baa0256b029451f6e768adOliver Neukum goto bail; 297079034073faf974973baa0256b029451f6e768adOliver Neukum } 298079034073faf974973baa0256b029451f6e768adOliver Neukum } 299079034073faf974973baa0256b029451f6e768adOliver Neukum } else { 300079034073faf974973baa0256b029451f6e768adOliver Neukum res = -ENODEV; 301079034073faf974973baa0256b029451f6e768adOliver Neukum goto bail; 302079034073faf974973baa0256b029451f6e768adOliver Neukum } 303079034073faf974973baa0256b029451f6e768adOliver Neukum 304079034073faf974973baa0256b029451f6e768adOliver Neukum spin_lock_irq(&list->hiddev->list_lock); 305bd25f4dd6972755579d0ea50d1a5ace2e9b00d1aArnd Bergmann list_add_tail(&list->node, &hiddev->list); 306079034073faf974973baa0256b029451f6e768adOliver Neukum spin_unlock_irq(&list->hiddev->list_lock); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3086cb4b040795c555c7ab4b1ba29b0dba2b5a42bebJiri Kosina mutex_lock(&hiddev->existancelock); 3090361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum if (!list->hiddev->open++) 3100361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum if (list->hiddev->exist) { 311bd25f4dd6972755579d0ea50d1a5ace2e9b00d1aArnd Bergmann struct hid_device *hid = hiddev->hid; 3120361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum res = usbhid_get_power(hid); 3130361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum if (res < 0) { 3140361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum res = -EIO; 3156cb4b040795c555c7ab4b1ba29b0dba2b5a42bebJiri Kosina goto bail_unlock; 3160361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum } 3170361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum usbhid_open(hid); 3180361a28d3f9a4315a100c7b37ba0b55cfe15fe07Oliver Neukum } 3196cb4b040795c555c7ab4b1ba29b0dba2b5a42bebJiri Kosina mutex_unlock(&hiddev->existancelock); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3216cb4b040795c555c7ab4b1ba29b0dba2b5a42bebJiri Kosinabail_unlock: 3226cb4b040795c555c7ab4b1ba29b0dba2b5a42bebJiri Kosina mutex_unlock(&hiddev->existancelock); 323079034073faf974973baa0256b029451f6e768adOliver Neukumbail: 324079034073faf974973baa0256b029451f6e768adOliver Neukum file->private_data = NULL; 32548e7a3c95c9f98c2cb6f894820e3cc2d0448e92fJohannes Weiner kfree(list); 326079034073faf974973baa0256b029451f6e768adOliver Neukum return res; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "write" file op 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t hiddev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "read" file op 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t hiddev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 34296fe2ab830d7dffee1b3d8abf27ced4d7d5765e7Johannes Weiner DEFINE_WAIT(wait); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_list *list = file->private_data; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int event_size; 345079034073faf974973baa0256b029451f6e768adOliver Neukum int retval; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ? 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < event_size) 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 353079034073faf974973baa0256b029451f6e768adOliver Neukum /* lock against other threads */ 354079034073faf974973baa0256b029451f6e768adOliver Neukum retval = mutex_lock_interruptible(&list->thread_lock); 355079034073faf974973baa0256b029451f6e768adOliver Neukum if (retval) 356079034073faf974973baa0256b029451f6e768adOliver Neukum return -ERESTARTSYS; 357079034073faf974973baa0256b029451f6e768adOliver Neukum 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (retval == 0) { 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (list->head == list->tail) { 360079034073faf974973baa0256b029451f6e768adOliver Neukum prepare_to_wait(&list->hiddev->wait, &wait, TASK_INTERRUPTIBLE); 36105f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (list->head == list->tail) { 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (file->f_flags & O_NONBLOCK) { 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EAGAIN; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) { 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ERESTARTSYS; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!list->hiddev->exist) { 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EIO; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37505f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 376079034073faf974973baa0256b029451f6e768adOliver Neukum /* let O_NONBLOCK tasks run */ 377079034073faf974973baa0256b029451f6e768adOliver Neukum mutex_unlock(&list->thread_lock); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule(); 37906268b2a384ece73618c1ad7649d19905ab79806Peter Waechtler if (mutex_lock_interruptible(&list->thread_lock)) { 38006268b2a384ece73618c1ad7649d19905ab79806Peter Waechtler finish_wait(&list->hiddev->wait, &wait); 381079034073faf974973baa0256b029451f6e768adOliver Neukum return -EINTR; 38206268b2a384ece73618c1ad7649d19905ab79806Peter Waechtler } 38348d705522da4fa04bb0169a7ca3c9ab92e28b613Micon, David set_current_state(TASK_INTERRUPTIBLE); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 385079034073faf974973baa0256b029451f6e768adOliver Neukum finish_wait(&list->hiddev->wait, &wait); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 389079034073faf974973baa0256b029451f6e768adOliver Neukum if (retval) { 390079034073faf974973baa0256b029451f6e768adOliver Neukum mutex_unlock(&list->thread_lock); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 392079034073faf974973baa0256b029451f6e768adOliver Neukum } 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39505f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov while (list->head != list->tail && 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval + event_size <= count) { 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((list->flags & HIDDEV_FLAG_UREF) == 0) { 398079034073faf974973baa0256b029451f6e768adOliver Neukum if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE) { 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_event event; 400079034073faf974973baa0256b029451f6e768adOliver Neukum 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event.hid = list->buffer[list->tail].usage_code; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event.value = list->buffer[list->tail].value; 403079034073faf974973baa0256b029451f6e768adOliver Neukum if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event))) { 404079034073faf974973baa0256b029451f6e768adOliver Neukum mutex_unlock(&list->thread_lock); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 406079034073faf974973baa0256b029451f6e768adOliver Neukum } 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval += sizeof(struct hiddev_event); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE || 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (list->flags & HIDDEV_FLAG_REPORT) != 0) { 412079034073faf974973baa0256b029451f6e768adOliver Neukum 413079034073faf974973baa0256b029451f6e768adOliver Neukum if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref))) { 414079034073faf974973baa0256b029451f6e768adOliver Neukum mutex_unlock(&list->thread_lock); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 416079034073faf974973baa0256b029451f6e768adOliver Neukum } 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval += sizeof(struct hiddev_usage_ref); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 424079034073faf974973baa0256b029451f6e768adOliver Neukum mutex_unlock(&list->thread_lock); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "poll" file op 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * No kernel lock - fine 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int hiddev_poll(struct file *file, poll_table *wait) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_list *list = file->private_data; 436826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds poll_wait(file, &list->hiddev->wait, wait); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (list->head != list->tail) 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return POLLIN | POLLRDNORM; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!list->hiddev->exist) 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return POLLERR | POLLHUP; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "ioctl" file op 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 448cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvarestatic noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg) 449cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare{ 450cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare struct hid_device *hid = hiddev->hid; 451cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare struct hiddev_report_info rinfo; 452cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare struct hiddev_usage_ref_multi *uref_multi = NULL; 453cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare struct hiddev_usage_ref *uref; 454cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare struct hid_report *report; 455cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare struct hid_field *field; 456cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare int i; 457cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 458cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); 459cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (!uref_multi) 460cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare return -ENOMEM; 461cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare uref = &uref_multi->uref; 462cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { 463cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (copy_from_user(uref_multi, user_arg, 464cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare sizeof(*uref_multi))) 465cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto fault; 466cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare } else { 467cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (copy_from_user(uref, user_arg, sizeof(*uref))) 468cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto fault; 469cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare } 470cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 471cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare switch (cmd) { 472cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare case HIDIOCGUCODE: 473cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare rinfo.report_type = uref->report_type; 474cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare rinfo.report_id = uref->report_id; 475cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) 476cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto inval; 477cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 478cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (uref->field_index >= report->maxfield) 479cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto inval; 480cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 481cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare field = report->field[uref->field_index]; 482cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (uref->usage_index >= field->maxusage) 483cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto inval; 484cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 485cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare uref->usage_code = field->usage[uref->usage_index].hid; 486cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 487cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (copy_to_user(user_arg, uref, sizeof(*uref))) 488cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto fault; 489cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 490eb9910894d7857c273e049b297fd6251e5ecc43eJiri Slaby goto goodreturn; 491cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 492cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare default: 493cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (cmd != HIDIOCGUSAGE && 494cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare cmd != HIDIOCGUSAGES && 495cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare uref->report_type == HID_REPORT_TYPE_INPUT) 496cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto inval; 497cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 498cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (uref->report_id == HID_REPORT_ID_UNKNOWN) { 499cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare field = hiddev_lookup_usage(hid, uref); 500cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (field == NULL) 501cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto inval; 502cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare } else { 503cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare rinfo.report_type = uref->report_type; 504cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare rinfo.report_id = uref->report_id; 505cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) 506cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto inval; 507cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 508cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (uref->field_index >= report->maxfield) 509cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto inval; 510cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 511cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare field = report->field[uref->field_index]; 512cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 513cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (cmd == HIDIOCGCOLLECTIONINDEX) { 514cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (uref->usage_index >= field->maxusage) 515cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto inval; 516cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare } else if (uref->usage_index >= field->report_count) 517cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto inval; 518cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 519cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && 520cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare (uref_multi->num_values > HID_MAX_MULTI_USAGES || 521cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare uref->usage_index + uref_multi->num_values > field->report_count)) 522cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto inval; 523ac065bf214bb6a7fb7536f2dde686d4694342801Dan Carpenter } 524cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 525cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare switch (cmd) { 526cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare case HIDIOCGUSAGE: 527cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare uref->value = field->value[uref->usage_index]; 528cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (copy_to_user(user_arg, uref, sizeof(*uref))) 529cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto fault; 530cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto goodreturn; 531cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 532cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare case HIDIOCSUSAGE: 533cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare field->value[uref->usage_index] = uref->value; 534cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto goodreturn; 535cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 536cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare case HIDIOCGCOLLECTIONINDEX: 5374859484b0957ddc7fe3e0fa349d98b0f1c7876bdJiri Slaby i = field->usage[uref->usage_index].collection_index; 538cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare kfree(uref_multi); 5394859484b0957ddc7fe3e0fa349d98b0f1c7876bdJiri Slaby return i; 540cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare case HIDIOCGUSAGES: 541cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare for (i = 0; i < uref_multi->num_values; i++) 542cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare uref_multi->values[i] = 543cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare field->value[uref->usage_index + i]; 544cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (copy_to_user(user_arg, uref_multi, 545cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare sizeof(*uref_multi))) 546cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto fault; 547cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto goodreturn; 548cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare case HIDIOCSUSAGES: 549cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare for (i = 0; i < uref_multi->num_values; i++) 550cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare field->value[uref->usage_index + i] = 551cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare uref_multi->values[i]; 552cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare goto goodreturn; 553cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare } 554cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 555cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvaregoodreturn: 556cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare kfree(uref_multi); 557cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare return 0; 558cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvarefault: 559cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare kfree(uref_multi); 560cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare return -EFAULT; 561cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvareinval: 562cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare kfree(uref_multi); 563cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare return -EINVAL; 564cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare } 565cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare} 566cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 567cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvarestatic noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg) 568cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare{ 569cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare struct hid_device *hid = hiddev->hid; 570cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare struct usb_device *dev = hid_to_usb_dev(hid); 571cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare int idx, len; 572cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare char *buf; 573cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 574cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (get_user(idx, (int __user *)user_arg)) 575cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare return -EFAULT; 576cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 577cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL) 578cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare return -ENOMEM; 579cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 580cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) { 581cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare kfree(buf); 582cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare return -EINVAL; 583cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare } 584cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 585cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare if (copy_to_user(user_arg+sizeof(int), buf, len+1)) { 586cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare kfree(buf); 587cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare return -EFAULT; 588cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare } 589cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 590cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare kfree(buf); 591cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 592cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare return len; 593cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare} 594cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare 5957961df16819085b8a357720d89d0239036e6af2aAlan Coxstatic long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_list *list = file->private_data; 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev *hiddev = list->hiddev; 5991a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak struct hid_device *hid; 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_collection_info cinfo; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_report_info rinfo; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_field_info finfo; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev_devinfo dinfo; 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hid_report *report; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hid_field *field; 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *user_arg = (void __user *)arg; 60733d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak int i, r = -EINVAL; 6081a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak 6097961df16819085b8a357720d89d0239036e6af2aAlan Cox /* Called without BKL by compat methods so no BKL taken */ 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak mutex_lock(&hiddev->existancelock); 61233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (!hiddev->exist) { 61333d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = -ENODEV; 61433d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak goto ret_unlock; 61533d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak } 61633d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak 61733d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak hid = hiddev->hid; 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCGVERSION: 62233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = put_user(HID_VERSION, (int __user *)arg) ? 62333d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak -EFAULT : 0; 62433d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCAPPLICATION: 62733d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (arg < 0 || arg >= hid->maxapplication) 62833d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < hid->maxcollection; i++) 63105f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov if (hid->collection[i].type == 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HID_COLLECTION_APPLICATION && arg-- == 0) 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 63405f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 63533d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (i < hid->maxcollection) 6361a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak r = hid->collection[i].usage; 63733d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCGDEVINFO: 64033d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak { 64133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak struct usb_device *dev = hid_to_usb_dev(hid); 64233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak struct usbhid_device *usbhid = hid->driver_data; 64333d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak 6449561f7faa45cb855b1ba83a4acf3f2ad3665e71fDan Carpenter memset(&dinfo, 0, sizeof(dinfo)); 6459561f7faa45cb855b1ba83a4acf3f2ad3665e71fDan Carpenter 64633d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak dinfo.bustype = BUS_USB; 64733d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak dinfo.busnum = dev->bus->busnum; 64833d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak dinfo.devnum = dev->devnum; 64933d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak dinfo.ifnum = usbhid->ifnum; 65033d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor); 65133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak dinfo.product = le16_to_cpu(dev->descriptor.idProduct); 65233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice); 65333d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak dinfo.num_applications = hid->maxapplication; 65433d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak 65533d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = copy_to_user(user_arg, &dinfo, sizeof(dinfo)) ? 65633d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak -EFAULT : 0; 65733d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 6581a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak } 6591a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCGFLAG: 66133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = put_user(list->flags, (int __user *)arg) ? 66233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak -EFAULT : 0; 66333d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCSFLAG: 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int newflags; 66833d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak 66933d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (get_user(newflags, (int __user *)arg)) { 67033d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = -EFAULT; 67133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 67233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak } 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((newflags & ~HIDDEV_FLAGS) != 0 || 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((newflags & HIDDEV_FLAG_REPORT) != 0 && 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (newflags & HIDDEV_FLAG_UREF) == 0)) 67733d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list->flags = newflags; 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = 0; 68233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCGSTRING: 68633d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = hiddev_ioctl_string(hiddev, cmd, user_arg); 68733d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCINITREPORT: 6904916b3a57fc94664677d439b911b8aaf86c7ec23Jiri Kosina usbhid_init_reports(hid); 69133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = 0; 69233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCGREPORT: 69533d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) { 69633d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = -EFAULT; 69733d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 69833d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak } 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT) 70133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7021a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak 7031a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak report = hiddev_lookup_report(hid, &rinfo); 70433d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (report == NULL) 70533d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7061a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak 7071a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak usbhid_submit_report(hid, report, USB_DIR_IN); 7081a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak usbhid_wait_io(hid); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71033d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = 0; 71133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCSREPORT: 71433d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) { 71533d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = -EFAULT; 71633d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 71733d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak } 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rinfo.report_type == HID_REPORT_TYPE_INPUT) 72033d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7211a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak 7221a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak report = hiddev_lookup_report(hid, &rinfo); 72333d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (report == NULL) 72433d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7251a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak 7261a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak usbhid_submit_report(hid, report, USB_DIR_OUT); 7271a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak usbhid_wait_io(hid); 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72933d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = 0; 73033d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCGREPORTINFO: 73333d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) { 73433d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = -EFAULT; 73533d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7361a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak } 7371a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak 7381a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak report = hiddev_lookup_report(hid, &rinfo); 73933d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (report == NULL) 74033d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rinfo.num_fields = report->maxfield; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74433d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = copy_to_user(user_arg, &rinfo, sizeof(rinfo)) ? 74533d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak -EFAULT : 0; 74633d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCGFIELDINFO: 74933d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (copy_from_user(&finfo, user_arg, sizeof(finfo))) { 75033d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = -EFAULT; 75133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 75233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak } 75333d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rinfo.report_type = finfo.report_type; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rinfo.report_id = finfo.report_id; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7571a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak report = hiddev_lookup_report(hid, &rinfo); 75833d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (report == NULL) 75933d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7601a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak 76133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (finfo.field_index >= report->maxfield) 76233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds field = report->field[finfo.field_index]; 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&finfo, 0, sizeof(finfo)); 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.report_type = rinfo.report_type; 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.report_id = rinfo.report_id; 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.field_index = field->report_count - 1; 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.maxusage = field->maxusage; 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.flags = field->flags; 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.physical = field->physical; 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.logical = field->logical; 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.application = field->application; 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.logical_minimum = field->logical_minimum; 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.logical_maximum = field->logical_maximum; 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.physical_minimum = field->physical_minimum; 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.physical_maximum = field->physical_maximum; 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.unit_exponent = field->unit_exponent; 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finfo.unit = field->unit; 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = copy_to_user(user_arg, &finfo, sizeof(finfo)) ? 78233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak -EFAULT : 0; 78333d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCGUCODE: 786cf2a299e48cbeb6c942e1f765b92ca6058355f68Jean Delvare /* fall through */ 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCGUSAGE: 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCSUSAGE: 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCGUSAGES: 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCSUSAGES: 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCGCOLLECTIONINDEX: 79233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = hiddev_ioctl_usage(hiddev, cmd, user_arg); 79333d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case HIDIOCGCOLLECTIONINFO: 79633d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) { 79733d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = -EFAULT; 79833d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 7991a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak } 8001a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak 80133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak if (cinfo.index >= hid->maxcollection) 80233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cinfo.type = hid->collection[cinfo.index].type; 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cinfo.usage = hid->collection[cinfo.index].usage; 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cinfo.level = hid->collection[cinfo.index].level; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80833d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak r = copy_to_user(user_arg, &cinfo, sizeof(cinfo)) ? 80933d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak -EFAULT : 0; 81033d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) 81433d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) { 817dd2ed487fdd78b50549b2ca8418875c0d9f4a30eDaniel Mack int len = strlen(hid->name) + 1; 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len > _IOC_SIZE(cmd)) 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = _IOC_SIZE(cmd); 8201a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak r = copy_to_user(user_arg, hid->name, len) ? 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -EFAULT : len; 82233d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) { 826dd2ed487fdd78b50549b2ca8418875c0d9f4a30eDaniel Mack int len = strlen(hid->phys) + 1; 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len > _IOC_SIZE(cmd)) 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = _IOC_SIZE(cmd); 8291a8e8fab790ea7af81b8f964fdec706ad1ec2271Valentine Barshak r = copy_to_user(user_arg, hid->phys, len) ? 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -EFAULT : len; 83133d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak break; 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 83433d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak 83533d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshakret_unlock: 83633d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak mutex_unlock(&hiddev->existancelock); 83733d6eb570b1f3fe5ba93cef465c5be66535c2c9aValentine Barshak return r; 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 840bb6c8d8fa9b5587eea18078ce0bcf6bb2905789fPhilip Langdale#ifdef CONFIG_COMPAT 841bb6c8d8fa9b5587eea18078ce0bcf6bb2905789fPhilip Langdalestatic long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 842bb6c8d8fa9b5587eea18078ce0bcf6bb2905789fPhilip Langdale{ 84388af45bafdda8f892c9d45ce38d55fdf7e734513Jiri Kosina return hiddev_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); 844bb6c8d8fa9b5587eea18078ce0bcf6bb2905789fPhilip Langdale} 845bb6c8d8fa9b5587eea18078ce0bcf6bb2905789fPhilip Langdale#endif 846bb6c8d8fa9b5587eea18078ce0bcf6bb2905789fPhilip Langdale 847066202dd48cf3296b6cc22b5fcf89aef33fa0efcLuiz Fernando N. Capitulinostatic const struct file_operations hiddev_fops = { 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = hiddev_read, 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = hiddev_write, 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .poll = hiddev_poll, 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = hiddev_open, 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = hiddev_release, 8547961df16819085b8a357720d89d0239036e6af2aAlan Cox .unlocked_ioctl = hiddev_ioctl, 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fasync = hiddev_fasync, 856bb6c8d8fa9b5587eea18078ce0bcf6bb2905789fPhilip Langdale#ifdef CONFIG_COMPAT 857bb6c8d8fa9b5587eea18078ce0bcf6bb2905789fPhilip Langdale .compat_ioctl = hiddev_compat_ioctl, 858bb6c8d8fa9b5587eea18078ce0bcf6bb2905789fPhilip Langdale#endif 8596038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .llseek = noop_llseek, 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8622c9ede55ecec58099b72e4bb8eab719f32f72c31Al Virostatic char *hiddev_devnode(struct device *dev, umode_t *mode) 863f7a386c5b8ff34cd84ae922603d1c6f9d234edeeKay Sievers{ 864f7a386c5b8ff34cd84ae922603d1c6f9d234edeeKay Sievers return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); 865f7a386c5b8ff34cd84ae922603d1c6f9d234edeeKay Sievers} 866f7a386c5b8ff34cd84ae922603d1c6f9d234edeeKay Sievers 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_class_driver hiddev_class = { 868d6e5bcf4a7ebbe258124a931f1449338340a99b5Greg Kroah-Hartman .name = "hiddev%d", 869e454cea20bdcff10ee698d11b8882662a0153a47Kay Sievers .devnode = hiddev_devnode, 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fops = &hiddev_fops, 87105f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov .minor_base = HIDDEV_MINOR_BASE, 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is where hid.c calls us to connect a hid device to the hiddev driver 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 87793c10132a7ac160df3175b53f7ee857625412165Jiri Slabyint hiddev_connect(struct hid_device *hid, unsigned int force) 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev *hiddev; 8804916b3a57fc94664677d439b911b8aaf86c7ec23Jiri Kosina struct usbhid_device *usbhid = hid->driver_data; 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88393c10132a7ac160df3175b53f7ee857625412165Jiri Slaby if (!force) { 88493c10132a7ac160df3175b53f7ee857625412165Jiri Slaby unsigned int i; 88593c10132a7ac160df3175b53f7ee857625412165Jiri Slaby for (i = 0; i < hid->maxcollection; i++) 88693c10132a7ac160df3175b53f7ee857625412165Jiri Slaby if (hid->collection[i].type == 88793c10132a7ac160df3175b53f7ee857625412165Jiri Slaby HID_COLLECTION_APPLICATION && 88893c10132a7ac160df3175b53f7ee857625412165Jiri Slaby !IS_INPUT_APPLICATION(hid->collection[i].usage)) 88993c10132a7ac160df3175b53f7ee857625412165Jiri Slaby break; 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89193c10132a7ac160df3175b53f7ee857625412165Jiri Slaby if (i == hid->maxcollection) 89293c10132a7ac160df3175b53f7ee857625412165Jiri Slaby return -1; 89393c10132a7ac160df3175b53f7ee857625412165Jiri Slaby } 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 895bbdb7dafb5b5a3c0197cbabd5055d8e9c093e3eaOliver Neukum if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL))) 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&hiddev->wait); 899826d598242d9200ddee63fce96f03793fddee4fcDmitry Torokhov INIT_LIST_HEAD(&hiddev->list); 900cdcb44e87bedcf5070eece61f89f9373a3810031Jiri Kosina spin_lock_init(&hiddev->list_lock); 901079034073faf974973baa0256b029451f6e768adOliver Neukum mutex_init(&hiddev->existancelock); 90276052749143d03006271cc0ce8205ad756917062Jiri Kosina hid->hiddev = hiddev; 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hiddev->hid = hid; 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hiddev->exist = 1; 905079034073faf974973baa0256b029451f6e768adOliver Neukum retval = usb_register_dev(usbhid->intf, &hiddev_class); 906079034073faf974973baa0256b029451f6e768adOliver Neukum if (retval) { 9074291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hid, "Not able to get a minor for this device\n"); 90876052749143d03006271cc0ce8205ad756917062Jiri Kosina hid->hiddev = NULL; 909079034073faf974973baa0256b029451f6e768adOliver Neukum kfree(hiddev); 910079034073faf974973baa0256b029451f6e768adOliver Neukum return -1; 911079034073faf974973baa0256b029451f6e768adOliver Neukum } 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is where hid.c calls us to disconnect a hiddev device from the 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * corresponding hid device (usually because the usb device has disconnected) 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_class_driver hiddev_class; 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid hiddev_disconnect(struct hid_device *hid) 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hiddev *hiddev = hid->hiddev; 9234916b3a57fc94664677d439b911b8aaf86c7ec23Jiri Kosina struct usbhid_device *usbhid = hid->driver_data; 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 925ba18311dff7933ccb9c41bbbb1ad3d70840069b5Ming Lei usb_deregister_dev(usbhid->intf, &hiddev_class); 926ba18311dff7933ccb9c41bbbb1ad3d70840069b5Ming Lei 927079034073faf974973baa0256b029451f6e768adOliver Neukum mutex_lock(&hiddev->existancelock); 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hiddev->exist = 0; 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hiddev->open) { 9317f77897ef2b6a5ee4eb8bc24fe8b1f3eab254328Jiri Kosina mutex_unlock(&hiddev->existancelock); 9324916b3a57fc94664677d439b911b8aaf86c7ec23Jiri Kosina usbhid_close(hiddev->hid); 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&hiddev->wait); 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9357f77897ef2b6a5ee4eb8bc24fe8b1f3eab254328Jiri Kosina mutex_unlock(&hiddev->existancelock); 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(hiddev); 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 939