ChangeSet 1.1252, 2003/06/18 16:55:14-07:00, stewart@inverse.wetlogic.net [PATCH] USB: HIDDev uref backport for 2.4? drivers/usb/hid-core.c | 90 ++++++++++++-- drivers/usb/hid-input.c | 7 - drivers/usb/hid.h | 11 + drivers/usb/hiddev.c | 295 +++++++++++++++++++++++++++++++----------------- include/linux/hiddev.h | 45 ++++++- 5 files changed, 320 insertions(+), 128 deletions(-) diff -Nru a/drivers/usb/hid-core.c b/drivers/usb/hid-core.c --- a/drivers/usb/hid-core.c Wed Jun 18 17:35:02 2003 +++ b/drivers/usb/hid-core.c Wed Jun 18 17:35:02 2003 @@ -108,10 +108,11 @@ memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + values * sizeof(unsigned)); - report->field[report->maxfield++] = field; + report->field[report->maxfield] = field; field->usage = (struct hid_usage *)(field + 1); field->value = (unsigned *)(field->usage + usages); field->report = report; + field->index = report->maxfield++; return field; } @@ -127,18 +128,42 @@ usage = parser->local.usage[0]; - if (type == HID_COLLECTION_APPLICATION - && parser->device->maxapplication < HID_MAX_APPLICATIONS) - parser->device->application[parser->device->maxapplication++] = usage; - if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { dbg("collection stack overflow"); return -1; } - collection = parser->collection_stack + parser->collection_stack_ptr++; + if (parser->device->maxcollection == parser->device->collection_size) { + collection = kmalloc(sizeof(struct hid_collection) * + parser->device->collection_size * 2, + GFP_KERNEL); + if (collection == NULL) { + dbg("failed to reallocate collection array"); + return -1; + } + memcpy(collection, parser->device->collection, + sizeof(struct hid_collection) * + parser->device->collection_size); + memset(collection + parser->device->collection_size, 0, + sizeof(struct hid_collection) * + parser->device->collection_size); + kfree(parser->device->collection); + parser->device->collection = collection; + parser->device->collection_size *= 2; + } + + parser->collection_stack[parser->collection_stack_ptr++] = + parser->device->maxcollection; + + collection = parser->device->collection + + parser->device->maxcollection++; + collection->type = type; collection->usage = usage; + collection->level = parser->collection_stack_ptr - 1; + + if (type == HID_COLLECTION_APPLICATION) + parser->device->maxapplication++; return 0; } @@ -166,8 +191,9 @@ { int n; for (n = parser->collection_stack_ptr - 1; n >= 0; n--) - if (parser->collection_stack[n].type == type) - return parser->collection_stack[n].usage; + if (parser->device->collection[parser->collection_stack[n]].type == type) + return parser->device->collection[parser->collection_stack[n]].usage; + return 0; /* we know nothing about this usage type */ } @@ -181,7 +207,12 @@ dbg("usage index exceeded"); return -1; } - parser->local.usage[parser->local.usage_index++] = usage; + parser->local.usage[parser->local.usage_index] = usage; + parser->local.collection_index[parser->local.usage_index] = + parser->collection_stack_ptr ? + parser->collection_stack[parser->collection_stack_ptr - 1] : 0; + parser->local.usage_index++; + return 0; } @@ -222,8 +253,11 @@ field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); - for (i = 0; i < usages; i++) + for (i = 0; i < usages; i++) { field->usage[i].hid = parser->local.usage[i]; + field->usage[i].collection_index = + parser->local.collection_index[i]; + } field->maxusage = usages; field->flags = flags; @@ -461,7 +495,7 @@ switch (item->tag) { case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: - ret = open_collection(parser, data & 3); + ret = open_collection(parser, data & 0xff); break; case HID_MAIN_ITEM_TAG_END_COLLECTION: ret = close_collection(parser); @@ -530,6 +564,7 @@ } if (device->rdesc) kfree(device->rdesc); + if (device->collection) kfree(device->collection); } /* @@ -618,17 +653,30 @@ return NULL; memset(device, 0, sizeof(struct hid_device)); + if (!(device->collection = kmalloc(sizeof(struct hid_collection) * + HID_DEFAULT_NUM_COLLECTIONS, + GFP_KERNEL))) { + kfree(device); + return NULL; + } + memset(device->collection, 0, sizeof(struct hid_collection) * + HID_DEFAULT_NUM_COLLECTIONS); + device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; + for (i = 0; i < HID_REPORT_TYPES; i++) INIT_LIST_HEAD(&device->report_enum[i].report_list); if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) { + kfree(device->collection); kfree(device); return NULL; } memcpy(device->rdesc, start, size); + device->rsize = size; if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) { kfree(device->rdesc); + kfree(device->collection); kfree(device); return NULL; } @@ -736,7 +784,7 @@ if (hid->claimed & HID_CLAIMED_INPUT) hidinput_hid_event(hid, field, usage, value); if (hid->claimed & HID_CLAIMED_HIDDEV) - hiddev_hid_event(hid, usage->hid, value); + hiddev_hid_event(hid, field, usage, value); } @@ -827,6 +875,9 @@ return -1; } + if (hid->claimed & HID_CLAIMED_HIDDEV) + hiddev_report_event(hid, report); + size = ((report->size - 1) >> 3) + 1; if (len < size) { @@ -1113,6 +1164,10 @@ #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 +#define USB_VENDOR_ID_MGE 0x0463 +#define USB_DEVICE_ID_MGE_UPS 0xffff +#define USB_DEVICE_ID_MGE_UPS1 0x0001 + struct hid_blacklist { __u16 idVendor; __u16 idProduct; @@ -1158,6 +1213,8 @@ { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_OKI, USB_VENDOR_ID_OKI_MULITI, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV }, { 0, 0 } }; @@ -1311,11 +1368,14 @@ printk("hiddev%d", hid->minor); c = "Device"; - for (i = 0; i < hid->maxapplication; i++) - if ((hid->application[i] & 0xffff) < ARRAY_SIZE(hid_types)) { - c = hid_types[hid->application[i] & 0xffff]; + for (i = 0; i < hid->maxcollection; i++) { + if (hid->collection[i].type == HID_COLLECTION_APPLICATION && + (hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK && + (hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) { + c = hid_types[hid->collection[i].usage & 0xffff]; break; } + } printk(": USB HID v%x.%02x %s [%s] on usb%d:%d.%d\n", hid->version >> 8, hid->version & 0xff, c, hid->name, diff -Nru a/drivers/usb/hid-input.c b/drivers/usb/hid-input.c --- a/drivers/usb/hid-input.c Wed Jun 18 17:35:02 2003 +++ b/drivers/usb/hid-input.c Wed Jun 18 17:35:02 2003 @@ -430,11 +430,12 @@ INIT_LIST_HEAD(&hid->inputs); - for (i = 0; i < hid->maxapplication; i++) - if (IS_INPUT_APPLICATION(hid->application[i])) + for (i = 0; i < hid->maxcollection; i++) + if (hid->collection[i].type == HID_COLLECTION_APPLICATION && + IS_INPUT_APPLICATION(hid->collection[i].usage)) break; - if (i == hid->maxapplication) + if (i == hid->maxcollection) return -1; for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { diff -Nru a/drivers/usb/hid.h b/drivers/usb/hid.h --- a/drivers/usb/hid.h Wed Jun 18 17:35:02 2003 +++ b/drivers/usb/hid.h Wed Jun 18 17:35:02 2003 @@ -216,9 +216,11 @@ #define HID_MAX_DESCRIPTOR_SIZE 4096 #define HID_MAX_USAGES 1024 #define HID_MAX_APPLICATIONS 16 +#define HID_DEFAULT_NUM_COLLECTIONS 16 struct hid_local { unsigned usage[HID_MAX_USAGES]; /* usage array */ + unsigned collection_index[HID_MAX_USAGES]; /* collection index array */ unsigned usage_index; unsigned usage_minimum; unsigned delimiter_depth; @@ -233,10 +235,12 @@ struct hid_collection { unsigned type; unsigned usage; + unsigned level; }; struct hid_usage { unsigned hid; /* hid usage code */ + unsigned collection_index; /* index into collection array */ __u16 code; /* input driver code */ __u8 type; /* input driver type */ __s8 hat_min; /* hat switch fun */ @@ -262,6 +266,7 @@ unsigned unit_exponent; unsigned unit; struct hid_report *report; /* associated report */ + unsigned index; /* index into report->field[] */ }; #define HID_MAX_FIELDS 64 @@ -306,7 +311,9 @@ struct hid_device { /* device report descriptor */ __u8 *rdesc; unsigned rsize; - unsigned application[HID_MAX_APPLICATIONS]; /* List of HID applications */ + struct hid_collection *collection; /* List of HID collections */ + unsigned collection_size; /* Number of allocated hid_collections */ + unsigned maxcollection; /* Number of parsed collections */ unsigned maxapplication; /* Number of applications */ unsigned version; /* HID version */ unsigned country; /* HID country */ @@ -341,7 +348,7 @@ struct hid_global global_stack[HID_GLOBAL_STACK_SIZE]; unsigned global_stack_ptr; struct hid_local local; - struct hid_collection collection_stack[HID_COLLECTION_STACK_SIZE]; + unsigned collection_stack[HID_COLLECTION_STACK_SIZE]; unsigned collection_stack_ptr; struct hid_device *device; }; diff -Nru a/drivers/usb/hiddev.c b/drivers/usb/hiddev.c --- a/drivers/usb/hiddev.c Wed Jun 18 17:35:02 2003 +++ b/drivers/usb/hiddev.c Wed Jun 18 17:35:02 2003 @@ -50,9 +50,10 @@ }; struct hiddev_list { - struct hiddev_event buffer[HIDDEV_BUFFER_SIZE]; + struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE]; int head; int tail; + unsigned flags; struct fasync_struct *fasync; struct hiddev *hiddev; struct hiddev_list *next; @@ -70,7 +71,8 @@ static struct hid_report * hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) { - struct hid_report_enum *report_enum; + unsigned flags = rinfo->report_id & ~HID_REPORT_ID_MASK; + struct hid_report_enum *report_enum = NULL; struct list_head *list; if (rinfo->report_type < HID_REPORT_TYPE_MIN || @@ -78,27 +80,29 @@ report_enum = hid->report_enum + (rinfo->report_type - HID_REPORT_TYPE_MIN); - if ((rinfo->report_id & ~HID_REPORT_ID_MASK) != 0) { - switch (rinfo->report_id & ~HID_REPORT_ID_MASK) { - case HID_REPORT_ID_FIRST: - list = report_enum->report_list.next; - if (list == &report_enum->report_list) return NULL; - rinfo->report_id = ((struct hid_report *) list)->id; - break; - - case HID_REPORT_ID_NEXT: - list = (struct list_head *) - report_enum->report_id_hash[rinfo->report_id & - HID_REPORT_ID_MASK]; - if (list == NULL) return NULL; - list = list->next; - if (list == &report_enum->report_list) return NULL; - rinfo->report_id = ((struct hid_report *) list)->id; - break; - - default: - return NULL; - } + + switch (flags) { + case 0: /* Nothing to do -- report_id is already set correctly */ + break; + + case HID_REPORT_ID_FIRST: + list = report_enum->report_list.next; + if (list == &report_enum->report_list) return NULL; + rinfo->report_id = ((struct hid_report *) list)->id; + break; + + case HID_REPORT_ID_NEXT: + list = (struct list_head *) + report_enum->report_id_hash[rinfo->report_id & + HID_REPORT_ID_MASK]; + if (list == NULL) return NULL; + list = list->next; + if (list == &report_enum->report_list) return NULL; + rinfo->report_id = ((struct hid_report *) list)->id; + break; + + default: + return NULL; } return report_enum->report_id_hash[rinfo->report_id]; @@ -142,21 +146,20 @@ return NULL; } -/* - * This is where hid.c calls into hiddev to pass an event that occurred over - * the interrupt pipe - */ -void hiddev_hid_event(struct hid_device *hid, unsigned int usage, int value) +static void hiddev_send_event(struct hid_device *hid, + struct hiddev_usage_ref *uref) { struct hiddev *hiddev = hid->hiddev; struct hiddev_list *list = hiddev->list; while (list) { - list->buffer[list->head].hid = usage; - list->buffer[list->head].value = value; - list->head = (list->head + 1) & (HIDDEV_BUFFER_SIZE - 1); - - kill_fasync(&list->fasync, SIGIO, POLL_IN); + if (uref->field_index != HID_FIELD_INDEX_NONE || + (list->flags & HIDDEV_FLAG_REPORT) != 0) { + list->buffer[list->head] = *uref; + list->head = (list->head + 1) & + (HIDDEV_BUFFER_SIZE - 1); + kill_fasync(&list->fasync, SIGIO, POLL_IN); + } list = list->next; } @@ -165,6 +168,46 @@ } /* + * This is where hid.c calls into hiddev to pass an event that occurred over + * the interrupt pipe + */ +void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + unsigned type = field->report_type; + struct hiddev_usage_ref uref; + + uref.report_type = + (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : + ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : + ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); + uref.report_id = field->report->id; + uref.field_index = field->index; + uref.usage_index = (usage - field->usage); + uref.usage_code = usage->hid; + uref.value = value; + + hiddev_send_event(hid, &uref); +} + + +void hiddev_report_event(struct hid_device *hid, struct hid_report *report) +{ + unsigned type = report->type; + struct hiddev_usage_ref uref; + + memset(&uref, 0, sizeof(uref)); + uref.report_type = + (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : + ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : + ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); + uref.report_id = report->id; + uref.field_index = HID_FIELD_INDEX_NONE; + + hiddev_send_event(hid, &uref); +} + +/* * fasync file op */ static int hiddev_fasync(int fd, struct file *file, int on) @@ -193,7 +236,6 @@ struct hiddev_list *list = file->private_data; struct hiddev_list **listptr; - lock_kernel(); listptr = &list->hiddev->list; hiddev_fasync(-1, file, 0); @@ -209,7 +251,6 @@ } kfree(list); - unlock_kernel(); return 0; } @@ -259,43 +300,66 @@ { DECLARE_WAITQUEUE(wait, current); struct hiddev_list *list = file->private_data; + int event_size; int retval = 0; - if (list->head == list->tail) { + event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ? + sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event); - add_wait_queue(&list->hiddev->wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); + if (count < event_size) return 0; - while (list->head == list->tail) { - - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - if (!list->hiddev->exist) { - retval = -EIO; - break; + while (retval == 0) { + if (list->head == list->tail) { + add_wait_queue(&list->hiddev->wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (list->head == list->tail) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + if (!list->hiddev->exist) { + retval = -EIO; + break; + } + + schedule(); } - schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&list->hiddev->wait, &wait); } - set_current_state(TASK_RUNNING); - remove_wait_queue(&list->hiddev->wait, &wait); - } + if (retval) + return retval; - if (retval) - return retval; + while (list->head != list->tail && + retval + event_size <= count) { + if ((list->flags & HIDDEV_FLAG_UREF) == 0) { + if (list->buffer[list->tail].field_index != + HID_FIELD_INDEX_NONE) { + struct hiddev_event event; + event.hid = list->buffer[list->tail].usage_code; + event.value = list->buffer[list->tail].value; + if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event))) + return -EFAULT; + retval += sizeof(struct hiddev_event); + } + } else { + if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE || + (list->flags & HIDDEV_FLAG_REPORT) != 0) { + if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref))) + return -EFAULT; + retval += sizeof(struct hiddev_usage_ref); + } + } + list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1); + } - while (list->head != list->tail && retval + sizeof(struct hiddev_event) <= count) { - if (copy_to_user(buffer + retval, list->buffer + list->tail, - sizeof(struct hiddev_event))) return -EFAULT; - list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1); - retval += sizeof(struct hiddev_event); } return retval; @@ -329,10 +393,14 @@ struct hiddev *hiddev = list->hiddev; struct hid_device *hid = hiddev->hid; struct usb_device *dev = hid->dev; + struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; + struct hiddev_field_info finfo; struct hiddev_usage_ref uref; + struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; + int i; if (!hiddev->exist) return -EIO; @@ -344,11 +412,18 @@ case HIDIOCAPPLICATION: if (arg < 0 || arg >= hid->maxapplication) return -EINVAL; - return hid->application[arg]; + + for (i = 0; i < hid->maxcollection; i++) + if (hid->collection[i].type == + HID_COLLECTION_APPLICATION && arg-- == 0) + break; + + if (i == hid->maxcollection) + return -EINVAL; + + return hid->collection[i].usage; case HIDIOCGDEVINFO: - { - struct hiddev_devinfo dinfo; dinfo.bustype = BUS_USB; dinfo.busnum = dev->bus->busnum; dinfo.devnum = dev->devnum; @@ -358,7 +433,25 @@ dinfo.version = dev->descriptor.bcdDevice; dinfo.num_applications = hid->maxapplication; return copy_to_user((void *) arg, &dinfo, sizeof(dinfo)); - } + + case HIDIOCGFLAG: + return put_user(list->flags, (int *) arg); + + case HIDIOCSFLAG: + { + int newflags; + if (get_user(newflags, (int *) arg)) + return -EFAULT; + + if ((newflags & ~HIDDEV_FLAGS) != 0 || + ((newflags & HIDDEV_FLAG_REPORT) != 0 && + (newflags & HIDDEV_FLAG_UREF) == 0)) + return -EINVAL; + + list->flags = newflags; + + return 0; + } case HIDIOCGSTRING: { @@ -387,7 +480,6 @@ } case HIDIOCINITREPORT: - hid_init_reports(hid); return 0; @@ -432,8 +524,6 @@ return copy_to_user((void *) arg, &rinfo, sizeof(rinfo)); case HIDIOCGFIELDINFO: - { - struct hiddev_field_info finfo; if (copy_from_user(&finfo, (void *) arg, sizeof(finfo))) return -EFAULT; rinfo.report_type = finfo.report_type; @@ -462,7 +552,6 @@ finfo.unit = field->unit; return copy_to_user((void *) arg, &finfo, sizeof(finfo)); - } case HIDIOCGUCODE: if (copy_from_user(&uref, (void *) arg, sizeof(uref))) @@ -485,9 +574,15 @@ return copy_to_user((void *) arg, &uref, sizeof(uref)); case HIDIOCGUSAGE: + case HIDIOCSUSAGE: + case HIDIOCGCOLLECTIONINDEX: if (copy_from_user(&uref, (void *) arg, sizeof(uref))) return -EFAULT; + if (cmd == HIDIOCSUSAGE && + uref.report_type == HID_REPORT_TYPE_INPUT) + return -EINVAL; + if (uref.report_id == HID_REPORT_ID_UNKNOWN) { field = hiddev_lookup_usage(hid, &uref); if (field == NULL) @@ -506,38 +601,32 @@ return -EINVAL; } - uref.value = field->value[uref.usage_index]; + switch (cmd) { + case HIDIOCGUSAGE: + uref.value = field->value[uref.usage_index]; + return copy_to_user((void *) arg, &uref, sizeof(uref)); + + case HIDIOCSUSAGE: + field->value[uref.usage_index] = uref.value; + return 0; - return copy_to_user((void *) arg, &uref, sizeof(uref)); + case HIDIOCGCOLLECTIONINDEX: + return field->usage[uref.usage_index].collection_index; + } + break; - case HIDIOCSUSAGE: - if (copy_from_user(&uref, (void *) arg, sizeof(uref))) + case HIDIOCGCOLLECTIONINFO: + if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo))) return -EFAULT; - if (uref.report_type == HID_REPORT_TYPE_INPUT) + if (cinfo.index >= hid->maxcollection) return -EINVAL; - if (uref.report_id == HID_REPORT_ID_UNKNOWN) { - field = hiddev_lookup_usage(hid, &uref); - if (field == NULL) - return -EINVAL; - } else { - rinfo.report_type = uref.report_type; - rinfo.report_id = uref.report_id; - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; - - if (uref.field_index >= report->maxfield) - return -EINVAL; - - field = report->field[uref.field_index]; - if (uref.usage_index >= field->maxusage) - return -EINVAL; - } + cinfo.type = hid->collection[cinfo.index].type; + cinfo.usage = hid->collection[cinfo.index].usage; + cinfo.level = hid->collection[cinfo.index].level; - field->value[uref.usage_index] = uref.value; - - return 0; + return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); default: @@ -576,12 +665,18 @@ int minor, i; char devfs_name[16]; - for (i = 0; i < hid->maxapplication; i++) - if (!IS_INPUT_APPLICATION(hid->application[i])) - break; - if (i == hid->maxapplication) - return -1; + + if ((hid->quirks & HID_QUIRK_HIDDEV) == 0) { + for (i = 0; i < hid->maxcollection; i++) + if (hid->collection[i].type == + HID_COLLECTION_APPLICATION && + !IS_INPUT_APPLICATION(hid->collection[i].usage)) + break; + + if (i == hid->maxcollection) + return -1; + } for (minor = 0; minor < HIDDEV_MINORS && hiddev_table[minor]; minor++); if (minor == HIDDEV_MINORS) { diff -Nru a/include/linux/hiddev.h b/include/linux/hiddev.h --- a/include/linux/hiddev.h Wed Jun 18 17:35:02 2003 +++ b/include/linux/hiddev.h Wed Jun 18 17:35:02 2003 @@ -49,6 +49,13 @@ unsigned num_applications; }; +struct hiddev_collection_info { + unsigned index; + unsigned type; + unsigned usage; + unsigned level; +}; + #define HID_STRING_SIZE 256 struct hiddev_string_descriptor { int index; @@ -119,12 +126,17 @@ __s32 value; }; +/* FIELD_INDEX_NONE is returned in read() data from the kernel when flags + * is set to (HIDDEV_FLAG_UREF | HIDDEV_FLAG_REPORT) and a new report has + * been sent by the device + */ +#define HID_FIELD_INDEX_NONE 0xffffffff /* * Protocol version. */ -#define HID_VERSION 0x010002 +#define HID_VERSION 0x010004 /* * IOCTLs (0x00 - 0x7f) @@ -138,11 +150,22 @@ #define HIDIOCGNAME(len) _IOC(_IOC_READ, 'H', 0x06, len) #define HIDIOCGREPORT _IOW('H', 0x07, struct hiddev_report_info) #define HIDIOCSREPORT _IOW('H', 0x08, struct hiddev_report_info) -#define HIDIOCGREPORTINFO _IOWR('H', 0x09, struct hiddev_report_info) -#define HIDIOCGFIELDINFO _IOWR('H', 0x0A, struct hiddev_field_info) -#define HIDIOCGUSAGE _IOWR('H', 0x0B, struct hiddev_usage_ref) -#define HIDIOCSUSAGE _IOW('H', 0x0C, struct hiddev_usage_ref) -#define HIDIOCGUCODE _IOWR('H', 0x0D, struct hiddev_usage_ref) +#define HIDIOCGREPORTINFO _IOWR('H', 0x09, struct hiddev_report_info) +#define HIDIOCGFIELDINFO _IOWR('H', 0x0A, struct hiddev_field_info) +#define HIDIOCGUSAGE _IOWR('H', 0x0B, struct hiddev_usage_ref) +#define HIDIOCSUSAGE _IOW('H', 0x0C, struct hiddev_usage_ref) +#define HIDIOCGUCODE _IOWR('H', 0x0D, struct hiddev_usage_ref) +#define HIDIOCGFLAG _IOR('H', 0x0E, int) +#define HIDIOCSFLAG _IOW('H', 0x0F, int) +#define HIDIOCGCOLLECTIONINDEX _IOW('H', 0x10, struct hiddev_usage_ref) +#define HIDIOCGCOLLECTIONINFO _IOWR('H', 0x11, struct hiddev_collection_info) + +/* + * Flags to be used in HIDIOCSFLAG + */ +#define HIDDEV_FLAG_UREF 0x1 +#define HIDDEV_FLAG_REPORT 0x2 +#define HIDDEV_FLAGS 0x3 /* To traverse the input report descriptor info for a HID device, perform the * following: @@ -179,13 +202,19 @@ #ifdef CONFIG_USB_HIDDEV int hiddev_connect(struct hid_device *); void hiddev_disconnect(struct hid_device *); -void hiddev_hid_event(struct hid_device *, unsigned int usage, int value); +void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value); int __init hiddev_init(void); void __exit hiddev_exit(void); #else static inline int hiddev_connect(struct hid_device *hid) { return -1; } static inline void hiddev_disconnect(struct hid_device *hid) { } -static inline void hiddev_hid_event(struct hid_device *hid, unsigned int usage, int value) { } +static inline void hiddev_hid_event(struct hid_device *hid, + struct hid_field *field, + struct hid_usage *usage, + __s32 value) { } +static inline void hiddev_report_event(struct hid_device *hid, + struct hid_report *report) { } static inline int hiddev_init(void) { return 0; } static inline void hiddev_exit(void) { } #endif