[PATCH] USB: hid for ia64
Linux Kernel Mailing List <[email protected]>
| Newsgroups | gmane.linux.kernel.commits.2-4 |
|---|---|
| Message-ID | <[email protected]> |
ChangeSet 1.1569, 2005/02/14 05:08:11-02:00, [email protected] [PATCH] USB: hid for ia64 Apparently, the HP rx5670 fails to reboot if a USB keyboard if attached without this patch (and the OHCI fix we accepted for 2.4.29). This bug is better known for its effect on Altix, but SGI ships a magic kernel anyhow, so I don't want to use that as justification. The original patch comes from Jes Sorensen, but then I corrupted his idea with my simplifications and a partial backport from 2.6, so if this fails do not e-mail him. hid-core.c | 28 ++++++++++++++++++++++++---- hid.h | 5 +++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff -Nru a/drivers/usb/hid-core.c b/drivers/usb/hid-core.c --- a/drivers/usb/hid-core.c 2005-02-13 18:04:28 -08:00 +++ b/drivers/usb/hid-core.c 2005-02-13 18:04:28 -08:00 @@ -1064,18 +1064,31 @@ static void hid_ctrl(struct urb *urb) { struct hid_device *hid = urb->context; + unsigned long flags; if (urb->status) warn("ctrl urb status %d received", urb->status); + spin_lock_irqsave(&hid->outlock, flags); + hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1); - if (hid->outhead != hid->outtail) - hid_submit_out(hid); + if (hid->outhead != hid->outtail) { + if (hid_submit_out(hid)) { + clear_bit(HID_OUT_RUNNING, &hid->iofl); + } + spin_unlock_irqrestore(&hid->outlock, flags); + return; + } + + clear_bit(HID_OUT_RUNNING, &hid->iofl); + spin_unlock_irqrestore(&hid->outlock, flags); } void hid_write_report(struct hid_device *hid, struct hid_report *report) { + unsigned long flags; + if (hid->report_enum[report->type].numbered) { hid->out[hid->outhead].buffer[0] = report->id; hid_output_report(report, hid->out[hid->outhead].buffer + 1); @@ -1087,13 +1100,18 @@ hid->out[hid->outhead].dr.wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); + spin_lock_irqsave(&hid->outlock, flags); + hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1); if (hid->outhead == hid->outtail) hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1); - if (hid->urbout.status != -EINPROGRESS) - hid_submit_out(hid); + if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl)) + if (hid_submit_out(hid)) + clear_bit(HID_OUT_RUNNING, &hid->iofl); + + spin_unlock_irqrestore(&hid->outlock, flags); } int hid_open(struct hid_device *hid) @@ -1332,6 +1350,8 @@ hid_free_device(hid); return NULL; } + + spin_lock_init(&hid->outlock); hid->version = hdesc->bcdHID; hid->country = hdesc->bCountryCode; diff -Nru a/drivers/usb/hid.h b/drivers/usb/hid.h --- a/drivers/usb/hid.h 2005-02-13 18:04:28 -08:00 +++ b/drivers/usb/hid.h 2005-02-13 18:04:28 -08:00 @@ -302,6 +302,8 @@ #define HID_CLAIMED_INPUT 1 #define HID_CLAIMED_HIDDEV 2 +#define HID_OUT_RUNNING 2 + struct hid_input { struct list_head list; struct hid_report *report; @@ -322,12 +324,15 @@ struct usb_device *dev; /* USB device */ int ifnum; /* USB interface number */ + unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ + struct urb urb; /* USB URB structure */ char buffer[HID_BUFFER_SIZE]; /* Rx buffer */ struct urb urbout; /* Output URB */ struct hid_control_fifo out[HID_CONTROL_FIFO_SIZE]; /* Transmit buffer */ unsigned char outhead, outtail; /* Tx buffer head & tail */ + spinlock_t outlock; /* Output fifo spinlock */ unsigned claimed; /* Claimed by hidinput, hiddev? */ unsigned quirks; /* Various quirks the device can pull on us */