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