From 25f723de857000d2be110e4be49cde05c2d61eb6 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Wed, 22 Apr 2015 23:22:01 +0200 Subject: [PATCH] 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. --- src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp | 3 +++ .../drivers/input/usb_hid/JoystickProtocolHandler.cpp | 3 +++ .../drivers/input/usb_hid/KeyboardProtocolHandler.cpp | 7 +++++-- .../kernel/drivers/input/usb_hid/KeyboardProtocolHandler.h | 2 +- .../kernel/drivers/input/usb_hid/MouseProtocolHandler.cpp | 7 +++++-- .../kernel/drivers/input/usb_hid/MouseProtocolHandler.h | 2 +- .../kernel/drivers/input/usb_hid/ProtocolHandler.cpp | 3 +++ src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h | 3 +++ .../kernel/drivers/input/usb_hid/TabletProtocolHandler.cpp | 7 +++++-- .../kernel/drivers/input/usb_hid/TabletProtocolHandler.h | 2 +- 10 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp b/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp index 7ed6017933..9ec2b618d8 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp @@ -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; } diff --git a/src/add-ons/kernel/drivers/input/usb_hid/JoystickProtocolHandler.cpp b/src/add-ons/kernel/drivers/input/usb_hid/JoystickProtocolHandler.cpp index 20ab159764..6900951c20 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/JoystickProtocolHandler.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/JoystickProtocolHandler.cpp @@ -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 diff --git a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.cpp b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.cpp index a04f896db1..15211d0f9c 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.cpp @@ -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 diff --git a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.h b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.h index 16a290c7ad..9c911610a0 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.h @@ -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; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.cpp b/src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.cpp index 4533ec4cff..daf5c3edc0 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.cpp @@ -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 diff --git a/src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.h b/src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.h index eb9ffddab2..81ab7a7cb0 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.h @@ -34,7 +34,7 @@ public: size_t length); private: - status_t _ReadReport(void *buffer); + status_t _ReadReport(void *buffer, uint32 *cookie); HIDReport & fReport; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.cpp b/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.cpp index 1d8cffb553..0094fde8fb 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.cpp @@ -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); } diff --git a/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h b/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h index 8c6968bfa3..92a41d4fb7 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h @@ -9,6 +9,9 @@ #include +#define PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED 0x80000000 + + class HIDDevice; class HIDReport; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/TabletProtocolHandler.cpp b/src/add-ons/kernel/drivers/input/usb_hid/TabletProtocolHandler.cpp index c5507c554c..18496fef3d 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/TabletProtocolHandler.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/TabletProtocolHandler.cpp @@ -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 diff --git a/src/add-ons/kernel/drivers/input/usb_hid/TabletProtocolHandler.h b/src/add-ons/kernel/drivers/input/usb_hid/TabletProtocolHandler.h index 342a466d9c..55a81bc531 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/TabletProtocolHandler.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/TabletProtocolHandler.h @@ -36,7 +36,7 @@ public: size_t length); private: - status_t _ReadReport(void *buffer); + status_t _ReadReport(void *buffer, uint32 *cookie); HIDReport & fReport;