18
18
#define LOG_TAG "USBPM: "
19
19
20
20
static struct usb_dev_sys_ctx_info g_ctx ;
21
+ static inline uint8_t usb_dev_get_ep_type (struct usb_dev * udev , int pid ,
22
+ int epnum );
21
23
22
24
static void
23
25
usb_dev_comp_req (struct libusb_transfer * libusb_xfer )
@@ -30,12 +32,15 @@ usb_dev_comp_req(struct libusb_transfer *libusb_xfer)
30
32
int bstart , bcount ;
31
33
32
34
assert (libusb_xfer );
33
- assert (libusb_xfer -> user_data );
34
35
36
+ /* async request */
35
37
req = libusb_xfer -> user_data ;
36
38
len = libusb_xfer -> actual_length ;
37
- xfer = req -> xfer ;
39
+ assert (req );
40
+ assert (req -> udev );
38
41
42
+ /* async transfer */
43
+ xfer = req -> xfer ;
39
44
assert (xfer );
40
45
assert (xfer -> dev );
41
46
@@ -52,13 +57,39 @@ usb_dev_comp_req(struct libusb_transfer *libusb_xfer)
52
57
USB_DATA_XFER_LOCK (xfer );
53
58
xfer -> status = USB_ERR_NORMAL_COMPLETION ;
54
59
60
+ switch (libusb_xfer -> status ) {
61
+ case LIBUSB_TRANSFER_STALL :
62
+ xfer -> status = USB_ERR_STALLED ;
63
+ goto out ;
64
+ case LIBUSB_TRANSFER_NO_DEVICE :
65
+ case LIBUSB_TRANSFER_ERROR :
66
+ case LIBUSB_TRANSFER_TIMED_OUT :
67
+ case LIBUSB_TRANSFER_CANCELLED :
68
+ case LIBUSB_TRANSFER_OVERFLOW :
69
+ /* FIXME: should treat every failure properly */
70
+ UPRINTF (LWRN , "failure: %x\r\n" , libusb_xfer -> status );
71
+ break ;
72
+ case LIBUSB_TRANSFER_COMPLETED :
73
+ break ;
74
+ default :
75
+ UPRINTF (LWRN , "unknown failure: %x\r\n" , libusb_xfer -> status );
76
+ break ;
77
+ }
78
+
55
79
/* in case the xfer is reset by the USB_DATA_XFER_RESET */
56
- if (xfer -> reset == 1 ||
57
- libusb_xfer -> status != LIBUSB_TRANSFER_COMPLETED ) {
80
+ if (xfer -> reset == 1 ) {
58
81
UPRINTF (LDBG , "ep%d reset detected\r\n" , xfer -> epid );
59
82
xfer -> reset = 0 ;
60
- USB_DATA_XFER_UNLOCK (xfer );
61
- goto reset_out ;
83
+ /* ONLY interrupt transfer needs this.
84
+ * The transfer here is an old one before endpoint reset, so it
85
+ * should be discarded. But for bulk transfer, the transfer here
86
+ * is a new one after reset, so it should be kept.
87
+ */
88
+ if (usb_dev_get_ep_type (req -> udev , xfer -> pid & 1 ,
89
+ xfer -> epid / 2 ) == USB_ENDPOINT_INT ) {
90
+ UPRINTF (LDBG , "goto reset out\r\n" );
91
+ goto reset_out ;
92
+ }
62
93
}
63
94
64
95
/* post process the usb transfer data */
@@ -84,10 +115,9 @@ usb_dev_comp_req(struct libusb_transfer *libusb_xfer)
84
115
idx = (idx + 1 ) % USB_MAX_XFER_BLOCKS ;
85
116
}
86
117
87
- reset_out :
88
118
if (short_data )
89
119
xfer -> status = USB_ERR_SHORT_XFER ;
90
-
120
+ out :
91
121
/* notify the USB core this transfer is over */
92
122
if (g_ctx .notify_cb )
93
123
do_intr = g_ctx .notify_cb (xfer -> dev , xfer );
@@ -96,6 +126,7 @@ usb_dev_comp_req(struct libusb_transfer *libusb_xfer)
96
126
if (do_intr && g_ctx .intr_cb )
97
127
g_ctx .intr_cb (xfer -> dev , NULL );
98
128
129
+ reset_out :
99
130
/* unlock and release memory */
100
131
USB_DATA_XFER_UNLOCK (xfer );
101
132
libusb_free_transfer (libusb_xfer );
@@ -649,11 +680,19 @@ usb_dev_request(void *pdata, struct usb_data_xfer *xfer)
649
680
usb_dev_set_if (udev , index , value , xfer );
650
681
goto out ;
651
682
case UREQ (UR_CLEAR_FEATURE , UT_WRITE_ENDPOINT ):
652
- if (value == 0 ) {
653
- UPRINTF (LDBG , "UR_CLEAR_HALT\n" );
654
- libusb_clear_halt (udev -> handle , index );
655
- goto out ;
683
+ if (value ) {
684
+ /* according to usb spec (ch9), this is impossible */
685
+ UPRINTF (LWRN , "Clear Feature request with non-zero "
686
+ "value %d\r\n" , value );
687
+ break ;
656
688
}
689
+
690
+ UPRINTF (LDBG , "UR_CLEAR_HALT\n" );
691
+ rc = libusb_clear_halt (udev -> handle , index );
692
+ if (rc )
693
+ UPRINTF (LWRN , "fail to clear halted ep, rc %d\r\n" , rc );
694
+ goto out ;
695
+
657
696
}
658
697
659
698
/* send it to physical device */
0 commit comments