From 7380abeb440bbe243639d11100261eebad44d1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 15 Apr 2010 09:03:32 +0000 Subject: [PATCH] * Implemented the debugger mode for the USB keyboard driver. * Made the USB keyboard driver safe to be used from more than one team - only the first one will be able to retrieve any keys. Before, since there was no locking, internal structures would have been messed up in that case. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36283 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/drivers/input/usb_hid/HIDDevice.h | 3 +- .../drivers/input/usb_hid/KeyboardDevice.cpp | 94 ++++++++++++++----- .../drivers/input/usb_hid/KeyboardDevice.h | 7 ++ 3 files changed, 77 insertions(+), 27 deletions(-) diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.h b/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.h index 714827783b..80484d4769 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.h @@ -26,9 +26,10 @@ public: status_t InitCheck() const { return fStatus; } - bool IsOpen() const { return fOpenCount > 0; }; + bool IsOpen() const { return fOpenCount > 0; } status_t Open(ProtocolHandler *handler, uint32 flags); status_t Close(ProtocolHandler *handler); + int32 OpenCount() const { return fOpenCount; } void Removed(); bool IsRemoved() const { return fRemoved; } diff --git a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp index dfb43f69eb..f641a61e05 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp @@ -9,6 +9,7 @@ #include #include +#include #include @@ -26,7 +27,8 @@ #define RIGHT_ALT_KEY 0x40 #define ALT_KEYS (LEFT_ALT_KEY | RIGHT_ALT_KEY) -#define KEYBOARD_FLAG_DEBUGGER 0x01 +#define KEYBOARD_FLAG_READER 0x01 +#define KEYBOARD_FLAG_DEBUGGER 0x02 static usb_id sDebugKeyboardPipe = 0; @@ -60,8 +62,11 @@ KeyboardDevice::KeyboardDevice(HIDReport *inputReport, HIDReport *outputReport) fLastModifiers(0), fCurrentKeys(NULL), fLastKeys(NULL), + fHasReader(0), fHasDebugReader(false) { + mutex_init(&fLock, "usb keyboard"); + // find modifiers and keys for (uint32 i = 0; i < inputReport->CountItems(); i++) { HIDReportItem *item = inputReport->ItemAt(i); @@ -145,6 +150,8 @@ KeyboardDevice::~KeyboardDevice() remove_debugger_command("get_usb_keyboard_config", &debug_get_keyboard_config); } + + mutex_destroy(&fLock); } @@ -209,44 +216,79 @@ KeyboardDevice::Open(uint32 flags, uint32 *cookie) return status; } - fCurrentRepeatDelay = B_INFINITE_TIMEOUT; - fCurrentRepeatKey = 0; + if (Device()->OpenCount() == 1) { + fCurrentRepeatDelay = B_INFINITE_TIMEOUT; + fCurrentRepeatKey = 0; + } + return B_OK; } +status_t +KeyboardDevice::Close(uint32 *cookie) +{ + if ((*cookie & KEYBOARD_FLAG_DEBUGGER) != 0) + fHasDebugReader = false; + if ((*cookie & KEYBOARD_FLAG_READER) != 0) + atomic_and(&fHasReader, 0); + + return ProtocolHandler::Close(cookie); +} + + status_t KeyboardDevice::Control(uint32 *cookie, uint32 op, void *buffer, size_t length) { switch (op) { case KB_READ: { - bigtime_t enterTime = system_time(); - while (RingBufferReadable() == 0) { - status_t result = _ReadReport(fCurrentRepeatDelay); - if (result != B_OK && result != B_TIMED_OUT) - return result; + if (*cookie == 0) { + if (atomic_or(&fHasReader, 1) != 0) + return B_BUSY; - if (!Device()->IsOpen()) - return B_ERROR; - - if (RingBufferReadable() == 0 && fCurrentRepeatKey != 0 - && system_time() - enterTime > fCurrentRepeatDelay) { - // this case is for handling key repeats, it means no - // interrupt transfer has happened or it didn't produce any - // new key events, but a repeated key down is due - _WriteKey(fCurrentRepeatKey, true); - - // the next timeout is reduced to the repeat_rate - fCurrentRepeatDelay = fRepeatRate; - break; - } + // We're the first, so we become the only reader + *cookie = KEYBOARD_FLAG_READER; } - // process what is in the ring_buffer, it could be written - // there because we handled an interrupt transfer or because - // we wrote the current repeat key - return RingBufferRead(buffer, sizeof(raw_key_info)); + while (true) { + MutexLocker locker(fLock); + + bigtime_t enterTime = system_time(); + while (RingBufferReadable() == 0) { + status_t result = _ReadReport(fCurrentRepeatDelay); + if (result != B_OK && result != B_TIMED_OUT) + return result; + + if (!Device()->IsOpen()) + return B_ERROR; + + if (RingBufferReadable() == 0 && fCurrentRepeatKey != 0 + && system_time() - enterTime > fCurrentRepeatDelay) { + // this case is for handling key repeats, it means no + // interrupt transfer has happened or it didn't produce any + // new key events, but a repeated key down is due + _WriteKey(fCurrentRepeatKey, true); + + // the next timeout is reduced to the repeat_rate + fCurrentRepeatDelay = fRepeatRate; + break; + } + } + + if (fHasDebugReader && (*cookie & KEYBOARD_FLAG_DEBUGGER) + == 0) { + // Handover buffer to the debugger instead + locker.Unlock(); + snooze(25000); + continue; + } + + // process what is in the ring_buffer, it could be written + // there because we handled an interrupt transfer or because + // we wrote the current repeat key + return RingBufferRead(buffer, sizeof(raw_key_info)); + } } case KB_SET_LEDS: diff --git a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.h b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.h index d8742ff7b9..3c9cfb950f 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.h @@ -8,6 +8,8 @@ #include "ProtocolHandler.h" +#include + class HIDReportItem; @@ -27,6 +29,8 @@ public: HIDReport *input); virtual status_t Open(uint32 flags, uint32 *cookie); + virtual status_t Close(uint32 *cookie); + virtual status_t Control(uint32 *cookie, uint32 op, void *buffer, size_t length); @@ -36,6 +40,8 @@ private: status_t _ReadReport(bigtime_t timeout); private: + mutex fLock; + HIDReport * fInputReport; HIDReport * fOutputReport; @@ -55,6 +61,7 @@ private: uint16 * fCurrentKeys; uint16 * fLastKeys; + int32 fHasReader; bool fHasDebugReader; };