* 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
This commit is contained in:
Axel Dörfler
2010-04-15 09:03:32 +00:00
parent d5009951b7
commit 7380abeb44
3 changed files with 77 additions and 27 deletions
@@ -26,9 +26,10 @@ public:
status_t InitCheck() const { return fStatus; } 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 Open(ProtocolHandler *handler, uint32 flags);
status_t Close(ProtocolHandler *handler); status_t Close(ProtocolHandler *handler);
int32 OpenCount() const { return fOpenCount; }
void Removed(); void Removed();
bool IsRemoved() const { return fRemoved; } bool IsRemoved() const { return fRemoved; }
@@ -9,6 +9,7 @@
#include <string.h> #include <string.h>
#include <usb/USB_hid.h> #include <usb/USB_hid.h>
#include <util/AutoLock.h>
#include <debug.h> #include <debug.h>
@@ -26,7 +27,8 @@
#define RIGHT_ALT_KEY 0x40 #define RIGHT_ALT_KEY 0x40
#define ALT_KEYS (LEFT_ALT_KEY | RIGHT_ALT_KEY) #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; static usb_id sDebugKeyboardPipe = 0;
@@ -60,8 +62,11 @@ KeyboardDevice::KeyboardDevice(HIDReport *inputReport, HIDReport *outputReport)
fLastModifiers(0), fLastModifiers(0),
fCurrentKeys(NULL), fCurrentKeys(NULL),
fLastKeys(NULL), fLastKeys(NULL),
fHasReader(0),
fHasDebugReader(false) fHasDebugReader(false)
{ {
mutex_init(&fLock, "usb keyboard");
// find modifiers and keys // find modifiers and keys
for (uint32 i = 0; i < inputReport->CountItems(); i++) { for (uint32 i = 0; i < inputReport->CountItems(); i++) {
HIDReportItem *item = inputReport->ItemAt(i); HIDReportItem *item = inputReport->ItemAt(i);
@@ -145,6 +150,8 @@ KeyboardDevice::~KeyboardDevice()
remove_debugger_command("get_usb_keyboard_config", remove_debugger_command("get_usb_keyboard_config",
&debug_get_keyboard_config); &debug_get_keyboard_config);
} }
mutex_destroy(&fLock);
} }
@@ -209,44 +216,79 @@ KeyboardDevice::Open(uint32 flags, uint32 *cookie)
return status; return status;
} }
fCurrentRepeatDelay = B_INFINITE_TIMEOUT; if (Device()->OpenCount() == 1) {
fCurrentRepeatKey = 0; fCurrentRepeatDelay = B_INFINITE_TIMEOUT;
fCurrentRepeatKey = 0;
}
return B_OK; 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 status_t
KeyboardDevice::Control(uint32 *cookie, uint32 op, void *buffer, size_t length) KeyboardDevice::Control(uint32 *cookie, uint32 op, void *buffer, size_t length)
{ {
switch (op) { switch (op) {
case KB_READ: case KB_READ:
{ {
bigtime_t enterTime = system_time(); if (*cookie == 0) {
while (RingBufferReadable() == 0) { if (atomic_or(&fHasReader, 1) != 0)
status_t result = _ReadReport(fCurrentRepeatDelay); return B_BUSY;
if (result != B_OK && result != B_TIMED_OUT)
return result;
if (!Device()->IsOpen()) // We're the first, so we become the only reader
return B_ERROR; *cookie = KEYBOARD_FLAG_READER;
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;
}
} }
// process what is in the ring_buffer, it could be written while (true) {
// there because we handled an interrupt transfer or because MutexLocker locker(fLock);
// we wrote the current repeat key
return RingBufferRead(buffer, sizeof(raw_key_info)); 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: case KB_SET_LEDS:
@@ -8,6 +8,8 @@
#include "ProtocolHandler.h" #include "ProtocolHandler.h"
#include <lock.h>
class HIDReportItem; class HIDReportItem;
@@ -27,6 +29,8 @@ public:
HIDReport *input); HIDReport *input);
virtual status_t Open(uint32 flags, uint32 *cookie); virtual status_t Open(uint32 flags, uint32 *cookie);
virtual status_t Close(uint32 *cookie);
virtual status_t Control(uint32 *cookie, uint32 op, void *buffer, virtual status_t Control(uint32 *cookie, uint32 op, void *buffer,
size_t length); size_t length);
@@ -36,6 +40,8 @@ private:
status_t _ReadReport(bigtime_t timeout); status_t _ReadReport(bigtime_t timeout);
private: private:
mutex fLock;
HIDReport * fInputReport; HIDReport * fInputReport;
HIDReport * fOutputReport; HIDReport * fOutputReport;
@@ -55,6 +61,7 @@ private:
uint16 * fCurrentKeys; uint16 * fCurrentKeys;
uint16 * fLastKeys; uint16 * fLastKeys;
int32 fHasReader;
bool fHasDebugReader; bool fHasDebugReader;
}; };