The following patch from Paul Stewart (<[EMAIL PROTECTED]>) add two ioctl
flags
for managing objects tree of complex HID devices.
Those two ioctl are:
- HIDIOCGCOLLECTIONINDEX
- HIDIOCGCOLLECTIONINFO
This is needed to avoid problems with redondant HID objects (eg multiple
outlets for an UPS).
Please merge.
Arnaud
=======================================================================================
diff -ur linux-2.4.20-pre10-orig/drivers/usb/hid-core.c
linux-2.4.20-pre10/drivers/usb/hid-core.c
--- linux-2.4.20-pre10-orig/drivers/usb/hid-core.c Tue Oct 15 08:01:27 2002
+++ linux-2.4.20-pre10/drivers/usb/hid-core.c Wed Oct 16 11:00:34 2002
@@ -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) {
@@ -1086,6 +1137,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;
@@ -1115,6 +1170,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 }
};
@@ -1268,11 +1325,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 -ur linux-2.4.20-pre10-orig/drivers/usb/hid-input.c
linux-2.4.20-pre10/drivers/usb/hid-input.c
--- linux-2.4.20-pre10-orig/drivers/usb/hid-input.c Sun Nov 11 10:09:37 2001
+++ linux-2.4.20-pre10/drivers/usb/hid-input.c Wed Oct 16 10:24:54 2002
@@ -384,11 +384,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 -ur linux-2.4.20-pre10-orig/drivers/usb/hid.h
linux-2.4.20-pre10/drivers/usb/hid.h
--- linux-2.4.20-pre10-orig/drivers/usb/hid.h Tue Oct 15 08:01:27 2002
+++ linux-2.4.20-pre10/drivers/usb/hid.h Wed Oct 16 10:19:22 2002
@@ -186,6 +186,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
@@ -213,9 +214,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;
@@ -230,10 +233,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 */
@@ -259,6 +264,7 @@
unsigned unit_exponent;
unsigned unit;
struct hid_report *report; /* associated report */
+ unsigned index; /* index into report->field[] */
};
#define HID_MAX_FIELDS 64
@@ -297,7 +303,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 */
@@ -332,7 +340,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 -ur linux-2.4.20-pre10-orig/drivers/usb/hiddev.c
linux-2.4.20-pre10/drivers/usb/hiddev.c
--- linux-2.4.20-pre10-orig/drivers/usb/hiddev.c Sat Oct 20 19:13:11 2001
+++ linux-2.4.20-pre10/drivers/usb/hiddev.c Wed Oct 16 10:14:28 2002
@@ -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,45 @@
}
/*
+ * 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;
+
+ hiddev_send_event(hid, &uref);
+}
+
+/*
* fasync file op
*/
static int hiddev_fasync(int fd, struct file *file, int on)
@@ -193,7 +235,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 +250,6 @@
}
kfree(list);
- unlock_kernel();
return 0;
}
@@ -259,43 +299,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 +392,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 +411,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 +432,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 +479,6 @@
}
case HIDIOCINITREPORT:
-
hid_init_reports(hid);
return 0;
@@ -432,8 +523,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 +551,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 +573,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 +600,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 +664,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 -ur linux-2.4.20-pre10-orig/include/linux/hiddev.h
linux-2.4.20-pre10/include/linux/hiddev.h
--- linux-2.4.20-pre10-orig/include/linux/hiddev.h Tue Oct 15 08:01:28 2002
+++ linux-2.4.20-pre10/include/linux/hiddev.h Wed Oct 16 10:19:22 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;
@@ -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,20 @@
#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);
+void hiddev_report_event(struct hid_device *hid, struct hid_report *report);
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 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:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel