summaryrefslogtreecommitdiff
blob: 6d644d972e6be0e33f20a52f37d6dfa41a952d52 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2005/01/13 13:32:43+01:00 vojtech@suse.cz 
#   input: Handle -EILSEQ return code in the HID driver completion
#          handlers as unplug.
#          Flush request queue on unplug, too.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-core.c
#   2005/01/13 13:32:33+01:00 vojtech@suse.cz +18 -5
#   input: Handle -EILSEQ return code in the HID driver completion
#          handlers as unplug.
#          Flush request queue on unplug, too.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
--- ./drivers/usb/input/hid-core.c.ukbdt	2006-02-16 14:10:14.000000000 +0300
+++ ./drivers/usb/input/hid-core.c	2006-02-16 15:18:35.000000000 +0300
@@ -924,7 +924,8 @@ static void hid_irq_in(struct urb *urb, 
 			break;
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
-		case -ESHUTDOWN:
+		case -ESHUTDOWN:	/* unplug */
+		case -EILSEQ:		/* unplug timeout on uhci */
 			return;
 		default:		/* error */
 			warn("input irq status %d received", urb->status);
@@ -1132,12 +1133,15 @@ static void hid_irq_out(struct urb *urb,
 {
 	struct hid_device *hid = urb->context;
 	unsigned long flags;
+	int unplug = 0;
 
 	switch (urb->status) {
 		case 0:			/* success */
+		case -ESHUTDOWN:	/* unplug */
+		case -EILSEQ:		/* unplug timeout on uhci */
+			unplug = 1;
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
-		case -ESHUTDOWN:
 			break;
 		default:		/* error */
 			warn("output irq status %d received", urb->status);
@@ -1145,7 +1149,10 @@ static void hid_irq_out(struct urb *urb,
 
 	spin_lock_irqsave(&hid->outlock, flags);
 
-	hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
+	if (unplug)
+		hid->outtail = hid->outhead;
+	else
+		hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
 
 	if (hid->outhead != hid->outtail) {
 		if (hid_submit_out(hid)) {
@@ -1169,6 +1176,7 @@ static void hid_ctrl(struct urb *urb, st
 {
 	struct hid_device *hid = urb->context;
 	unsigned long flags;
+	int unplug = 0;
 
 	spin_lock_irqsave(&hid->ctrllock, flags);
 
@@ -1176,16 +1184,21 @@ static void hid_ctrl(struct urb *urb, st
 		case 0:			/* success */
 			if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) 
 				hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, regs);
+		case -ESHUTDOWN:	/* unplug */
+		case -EILSEQ:		/* unplug timectrl on uhci */
+			unplug = 1;
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
-		case -ESHUTDOWN:
 		case -EPIPE:		/* report not available */
 			break;
 		default:		/* error */
 			warn("ctrl urb status %d received", urb->status);
 	}
 
-	hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+	if (unplug)
+		hid->ctrltail = hid->ctrlhead;
+	else
+		hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
 
 	if (hid->ctrlhead != hid->ctrltail) {
 		if (hid_submit_ctrl(hid)) {