Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

UHCI: short control URBs get a status stage

It has recently been pointed out that short control transfers should
have a status stage, even if they generate an error because
URB_SHORT_NOT_OK was set. This patch (as935) changes uhci-hcd to
enable the status stage when this happens.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
e7e7c360 e94fa28f

+38 -21
+38 -21
drivers/usb/host/uhci-q.c
··· 827 827 * If direction is "send", change the packet ID from SETUP (0x2D) 828 828 * to OUT (0xE1). Else change it from SETUP to IN (0x69) and 829 829 * set Short Packet Detect (SPD) for all data packets. 830 + * 831 + * 0-length transfers always get treated as "send". 830 832 */ 831 - if (usb_pipeout(urb->pipe)) 833 + if (usb_pipeout(urb->pipe) || len == 0) 832 834 destination ^= (USB_PID_SETUP ^ USB_PID_OUT); 833 835 else { 834 836 destination ^= (USB_PID_SETUP ^ USB_PID_IN); ··· 841 839 * Build the DATA TDs 842 840 */ 843 841 while (len > 0) { 844 - int pktsze = min(len, maxsze); 842 + int pktsze = maxsze; 843 + 844 + if (len <= pktsze) { /* The last data packet */ 845 + pktsze = len; 846 + status &= ~TD_CTRL_SPD; 847 + } 845 848 846 849 td = uhci_alloc_td(uhci); 847 850 if (!td) ··· 873 866 goto nomem; 874 867 *plink = LINK_TO_TD(td); 875 868 876 - /* 877 - * It's IN if the pipe is an output pipe or we're not expecting 878 - * data back. 879 - */ 880 - destination &= ~TD_TOKEN_PID_MASK; 881 - if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) 882 - destination |= USB_PID_IN; 883 - else 884 - destination |= USB_PID_OUT; 885 - 869 + /* Change direction for the status transaction */ 870 + destination ^= (USB_PID_IN ^ USB_PID_OUT); 886 871 destination |= TD_TOKEN_TOGGLE; /* End in Data1 */ 887 - 888 - status &= ~TD_CTRL_SPD; 889 872 890 873 uhci_add_td_to_urbp(td, urbp); 891 874 uhci_fill_td(td, status | TD_CTRL_IOC, ··· 1182 1185 } 1183 1186 } 1184 1187 1188 + /* Did we receive a short packet? */ 1185 1189 } else if (len < uhci_expected_length(td_token(td))) { 1186 1190 1187 - /* We received a short packet */ 1188 - if (urb->transfer_flags & URB_SHORT_NOT_OK) 1191 + /* For control transfers, go to the status TD if 1192 + * this isn't already the last data TD */ 1193 + if (qh->type == USB_ENDPOINT_XFER_CONTROL) { 1194 + if (td->list.next != urbp->td_list.prev) 1195 + ret = 1; 1196 + } 1197 + 1198 + /* For bulk and interrupt, this may be an error */ 1199 + else if (urb->transfer_flags & URB_SHORT_NOT_OK) 1189 1200 ret = -EREMOTEIO; 1190 1201 1191 1202 /* Fixup needed only if this isn't the URB's last TD */ ··· 1213 1208 1214 1209 err: 1215 1210 if (ret < 0) { 1216 - /* In case a control transfer gets an error 1217 - * during the setup stage */ 1218 - urb->actual_length = max(urb->actual_length, 0); 1219 - 1220 1211 /* Note that the queue has stopped and save 1221 1212 * the next toggle value */ 1222 1213 qh->element = UHCI_PTR_TERM; ··· 1490 1489 { 1491 1490 struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; 1492 1491 1492 + if (qh->type == USB_ENDPOINT_XFER_CONTROL) { 1493 + 1494 + /* urb->actual_length < 0 means the setup transaction didn't 1495 + * complete successfully. Either it failed or the URB was 1496 + * unlinked first. Regardless, don't confuse people with a 1497 + * negative length. */ 1498 + urb->actual_length = max(urb->actual_length, 0); 1499 + 1500 + /* Report erroneous short transfers */ 1501 + if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && 1502 + urb->actual_length < 1503 + urb->transfer_buffer_length && 1504 + urb->status == 0)) 1505 + urb->status = -EREMOTEIO; 1506 + } 1507 + 1493 1508 /* When giving back the first URB in an Isochronous queue, 1494 1509 * reinitialize the QH's iso-related members for the next URB. */ 1495 - if (qh->type == USB_ENDPOINT_XFER_ISOC && 1510 + else if (qh->type == USB_ENDPOINT_XFER_ISOC && 1496 1511 urbp->node.prev == &qh->queue && 1497 1512 urbp->node.next != &qh->queue) { 1498 1513 struct urb *nurb = list_entry(urbp->node.next,