ChangeSet 1.1252, 2003/06/18 16:55:14-07:00, [EMAIL PROTECTED]

[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



-------------------------------------------------------
This SF.Net email is sponsored by: INetU
Attention Web Developers & Consultants: Become An INetU Hosting Partner.
Refer Dedicated Servers. We Manage Them. You Get 10% Monthly Commission!
INetU Dedicated Managed Hosting http://www.inetu.net/partner/index.php
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to