On Fri, Jun 08, 2001 at 07:43:31AM +1000, root wrote: > While running a descriptor dump (code attached) on my USB speakers with > the hiddev ioctl()s in 2.4.5-ac7, I hit the following oops using JE's > UHCI. Repeatable on this HCD, not tried on OHCI or GA's UHCI. > > >>EIP; 00000000 Before first symbol > Trace; c885d423 <[hid]hiddev_ioctl+293/920> > Trace; c019a702 <write_chan+1d2/1f0> > Trace; c019534d <tty_write+26d/350> > Trace; c019a530 <write_chan+0/1f0> > Trace; c0196ec2 <tty_ioctl+3d2/3f0> > Trace; c014e8b7 <sys_ioctl+237/2c0> > Trace; c0107437 <system_call+33/38> > > On a related note, what is the concensus about whether speaker HID > should be directed to input or to raw HID events? I am currently > thinking input events, because that would allow common work with > equivalent buttons on a keyboard. It doesn't work in -ac7. My fault. A patch against ac9 (already sent to Alan) to make it work is attached. -- Vojtech Pavlik SuSE Labs
diff -urN linux-2.4.5-ac9/drivers/usb/hid-core.c linux/drivers/usb/hid-core.c --- linux-2.4.5-ac9/drivers/usb/hid-core.c Wed Jun 6 10:41:18 2001 +++ linux/drivers/usb/hid-core.c Wed Jun 6 15:13:52 2001 @@ -737,7 +737,7 @@ hidinput_hid_event(hid, field, usage, value); #ifdef CONFIG_USB_HIDDEV if (hid->claimed & HID_CLAIMED_HIDDEV) - hiddev_hid_event(hid->hiddev.private, usage->hid, value); + hiddev_hid_event(hid, usage->hid, value); #endif } @@ -796,9 +796,9 @@ memcpy(field->value, value, count * sizeof(__s32)); } -static int hid_input_report(u8 *data, int len, struct hid_device *hid) +static int hid_input_report(int type, u8 *data, int len, struct hid_device *hid) { - struct hid_report_enum *report_enum = hid->report_enum + HID_INPUT_REPORT; + struct hid_report_enum *report_enum = hid->report_enum + type; struct hid_report *report; int n, size; @@ -884,14 +884,14 @@ return; } - hid_input_report(urb->transfer_buffer, urb->actual_length, urb->context); + hid_input_report(HID_INPUT_REPORT, urb->transfer_buffer, urb->actual_length, +urb->context); } /* * hid_read_report() reads in report values without waiting for an irq urb. */ -static void hid_read_report(struct hid_device *hid, struct hid_report *report) +void hid_read_report(struct hid_device *hid, struct hid_report *report) { int len = ((report->size - 1) >> 3) + 1 + hid->report_enum[report->type].numbered; u8 data[len]; @@ -902,7 +902,7 @@ return; } - hid_input_report(data, len, hid); + hid_input_report(report->type, data, len, hid); } /* @@ -1051,7 +1051,7 @@ /* * Initialize all readable reports */ -static void hid_init_reports(struct hid_device *hid) +void hid_init_reports(struct hid_device *hid) { int i; struct hid_report *report; @@ -1126,7 +1126,7 @@ } #ifdef DEBUG_DATA - printk(KERN_DEBUG __FILE__ ": report (size %u, read %d) = ", rsize, n); + printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = +", rsize, n); for (n = 0; n < rsize; n++) printk(" %02x", (unsigned) rdesc[n]); printk("\n"); @@ -1232,7 +1232,7 @@ if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV)) printk(","); if (hid->claimed & HID_CLAIMED_HIDDEV) - printk("hiddev%d", hid->hiddev.minor); + printk("hiddev%d", hid->minor); c = "Device"; for (i = 0; i < hid->maxapplication; i++) diff -urN linux-2.4.5-ac9/drivers/usb/hid-debug.h linux/drivers/usb/hid-debug.h --- linux-2.4.5-ac9/drivers/usb/hid-debug.h Wed Jun 6 10:41:18 2001 +++ linux/drivers/usb/hid-debug.h Wed Jun 6 14:03:47 2001 @@ -231,7 +231,7 @@ } static void hid_dump_input(struct hid_usage *usage, __s32 value) { - printk("hidd: input "); + printk("hid-debug: input "); resolv_usage(usage->hid); printk(" = %d\n", value); } diff -urN linux-2.4.5-ac9/drivers/usb/hid.h linux/drivers/usb/hid.h --- linux-2.4.5-ac9/drivers/usb/hid.h Wed Jun 6 10:41:18 2001 +++ linux/drivers/usb/hid.h Wed Jun 6 15:12:12 2001 @@ -288,14 +288,6 @@ char buffer[HID_BUFFER_SIZE]; }; -struct hid_iodev { - int minor; - void *private; /* hiddev opaque device structure */ - void (*read_report)(struct hid_device *, struct hid_report *); - void (*read_all_reports)(struct hid_device *); - void (*write_report)(struct hid_device *, struct hid_report *); -}; - #define HID_CLAIMED_INPUT 1 #define HID_CLAIMED_HIDDEV 2 @@ -322,7 +314,8 @@ unsigned quirks; /* Various quirks the device can pull on us */ struct input_dev input; /* The input structure */ - struct hid_iodev hiddev; /* The hiddev structure */ + void *hiddev; /* The hiddev +structure */ + int minor; /* Hiddev +minor number */ int open; /* is the device open by anyone? */ char name[128]; /* Device name */ @@ -376,3 +369,5 @@ int hid_find_field(struct hid_device *, unsigned int, unsigned int, struct hid_field **); int hid_set_field(struct hid_field *, unsigned, __s32); void hid_write_report(struct hid_device *, struct hid_report *); +void hid_read_report(struct hid_device *, struct hid_report *); +void hid_init_reports(struct hid_device *hid); diff -urN linux-2.4.5-ac9/drivers/usb/hiddev.c linux/drivers/usb/hiddev.c --- linux-2.4.5-ac9/drivers/usb/hiddev.c Wed Jun 6 10:41:18 2001 +++ linux/drivers/usb/hiddev.c Wed Jun 6 15:14:54 2001 @@ -146,9 +146,9 @@ * This is where hid.c calls into hiddev to pass an event that occurred over * the interrupt pipe */ -void hiddev_hid_event(void *private, unsigned int usage, int value) +void hiddev_hid_event(struct hid_device *hid, unsigned int usage, int value) { - struct hiddev *hiddev = private; + struct hiddev *hiddev = hid->hiddev; struct hiddev_list *list = hiddev->list; while (list) { @@ -176,15 +176,6 @@ } /* - * If there are no more readers, deregister interest in interrupt events - */ -static void hiddev_close(struct hiddev *hiddev) -{ - struct hid_device *hid = hiddev->hid; - if (!--hid->open) usb_unlink_urb(&hid->urb); -} - -/* * De-allocate a hiddev structure */ static void hiddev_cleanup(struct hiddev *hiddev) @@ -211,11 +202,10 @@ *listptr = (*listptr)->next; if (!--list->hiddev->open) { - if (list->hiddev->exist) { - hiddev_close(list->hiddev); - } else { + if (list->hiddev->exist) + hid_close(list->hiddev->hid); + else hiddev_cleanup(list->hiddev); - } } kfree(list); @@ -229,7 +219,6 @@ */ static int hiddev_open(struct inode * inode, struct file * file) { struct hiddev_list *list; - struct hid_device *hid; int i = MINOR(inode->i_rdev) - HIDDEV_MINOR_BASE; @@ -247,13 +236,8 @@ file->private_data = list; if (!list->hiddev->open++) - if (list->hiddev->exist) { - hid = hiddev_table[i]->hid; - if (!hid->open++) { - hid->urb.dev = hid->dev; - if (usb_submit_urb(&hid->urb)) return -EIO; - } - } + if (list->hiddev->exist) + hid_open(hiddev_table[i]->hid); return 0; } @@ -403,7 +387,8 @@ } case HIDIOCINITREPORT: - (*hid->hiddev.read_all_reports)(hid); + + hid_init_reports(hid); return 0; @@ -417,7 +402,7 @@ if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - (*hid->hiddev.read_report)(hid, report); + hid_read_report(hid, report); return 0; @@ -431,7 +416,7 @@ if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - (*hid->hiddev.write_report)(hid, report); + hid_write_report(hid, report); return 0; @@ -622,8 +607,8 @@ minor + HIDDEV_MINOR_BASE, S_IFCHR | S_IRUGO | S_IWUSR, &hiddev_fops, NULL); - hid->hiddev.minor = minor; - hid->hiddev.private = hiddev; + hid->minor = minor; + hid->hiddev = hiddev; return 0; } @@ -632,14 +617,14 @@ * This is where hid.c calls us to disconnect a hiddev device from the * corresponding hid device (usually because the usb device has disconnected) */ -void hiddev_disconnect(void *private) +void hiddev_disconnect(struct hid_device *hid) { - struct hiddev *hiddev = private; + struct hiddev *hiddev = hid->hiddev; hiddev->exist = 0; if (hiddev->open) { - hiddev_close(hiddev); + hid_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); } else { hiddev_cleanup(hiddev); diff -urN linux-2.4.5-ac9/include/linux/hiddev.h linux/include/linux/hiddev.h --- linux-2.4.5-ac9/include/linux/hiddev.h Wed Jun 6 10:41:19 2001 +++ linux/include/linux/hiddev.h Wed Jun 6 15:16:12 2001 @@ -178,14 +178,14 @@ #ifdef CONFIG_USB_HIDDEV int hiddev_connect(struct hid_device *); -void hiddev_disconnect(void *); -void hiddev_hid_event(void *private, unsigned int usage, int value); +void hiddev_disconnect(struct hid_device *); +void hiddev_hid_event(struct hid_device *, unsigned int usage, int value); int __init hiddev_init(void); void __exit hiddev_exit(void); #else static inline void *hiddev_connect(struct hid_device *hid) { return NULL; } -static inline void hiddev_disconnect(void *private) { } -static inline void hiddev_event(void *private, unsigned int usage, int value) { } +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; } static inline void hiddev_exit(void) { } #endif