Currently hid-core follows the same code path for input reports
regardless of whether they are a result of interrupt transfers or
control transfers. That leads to interrupt events erroneously being
reported to hiddev for regular control transfers.

Prior to 2.6.12 the problem was mitigated by the fact that 
reporting to hiddev is supressed if the field value has not changed,
which is often the case. Said filtering was removed in 2.6.12-rc1 which
means any input reports fetched via control transfers result in hiddev
interrupt events. This behavior can quickly lead to a feedback loop
where a userspace app, in response to interrupt events, issues control
transfers which in turn create more interrupt events.

This patch prevents input reports that arrive via control transfers from
being reported to hiddev as interrupt events. The method used to
differentiate the tranfer types is gross; better ideas are welcome.

Signed-off-by: Adam Kropelin <[EMAIL PROTECTED]>


--- linux-2.6.12/drivers/usb/input/hid-core.c   2005-06-17 15:48:29.000000000 
-0400
+++ linux-2.6.12.adk/drivers/usb/input/hid-core.c       2005-06-20 
19:50:47.000000000 -0400
@@ -789,13 +789,20 @@
        return -1;
 }
 
-static void hid_process_event(struct hid_device *hid, struct hid_field *field, 
struct hid_usage *usage, __s32 value, struct pt_regs *regs)
+static void hid_process_event(struct hid_device *hid, struct hid_field *field, 
struct hid_usage *usage, __s32 value, struct urb *urb, struct pt_regs *regs)
 {
        hid_dump_input(usage, value);
        if (hid->claimed & HID_CLAIMED_INPUT)
                hidinput_hid_event(hid, field, usage, value, regs);
-       if (hid->claimed & HID_CLAIMED_HIDDEV)
-               hiddev_hid_event(hid, field, usage, value, regs);
+       if (hid->claimed & HID_CLAIMED_HIDDEV) {
+               if (urb == hid->urbin) {
+                       dbg("Reporting interrupt event to hiddev (rpt 0x%02x)", 
*(u8*)urb->transfer_buffer);
+                       hiddev_hid_event(hid, field, usage, value, regs);
+               } else {
+                       dbg("Not interrupt xfer; skipping hiddev reporting (rpt 
0x%02x)",
+                               *(u8*)urb->transfer_buffer);
+               }
+       }
 }
 
 /*
@@ -804,7 +811,7 @@
  * reporting to the layer).
  */
 
-static void hid_input_field(struct hid_device *hid, struct hid_field *field, 
__u8 *data, struct pt_regs *regs)
+static void hid_input_field(struct hid_device *hid, struct hid_field *field, 
__u8 *data, struct urb *urb, struct pt_regs *regs)
 {
        unsigned n;
        unsigned count = field->report_count;
@@ -831,19 +838,19 @@
        for (n = 0; n < count; n++) {
 
                if (HID_MAIN_ITEM_VARIABLE & field->flags) {
-                       hid_process_event(hid, field, &field->usage[n], 
value[n], regs);
+                       hid_process_event(hid, field, &field->usage[n], 
value[n], urb, regs);
                        continue;
                }
 
                if (field->value[n] >= min && field->value[n] <= max
                        && field->usage[field->value[n] - min].hid
                        && search(value, field->value[n], count))
-                               hid_process_event(hid, field, 
&field->usage[field->value[n] - min], 0, regs);
+                               hid_process_event(hid, field, 
&field->usage[field->value[n] - min], 0, urb, regs);
 
                if (value[n] >= min && value[n] <= max
                        && field->usage[value[n] - min].hid
                        && search(field->value, value[n], count))
-                               hid_process_event(hid, field, 
&field->usage[value[n] - min], 1, regs);
+                               hid_process_event(hid, field, 
&field->usage[value[n] - min], 1, urb, regs);
        }
 
        memcpy(field->value, value, count * sizeof(__s32));
@@ -899,7 +906,7 @@
                hiddev_report_event(hid, report);
 
        for (n = 0; n < report->maxfield; n++)
-               hid_input_field(hid, report->field[n], data, regs);
+               hid_input_field(hid, report->field[n], data, urb, regs);
 
        if (hid->claimed & HID_CLAIMED_INPUT)
                hidinput_report_event(hid, report);


-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to