* 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

View File

@ -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; }

View File

@ -9,6 +9,7 @@
#include <string.h>
#include <usb/USB_hid.h>
#include <util/AutoLock.h>
#include <debug.h>
@ -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:

View File

@ -8,6 +8,8 @@
#include "ProtocolHandler.h"
#include <lock.h>
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;
};