* Added arch_debug_blue_screen_try_getchar() and arch_debug_serial_try_getchar()

which don't wait for a character, but return -1 when no character is
  available ATM. Implemented correctly for x86 only.
* Changed the semantics of the debugger_module_info::debugger_getchar() hook.
  It is supposed to return immediately now.
* Adjusted usb_keyboard accordingly. Hacked UHCI's debug_process_transfer() to
  achieve that. It does now start, check, or cancel a transfer. Split
  UHCI::ProcessDebugTransfer() into StartDebugTransfer(), and
  CheckDebugTransfer() accordingly, and also added a CancelDebugTransfer().
  The latter seems to have issues. Michael, please have a look. I have no clue
  what I'm doing. :-)
* Adjusted kgetc() to poll all possible inputs using the new
  functions/semantics. This allows to use any input (USB, PS/2, serial) in KDL.
* Removed the no longer needed "serial_input" command.
* read_line(): Also support 0x7f as backspace code. That's what xterm sends.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42126 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2011-06-12 17:15:42 +00:00
parent 21d6b8e2c7
commit 8bcc50c336
12 changed files with 363 additions and 181 deletions

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de
* Distributed under the terms of the MIT License.
*
@ -18,7 +18,9 @@ struct kernel_args;
extern "C" {
#endif
int arch_debug_blue_screen_try_getchar(void);
char arch_debug_blue_screen_getchar(void);
int arch_debug_serial_try_getchar(void);
char arch_debug_serial_getchar(void);
void arch_debug_serial_putchar(char c);
void arch_debug_serial_puts(const char *s);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2004-2006, Haiku Inc. All rights reserved.
* Copyright 2004-2011, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -23,6 +23,28 @@ static int32 sDebuggerCommandAdded = 0;
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
class DebugTransfer : public Transfer {
public:
DebugTransfer(Pipe *pipe)
:
Transfer(pipe)
{
}
uhci_td *firstDescriptor;
uhci_qh *transferQueue;
};
/*! The function is an evil hack to allow <tt> <kdebug>usb_keyboard </tt> to
execute transfers.
When invoked the first time, a new transfer is started, each time the
function is called afterwards, it is checked whether the transfer is already
completed. If called with argv[1] == "cancel" the function cancels a
possibly pending transfer.
*/
static int
debug_process_transfer(int argc, char **argv)
{
@ -42,9 +64,38 @@ debug_process_transfer(int argc, char **argv)
if (length == 0)
return 5;
Transfer transfer(pipe);
transfer.SetData(data, length);
return ((UHCI *)pipe->GetBusManager())->ProcessDebugTransfer(&transfer);
static uint8 transferBuffer[sizeof(DebugTransfer)]
__attribute__((aligned(16)));
static DebugTransfer* transfer;
UHCI *bus = (UHCI *)pipe->GetBusManager();
if (argc > 1 && strcmp(argv[1], "cancel") == 0) {
if (transfer != NULL) {
bus->CancelDebugTransfer(transfer);
transfer = NULL;
}
return 0;
}
if (transfer != NULL) {
bool stillPending;
status_t error = bus->CheckDebugTransfer(transfer, stillPending);
if (!stillPending)
transfer = NULL;
return error == B_OK ? 0 : 6;
}
transfer = new(transferBuffer) DebugTransfer(pipe);
transfer->SetData(data, length);
if (bus->StartDebugTransfer(transfer) != B_OK) {
transfer = NULL;
return 7;
}
return 0;
}
#endif
@ -672,73 +723,102 @@ UHCI::SubmitTransfer(Transfer *transfer)
status_t
UHCI::ProcessDebugTransfer(Transfer *transfer)
UHCI::StartDebugTransfer(DebugTransfer *transfer)
{
uhci_td *firstDescriptor = NULL;
uhci_qh *transferQueue = NULL;
status_t result = CreateFilledTransfer(transfer, &firstDescriptor,
&transferQueue);
transfer->firstDescriptor = NULL;
transfer->transferQueue = NULL;
status_t result = CreateFilledTransfer(transfer, &transfer->firstDescriptor,
&transfer->transferQueue);
if (result < B_OK)
return result;
fQueues[UHCI_DEBUG_QUEUE]->AppendTransfer(transferQueue, false);
fQueues[UHCI_DEBUG_QUEUE]->AppendTransfer(transfer->transferQueue, false);
while (true) {
bool transferOK = false;
bool transferError = false;
uhci_td *descriptor = firstDescriptor;
return B_OK;
}
while (descriptor) {
uint32 status = descriptor->status;
if (status & TD_STATUS_ACTIVE)
break;
if (status & TD_ERROR_MASK) {
transferError = true;
break;
}
status_t
UHCI::CheckDebugTransfer(DebugTransfer *transfer, bool &_stillPending)
{
bool transferOK = false;
bool transferError = false;
uhci_td *descriptor = transfer->firstDescriptor;
if ((descriptor->link_phy & TD_TERMINATE)
|| uhci_td_actual_length(descriptor)
< uhci_td_maximum_length(descriptor)) {
transferOK = true;
break;
}
while (descriptor) {
uint32 status = descriptor->status;
if (status & TD_STATUS_ACTIVE)
break;
descriptor = (uhci_td *)descriptor->link_log;
if (status & TD_ERROR_MASK) {
transferError = true;
break;
}
if (!transferOK && !transferError) {
spin(200);
continue;
if ((descriptor->link_phy & TD_TERMINATE)
|| uhci_td_actual_length(descriptor)
< uhci_td_maximum_length(descriptor)) {
transferOK = true;
break;
}
if (transferOK) {
size_t actualLength = 0;
uint8 lastDataToggle = 0;
if (transfer->TransferPipe()->Direction() == Pipe::In) {
// data to read out
iovec *vector = transfer->Vector();
size_t vectorCount = transfer->VectorCount();
actualLength = ReadDescriptorChain(firstDescriptor,
vector, vectorCount, &lastDataToggle);
} else {
// read the actual length that was sent
actualLength = ReadActualLength(firstDescriptor,
&lastDataToggle);
}
transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
}
fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transferQueue, false);
FreeDescriptorChain(firstDescriptor);
FreeTransferQueue(transferQueue);
return transferOK ? B_OK : B_IO_ERROR;
descriptor = (uhci_td *)descriptor->link_log;
}
return B_ERROR;
if (!transferOK && !transferError) {
spin(200);
_stillPending = true;
return B_OK;
}
if (transferOK) {
size_t actualLength = 0;
uint8 lastDataToggle = 0;
if (transfer->TransferPipe()->Direction() == Pipe::In) {
// data to read out
iovec *vector = transfer->Vector();
size_t vectorCount = transfer->VectorCount();
actualLength = ReadDescriptorChain(transfer->firstDescriptor,
vector, vectorCount, &lastDataToggle);
} else {
// read the actual length that was sent
actualLength = ReadActualLength(transfer->firstDescriptor,
&lastDataToggle);
}
transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
}
fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transfer->transferQueue, false);
FreeDescriptorChain(transfer->firstDescriptor);
FreeTransferQueue(transfer->transferQueue);
_stillPending = false;
return transferOK ? B_OK : B_IO_ERROR;
}
void
UHCI::CancelDebugTransfer(DebugTransfer *transfer)
{
// clear the active bit so the descriptors are canceled
uhci_td *descriptor = transfer->firstDescriptor;
while (descriptor) {
descriptor->status &= ~TD_STATUS_ACTIVE;
descriptor = (uhci_td *)descriptor->link_log;
}
transfer->Finished(B_CANCELED, 0);
// dequeue and free resources
fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transfer->transferQueue, false);
FreeDescriptorChain(transfer->firstDescriptor);
FreeTransferQueue(transfer->transferQueue);
// TODO: [bonefish] The Free*() calls cause "PMA: provided address resulted
// in invalid index" to be printed, so apparently something is not right.
// Though I have not clue what. This is the same cleanup code as in
// CheckDebugTransfer() that should undo the CreateFilledTransfer() from
// StartDebugTransfer().
}
@ -1832,7 +1912,7 @@ status_t
UHCI::AddTo(Stack *stack)
{
#ifdef TRACE_USB
set_dprintf_enabled(true);
set_dprintf_enabled(true);
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
load_driver_symbols("uhci");
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright 2004-2006, Haiku Inc. All rights reserved.
* Copyright 2004-2011, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -24,6 +24,7 @@
struct pci_info;
struct pci_module_info;
class UHCIRootHub;
class DebugTransfer;
class Queue {
@ -97,7 +98,11 @@ public:
status_t Start();
virtual status_t SubmitTransfer(Transfer *transfer);
status_t ProcessDebugTransfer(Transfer *transfer);
status_t StartDebugTransfer(DebugTransfer *transfer);
status_t CheckDebugTransfer(DebugTransfer *transfer,
bool &_stillPending);
void CancelDebugTransfer(
DebugTransfer *transfer);
virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force);
status_t CancelQueuedIsochronousTransfers(Pipe *pipe, bool force);
status_t SubmitRequest(Transfer *transfer);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2009, Haiku Inc. All rights reserved.
* Copyright 2009-2011, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -176,6 +176,9 @@ enter_debugger(void)
static void
exit_debugger(void)
{
// make sure a possibly pending transfer is canceled
evaluate_debug_command("uhci_process_transfer cancel");
sUseUSBKeyboard = false;
}
@ -195,11 +198,12 @@ debugger_getchar(void)
if (!sUseUSBKeyboard)
return -1;
while (sBufferedCharCount == 0) {
if (sBufferedCharCount == 0) {
set_debug_variable("_usbPipe", (uint64)sUSBPipe);
set_debug_variable("_usbTransferData", (uint64)sUSBTransferData);
set_debug_variable("_usbTransferLength", (uint64)sUSBTransferLength);
evaluate_debug_command("uhci_process_transfer");
if (evaluate_debug_command("uhci_process_transfer") != 0)
return -1;
bool phantomState = true;
for (size_t i = 2; i < sUSBTransferLength; i++) {
@ -210,7 +214,7 @@ debugger_getchar(void)
}
if (phantomState)
continue;
return -1;
uint8 modifiers = 0;
for (uint32 i = 0; i < 8; i++) {
@ -272,6 +276,9 @@ debugger_getchar(void)
sLastTransferData[i] = sUSBTransferData[i];
}
if (sBufferedCharCount == 0)
return -1;
int result = sBufferedChars[sBufferReadIndex++];
sBufferReadIndex %= sBufferSize;
sBufferedCharCount--;
@ -302,7 +309,7 @@ static struct debugger_module_info sModuleInfo = {
&debugger_getchar
};
module_info *modules[] = {
module_info *modules[] = {
(module_info *)&sModuleInfo,
NULL
};

View File

@ -31,6 +31,14 @@ arch_debug_install_interrupt_handlers(void)
}
int
arch_debug_blue_screen_try_getchar(void)
{
// TODO: Implement correctly!
return arch_debug_blue_screen_getchar();
}
char
arch_debug_blue_screen_getchar(void)
{
@ -38,6 +46,14 @@ arch_debug_blue_screen_getchar(void)
}
int
arch_debug_serial_try_getchar(void)
{
// TODO: Implement correctly!
return arch_debug_serial_getchar();
}
char
arch_debug_serial_getchar(void)
{

View File

@ -31,6 +31,14 @@ arch_debug_install_interrupt_handlers(void)
}
int
arch_debug_blue_screen_try_getchar(void)
{
// TODO: Implement correctly!
return arch_debug_blue_screen_getchar();
}
char
arch_debug_blue_screen_getchar(void)
{
@ -38,6 +46,14 @@ arch_debug_blue_screen_getchar(void)
}
int
arch_debug_serial_try_getchar(void)
{
// TODO: Implement correctly!
return arch_debug_serial_getchar();
}
char
arch_debug_serial_getchar(void)
{

View File

@ -31,6 +31,14 @@ arch_debug_install_interrupt_handlers(void)
}
int
arch_debug_blue_screen_try_getchar(void)
{
#warning IMPLEMENT arch_debug_blue_screen_try_getchar
return -1;
}
char
arch_debug_blue_screen_getchar(void)
{
@ -39,6 +47,14 @@ arch_debug_blue_screen_getchar(void)
}
int
arch_debug_serial_try_getchar(void)
{
#warning IMPLEMENT arch_debug_serial_try_getchar
return -1;
}
char
arch_debug_serial_getchar(void)
{

View File

@ -28,6 +28,14 @@ arch_debug_install_interrupt_handlers(void)
}
int
arch_debug_blue_screen_try_getchar(void)
{
// TODO: Implement correctly!
return arch_debug_blue_screen_getchar();
}
char
arch_debug_blue_screen_getchar(void)
{
@ -35,6 +43,14 @@ arch_debug_blue_screen_getchar(void)
}
int
arch_debug_serial_try_getchar(void)
{
// TODO: Implement correctly!
return arch_debug_serial_getchar();
}
char
arch_debug_serial_getchar(void)
{

View File

@ -166,8 +166,8 @@ arch_debug_install_interrupt_handlers(void)
}
char
arch_debug_blue_screen_getchar(void)
int
arch_debug_blue_screen_try_getchar(void)
{
/* polling the keyboard, similar to code in keyboard
* driver, but without using an interrupt
@ -194,105 +194,126 @@ arch_debug_blue_screen_getchar(void)
return key;
}
while (true) {
uint8 status = in8(PS2_PORT_CTRL);
uint8 status = in8(PS2_PORT_CTRL);
if ((status & PS2_STATUS_OUTPUT_BUFFER_FULL) == 0) {
// no data in keyboard buffer
spin(200);
continue;
if ((status & PS2_STATUS_OUTPUT_BUFFER_FULL) == 0) {
// no data in keyboard buffer
return -1;
}
key = in8(PS2_PORT_DATA);
if (status & PS2_STATUS_AUX_DATA) {
// we read mouse data, ignore it
return -1;
}
if (key & 0x80) {
// key up
switch (key & ~0x80) {
case LEFT_SHIFT:
case RIGHT_SHIFT:
shiftPressed = false;
return -1;
case LEFT_CONTROL:
controlPressed = false;
return -1;
case LEFT_ALT:
altPressed = false;
return -1;
}
} else {
// key down
switch (key) {
case LEFT_SHIFT:
case RIGHT_SHIFT:
shiftPressed = true;
return -1;
spin(200);
key = in8(PS2_PORT_DATA);
case LEFT_CONTROL:
controlPressed = true;
return -1;
if (status & PS2_STATUS_AUX_DATA) {
// we read mouse data, ignore it
continue;
}
case LEFT_ALT:
altPressed = true;
return -1;
if (key & 0x80) {
// key up
switch (key & ~0x80) {
case LEFT_SHIFT:
case RIGHT_SHIFT:
shiftPressed = false;
break;
case LEFT_CONTROL:
controlPressed = false;
break;
case LEFT_ALT:
altPressed = false;
break;
}
} else {
// key down
switch (key) {
case LEFT_SHIFT:
case RIGHT_SHIFT:
shiftPressed = true;
break;
case LEFT_CONTROL:
controlPressed = true;
break;
case LEFT_ALT:
altPressed = true;
break;
// start escape sequence for cursor movement
case CURSOR_UP:
special = 0x80 | 'A';
return '\x1b';
case CURSOR_DOWN:
special = 0x80 | 'B';
return '\x1b';
case CURSOR_RIGHT:
special = 0x80 | 'C';
return '\x1b';
case CURSOR_LEFT:
special = 0x80 | 'D';
return '\x1b';
case CURSOR_HOME:
special = 0x80 | 'H';
return '\x1b';
case CURSOR_END:
special = 0x80 | 'F';
return '\x1b';
case PAGE_UP:
special = 0x80 | '5';
special2 = '~';
return '\x1b';
case PAGE_DOWN:
special = 0x80 | '6';
special2 = '~';
return '\x1b';
// start escape sequence for cursor movement
case CURSOR_UP:
special = 0x80 | 'A';
return '\x1b';
case CURSOR_DOWN:
special = 0x80 | 'B';
return '\x1b';
case CURSOR_RIGHT:
special = 0x80 | 'C';
return '\x1b';
case CURSOR_LEFT:
special = 0x80 | 'D';
return '\x1b';
case CURSOR_HOME:
special = 0x80 | 'H';
return '\x1b';
case CURSOR_END:
special = 0x80 | 'F';
return '\x1b';
case PAGE_UP:
special = 0x80 | '5';
special2 = '~';
return '\x1b';
case PAGE_DOWN:
special = 0x80 | '6';
special2 = '~';
return '\x1b';
case DELETE:
if (controlPressed && altPressed)
arch_cpu_shutdown(true);
case DELETE:
if (controlPressed && altPressed)
arch_cpu_shutdown(true);
special = 0x80 | '3';
special2 = '~';
return '\x1b';
special = 0x80 | '3';
special2 = '~';
return '\x1b';
default:
if (controlPressed) {
char c = kShiftedKeymap[key];
if (c >= 'A' && c <= 'Z')
return 0x1f & c;
}
default:
if (controlPressed) {
char c = kShiftedKeymap[key];
if (c >= 'A' && c <= 'Z')
return 0x1f & c;
}
if (altPressed)
return kAltedKeymap[key];
if (altPressed)
return kAltedKeymap[key];
return shiftPressed
? kShiftedKeymap[key] : kUnshiftedKeymap[key];
}
return shiftPressed
? kShiftedKeymap[key] : kUnshiftedKeymap[key];
}
}
return -1;
}
char
arch_debug_blue_screen_getchar(void)
{
while (true) {
int c = arch_debug_blue_screen_try_getchar();
if (c >= 0)
return (char)c;
PAUSE();
}
}
int
arch_debug_serial_try_getchar(void)
{
if ((in8(sSerialBasePort + SERIAL_LINE_STATUS) & 0x1) == 0)
return -1;
return in8(sSerialBasePort + SERIAL_RECEIVE_BUFFER);
}

View File

@ -659,6 +659,13 @@ blue_screen_clear_screen(void)
}
int
blue_screen_try_getchar(void)
{
return arch_debug_blue_screen_try_getchar();
}
char
blue_screen_getchar(void)
{

View File

@ -20,6 +20,7 @@ bool blue_screen_paging_enabled(void);
void blue_screen_set_paging(bool enabled);
void blue_screen_clear_screen(void);
int blue_screen_try_getchar(void);
char blue_screen_getchar(void);
void blue_screen_putchar(char c);
void blue_screen_puts(const char *text);

View File

@ -90,7 +90,6 @@ static bool sSyslogOutputEnabled = true;
static bool sBlueScreenEnabled = false;
// must always be false on startup
static bool sDebugScreenEnabled = false;
static bool sSerialInputEnabled = false;
static bool sBlueScreenOutput = true;
static bool sEmergencyKeysEnabled = true;
static spinlock sSpinlock = B_SPINLOCK_INITIALIZER;
@ -474,7 +473,8 @@ read_line(char* buffer, int32 maxLength,
}
break;
}
case 8: // backspace
case 8: // backspace (CTRL-H)
case 0x7f: // backspace (xterm)
if (position > 0) {
kputs("\x1b[1D"); // move to the left one
position--;
@ -681,22 +681,30 @@ read_line(char* buffer, int32 maxLength,
char
kgetc(void)
{
if (sSerialInputEnabled)
return arch_debug_serial_getchar();
while (true) {
// check serial input
int c = arch_debug_serial_try_getchar();
if (c >= 0)
return (char)c;
// give the kernel debugger modules a chance first
for (uint32 i = 0; i < kMaxDebuggerModules; i++) {
if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_getchar) {
int getChar = sDebuggerModules[i]->debugger_getchar();
if (getChar >= 0)
return (char)getChar;
// check blue screen input
if (sBlueScreenOutput) {
c = blue_screen_try_getchar();
if (c >= 0)
return (char)c;
}
// give the kernel debugger modules a chance
for (uint32 i = 0; i < kMaxDebuggerModules; i++) {
if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_getchar) {
int getChar = sDebuggerModules[i]->debugger_getchar();
if (getChar >= 0)
return (char)getChar;
}
}
PAUSE();
}
if (sBlueScreenOutput)
return blue_screen_getchar();
return arch_debug_serial_getchar();
}
@ -1136,16 +1144,6 @@ cmd_dump_syslog(int argc, char** argv)
}
static int
cmd_serial_input(int argc, char** argv)
{
sSerialInputEnabled = !sSerialInputEnabled;
kprintf("Serial input is turned %s now.\n",
sSerialInputEnabled ? "on" : "off");
return 0;
}
static int
cmd_switch_cpu(int argc, char** argv)
{
@ -1413,9 +1411,6 @@ syslog_init_post_vm(struct kernel_args* args)
"Dumps the whole syslog buffer, or, if -k is specified, only "
"the part that hasn't been sent yet.\n", 0);
add_debugger_command("serial_input", &cmd_serial_input,
"Enable or disable serial input");
return B_OK;
err2: