USB: Generalize logic for debug transfers used within KDL.
Pull debug transfer methods into the base BusManager class and implement them for UHCI and EHCI. This makes it possible to have a single debugger command installed by the USB stack instead of HCI specific ones.
This commit is contained in:
@@ -264,6 +264,29 @@ BusManager::Stop()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BusManager::StartDebugTransfer(Transfer *transfer)
|
||||||
|
{
|
||||||
|
// virtual function to be overridden
|
||||||
|
return B_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BusManager::CheckDebugTransfer(Transfer *transfer)
|
||||||
|
{
|
||||||
|
// virtual function to be overridden
|
||||||
|
return B_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BusManager::CancelDebugTransfer(Transfer *transfer)
|
||||||
|
{
|
||||||
|
// virtual function to be overridden
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
BusManager::SubmitTransfer(Transfer *transfer)
|
BusManager::SubmitTransfer(Transfer *transfer)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,6 +17,54 @@ Stack *gUSBStack = NULL;
|
|||||||
|
|
||||||
|
|
||||||
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
|
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
|
||||||
|
/*! 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 status_t
|
||||||
|
debug_run_transfer(Pipe *pipe, uint8 *data, size_t dataLength,
|
||||||
|
usb_request_data *requestData, bool cancel)
|
||||||
|
{
|
||||||
|
static uint8 transferBuffer[sizeof(Transfer)]
|
||||||
|
__attribute__((aligned(16)));
|
||||||
|
static Transfer *transfer = NULL;
|
||||||
|
|
||||||
|
BusManager *bus = pipe->GetBusManager();
|
||||||
|
|
||||||
|
if (cancel) {
|
||||||
|
if (transfer != NULL) {
|
||||||
|
bus->CancelDebugTransfer(transfer);
|
||||||
|
transfer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transfer != NULL) {
|
||||||
|
status_t error = bus->CheckDebugTransfer(transfer);
|
||||||
|
if (error != B_DEV_PENDING)
|
||||||
|
transfer = NULL;
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer = new(transferBuffer) Transfer(pipe);
|
||||||
|
transfer->SetData(data, dataLength);
|
||||||
|
transfer->SetRequestData(requestData);
|
||||||
|
|
||||||
|
status_t error = bus->StartDebugTransfer(transfer);
|
||||||
|
if (error != B_OK) {
|
||||||
|
transfer = NULL;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_DEV_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
debug_get_pipe_for_id(int argc, char **argv)
|
debug_get_pipe_for_id(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -34,6 +82,23 @@ debug_get_pipe_for_id(int argc, char **argv)
|
|||||||
set_debug_variable("_usbPipe", (uint64)object);
|
set_debug_variable("_usbPipe", (uint64)object);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
debug_process_transfer(int argc, char **argv)
|
||||||
|
{
|
||||||
|
Pipe *pipe = (Pipe *)get_debug_variable("_usbPipe", 0);
|
||||||
|
if (pipe == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
uint8 *data = (uint8 *)get_debug_variable("_usbTransferData", 0);
|
||||||
|
size_t length = (size_t)get_debug_variable("_usbTransferLength", 0);
|
||||||
|
usb_request_data *requestData
|
||||||
|
= (usb_request_data *)get_debug_variable("_usbRequestData", 0);
|
||||||
|
|
||||||
|
return debug_run_transfer(pipe, data, length, requestData,
|
||||||
|
argc > 1 && strcmp(argv[1], "cancel") == 0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -83,7 +148,11 @@ bus_std_ops(int32 op, ...)
|
|||||||
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
|
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
|
||||||
add_debugger_command("get_usb_pipe_for_id",
|
add_debugger_command("get_usb_pipe_for_id",
|
||||||
&debug_get_pipe_for_id,
|
&debug_get_pipe_for_id,
|
||||||
"Gets the config for a USB pipe");
|
"Sets _usbPipe by resolving _usbPipeID");
|
||||||
|
add_debugger_command("usb_process_transfer",
|
||||||
|
&debug_process_transfer,
|
||||||
|
"Transfers _usbTransferData with _usbTransferLength"
|
||||||
|
" (and/or _usbRequestData) to pipe _usbPipe");
|
||||||
#elif HAIKU_TARGET_PLATFORM_BEOS
|
#elif HAIKU_TARGET_PLATFORM_BEOS
|
||||||
// Plain R5 workaround, see comment above.
|
// Plain R5 workaround, see comment above.
|
||||||
shared = create_area("shared usb stack", &address,
|
shared = create_area("shared usb stack", &address,
|
||||||
|
|||||||
@@ -211,6 +211,10 @@ virtual void FreeDevice(Device *device);
|
|||||||
virtual status_t Start();
|
virtual status_t Start();
|
||||||
virtual status_t Stop();
|
virtual status_t Stop();
|
||||||
|
|
||||||
|
virtual status_t StartDebugTransfer(Transfer *transfer);
|
||||||
|
virtual status_t CheckDebugTransfer(Transfer *transfer);
|
||||||
|
virtual void CancelDebugTransfer(Transfer *transfer);
|
||||||
|
|
||||||
virtual status_t SubmitTransfer(Transfer *transfer);
|
virtual status_t SubmitTransfer(Transfer *transfer);
|
||||||
virtual status_t CancelQueuedTransfers(Pipe *pipe,
|
virtual status_t CancelQueuedTransfers(Pipe *pipe,
|
||||||
bool force);
|
bool force);
|
||||||
@@ -680,6 +684,10 @@ public:
|
|||||||
|
|
||||||
void SetCallback(usb_callback_func callback,
|
void SetCallback(usb_callback_func callback,
|
||||||
void *cookie);
|
void *cookie);
|
||||||
|
usb_callback_func Callback() const
|
||||||
|
{ return fCallback; }
|
||||||
|
void * CallbackCookie() const
|
||||||
|
{ return fCallbackCookie; }
|
||||||
|
|
||||||
void Finished(uint32 status,
|
void Finished(uint32 status,
|
||||||
size_t actualLength);
|
size_t actualLength);
|
||||||
|
|||||||
@@ -22,8 +22,6 @@
|
|||||||
pci_module_info *EHCI::sPCIModule = NULL;
|
pci_module_info *EHCI::sPCIModule = NULL;
|
||||||
pci_x86_module_info *EHCI::sPCIx86Module = NULL;
|
pci_x86_module_info *EHCI::sPCIx86Module = NULL;
|
||||||
|
|
||||||
static int32 sDebuggerCommandAdded = 0;
|
|
||||||
|
|
||||||
|
|
||||||
static int32
|
static int32
|
||||||
ehci_std_ops(int32 op, ...)
|
ehci_std_ops(int32 op, ...)
|
||||||
@@ -107,83 +105,6 @@ print_queue(ehci_qh *queueHead)
|
|||||||
#endif // TRACE_USB
|
#endif // TRACE_USB
|
||||||
|
|
||||||
|
|
||||||
class DebugTransfer : public Transfer {
|
|
||||||
public:
|
|
||||||
DebugTransfer(Pipe *pipe)
|
|
||||||
:
|
|
||||||
Transfer(pipe)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ehci_qh * queue_head;
|
|
||||||
ehci_qtd * data_descriptor;
|
|
||||||
bool direction_in;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*! 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)
|
|
||||||
{
|
|
||||||
Pipe *pipe = (Pipe *)get_debug_variable("_usbPipe", 0);
|
|
||||||
if (pipe == NULL)
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
// check if we have a EHCI bus at all
|
|
||||||
if (pipe->GetBusManager()->TypeName()[0] != 'e')
|
|
||||||
return 3;
|
|
||||||
|
|
||||||
uint8 *data = (uint8 *)get_debug_variable("_usbTransferData", 0);
|
|
||||||
if (data == NULL)
|
|
||||||
return 4;
|
|
||||||
|
|
||||||
size_t length = (size_t)get_debug_variable("_usbTransferLength", 0);
|
|
||||||
if (length == 0)
|
|
||||||
return 5;
|
|
||||||
|
|
||||||
static uint8 transferBuffer[sizeof(DebugTransfer)]
|
|
||||||
__attribute__((aligned(16)));
|
|
||||||
static DebugTransfer *transfer = NULL;
|
|
||||||
|
|
||||||
EHCI *bus = (EHCI *)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)
|
|
||||||
return 6;
|
|
||||||
|
|
||||||
transfer = NULL;
|
|
||||||
return error == B_OK ? 0 : 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
transfer = new(transferBuffer) DebugTransfer(pipe);
|
|
||||||
transfer->SetData(data, length);
|
|
||||||
|
|
||||||
if (bus->StartDebugTransfer(transfer) != B_OK) {
|
|
||||||
transfer = NULL;
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
//
|
//
|
||||||
@@ -636,12 +557,6 @@ EHCI::EHCI(pci_info *info, Stack *stack)
|
|||||||
TRACE("set the async list addr to 0x%08" B_PRIx32 "\n",
|
TRACE("set the async list addr to 0x%08" B_PRIx32 "\n",
|
||||||
ReadOpReg(EHCI_ASYNCLISTADDR));
|
ReadOpReg(EHCI_ASYNCLISTADDR));
|
||||||
|
|
||||||
if (atomic_add(&sDebuggerCommandAdded, 1) == 0) {
|
|
||||||
add_debugger_command("ehci_process_transfer",
|
|
||||||
&debug_process_transfer,
|
|
||||||
"Processes a USB transfer with the given variables");
|
|
||||||
}
|
|
||||||
|
|
||||||
fInitOK = true;
|
fInitOK = true;
|
||||||
TRACE("EHCI host controller driver constructed\n");
|
TRACE("EHCI host controller driver constructed\n");
|
||||||
}
|
}
|
||||||
@@ -651,11 +566,6 @@ EHCI::~EHCI()
|
|||||||
{
|
{
|
||||||
TRACE("tear down EHCI host controller driver\n");
|
TRACE("tear down EHCI host controller driver\n");
|
||||||
|
|
||||||
if (atomic_add(&sDebuggerCommandAdded, -1) == 1) {
|
|
||||||
remove_debugger_command("ehci_process_transfer",
|
|
||||||
&debug_process_transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteOpReg(EHCI_USBCMD, 0);
|
WriteOpReg(EHCI_USBCMD, 0);
|
||||||
WriteOpReg(EHCI_CONFIGFLAG, 0);
|
WriteOpReg(EHCI_CONFIGFLAG, 0);
|
||||||
CancelAllPendingTransfers();
|
CancelAllPendingTransfers();
|
||||||
@@ -783,37 +693,41 @@ EHCI::Start()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
EHCI::StartDebugTransfer(DebugTransfer *transfer)
|
EHCI::StartDebugTransfer(Transfer *transfer)
|
||||||
{
|
{
|
||||||
Pipe *pipe = transfer->TransferPipe();
|
static transfer_data transferData;
|
||||||
transfer->queue_head = CreateQueueHead();
|
|
||||||
if (transfer->queue_head == NULL)
|
transferData.queue_head = CreateQueueHead();
|
||||||
|
if (transferData.queue_head == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
status_t result = InitQueueHead(transfer->queue_head, pipe);
|
Pipe *pipe = transfer->TransferPipe();
|
||||||
|
status_t result = InitQueueHead(transferData.queue_head, pipe);
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
FreeQueueHead(transfer->queue_head);
|
FreeQueueHead(transferData.queue_head);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pipe->Type() & USB_OBJECT_CONTROL_PIPE) != 0) {
|
if ((pipe->Type() & USB_OBJECT_CONTROL_PIPE) != 0) {
|
||||||
result = FillQueueWithRequest(transfer, transfer->queue_head,
|
result = FillQueueWithRequest(transfer, transferData.queue_head,
|
||||||
&transfer->data_descriptor, &transfer->direction_in);
|
&transferData.data_descriptor, &transferData.incoming);
|
||||||
} else {
|
} else {
|
||||||
result = FillQueueWithData(transfer, transfer->queue_head,
|
result = FillQueueWithData(transfer, transferData.queue_head,
|
||||||
&transfer->data_descriptor, &transfer->direction_in);
|
&transferData.data_descriptor, &transferData.incoming);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
FreeQueueHead(transfer->queue_head);
|
FreeQueueHead(transferData.queue_head);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) != 0)
|
if ((pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) != 0)
|
||||||
LinkPeriodicDebugQueueHead(transfer->queue_head, pipe);
|
LinkPeriodicDebugQueueHead(transferData.queue_head, pipe);
|
||||||
else
|
else
|
||||||
LinkAsyncDebugQueueHead(transfer->queue_head);
|
LinkAsyncDebugQueueHead(transferData.queue_head);
|
||||||
|
|
||||||
|
// we abuse the callback cookie to hold our transfer data
|
||||||
|
transfer->SetCallback(NULL, &transferData);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -853,11 +767,12 @@ EHCI::LinkPeriodicDebugQueueHead(ehci_qh *queueHead, Pipe *pipe)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
EHCI::CheckDebugTransfer(DebugTransfer *transfer, bool &_stillPending)
|
EHCI::CheckDebugTransfer(Transfer *transfer)
|
||||||
{
|
{
|
||||||
bool transferOK = false;
|
bool transferOK = false;
|
||||||
bool transferError = false;
|
bool transferError = false;
|
||||||
ehci_qtd *descriptor = transfer->queue_head->element_log;
|
transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
|
||||||
|
ehci_qtd *descriptor = transferData->queue_head->element_log;
|
||||||
|
|
||||||
while (descriptor) {
|
while (descriptor) {
|
||||||
uint32 status = descriptor->token;
|
uint32 status = descriptor->token;
|
||||||
@@ -895,36 +810,36 @@ EHCI::CheckDebugTransfer(DebugTransfer *transfer, bool &_stillPending)
|
|||||||
|
|
||||||
if (!transferOK && !transferError) {
|
if (!transferOK && !transferError) {
|
||||||
spin(75);
|
spin(75);
|
||||||
_stillPending = true;
|
return B_DEV_PENDING;
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transferOK) {
|
if (transferOK) {
|
||||||
bool nextDataToggle = false;
|
bool nextDataToggle = false;
|
||||||
if (transfer->data_descriptor != NULL && transfer->direction_in) {
|
if (transferData->data_descriptor != NULL && transferData->incoming) {
|
||||||
// data to read out
|
// data to read out
|
||||||
iovec *vector = transfer->Vector();
|
iovec *vector = transfer->Vector();
|
||||||
size_t vectorCount = transfer->VectorCount();
|
size_t vectorCount = transfer->VectorCount();
|
||||||
|
|
||||||
ReadDescriptorChain(transfer->data_descriptor,
|
ReadDescriptorChain(transferData->data_descriptor,
|
||||||
vector, vectorCount, &nextDataToggle);
|
vector, vectorCount, &nextDataToggle);
|
||||||
} else if (transfer->data_descriptor != NULL)
|
} else if (transferData->data_descriptor != NULL)
|
||||||
ReadActualLength(transfer->data_descriptor, &nextDataToggle);
|
ReadActualLength(transferData->data_descriptor, &nextDataToggle);
|
||||||
|
|
||||||
transfer->TransferPipe()->SetDataToggle(nextDataToggle);
|
transfer->TransferPipe()->SetDataToggle(nextDataToggle);
|
||||||
}
|
}
|
||||||
|
|
||||||
CleanupDebugTransfer(transfer);
|
CleanupDebugTransfer(transfer);
|
||||||
_stillPending = false;
|
|
||||||
return transferOK ? B_OK : B_IO_ERROR;
|
return transferOK ? B_OK : B_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
EHCI::CancelDebugTransfer(DebugTransfer *transfer)
|
EHCI::CancelDebugTransfer(Transfer *transfer)
|
||||||
{
|
{
|
||||||
|
transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
|
||||||
|
|
||||||
// clear the active bit so the descriptors are canceled
|
// clear the active bit so the descriptors are canceled
|
||||||
ehci_qtd *descriptor = transfer->queue_head->element_log;
|
ehci_qtd *descriptor = transferData->queue_head->element_log;
|
||||||
while (descriptor != NULL) {
|
while (descriptor != NULL) {
|
||||||
descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
|
descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
|
||||||
descriptor = descriptor->next_log;
|
descriptor = descriptor->next_log;
|
||||||
@@ -936,9 +851,10 @@ EHCI::CancelDebugTransfer(DebugTransfer *transfer)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
EHCI::CleanupDebugTransfer(DebugTransfer *transfer)
|
EHCI::CleanupDebugTransfer(Transfer *transfer)
|
||||||
{
|
{
|
||||||
ehci_qh *queueHead = transfer->queue_head;
|
transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
|
||||||
|
ehci_qh *queueHead = transferData->queue_head;
|
||||||
ehci_qh *prevHead = queueHead->prev_log;
|
ehci_qh *prevHead = queueHead->prev_log;
|
||||||
if (prevHead != NULL) {
|
if (prevHead != NULL) {
|
||||||
prevHead->next_phy = queueHead->next_phy;
|
prevHead->next_phy = queueHead->next_phy;
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ struct pci_info;
|
|||||||
struct pci_module_info;
|
struct pci_module_info;
|
||||||
struct pci_x86_module_info;
|
struct pci_x86_module_info;
|
||||||
|
|
||||||
class DebugTransfer;
|
|
||||||
class EHCIRootHub;
|
class EHCIRootHub;
|
||||||
|
|
||||||
|
|
||||||
@@ -57,16 +56,13 @@ public:
|
|||||||
|
|
||||||
status_t Start();
|
status_t Start();
|
||||||
|
|
||||||
status_t StartDebugTransfer(DebugTransfer *transfer);
|
virtual status_t StartDebugTransfer(Transfer *transfer);
|
||||||
status_t CheckDebugTransfer(DebugTransfer *transfer,
|
virtual status_t CheckDebugTransfer(Transfer *transfer);
|
||||||
bool &_stillPending);
|
|
||||||
void LinkAsyncDebugQueueHead(ehci_qh *queueHead);
|
void LinkAsyncDebugQueueHead(ehci_qh *queueHead);
|
||||||
void LinkPeriodicDebugQueueHead(
|
void LinkPeriodicDebugQueueHead(
|
||||||
ehci_qh *queueHead, Pipe *pipe);
|
ehci_qh *queueHead, Pipe *pipe);
|
||||||
void CancelDebugTransfer(
|
virtual void CancelDebugTransfer(Transfer *transfer);
|
||||||
DebugTransfer *transfer);
|
void CleanupDebugTransfer(Transfer *transfer);
|
||||||
void CleanupDebugTransfer(
|
|
||||||
DebugTransfer *transfer);
|
|
||||||
|
|
||||||
virtual status_t SubmitTransfer(Transfer *transfer);
|
virtual status_t SubmitTransfer(Transfer *transfer);
|
||||||
status_t SubmitIsochronous(Transfer *transfer);
|
status_t SubmitIsochronous(Transfer *transfer);
|
||||||
|
|||||||
@@ -21,86 +21,6 @@
|
|||||||
pci_module_info *UHCI::sPCIModule = NULL;
|
pci_module_info *UHCI::sPCIModule = NULL;
|
||||||
pci_x86_module_info *UHCI::sPCIx86Module = NULL;
|
pci_x86_module_info *UHCI::sPCIx86Module = NULL;
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
Pipe *pipe = (Pipe *)get_debug_variable("_usbPipe", 0);
|
|
||||||
if (pipe == NULL)
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
// check if we have a UHCI bus at all
|
|
||||||
if (pipe->GetBusManager()->TypeName()[0] != 'u')
|
|
||||||
return 3;
|
|
||||||
|
|
||||||
uint8 *data = (uint8 *)get_debug_variable("_usbTransferData", 0);
|
|
||||||
if (data == NULL)
|
|
||||||
return 4;
|
|
||||||
|
|
||||||
size_t length = (size_t)get_debug_variable("_usbTransferLength", 0);
|
|
||||||
if (length == 0)
|
|
||||||
return 5;
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
static int32
|
static int32
|
||||||
uhci_std_ops(int32 op, ...)
|
uhci_std_ops(int32 op, ...)
|
||||||
@@ -586,14 +506,6 @@ UHCI::UHCI(pci_info *info, Stack *stack)
|
|||||||
WriteReg16(UHCI_USBINTR, UHCI_USBINTR_CRC | UHCI_USBINTR_IOC
|
WriteReg16(UHCI_USBINTR, UHCI_USBINTR_CRC | UHCI_USBINTR_IOC
|
||||||
| UHCI_USBINTR_SHORT);
|
| UHCI_USBINTR_SHORT);
|
||||||
|
|
||||||
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
|
|
||||||
if (atomic_add(&sDebuggerCommandAdded, 1) == 0) {
|
|
||||||
add_debugger_command("uhci_process_transfer",
|
|
||||||
&debug_process_transfer,
|
|
||||||
"Processes a USB transfer with the given variables");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TRACE("UHCI host controller driver constructed\n");
|
TRACE("UHCI host controller driver constructed\n");
|
||||||
fInitOK = true;
|
fInitOK = true;
|
||||||
}
|
}
|
||||||
@@ -601,13 +513,6 @@ UHCI::UHCI(pci_info *info, Stack *stack)
|
|||||||
|
|
||||||
UHCI::~UHCI()
|
UHCI::~UHCI()
|
||||||
{
|
{
|
||||||
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
|
|
||||||
if (atomic_add(&sDebuggerCommandAdded, -1) == 1) {
|
|
||||||
remove_debugger_command("uhci_process_transfer",
|
|
||||||
&debug_process_transfer);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int32 result = 0;
|
int32 result = 0;
|
||||||
fStopThreads = true;
|
fStopThreads = true;
|
||||||
delete_sem(fFinishTransfersSem);
|
delete_sem(fFinishTransfersSem);
|
||||||
@@ -760,27 +665,32 @@ UHCI::SubmitTransfer(Transfer *transfer)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
UHCI::StartDebugTransfer(DebugTransfer *transfer)
|
UHCI::StartDebugTransfer(Transfer *transfer)
|
||||||
{
|
{
|
||||||
transfer->firstDescriptor = NULL;
|
static transfer_data transferData;
|
||||||
transfer->transferQueue = NULL;
|
transferData.first_descriptor = NULL;
|
||||||
status_t result = CreateFilledTransfer(transfer, &transfer->firstDescriptor,
|
transferData.transfer_queue = NULL;
|
||||||
&transfer->transferQueue);
|
status_t result = CreateFilledTransfer(transfer,
|
||||||
|
&transferData.first_descriptor, &transferData.transfer_queue);
|
||||||
if (result < B_OK)
|
if (result < B_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
fQueues[UHCI_DEBUG_QUEUE]->AppendTransfer(transfer->transferQueue, false);
|
fQueues[UHCI_DEBUG_QUEUE]->AppendTransfer(transferData.transfer_queue,
|
||||||
|
false);
|
||||||
|
|
||||||
|
// we abuse the callback cookie to hold our transfer data
|
||||||
|
transfer->SetCallback(NULL, &transferData);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
UHCI::CheckDebugTransfer(DebugTransfer *transfer, bool &_stillPending)
|
UHCI::CheckDebugTransfer(Transfer *transfer)
|
||||||
{
|
{
|
||||||
bool transferOK = false;
|
bool transferOK = false;
|
||||||
bool transferError = false;
|
bool transferError = false;
|
||||||
uhci_td *descriptor = transfer->firstDescriptor;
|
transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
|
||||||
|
uhci_td *descriptor = transferData->first_descriptor;
|
||||||
|
|
||||||
while (descriptor) {
|
while (descriptor) {
|
||||||
uint32 status = descriptor->status;
|
uint32 status = descriptor->status;
|
||||||
@@ -804,8 +714,7 @@ UHCI::CheckDebugTransfer(DebugTransfer *transfer, bool &_stillPending)
|
|||||||
|
|
||||||
if (!transferOK && !transferError) {
|
if (!transferOK && !transferError) {
|
||||||
spin(200);
|
spin(200);
|
||||||
_stillPending = true;
|
return B_DEV_PENDING;
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transferOK) {
|
if (transferOK) {
|
||||||
@@ -815,29 +724,31 @@ UHCI::CheckDebugTransfer(DebugTransfer *transfer, bool &_stillPending)
|
|||||||
iovec *vector = transfer->Vector();
|
iovec *vector = transfer->Vector();
|
||||||
size_t vectorCount = transfer->VectorCount();
|
size_t vectorCount = transfer->VectorCount();
|
||||||
|
|
||||||
ReadDescriptorChain(transfer->firstDescriptor,
|
ReadDescriptorChain(transferData->first_descriptor,
|
||||||
vector, vectorCount, &lastDataToggle);
|
vector, vectorCount, &lastDataToggle);
|
||||||
} else {
|
} else {
|
||||||
// read the actual length that was sent
|
// read the actual length that was sent
|
||||||
ReadActualLength(transfer->firstDescriptor, &lastDataToggle);
|
ReadActualLength(transferData->first_descriptor, &lastDataToggle);
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
|
transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transfer->transferQueue, false);
|
fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transferData->transfer_queue,
|
||||||
FreeDescriptorChain(transfer->firstDescriptor);
|
false);
|
||||||
FreeTransferQueue(transfer->transferQueue);
|
FreeDescriptorChain(transferData->first_descriptor);
|
||||||
_stillPending = false;
|
FreeTransferQueue(transferData->transfer_queue);
|
||||||
return transferOK ? B_OK : B_IO_ERROR;
|
return transferOK ? B_OK : B_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
UHCI::CancelDebugTransfer(DebugTransfer *transfer)
|
UHCI::CancelDebugTransfer(Transfer *transfer)
|
||||||
{
|
{
|
||||||
|
transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
|
||||||
|
|
||||||
// clear the active bit so the descriptors are canceled
|
// clear the active bit so the descriptors are canceled
|
||||||
uhci_td *descriptor = transfer->firstDescriptor;
|
uhci_td *descriptor = transferData->first_descriptor;
|
||||||
while (descriptor) {
|
while (descriptor) {
|
||||||
descriptor->status &= ~TD_STATUS_ACTIVE;
|
descriptor->status &= ~TD_STATUS_ACTIVE;
|
||||||
descriptor = (uhci_td *)descriptor->link_log;
|
descriptor = (uhci_td *)descriptor->link_log;
|
||||||
@@ -846,9 +757,10 @@ UHCI::CancelDebugTransfer(DebugTransfer *transfer)
|
|||||||
transfer->Finished(B_CANCELED, 0);
|
transfer->Finished(B_CANCELED, 0);
|
||||||
|
|
||||||
// dequeue and free resources
|
// dequeue and free resources
|
||||||
fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transfer->transferQueue, false);
|
fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transferData->transfer_queue,
|
||||||
FreeDescriptorChain(transfer->firstDescriptor);
|
false);
|
||||||
FreeTransferQueue(transfer->transferQueue);
|
FreeDescriptorChain(transferData->first_descriptor);
|
||||||
|
FreeTransferQueue(transferData->transfer_queue);
|
||||||
// TODO: [bonefish] The Free*() calls cause "PMA: provided address resulted
|
// TODO: [bonefish] The Free*() calls cause "PMA: provided address resulted
|
||||||
// in invalid index" to be printed, so apparently something is not right.
|
// 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
|
// Though I have not clue what. This is the same cleanup code as in
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
struct pci_info;
|
struct pci_info;
|
||||||
struct pci_module_info;
|
struct pci_module_info;
|
||||||
struct pci_x86_module_info;
|
struct pci_x86_module_info;
|
||||||
|
|
||||||
class UHCIRootHub;
|
class UHCIRootHub;
|
||||||
class DebugTransfer;
|
|
||||||
|
|
||||||
|
|
||||||
class Queue {
|
class Queue {
|
||||||
@@ -99,11 +99,11 @@ public:
|
|||||||
|
|
||||||
status_t Start();
|
status_t Start();
|
||||||
virtual status_t SubmitTransfer(Transfer *transfer);
|
virtual status_t SubmitTransfer(Transfer *transfer);
|
||||||
status_t StartDebugTransfer(DebugTransfer *transfer);
|
|
||||||
status_t CheckDebugTransfer(DebugTransfer *transfer,
|
virtual status_t StartDebugTransfer(Transfer *transfer);
|
||||||
bool &_stillPending);
|
virtual status_t CheckDebugTransfer(Transfer *transfer);
|
||||||
void CancelDebugTransfer(
|
virtual void CancelDebugTransfer(Transfer *transfer);
|
||||||
DebugTransfer *transfer);
|
|
||||||
virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force);
|
virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force);
|
||||||
status_t CancelQueuedIsochronousTransfers(Pipe *pipe, bool force);
|
status_t CancelQueuedIsochronousTransfers(Pipe *pipe, bool force);
|
||||||
status_t SubmitRequest(Transfer *transfer);
|
status_t SubmitRequest(Transfer *transfer);
|
||||||
|
|||||||
Reference in New Issue
Block a user