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. Please merge. - Dave
--- ./drivers-dist/usb/core/message.c Fri Oct 18 09:48:17 2002 +++ ./drivers/usb/core/message.c Sun Oct 20 18:15:14 2002 @@ -687,6 +687,7 @@ * sometimes referred to as being "stalled". Such endpoints are unable * to transmit or receive data until the halt status is cleared. Any URBs - * queued queued for such an endpoint should normally be unlinked before - * clearing the halt condition. + * queued for such an endpoint should normally be unlinked by the driver + * 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 @@ -702,46 +703,32 @@ { int result; - __u16 status; - unsigned char *buffer; - int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7); - -/* - if (!usb_endpoint_halted(dev, endp & 0x0f, usb_endpoint_out(endp))) - return 0; -*/ - + int endp = usb_pipeendpoint(pipe); + + if (usb_pipein (pipe)) + endp |= USB_DIR_IN; + + /* 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), USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); - /* don't clear if failed */ - 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); - + /* don't un-halt or force to DATA0 except on success */ if (result < 0) return result; - if (le16_to_cpu(status) & 1) - return -EPIPE; /* still halted */ - - usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); - - /* toggle is reset on clear */ + /* NOTE: seems like Microsoft and Apple don't bother verifying + * the clear "took", so some devices could lock up if you check... + * such as the Hagiwara FlashGate DUAL. So we won't bother. + * + * NOTE: make sure the logic here doesn't diverge much from + * 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_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); return 0; --- ./drivers-dist/usb/storage/transport.c Wed Oct 16 14:02:11 2002 +++ ./drivers/usb/storage/transport.c Fri Oct 18 14:29:25 2002 @@ -519,5 +519,8 @@ { 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,