usb_hid: fix STALL handling

It is not allowed to do synchronous calls to the usb bus manager
while in a usb callback routine. This causes the usb stack to get
very confused.

This code now uses the async interface to clear the STALL, and will
try to continue normal operations after that request has been handled.

Fix sponsered by http://www.izcorp.com
This commit is contained in:
Ithamar R. Adema 2015-03-15 17:34:47 +00:00
parent 7f440923c8
commit f1a02a8e1e
2 changed files with 23 additions and 3 deletions

View File

@ -170,6 +170,7 @@ HIDDevice::HIDDevice(usb_device device, const usb_configuration_info *config,
if ((descriptor->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) if ((descriptor->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
&& (descriptor->attributes & USB_ENDPOINT_ATTR_MASK) && (descriptor->attributes & USB_ENDPOINT_ATTR_MASK)
== USB_ENDPOINT_ATTR_INTERRUPT) { == USB_ENDPOINT_ATTR_INTERRUPT) {
fEndpointAddress = descriptor->endpoint_address;
fInterruptPipe = interface->endpoint[i].handle; fInterruptPipe = interface->endpoint[i].handle;
break; break;
} }
@ -309,6 +310,20 @@ HIDDevice::ProtocolHandlerAt(uint32 index) const
} }
void
HIDDevice::_UnstallCallback(void *cookie, status_t status, void *data,
size_t actualLength)
{
HIDDevice *device = (HIDDevice *)cookie;
if (status != B_OK) {
TRACE_ALWAYS("Unable to unstall device: %s\n", strerror(status));
}
// Now report the original failure, since we're ready to retry
_TransferCallback(cookie, B_ERROR, device->fTransferBuffer, 0);
}
void void
HIDDevice::_TransferCallback(void *cookie, status_t status, void *data, HIDDevice::_TransferCallback(void *cookie, status_t status, void *data,
size_t actualLength) size_t actualLength)
@ -316,10 +331,11 @@ HIDDevice::_TransferCallback(void *cookie, status_t status, void *data,
HIDDevice *device = (HIDDevice *)cookie; HIDDevice *device = (HIDDevice *)cookie;
if (status == B_DEV_STALLED && !device->fRemoved) { if (status == B_DEV_STALLED && !device->fRemoved) {
// try clearing stalls right away, the report listeners will resubmit // try clearing stalls right away, the report listeners will resubmit
gUSBModule->clear_feature(device->fInterruptPipe, gUSBModule->queue_request(device->fDevice,
USB_FEATURE_ENDPOINT_HALT); USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, USB_REQUEST_CLEAR_FEATURE,
USB_FEATURE_ENDPOINT_HALT, device->fEndpointAddress, 0, NULL, _UnstallCallback, device);
return;
} }
atomic_set(&device->fTransferScheduled, 0); atomic_set(&device->fTransferScheduled, 0);
device->fParser.SetReport(status, device->fTransferBuffer, actualLength); device->fParser.SetReport(status, device->fTransferBuffer, actualLength);
} }

View File

@ -48,12 +48,16 @@ private:
static void _TransferCallback(void *cookie, static void _TransferCallback(void *cookie,
status_t status, void *data, status_t status, void *data,
size_t actualLength); size_t actualLength);
static void _UnstallCallback(void *cookie,
status_t status, void *data,
size_t actualLength);
private: private:
status_t fStatus; status_t fStatus;
usb_device fDevice; usb_device fDevice;
usb_pipe fInterruptPipe; usb_pipe fInterruptPipe;
size_t fInterfaceIndex; size_t fInterfaceIndex;
uint8 fEndpointAddress;
int32 fTransferScheduled; int32 fTransferScheduled;
size_t fTransferBufferSize; size_t fTransferBufferSize;