diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index a5a74b711f..f70213c9dd 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -155,7 +155,11 @@ Hub::Explore() if (result < B_OK) continue; - TRACE(("USB Hub (%d): port %d: status: 0x%04x; change: 0x%04x\n", DeviceAddress(), i, fPortStatus[i].status, fPortStatus[i].change)); +#ifdef TRACE_USB + if (fPortStatus[i].change) + TRACE(("USB Hub: port %d: status: 0x%04x; change: 0x%04x\n", i, fPortStatus[i].status, fPortStatus[i].change)); +#endif + if (fPortStatus[i].change & PORT_STATUS_CONNECTION) { if (fPortStatus[i].status & PORT_STATUS_CONNECTION) { // new device attached! diff --git a/src/add-ons/kernel/busses/usb/ehci.cpp b/src/add-ons/kernel/busses/usb/ehci.cpp index afbdb69de3..28741bacd7 100644 --- a/src/add-ons/kernel/busses/usb/ehci.cpp +++ b/src/add-ons/kernel/busses/usb/ehci.cpp @@ -60,7 +60,7 @@ void print_descriptor_chain(ehci_qtd *descriptor) { while (descriptor) { - dprintf(" %08x n%08x a%08x t%08x %08x %08x %08x %08x %08x s%d\n", + dprintf(" %08lx n%08lx a%08lx t%08lx %08lx %08lx %08lx %08lx %08lx s%ld\n", descriptor->this_phy, descriptor->next_phy, descriptor->alt_next_phy, descriptor->token, descriptor->buffer_phy[0], descriptor->buffer_phy[1], @@ -77,10 +77,10 @@ print_descriptor_chain(ehci_qtd *descriptor) void print_queue(ehci_qh *queueHead) { - dprintf("queue: t%08x n%08x ch%08x ca%08x cu%08x\n", + dprintf("queue: t%08lx n%08lx ch%08lx ca%08lx cu%08lx\n", queueHead->this_phy, queueHead->next_phy, queueHead->endpoint_chars, queueHead->endpoint_caps, queueHead->current_qtd_phy); - dprintf("overlay: n%08x a%08x t%08x %08x %08x %08x %08x %08x\n", + dprintf("overlay: n%08lx a%08lx t%08lx %08lx %08lx %08lx %08lx %08lx\n", queueHead->overlay.next_phy, queueHead->overlay.alt_next_phy, queueHead->overlay.token, queueHead->overlay.buffer_phy[0], queueHead->overlay.buffer_phy[1], queueHead->overlay.buffer_phy[2], @@ -136,7 +136,7 @@ EHCI::EHCI(pci_info *info, Stack *stack) size_t mapSize = (fPCIInfo->u.h0.base_register_sizes[0] + offset + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); - TRACE(("usb_ehci: map physical memory 0x%08x (base: 0x%08x; offset: %x); size: %d -> %d\n", fPCIInfo->u.h0.base_registers[0], physicalAddress, offset, fPCIInfo->u.h0.base_register_sizes[0], mapSize)); + TRACE(("usb_ehci: map physical memory 0x%08lx (base: 0x%08lx; offset: %lx); size: %ld\n", fPCIInfo->u.h0.base_registers[0], physicalAddress, offset, fPCIInfo->u.h0.base_register_sizes[0])); fRegisterArea = map_physical_memory("EHCI memory mapped registers", (void *)physicalAddress, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, @@ -148,8 +148,11 @@ EHCI::EHCI(pci_info *info, Stack *stack) fCapabilityRegisters += offset; fOperationalRegisters = fCapabilityRegisters + ReadCapReg8(EHCI_CAPLENGTH); - TRACE(("usb_ehci: mapped capability registers: 0x%08x\n", fCapabilityRegisters)); - TRACE(("usb_ehci: mapped operational registers: 0x%08x\n", fOperationalRegisters)); + TRACE(("usb_ehci: mapped capability registers: 0x%08lx\n", (uint32)fCapabilityRegisters)); + TRACE(("usb_ehci: mapped operational registers: 0x%08lx\n", (uint32)fOperationalRegisters)); + + TRACE(("usb_ehci: structural parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCSPARAMS))); + TRACE(("usb_ehci: capability parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCCPARAMS))); // read port count from capability register fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f; @@ -157,7 +160,7 @@ EHCI::EHCI(pci_info *info, Stack *stack) uint32 extendedCapPointer = ReadCapReg32(EHCI_HCCPARAMS) >> EHCI_ECP_SHIFT; extendedCapPointer &= EHCI_ECP_MASK; if (extendedCapPointer > 0) { - TRACE(("usb_ehci: extended capabilities register at %d\n", extendedCapPointer)); + TRACE(("usb_ehci: extended capabilities register at %ld\n", extendedCapPointer)); uint32 legacySupport = sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function, extendedCapPointer, 4); @@ -215,7 +218,7 @@ EHCI::EHCI(pci_info *info, Stack *stack) install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, InterruptHandler, (void *)this, 0); WriteOpReg(EHCI_USBINTR, EHCI_USBINTR_HOSTSYSERR - | EHCI_USBINTR_USBERRINT | EHCI_USBINTR_USBINT); + | EHCI_USBINTR_USBERRINT | EHCI_USBINTR_USBINT | EHCI_USBINTR_INTONAA); // allocate the periodic frame list fPeriodicFrameListArea = fStack->AllocateArea((void **)&fPeriodicFrameList, @@ -248,6 +251,7 @@ EHCI::EHCI(pci_info *info, Stack *stack) WriteOpReg(EHCI_ASYNCLISTADDR, (uint32)fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH); + TRACE(("usb_ehci: set the async list addr to 0x%08lx\n", ReadOpReg(EHCI_ASYNCLISTADDR))); fInitOK = true; TRACE(("usb_ehci: EHCI Host Controller Driver constructed\n")); @@ -277,7 +281,7 @@ status_t EHCI::Start() { TRACE(("usb_ehci: starting EHCI Host Controller\n")); - TRACE(("usb_ehci: usbcmd: 0x%08x; usbsts: 0x%08x\n", ReadOpReg(EHCI_USBCMD), ReadOpReg(EHCI_USBSTS))); + TRACE(("usb_ehci: usbcmd: 0x%08lx; usbsts: 0x%08lx\n", ReadOpReg(EHCI_USBCMD), ReadOpReg(EHCI_USBSTS))); uint32 frameListSize = (ReadOpReg(EHCI_USBCMD) >> EHCI_USBCMD_FLS_SHIFT) & EHCI_USBCMD_FLS_MASK; @@ -292,7 +296,7 @@ EHCI::Start() bool running = false; for (int32 i = 0; i < 10; i++) { uint32 status = ReadOpReg(EHCI_USBSTS); - TRACE(("usb_ehci: try %ld: status 0x%08x\n", i, status)); + TRACE(("usb_ehci: try %ld: status 0x%08lx\n", i, status)); if (status & EHCI_USBSTS_HCHALTED) { snooze(10000); @@ -377,14 +381,15 @@ EHCI::SubmitAsyncTransfer(Transfer *transfer) } if (pipe->Type() & USB_OBJECT_CONTROL_PIPE) { - queueHead->endpoint_chars |= EHCI_QH_CHARS_TOGGLE - | (pipe->Speed() != USB_SPEED_HIGHSPEED ? EHCI_QH_CHARS_CONTROL : 0); + queueHead->endpoint_chars |= + (pipe->Speed() != USB_SPEED_HIGHSPEED ? EHCI_QH_CHARS_CONTROL : 0); } queueHead->endpoint_chars |= (3 << EHCI_QH_CHARS_RL_SHIFT) | (pipe->MaxPacketSize() << EHCI_QH_CHARS_MPL_SHIFT) | (pipe->EndpointAddress() << EHCI_QH_CHARS_EPT_SHIFT) - | (pipe->DeviceAddress() << EHCI_QH_CHARS_DEV_SHIFT); + | (pipe->DeviceAddress() << EHCI_QH_CHARS_DEV_SHIFT) + | EHCI_QH_CHARS_TOGGLE; queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT) | (0x1c << EHCI_QH_CAPS_SCM_SHIFT); @@ -750,15 +755,12 @@ EHCI::Interrupt() if (status & EHCI_USBSTS_INTONAA) { TRACE(("usb_ehci: interrupt on async advance\n")); acknowledge |= EHCI_USBSTS_INTONAA; + fAsyncAdvance = true; } if (status & EHCI_USBSTS_HOSTSYSERR) { TRACE_ERROR(("usb_ehci: host system error!\n")); acknowledge |= EHCI_USBSTS_HOSTSYSERR; - print_queue(fAsyncQueueHead); - if (fAsyncQueueHead->next_log) { - print_queue((ehci_qh *)fAsyncQueueHead->next_log); - } } if (acknowledge) @@ -884,10 +886,73 @@ EHCI::FinishTransfers() transfer_data *transfer = fFirstTransfer; Unlock(); + ehci_qh *freeListHead = NULL; while (transfer) { bool transferDone = false; + ehci_qtd *descriptor = (ehci_qtd *)transfer->queue_head->element_log; - // ToDo... +#ifdef TRACE_USB + print_queue(transfer->queue_head); +#endif + + while (descriptor) { + uint32 status = descriptor->token; + if (status & EHCI_QTD_STATUS_ACTIVE) { + // still in progress + TRACE(("usb_ehci: qtd (0x%08lx) still active\n", descriptor->this_phy)); + break; + } + + if (status & EHCI_QTD_STATUS_ERRMASK) { + // a transfer error occured + TRACE_ERROR(("usb_ehci: qtd (0x%08lx) error: 0x%08lx\n", descriptor->this_phy, status)); + + uint32 callbackStatus = 0; + if (status & EHCI_QTD_STATUS_HALTED) + callbackStatus |= B_USB_STATUS_DEVICE_STALLED; + if (status & EHCI_QTD_STATUS_BUFFER) + callbackStatus |= B_USB_STATUS_DEVICE_TIMEOUT; + if (status & EHCI_QTD_STATUS_BABBLE) + callbackStatus |= B_USB_STATUS_ADAPTER_HARDWARE_ERROR; + if (status & EHCI_QTD_STATUS_TERROR) + callbackStatus |= B_USB_STATUS_DRIVER_INTERNAL_ERROR; + // ToDo: define better error values! + + UnlinkQueueHead(transfer->queue_head, &freeListHead); + transfer->transfer->Finished(callbackStatus, 0); + transferDone = true; + break; + } + + if (descriptor->next_phy & EHCI_QTD_TERMINATE) { + // we arrived at the last (stray) descriptor, we're done + TRACE(("usb_ehci: qtd (0x%08lx) done\n", descriptor->this_phy)); + + size_t actualLength = 0; + uint8 lastDataToggle = 0; + if (transfer->data_descriptor && transfer->incoming) { + // data to read out + actualLength = ReadDescriptorChain( + transfer->data_descriptor, + transfer->transfer->Vector(), + transfer->transfer->VectorCount(), + &lastDataToggle); + } else { + // calculate transfered length + actualLength = ReadActualLength( + (ehci_qtd *)transfer->queue_head->element_log, + &lastDataToggle); + } + + UnlinkQueueHead(transfer->queue_head, &freeListHead); + transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle); + transfer->transfer->Finished(B_USB_STATUS_SUCCESS, actualLength); + transferDone = true; + break; + } + + descriptor = (ehci_qtd *)descriptor->next_log; + } if (transferDone) { if (Lock()) { @@ -910,6 +975,20 @@ EHCI::FinishTransfers() transfer = transfer->link; } } + + if (freeListHead) { + fAsyncAdvance = false; + // set the doorbell and wait for the host controller to notify us + WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD); + while (!fAsyncAdvance) + snooze(10); + + while (freeListHead) { + ehci_qh *next = (ehci_qh *)freeListHead->next_log; + FreeQueueHead(freeListHead); + freeListHead = next; + } + } } } @@ -944,11 +1023,11 @@ EHCI::CreateQueueHead() result->overlay.next_phy = descriptor->this_phy; result->overlay.alt_next_phy = EHCI_QTD_TERMINATE; result->overlay.token = 0; - result->overlay.buffer_phy[0] = 0; - result->overlay.buffer_phy[1] = 0; - result->overlay.buffer_phy[2] = 0; - result->overlay.buffer_phy[3] = 0; - result->overlay.buffer_phy[4] = 0; + for (int32 i = 0; i < 5; i++) { + result->overlay.buffer_phy[i] = 0; + result->overlay.ext_buffer_phy[i] = 0; + } + return result; } @@ -959,9 +1038,8 @@ EHCI::FreeQueueHead(ehci_qh *queueHead) if (!queueHead) return; - FreeDescriptor((ehci_qtd *)queueHead->stray_log); + FreeDescriptorChain((ehci_qtd *)queueHead->element_log); fStack->FreeChunk(queueHead, (void *)queueHead->this_phy, sizeof(ehci_qh)); - } @@ -985,7 +1063,7 @@ EHCI::LinkQueueHead(ehci_qh *queueHead) status_t -EHCI::UnlinkQueueHead(ehci_qh *queueHead) +EHCI::UnlinkQueueHead(ehci_qh *queueHead, ehci_qh **freeListHead) { if (!Lock()) return B_ERROR; @@ -999,6 +1077,9 @@ EHCI::UnlinkQueueHead(ehci_qh *queueHead) queueHead->next_log = NULL; queueHead->prev_log = NULL; + queueHead->next_log = *freeListHead; + *freeListHead = queueHead; + Unlock(); return B_OK; } @@ -1070,9 +1151,34 @@ EHCI::FillQueueWithRequest(Transfer *transfer, ehci_qh *queueHead, status_t EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead, - ehci_qtd **dataDescriptor, bool *directionIn) + ehci_qtd **_dataDescriptor, bool *_directionIn) { - return B_ERROR; + Pipe *pipe = transfer->TransferPipe(); + bool directionIn = (pipe->Direction() == Pipe::In); + + ehci_qtd *firstDescriptor = NULL; + ehci_qtd *lastDescriptor = NULL; + ehci_qtd *strayDescriptor = (ehci_qtd *)queueHead->stray_log; + status_t result = CreateDescriptorChain(pipe, &firstDescriptor, + &lastDescriptor, strayDescriptor, transfer->VectorLength(), + directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT); + + if (result < B_OK) + return result; + + lastDescriptor->token |= EHCI_QTD_IOC; + if (!directionIn) { + WriteDescriptorChain(firstDescriptor, transfer->Vector(), + transfer->VectorCount()); + } + + queueHead->element_log = firstDescriptor; + queueHead->overlay.next_phy = firstDescriptor->this_phy; + queueHead->overlay.alt_next_phy = EHCI_QTD_TERMINATE; + + *_dataDescriptor = firstDescriptor; + *_directionIn = directionIn; + return B_OK; } @@ -1099,11 +1205,11 @@ EHCI::CreateDescriptor(size_t bufferSize, uint8 pid) result->token |= EHCI_QTD_STATUS_ACTIVE; if (bufferSize == 0) { result->buffer_log = NULL; - result->buffer_phy[0] = 0; - result->buffer_phy[1] = 0; - result->buffer_phy[2] = 0; - result->buffer_phy[3] = 0; - result->buffer_phy[4] = 0; + for (int32 i = 0; i < 5; i++) { + result->buffer_phy[i] = 0; + result->ext_buffer_phy[i] = 0; + } + return result; } @@ -1116,9 +1222,11 @@ EHCI::CreateDescriptor(size_t bufferSize, uint8 pid) addr_t physicalBase = (addr_t)physicalAddress; result->buffer_phy[0] = physicalBase; + result->ext_buffer_phy[0] = 0; for (int32 i = 1; i < 5; i++) { physicalBase += B_PAGE_SIZE; result->buffer_phy[i] = physicalBase & EHCI_QTD_PAGE_MASK; + result->ext_buffer_phy[i] = 0; } return result; @@ -1236,7 +1344,7 @@ EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, if (vectorOffset >= vector[vectorIndex].iov_len) { if (++vectorIndex >= vectorCount) { - TRACE(("usb_ehci: wrote descriptor chain (%d bytes, no more vectors)\n", actualLength)); + TRACE(("usb_ehci: wrote descriptor chain (%ld bytes, no more vectors)\n", actualLength)); return actualLength; } @@ -1255,7 +1363,7 @@ EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, current = (ehci_qtd *)current->next_log; } - TRACE(("usb_ehci: wrote descriptor chain (%d bytes)\n", actualLength)); + TRACE(("usb_ehci: wrote descriptor chain (%ld bytes)\n", actualLength)); return actualLength; } @@ -1271,12 +1379,13 @@ EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, size_t vectorOffset = 0; size_t bufferOffset = 0; - while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) > 0) { + while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) { if (!current->buffer_log) break; dataToggle = current->token & EHCI_QTD_DATA_TOGGLE; - size_t bufferSize = 0; // ToDo + size_t bufferSize = current->buffer_size; + bufferSize -= (current->token >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK; while (true) { size_t length = min_c(bufferSize - bufferOffset, @@ -1291,7 +1400,7 @@ EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, if (vectorOffset >= vector[vectorIndex].iov_len) { if (++vectorIndex >= vectorCount) { - TRACE(("usb_ehci: read descriptor chain (%d bytes, no more vectors)\n", actualLength)); + TRACE(("usb_ehci: read descriptor chain (%ld bytes, no more vectors)\n", actualLength)); if (lastDataToggle) *lastDataToggle = dataToggle > 0 ? 1 : 0; return actualLength; @@ -1312,7 +1421,7 @@ EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, current = (ehci_qtd *)current->next_log; } - TRACE(("usb_ehci: read descriptor chain (%d bytes)\n", actualLength)); + TRACE(("usb_ehci: read descriptor chain (%ld bytes)\n", actualLength)); if (lastDataToggle) *lastDataToggle = dataToggle > 0 ? 1 : 0; return actualLength; @@ -1326,9 +1435,10 @@ EHCI::ReadActualLength(ehci_qtd *topDescriptor, uint8 *lastDataToggle) ehci_qtd *current = topDescriptor; uint32 dataToggle = 0; - while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) > 0) { + while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) { dataToggle = current->token & EHCI_QTD_DATA_TOGGLE; - size_t length = 0; // ToDo + size_t length = current->buffer_size; + length -= (current->token >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK; actualLength += length; if (current->next_phy & EHCI_QTD_TERMINATE) @@ -1337,7 +1447,7 @@ EHCI::ReadActualLength(ehci_qtd *topDescriptor, uint8 *lastDataToggle) current = (ehci_qtd *)current->next_log; } - TRACE(("usb_ehci: read actual length (%d bytes)\n", actualLength)); + TRACE(("usb_ehci: read actual length (%ld bytes)\n", actualLength)); if (lastDataToggle) *lastDataToggle = dataToggle > 0 ? 1 : 0; return actualLength; diff --git a/src/add-ons/kernel/busses/usb/ehci.h b/src/add-ons/kernel/busses/usb/ehci.h index 280c4cd24a..318b67cd6a 100644 --- a/src/add-ons/kernel/busses/usb/ehci.h +++ b/src/add-ons/kernel/busses/usb/ehci.h @@ -9,7 +9,6 @@ #ifndef EHCI_H #define EHCI_H -#define TRACE_USB #include "usb_p.h" #include "ehci_hardware.h" @@ -74,7 +73,8 @@ static int32 FinishThread(void *data); void FreeQueueHead(ehci_qh *queueHead); status_t LinkQueueHead(ehci_qh *queueHead); - status_t UnlinkQueueHead(ehci_qh *queueHead); + status_t UnlinkQueueHead(ehci_qh *queueHead, + ehci_qh **freeList); // Queue functions status_t FillQueueWithRequest(Transfer *transfer, @@ -133,6 +133,7 @@ static pci_module_info *sPCIModule; // Async frame list ehci_qh *fAsyncQueueHead; + bool fAsyncAdvance; // Maintain a linked list of transfers transfer_data *fFirstTransfer; diff --git a/src/add-ons/kernel/busses/usb/ehci_hardware.h b/src/add-ons/kernel/busses/usb/ehci_hardware.h index a85171ab3a..e40b0fafe7 100644 --- a/src/add-ons/kernel/busses/usb/ehci_hardware.h +++ b/src/add-ons/kernel/busses/usb/ehci_hardware.h @@ -126,6 +126,7 @@ typedef struct { addr_t alt_next_phy; uint32 token; addr_t buffer_phy[5]; + addr_t ext_buffer_phy[5]; // Software Part addr_t this_phy; @@ -152,6 +153,7 @@ typedef struct { #define EHCI_QTD_PID_SETUP 0x02 #define EHCI_QTD_STATUS_SHIFT 0 #define EHCI_QTD_STATUS_MASK 0x7f +#define EHCI_QTD_STATUS_ERRMASK 0x78 #define EHCI_QTD_STATUS_ACTIVE (1 << 7) // Active #define EHCI_QTD_STATUS_HALTED (1 << 6) // Halted #define EHCI_QTD_STATUS_BUFFER (1 << 5) // Data Buffer Error @@ -176,6 +178,7 @@ typedef struct { addr_t alt_next_phy; uint32 token; addr_t buffer_phy[5]; + addr_t ext_buffer_phy[5]; } overlay; // Software Part