Commit 236d8160 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] usb: problem clearing halts

This is a slightly cleaned up version of that earlier patch:

- Makes both copies of the clear_halt() logic know that
   usb_pipein() returns boolean (zero/not) not integer (0/1).
   This resolves a problem folk have had with usb-storage.
   (I looked at kernel uses of usb_pipein and it really was
   only the clear_halt logic that cares.)

- Removes some code from the "standard" version; no point
   in Linux expecting devices to do something neither Microsoft
   nor Apple will test for.
parent 2c6bb9c0
...@@ -686,8 +686,9 @@ void usb_set_maxpacket(struct usb_device *dev) ...@@ -686,8 +686,9 @@ void usb_set_maxpacket(struct usb_device *dev)
* as reported by URB completion status. Endpoints that are halted are * as reported by URB completion status. Endpoints that are halted are
* sometimes referred to as being "stalled". Such endpoints are unable * sometimes referred to as being "stalled". Such endpoints are unable
* to transmit or receive data until the halt status is cleared. Any URBs * to transmit or receive data until the halt status is cleared. Any URBs
* queued queued for such an endpoint should normally be unlinked before * queued for such an endpoint should normally be unlinked by the driver
* clearing the halt condition. * before clearing the halt condition, as described in sections 5.7.5
* and 5.8.5 of the USB 2.0 spec.
* *
* Note that control and isochronous endpoints don't halt, although control * Note that control and isochronous endpoints don't halt, although control
* endpoints report "protocol stall" (for unsupported requests) using the * endpoints report "protocol stall" (for unsupported requests) using the
...@@ -701,48 +702,34 @@ void usb_set_maxpacket(struct usb_device *dev) ...@@ -701,48 +702,34 @@ void usb_set_maxpacket(struct usb_device *dev)
int usb_clear_halt(struct usb_device *dev, int pipe) int usb_clear_halt(struct usb_device *dev, int pipe)
{ {
int result; int result;
__u16 status; int endp = usb_pipeendpoint(pipe);
unsigned char *buffer;
int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
/* if (usb_pipein (pipe))
if (!usb_endpoint_halted(dev, endp & 0x0f, usb_endpoint_out(endp))) endp |= USB_DIR_IN;
return 0;
*/
/* we don't care if it wasn't halted first. in fact some devices
* (like some ibmcam model 1 units) seem to expect hosts to make
* this request for iso endpoints, which can't halt!
*/
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0,
HZ * USB_CTRL_SET_TIMEOUT); HZ * USB_CTRL_SET_TIMEOUT);
/* don't clear if failed */ /* don't un-halt or force to DATA0 except on success */
if (result < 0)
return result;
buffer = kmalloc(sizeof(status), GFP_KERNEL);
if (!buffer) {
err("unable to allocate memory for configuration descriptors");
return -ENOMEM;
}
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, endp,
// FIXME USB_CTRL_GET_TIMEOUT, yes? why not usb_get_status() ?
buffer, sizeof(status), HZ * USB_CTRL_SET_TIMEOUT);
memcpy(&status, buffer, sizeof(status));
kfree(buffer);
if (result < 0) if (result < 0)
return result; return result;
if (le16_to_cpu(status) & 1) /* NOTE: seems like Microsoft and Apple don't bother verifying
return -EPIPE; /* still halted */ * the clear "took", so some devices could lock up if you check...
* such as the Hagiwara FlashGate DUAL. So we won't bother.
usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); *
* NOTE: make sure the logic here doesn't diverge much from
/* toggle is reset on clear */ * the copy in usb-storage, for as long as we need two copies.
*/
/* toggle was reset by the clear, then ep was reactivated */
usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
return 0; return 0;
} }
......
...@@ -518,7 +518,10 @@ int usb_stor_bulk_msg(struct us_data *us, void *data, unsigned int pipe, ...@@ -518,7 +518,10 @@ int usb_stor_bulk_msg(struct us_data *us, void *data, unsigned int pipe,
int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
{ {
int result; int result;
int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); int endp = usb_pipeendpoint(pipe);
if (usb_pipein (pipe))
endp |= USB_DIR_IN;
result = usb_stor_control_msg(us, us->send_ctrl_pipe, result = usb_stor_control_msg(us, us->send_ctrl_pipe,
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment