diff --git a/headers/private/kernel/arch/debug_console.h b/headers/private/kernel/arch/debug_console.h index 470c9ef1b2..b98fb4636c 100644 --- a/headers/private/kernel/arch/debug_console.h +++ b/headers/private/kernel/arch/debug_console.h @@ -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); diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index 33f1d9b7a2..56225afdba 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -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 usb_keyboard 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 diff --git a/src/add-ons/kernel/busses/usb/uhci.h b/src/add-ons/kernel/busses/usb/uhci.h index 7a04d44d5b..ec2588e60e 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -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); diff --git a/src/add-ons/kernel/debugger/usb_keyboard/usb_keyboard.cpp b/src/add-ons/kernel/debugger/usb_keyboard/usb_keyboard.cpp index bf28d121a6..581b6dfb13 100644 --- a/src/add-ons/kernel/debugger/usb_keyboard/usb_keyboard.cpp +++ b/src/add-ons/kernel/debugger/usb_keyboard/usb_keyboard.cpp @@ -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 }; diff --git a/src/system/kernel/arch/arm/arch_debug_console.cpp b/src/system/kernel/arch/arm/arch_debug_console.cpp index dee7b98a49..6420aa8ac7 100644 --- a/src/system/kernel/arch/arm/arch_debug_console.cpp +++ b/src/system/kernel/arch/arm/arch_debug_console.cpp @@ -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) { diff --git a/src/system/kernel/arch/m68k/arch_debug_console.cpp b/src/system/kernel/arch/m68k/arch_debug_console.cpp index 350026ab94..41fc9e156f 100644 --- a/src/system/kernel/arch/m68k/arch_debug_console.cpp +++ b/src/system/kernel/arch/m68k/arch_debug_console.cpp @@ -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) { diff --git a/src/system/kernel/arch/mipsel/arch_debug_console.cpp b/src/system/kernel/arch/mipsel/arch_debug_console.cpp index f8ce0a4838..c5cb515b54 100644 --- a/src/system/kernel/arch/mipsel/arch_debug_console.cpp +++ b/src/system/kernel/arch/mipsel/arch_debug_console.cpp @@ -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) { diff --git a/src/system/kernel/arch/ppc/arch_debug_console.cpp b/src/system/kernel/arch/ppc/arch_debug_console.cpp index fae93fee35..a8318d5988 100644 --- a/src/system/kernel/arch/ppc/arch_debug_console.cpp +++ b/src/system/kernel/arch/ppc/arch_debug_console.cpp @@ -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) { diff --git a/src/system/kernel/arch/x86/arch_debug_console.cpp b/src/system/kernel/arch/x86/arch_debug_console.cpp index d165b8a721..8f4244da22 100644 --- a/src/system/kernel/arch/x86/arch_debug_console.cpp +++ b/src/system/kernel/arch/x86/arch_debug_console.cpp @@ -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); } diff --git a/src/system/kernel/debug/blue_screen.cpp b/src/system/kernel/debug/blue_screen.cpp index cbd03ea2fd..3cfa6f8be1 100644 --- a/src/system/kernel/debug/blue_screen.cpp +++ b/src/system/kernel/debug/blue_screen.cpp @@ -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) { diff --git a/src/system/kernel/debug/blue_screen.h b/src/system/kernel/debug/blue_screen.h index df2e79b8ea..9331c7bdf6 100644 --- a/src/system/kernel/debug/blue_screen.h +++ b/src/system/kernel/debug/blue_screen.h @@ -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); diff --git a/src/system/kernel/debug/debug.cpp b/src/system/kernel/debug/debug.cpp index 56b3261bfb..46d9a84318 100644 --- a/src/system/kernel/debug/debug.cpp +++ b/src/system/kernel/debug/debug.cpp @@ -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: