diff options
| author | Vojtech Pavlik <vojtech@suse.cz> | 2002-07-15 03:18:42 -0700 |
|---|---|---|
| committer | Vojtech Pavlik <vojtech@suse.cz> | 2002-07-15 03:18:42 -0700 |
| commit | b24be862cc6543ef76e17c55cc11c69e2dd8bc62 (patch) | |
| tree | c8bff63819bb2fe833304d075aea553827c1cc96 /drivers/usb/input/hiddev.c | |
| parent | 182147c1e9cae403852ec2e1107fe62b390012be (diff) | |
[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.
Diffstat (limited to 'drivers/usb/input/hiddev.c')
| -rw-r--r-- | drivers/usb/input/hiddev.c | 138 |
1 files changed, 73 insertions, 65 deletions
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 8b93b2f0a1bc..8b5cd439eee7 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -80,6 +80,7 @@ extern struct usb_driver hiddev_driver; 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 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) 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 @@ static int hiddev_open(struct inode * inode, struct file * file) { /* * "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 @@ static ssize_t hiddev_write(struct file * file, const char * buffer, /* * "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 @@ static unsigned int hiddev_poll(struct file *file, poll_table *wait) /* * "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 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, 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 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, 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 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, } case HIDIOCINITREPORT: - hid_init_reports(hid); return 0; @@ -483,8 +491,6 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, 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 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, 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 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, 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 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, return -EINVAL; } - uref.value = field->value[uref.usage_index]; - - return copy_to_user((void *) arg, &uref, sizeof(uref)); + switch (cmd) { + case HIDIOCGUSAGE: + uref.value = field->value[uref.usage_index]; + return copy_to_user((void *) arg, &uref, sizeof(uref)); + return 0; - case HIDIOCSUSAGE: - if (copy_from_user(&uref, (void *) arg, sizeof(uref))) - return -EFAULT; + case HIDIOCSUSAGE: + field->value[uref.usage_index] = uref.value; + return 0; - if (uref.report_type == HID_REPORT_TYPE_INPUT) - return -EINVAL; + case HIDIOCGCOLLECTIONINDEX: + return field->usage[uref.usage_index].collection_index; + } - 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; + return 0; - if (uref.field_index >= report->maxfield) - return -EINVAL; + case HIDIOCGCOLLECTIONINFO: + if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo))) + return -EFAULT; - field = report->field[uref.field_index]; - if (uref.usage_index >= field->maxusage) - return -EINVAL; - } + if (cinfo.index >= hid->maxcollection) + 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 hiddev_connect(struct hid_device *hid) 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 @@ int hiddev_connect(struct hid_device *hid) 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; |
