# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#                  ChangeSet    1.639   -> 1.640  
#       drivers/usb/input/hid.h 1.16    -> 1.17   
#       drivers/usb/input/hid-debug.h   1.6     -> 1.7    
#       include/linux/hiddev.h  1.4     -> 1.5    
#       Documentation/usb/hiddev.txt    1.2     -> 1.3    
#       drivers/usb/input/hid-input.c   1.7     -> 1.8    
#       drivers/usb/input/hiddev.c      1.16    -> 1.17   
#       drivers/usb/input/hid-core.c    1.27    -> 1.28   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/07/15      [EMAIL PROTECTED] 1.640
# [PATCH] Updates for hiddev by Paul Stewart
# 
# I've merged a patch Paul Stewart sent me some time ago, which should make life
# easier for the guys writing UPS daemons.
# --------------------------------------------
#
diff -Nru a/Documentation/usb/hiddev.txt b/Documentation/usb/hiddev.txt
--- a/Documentation/usb/hiddev.txt      Mon Jul 15 18:05:09 2002
+++ b/Documentation/usb/hiddev.txt      Mon Jul 15 18:05:09 2002
@@ -18,7 +18,7 @@
 The data flow for a HID event produced by a device is something like
 the following :
 
- usb.c ---> hid-core.c  ----> input.c ----> [keyboard/mouse/joystick/event]
+ usb.c ---> hid-core.c  ----> hid-input.c ----> [keyboard/mouse/joystick/event]
                          |
                          |
                           --> hiddev.c ----> POWER / MONITOR CONTROL 
@@ -106,6 +106,15 @@
 collections the device has from the num_applications field from the
 hiddev_devinfo structure. 
 
+HIDIOCGCOLLECTIONINFO - struct hiddev_collection_info (read/write)
+This returns a superset of the information above, providing not only
+application collections, but all the collections the device has.  It
+also returns the level the collection lives in the hierarchy.
+The user passes in a hiddev_collection_info struct with the index 
+field set to the index that should be returned.  The ioctl fills in 
+the other fields.  If the index is larger than the last collection 
+index, the ioctl returns -1 and sets errno to -EINVAL.
+
 HIDIOCGDEVINFO - struct hiddev_devinfo (read)
 Gets a hiddev_devinfo structure which describes the device.
 
@@ -171,6 +180,10 @@
 Sets the value of a usage in an output report.  The user fills in
 the hiddev_usage_ref structure as above, but additionally fills in
 the value field.
+
+HIDIOGCOLLECTIONINDEX - struct hiddev_usage_ref (write)
+Returns the collection index associated with this usage.  This
+indicates where in the collection hierarchy this usage sits.
 
 HIDIOCGFLAG - int (read)
 HIDIOCSFLAG - int (write)
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c      Mon Jul 15 18:05:09 2002
+++ b/drivers/usb/input/hid-core.c      Mon Jul 15 18:05:09 2002
@@ -127,18 +127,41 @@
 
        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 +189,8 @@
 {
        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 +204,11 @@
                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;
 }
 
@@ -221,8 +248,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;
@@ -460,7 +490,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);
@@ -621,17 +651,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;
        }
@@ -643,6 +686,8 @@
 
                if (item.format != HID_ITEM_FORMAT_SHORT) {
                        dbg("unexpected long global item");
+                       kfree(device->rdesc);
+                       kfree(device->collection);
                        hid_free_device(device);
                        kfree(parser);
                        return NULL;
@@ -651,6 +696,8 @@
                if (dispatch_type[item.type](parser, &item)) {
                        dbg("item %u %u %u %u parsing failed\n",
                                item.format, (unsigned)item.size, (unsigned)item.type, 
(unsigned)item.tag);
+                       kfree(device->rdesc);
+                       kfree(device->collection);
                        hid_free_device(device);
                        kfree(parser);
                        return NULL;
@@ -659,12 +706,16 @@
                if (start == end) {
                        if (parser->collection_stack_ptr) {
                                dbg("unbalanced collection at end of report 
description");
+                               kfree(device->rdesc);
+                               kfree(device->collection);
                                hid_free_device(device);
                                kfree(parser);
                                return NULL;
                        }
                        if (parser->local.delimiter_depth) {
                                dbg("unbalanced delimiter at end of report 
description");
+                               kfree(device->rdesc);
+                               kfree(device->collection);
                                hid_free_device(device);
                                kfree(parser);
                                return NULL;
@@ -675,6 +726,8 @@
        }
 
        dbg("item fetching failed at offset %d\n", (int)(end - start));
+       kfree(device->rdesc);
+       kfree(device->collection);
        hid_free_device(device);
        kfree(parser);
        return NULL;
@@ -1284,6 +1337,10 @@
 #define USB_DEVICE_ID_ATEN_2PORTKVM    0x2204
 #define USB_DEVICE_ID_ATEN_4PORTKVM    0x2205
 
+#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;
@@ -1301,6 +1358,8 @@
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
+       { 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 }
 };
 
@@ -1438,6 +1497,27 @@
        return NULL;
 }
 
+static void hid_disconnect(struct usb_device *dev, void *ptr)
+{
+       struct hid_device *hid = ptr;
+
+       usb_unlink_urb(hid->urbin);
+       usb_unlink_urb(hid->urbout);
+       usb_unlink_urb(hid->urbctrl);
+
+       if (hid->claimed & HID_CLAIMED_INPUT)
+               hidinput_disconnect(hid);
+       if (hid->claimed & HID_CLAIMED_HIDDEV)
+               hiddev_disconnect(hid);
+
+       usb_free_urb(hid->urbin);
+       usb_free_urb(hid->urbctrl);
+       if (hid->urbout)
+               usb_free_urb(hid->urbout);
+
+       hid_free_device(hid);
+}
+
 static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
                       const struct usb_device_id *id)
 {
@@ -1462,7 +1542,7 @@
                hid->claimed |= HID_CLAIMED_HIDDEV;
 
        if (!hid->claimed) {
-               hid_free_device(hid);
+               hid_disconnect(dev, hid);
                return NULL;
        }
 
@@ -1476,11 +1556,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;
                }
+       }
 
        usb_make_path(dev, path, 63);
 
@@ -1488,27 +1571,6 @@
                hid->version >> 8, hid->version & 0xff, c, hid->name, path);
 
        return hid;
-}
-
-static void hid_disconnect(struct usb_device *dev, void *ptr)
-{
-       struct hid_device *hid = ptr;
-
-       usb_unlink_urb(hid->urbin);
-       usb_unlink_urb(hid->urbout);
-       usb_unlink_urb(hid->urbctrl);
-
-       if (hid->claimed & HID_CLAIMED_INPUT)
-               hidinput_disconnect(hid);
-       if (hid->claimed & HID_CLAIMED_HIDDEV)
-               hiddev_disconnect(hid);
-
-       usb_free_urb(hid->urbin);
-       usb_free_urb(hid->urbctrl);
-       if (hid->urbout)
-               usb_free_urb(hid->urbout);
-
-       hid_free_device(hid);
 }
 
 static struct usb_device_id hid_usb_ids [] = {
diff -Nru a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h
--- a/drivers/usb/input/hid-debug.h     Mon Jul 15 18:05:09 2002
+++ b/drivers/usb/input/hid-debug.h     Mon Jul 15 18:05:09 2002
@@ -352,12 +352,6 @@
        unsigned i,k;
        static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
        
-       for (i = 0; i < device->maxapplication; i++) {
-               printk("Application(");
-               resolv_usage(device->application[i]);
-               printk(")\n");
-       }
-
        for (i = 0; i < HID_REPORT_TYPES; i++) {
                report_enum = device->report_enum + i;
                list = report_enum->report_list.next;
diff -Nru a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
--- a/drivers/usb/input/hid-input.c     Mon Jul 15 18:05:09 2002
+++ b/drivers/usb/input/hid-input.c     Mon Jul 15 18:05:09 2002
@@ -474,11 +474,12 @@
        struct list_head *list;
        int i, j, k;
 
-       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;
 
        hid->input.private = hid;
diff -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
--- a/drivers/usb/input/hid.h   Mon Jul 15 18:05:09 2002
+++ b/drivers/usb/input/hid.h   Mon Jul 15 18:05:09 2002
@@ -205,6 +205,7 @@
 #define HID_QUIRK_NOTOUCH      0x02
 #define HID_QUIRK_IGNORE       0x04
 #define HID_QUIRK_NOGET                0x08
+#define HID_QUIRK_HIDDEV       0x10
 
 /*
  * This is the global enviroment of the parser. This information is
@@ -231,10 +232,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;
@@ -249,10 +251,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 */
@@ -319,7 +323,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 
*/
@@ -374,7 +380,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/input/hiddev.c b/drivers/usb/input/hiddev.c
--- a/drivers/usb/input/hiddev.c        Mon Jul 15 18:05:09 2002
+++ b/drivers/usb/input/hiddev.c        Mon Jul 15 18:05:09 2002
@@ -80,6 +80,7 @@
 static struct hid_report *
 hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
 {
+       unsigned flags = rinfo->report_id & ~HID_REPORT_ID_MASK;
        struct hid_report_enum *report_enum;
        struct list_head *list;
 
@@ -88,27 +89,28 @@
 
        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];
@@ -256,8 +258,7 @@
 /*
  * "write" file op
  */
-static ssize_t hiddev_write(struct file * file, const char * buffer,
-                           size_t count, loff_t *ppos)
+static ssize_t hiddev_write(struct file * file, const char * buffer, size_t count, 
+loff_t *ppos)
 {
        return -EINVAL;
 }
@@ -265,8 +266,7 @@
 /*
  * "read" file op
  */
-static ssize_t hiddev_read(struct file * file, char * buffer, size_t count,
-                          loff_t *ppos)
+static ssize_t hiddev_read(struct file * file, char * buffer, size_t count, loff_t 
+*ppos)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct hiddev_list *list = file->private_data;
@@ -354,17 +354,20 @@
 /*
  * "ioctl" file op
  */
-static int hiddev_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, unsigned long arg)
+static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 
+unsigned long arg)
 {
        struct hiddev_list *list = file->private_data;
        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;
 
@@ -376,11 +379,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;
@@ -390,7 +400,6 @@
                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);
@@ -438,7 +447,6 @@
                }
 
        case HIDIOCINITREPORT:
-
                hid_init_reports(hid);
 
                return 0;
@@ -483,8 +491,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;
@@ -513,7 +519,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)))
@@ -536,9 +541,14 @@
                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 != HIDIOCGUSAGE && 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)
@@ -557,37 +567,35 @@
                                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));
+                               return 0;
+
+                       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;
+               }
 
-       case HIDIOCSUSAGE:
-               if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
+               return 0;
+
+       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;
-               }
-
-               field->value[uref.usage_index] = uref.value;
+               cinfo.type = hid->collection[cinfo.index].type;
+               cinfo.usage = hid->collection[cinfo.index].usage;
+               cinfo.level = hid->collection[cinfo.index].level;
 
+               if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo)))
+                       return -EFAULT;
                return 0;
 
        default:
@@ -628,11 +636,13 @@
        int retval;
        char devfs_name[16];
 
-       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 && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
                return -1;
 
        retval = usb_register_dev(&hiddev_fops, HIDDEV_MINOR_BASE, 1, &minor);
@@ -657,10 +667,8 @@
 
        sprintf(devfs_name, "hiddev%d", minor);
        hiddev->devfs = devfs_register(hiddev_devfs_handle, devfs_name,
-                                      DEVFS_FL_DEFAULT, USB_MAJOR,
-                                      minor + HIDDEV_MINOR_BASE,
-                                      S_IFCHR | S_IRUGO | S_IWUSR,
-                                      &hiddev_fops, NULL);
+               DEVFS_FL_DEFAULT, USB_MAJOR, minor + HIDDEV_MINOR_BASE,
+               S_IFCHR | S_IRUGO | S_IWUSR, &hiddev_fops, NULL);
        hid->minor = minor;
        hid->hiddev = hiddev;
 
diff -Nru a/include/linux/hiddev.h b/include/linux/hiddev.h
--- a/include/linux/hiddev.h    Mon Jul 15 18:05:09 2002
+++ b/include/linux/hiddev.h    Mon Jul 15 18:05:09 2002
@@ -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;
@@ -64,9 +71,9 @@
 /* To do a GUSAGE/SUSAGE, fill in at least usage_code,  report_type and 
  * report_id.  Set report_id to REPORT_ID_UNKNOWN if the rest of the fields 
  * are unknown.  Otherwise use a usage_ref struct filled in from a previous 
- * successful GUSAGE/SUSAGE call to save time.  To actually send a value
- * to the device, perform a SUSAGE first, followed by a SREPORT.  If an
- * INITREPORT is done, a GREPORT isn't necessary before a GUSAGE.
+ * successful GUSAGE call to save time.  To actually send a value to the
+ * device, perform a SUSAGE first, followed by a SREPORT.  An INITREPORT or a
+ * GREPORT isn't necessary for a GUSAGE to return valid data.
  */
 #define HID_REPORT_ID_UNKNOWN 0xffffffff
 #define HID_REPORT_ID_FIRST   0x00000100
@@ -129,7 +136,7 @@
  * Protocol version.
  */
 
-#define HID_VERSION            0x010003
+#define HID_VERSION            0x010004
 
 /*
  * IOCTLs (0x00 - 0x7f)
@@ -150,6 +157,8 @@
 #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
@@ -197,7 +206,7 @@
 int __init hiddev_init(void);
 void __exit hiddev_exit(void);
 #else
-static inline void *hiddev_connect(struct hid_device *hid) { return NULL; }
+static inline int hiddev_connect(struct hid_device *hid) { return -1; }
 static inline void hiddev_disconnect(struct hid_device *hid) { }
 static inline void hiddev_event(struct hid_device *hid, unsigned int usage, int 
value) { }
 static inline int hiddev_init(void) { return 0; }


-------------------------------------------------------
This sf.net email is sponsored by: Jabber - The world's fastest growing 
real-time communications platform! Don't just IM. Build it in! 
http://www.jabber.com/osdn/xim
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to