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:
parent
7f440923c8
commit
f1a02a8e1e
@ -170,6 +170,7 @@ HIDDevice::HIDDevice(usb_device device, const usb_configuration_info *config,
|
||||
if ((descriptor->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
|
||||
&& (descriptor->attributes & USB_ENDPOINT_ATTR_MASK)
|
||||
== USB_ENDPOINT_ATTR_INTERRUPT) {
|
||||
fEndpointAddress = descriptor->endpoint_address;
|
||||
fInterruptPipe = interface->endpoint[i].handle;
|
||||
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
|
||||
HIDDevice::_TransferCallback(void *cookie, status_t status, void *data,
|
||||
size_t actualLength)
|
||||
@ -316,10 +331,11 @@ HIDDevice::_TransferCallback(void *cookie, status_t status, void *data,
|
||||
HIDDevice *device = (HIDDevice *)cookie;
|
||||
if (status == B_DEV_STALLED && !device->fRemoved) {
|
||||
// try clearing stalls right away, the report listeners will resubmit
|
||||
gUSBModule->clear_feature(device->fInterruptPipe,
|
||||
USB_FEATURE_ENDPOINT_HALT);
|
||||
gUSBModule->queue_request(device->fDevice,
|
||||
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);
|
||||
device->fParser.SetReport(status, device->fTransferBuffer, actualLength);
|
||||
}
|
||||
|
@ -48,12 +48,16 @@ private:
|
||||
static void _TransferCallback(void *cookie,
|
||||
status_t status, void *data,
|
||||
size_t actualLength);
|
||||
static void _UnstallCallback(void *cookie,
|
||||
status_t status, void *data,
|
||||
size_t actualLength);
|
||||
|
||||
private:
|
||||
status_t fStatus;
|
||||
usb_device fDevice;
|
||||
usb_pipe fInterruptPipe;
|
||||
size_t fInterfaceIndex;
|
||||
uint8 fEndpointAddress;
|
||||
|
||||
int32 fTransferScheduled;
|
||||
size_t fTransferBufferSize;
|
||||
|
Loading…
Reference in New Issue
Block a user