[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 */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.