usb_hid: Let protocol handlers know of their closing.

On close a flag is set in the cookie of this user of a protocol handler
and the device cancels its pending transfer. This wakes up any possible
listeners. When the closed flag is set, an error code is returned from
_ReadReport() which causes the retry loop to be left. Handlers listening
on the same device which were not closed just retry the transfer.

This ensures that closing a device will cause pending control requests
to complete with a sensible error code.
This commit is contained in:
Michael Lotz 2015-04-22 23:22:01 +02:00
parent 6653e74873
commit 25f723de85
10 changed files with 30 additions and 9 deletions

View File

@ -247,6 +247,9 @@ status_t
HIDDevice::Close(ProtocolHandler *handler)
{
atomic_add(&fOpenCount, -1);
gUSBModule->cancel_queued_transfers(fInterruptPipe);
// This will wake up any listeners. Whether they should close or retry
// is handeled internally by the handlers.
return B_OK;
}

View File

@ -337,6 +337,9 @@ JoystickProtocolHandler::_Update()
return B_DEV_NOT_READY;
}
if (result == B_CANCELED)
return B_CANCELED;
if (result != B_INTERRUPTED) {
// interrupts happen when other reports come in on the same
// input as ours

View File

@ -340,7 +340,7 @@ KeyboardProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer,
bigtime_t enterTime = system_time();
while (RingBufferReadable() == 0) {
status_t result = _ReadReport(fCurrentRepeatDelay);
status_t result = _ReadReport(fCurrentRepeatDelay, cookie);
if (result != B_OK && result != B_TIMED_OUT)
return result;
@ -459,7 +459,7 @@ KeyboardProtocolHandler::_SetLEDs(uint8 *data)
status_t
KeyboardProtocolHandler::_ReadReport(bigtime_t timeout)
KeyboardProtocolHandler::_ReadReport(bigtime_t timeout, uint32 *cookie)
{
status_t result = fInputReport.WaitForReport(timeout);
if (result != B_OK) {
@ -468,6 +468,9 @@ KeyboardProtocolHandler::_ReadReport(bigtime_t timeout)
return B_ERROR;
}
if ((*cookie & PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED) != 0)
return B_CANCELED;
if (result != B_TIMED_OUT && result != B_INTERRUPTED) {
// we expect timeouts as we do repeat key handling this way,
// interrupts happen when other reports come in on the same

View File

@ -39,7 +39,7 @@ public:
private:
void _WriteKey(uint32 key, bool down);
status_t _SetLEDs(uint8 *data);
status_t _ReadReport(bigtime_t timeout);
status_t _ReadReport(bigtime_t timeout, uint32 *cookie);
private:
mutex fLock;

View File

@ -132,7 +132,7 @@ MouseProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer,
return B_BUFFER_OVERFLOW;
while (true) {
status_t result = _ReadReport(buffer);
status_t result = _ReadReport(buffer, cookie);
if (result != B_INTERRUPTED)
return result;
}
@ -161,7 +161,7 @@ MouseProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer,
status_t
MouseProtocolHandler::_ReadReport(void *buffer)
MouseProtocolHandler::_ReadReport(void *buffer, uint32 *cookie)
{
status_t result = fReport.WaitForReport(B_INFINITE_TIMEOUT);
if (result != B_OK) {
@ -170,6 +170,9 @@ MouseProtocolHandler::_ReadReport(void *buffer)
return B_DEV_NOT_READY;
}
if ((*cookie & PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED) != 0)
return B_CANCELED;
if (result != B_INTERRUPTED) {
// interrupts happen when other reports come in on the same
// input as ours

View File

@ -34,7 +34,7 @@ public:
size_t length);
private:
status_t _ReadReport(void *buffer);
status_t _ReadReport(void *buffer, uint32 *cookie);
HIDReport & fReport;

View File

@ -124,6 +124,9 @@ ProtocolHandler::Open(uint32 flags, uint32 *cookie)
status_t
ProtocolHandler::Close(uint32 *cookie)
{
*cookie |= PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED;
// This lets the handlers know that this user is gone.
return fDevice->Close(this);
}

View File

@ -9,6 +9,9 @@
#include <SupportDefs.h>
#define PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED 0x80000000
class HIDDevice;
class HIDReport;

View File

@ -189,7 +189,7 @@ TabletProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer,
return B_BUFFER_OVERFLOW;
while (true) {
status_t result = _ReadReport(buffer);
status_t result = _ReadReport(buffer, cookie);
if (result != B_INTERRUPTED)
return result;
}
@ -218,7 +218,7 @@ TabletProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer,
status_t
TabletProtocolHandler::_ReadReport(void *buffer)
TabletProtocolHandler::_ReadReport(void *buffer, uint32 *cookie)
{
status_t result = fReport.WaitForReport(B_INFINITE_TIMEOUT);
if (result != B_OK) {
@ -227,6 +227,9 @@ TabletProtocolHandler::_ReadReport(void *buffer)
return B_DEV_NOT_READY;
}
if ((*cookie & PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED) != 0)
return B_CANCELED;
if (result != B_INTERRUPTED) {
// interrupts happen when other reports come in on the same
// input as ours

View File

@ -36,7 +36,7 @@ public:
size_t length);
private:
status_t _ReadReport(void *buffer);
status_t _ReadReport(void *buffer, uint32 *cookie);
HIDReport & fReport;