diff --git a/src/add-ons/kernel/bus_managers/usb/Device.cpp b/src/add-ons/kernel/bus_managers/usb/Device.cpp index 655cd8b044..5eedfdebe7 100644 --- a/src/add-ons/kernel/bus_managers/usb/Device.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Device.cpp @@ -350,12 +350,11 @@ Device::DeviceDescriptor() const status_t Device::ReportDevice(usb_support_descriptor *supportDescriptors, uint32 supportDescriptorCount, const usb_notify_hooks *hooks, - void *cookies[], bool added) + usb_driver_cookie **cookies, bool added) { TRACE(("USB Device ReportDevice\n")); if ((added && hooks->device_added == NULL) - || (!added && hooks->device_removed == NULL) - || (!added && cookies[fDeviceAddress] == NULL)) + || (!added && hooks->device_removed == NULL)) return B_BAD_VALUE; bool supported = false; @@ -397,16 +396,31 @@ Device::ReportDevice(usb_support_descriptor *supportDescriptors, } if (supported) { + usb_id id = USBID(); if (added) { - status_t result = hooks->device_added(USBID(), &cookies[fDeviceAddress]); - if (result != B_OK) - cookies[fDeviceAddress] = NULL; + usb_driver_cookie *cookie = new(std::nothrow) usb_driver_cookie; + status_t result = hooks->device_added(id, &cookie->cookie); + cookie->device = id; + cookie->link = *cookies; + *cookies = cookie; return result; } - hooks->device_removed(cookies[fDeviceAddress]); - cookies[fDeviceAddress] = NULL; - return B_OK; + usb_driver_cookie **pointer = cookies; + usb_driver_cookie *cookie = *cookies; + while (cookie) { + if (cookie->device == id) + break; + pointer = &cookie->link; + cookie = cookie->link; + } + + if (cookie) { + hooks->device_removed(cookie->cookie); + *pointer = cookie->link; + delete cookie; + return B_OK; + } } return B_UNSUPPORTED; diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index 6bb81f5f81..42950f2d66 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -256,7 +256,7 @@ Hub::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID, status_t Hub::ReportDevice(usb_support_descriptor *supportDescriptors, uint32 supportDescriptorCount, const usb_notify_hooks *hooks, - void *cookies[], bool added) + usb_driver_cookie **cookies, bool added) { TRACE(("USB Hub ReportDevice\n")); diff --git a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp index 0a57d5fa4a..15fdd3ef03 100644 --- a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp @@ -62,6 +62,10 @@ Pipe::SetFeature(uint16 selector) status_t Pipe::ClearFeature(uint16 selector) { + // clearing a stalled condition resets the data toggle + if (selector == USB_FEATURE_ENDPOINT_HALT) + SetDataToggle(false); + return ((Device *)Parent())->DefaultPipe()->SendRequest( USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, USB_REQUEST_CLEAR_FEATURE, diff --git a/src/add-ons/kernel/bus_managers/usb/Stack.cpp b/src/add-ons/kernel/bus_managers/usb/Stack.cpp index 2bd351acb0..168ad5f638 100644 --- a/src/add-ons/kernel/bus_managers/usb/Stack.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Stack.cpp @@ -32,7 +32,7 @@ Stack::Stack() memset(fObjectArray, 0, objectArraySize); fAllocator = new(std::nothrow) PhysicalMemoryAllocator("USB Stack Allocator", - 8, B_PAGE_SIZE * 4, 50); + 8, B_PAGE_SIZE * 4, 64); if (!fAllocator) { TRACE_ERROR(("usb stack: failed to allocate the allocator\n")); return; @@ -233,7 +233,7 @@ Stack::NotifyDeviceChange(Device *device, bool added) || (!added && element->notify_hooks.device_removed != NULL)) { status_t result = device->ReportDevice(element->support_descriptors, element->support_descriptor_count, - &element->notify_hooks, element->cookies, added); + &element->notify_hooks, &element->cookies, added); if (result == B_OK) { const char *name = element->driver_name; @@ -268,9 +268,9 @@ Stack::RegisterDriver(const char *driverName, memcpy(info->support_descriptors, descriptors, descriptorsSize); info->support_descriptor_count = descriptorCount; - memset(info->cookies, 0, sizeof(void *) * 128); info->notify_hooks.device_added = NULL; info->notify_hooks.device_removed = NULL; + info->cookies = NULL; info->link = NULL; if (!Lock()) { @@ -310,7 +310,7 @@ Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks) // Report device will recurse down the whole tree rootHub->ReportDevice(element->support_descriptors, element->support_descriptor_count, hooks, - element->cookies, true); + &element->cookies, true); } } @@ -342,7 +342,7 @@ Stack::UninstallNotify(const char *driverName) if (rootHub) rootHub->ReportDevice(element->support_descriptors, element->support_descriptor_count, - &element->notify_hooks, element->cookies, false); + &element->notify_hooks, &element->cookies, false); } element->notify_hooks.device_added = NULL; diff --git a/src/add-ons/kernel/bus_managers/usb/usb_p.h b/src/add-ons/kernel/bus_managers/usb/usb_p.h index fb568d34f4..7347d8f686 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb_p.h +++ b/src/add-ons/kernel/bus_managers/usb/usb_p.h @@ -42,13 +42,20 @@ struct host_controller_info { }; +struct usb_driver_cookie { + usb_id device; + void *cookie; + usb_driver_cookie *link; +}; + + struct usb_driver_info { const char *driver_name; usb_support_descriptor *support_descriptors; uint32 support_descriptor_count; const char *republish_driver_name; usb_notify_hooks notify_hooks; - void *cookies[128]; + usb_driver_cookie *cookies; usb_driver_info *link; }; @@ -385,7 +392,8 @@ virtual status_t ReportDevice( usb_support_descriptor *supportDescriptors, uint32 supportDescriptorCount, const usb_notify_hooks *hooks, - void *cookies[], bool added); + usb_driver_cookie **cookies, + bool added); virtual status_t BuildDeviceName(char *string, uint32 *index, size_t bufferSize, Device *device); @@ -436,7 +444,8 @@ virtual status_t ReportDevice( usb_support_descriptor *supportDescriptors, uint32 supportDescriptorCount, const usb_notify_hooks *hooks, - void *cookies[], bool added); + usb_driver_cookie **cookies, + bool added); virtual status_t BuildDeviceName(char *string, uint32 *index, size_t bufferSize, Device *device); diff --git a/src/add-ons/kernel/busses/usb/ehci.cpp b/src/add-ons/kernel/busses/usb/ehci.cpp index f52b67864e..c321860177 100644 --- a/src/add-ons/kernel/busses/usb/ehci.cpp +++ b/src/add-ons/kernel/busses/usb/ehci.cpp @@ -942,6 +942,12 @@ EHCI::FinishTransfers() if (acquire_sem(fFinishTransfersSem) < B_OK) continue; + // eat up sems that have been released by multiple interrupts + int32 semCount = 0; + get_sem_count(fFinishTransfersSem, &semCount); + if (semCount > 0) + acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); + if (!Lock()) continue; @@ -993,7 +999,7 @@ EHCI::FinishTransfers() TRACE(("usb_ehci: qtd (0x%08lx) done\n", descriptor->this_phy)); size_t actualLength = 0; - uint8 lastDataToggle = 0; + bool nextDataToggle = false; if (transfer->data_descriptor && transfer->incoming) { // data to read out iovec *vector = transfer->transfer->Vector(); @@ -1019,7 +1025,7 @@ EHCI::FinishTransfers() actualLength = ReadDescriptorChain( transfer->data_descriptor, vector, vectorCount, - &lastDataToggle); + &nextDataToggle); #ifndef HAIKU_TARGET_PLATFORM_HAIKU if (clonedArea >= B_OK) @@ -1029,11 +1035,11 @@ EHCI::FinishTransfers() // calculate transfered length actualLength = ReadActualLength( (ehci_qtd *)transfer->queue_head->element_log, - &lastDataToggle); + &nextDataToggle); } UnlinkQueueHead(transfer->queue_head, &freeListHead); - transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle); + transfer->transfer->TransferPipe()->SetDataToggle(nextDataToggle); transfer->transfer->Finished(B_USB_STATUS_SUCCESS, actualLength); transferDone = true; break; @@ -1324,7 +1330,7 @@ EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor, ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize, uint8 pid) { - size_t packetSize = pipe->MaxPacketSize(); + size_t packetSize = B_PAGE_SIZE * 4; int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize; bool dataToggle = pipe->DataToggle(); @@ -1345,7 +1351,6 @@ EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor, if (lastDescriptor) LinkDescriptors(lastDescriptor, descriptor, strayDescriptor); - dataToggle = !dataToggle; bufferSize -= packetSize; lastDescriptor = descriptor; if (!firstDescriptor) @@ -1456,7 +1461,7 @@ EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, size_t EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, - size_t vectorCount, uint8 *lastDataToggle) + size_t vectorCount, bool *nextDataToggle) { uint32 dataToggle = 0; ehci_qtd *current = topDescriptor; @@ -1487,8 +1492,7 @@ EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, if (vectorOffset >= vector[vectorIndex].iov_len) { if (++vectorIndex >= vectorCount) { TRACE(("usb_ehci: read descriptor chain (%ld bytes, no more vectors)\n", actualLength)); - if (lastDataToggle) - *lastDataToggle = dataToggle > 0 ? 1 : 0; + *nextDataToggle = dataToggle > 0 ? true : false; return actualLength; } @@ -1508,14 +1512,13 @@ EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, } TRACE(("usb_ehci: read descriptor chain (%ld bytes)\n", actualLength)); - if (lastDataToggle) - *lastDataToggle = dataToggle > 0 ? 1 : 0; + *nextDataToggle = dataToggle > 0 ? true : false; return actualLength; } size_t -EHCI::ReadActualLength(ehci_qtd *topDescriptor, uint8 *lastDataToggle) +EHCI::ReadActualLength(ehci_qtd *topDescriptor, bool *nextDataToggle) { size_t actualLength = 0; ehci_qtd *current = topDescriptor; @@ -1534,8 +1537,7 @@ EHCI::ReadActualLength(ehci_qtd *topDescriptor, uint8 *lastDataToggle) } TRACE(("usb_ehci: read actual length (%ld bytes)\n", actualLength)); - if (lastDataToggle) - *lastDataToggle = dataToggle > 0 ? 1 : 0; + *nextDataToggle = dataToggle > 0 ? true : false; return actualLength; } diff --git a/src/add-ons/kernel/busses/usb/ehci.h b/src/add-ons/kernel/busses/usb/ehci.h index cf73ae7f95..bb9acabe21 100644 --- a/src/add-ons/kernel/busses/usb/ehci.h +++ b/src/add-ons/kernel/busses/usb/ehci.h @@ -107,9 +107,9 @@ static int32 FinishThread(void *data); iovec *vector, size_t vectorCount); size_t ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, size_t vectorCount, - uint8 *lastDataToggle); + bool *nextDataToggle); size_t ReadActualLength(ehci_qtd *topDescriptor, - uint8 *lastDataToggle); + bool *nextDataToggle); // Operational register functions inline void WriteOpReg(uint32 reg, uint32 value); diff --git a/src/add-ons/kernel/busses/usb/ehci_hardware.h b/src/add-ons/kernel/busses/usb/ehci_hardware.h index e40b0fafe7..3b2d0cb6b9 100644 --- a/src/add-ons/kernel/busses/usb/ehci_hardware.h +++ b/src/add-ons/kernel/busses/usb/ehci_hardware.h @@ -153,7 +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_ERRMASK 0x70 #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 diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index 6b431016e3..dd0fdc74a8 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -67,7 +67,7 @@ void print_descriptor_chain(uhci_td *descriptor) { while (descriptor) { - dprintf("ph: 0x%08x; lp: 0x%08x; vf: %s; q: %s; t: %s; st: 0x%08x; to: 0x%08x\n", + dprintf("ph: 0x%08lx; lp: 0x%08lx; vf: %s; q: %s; t: %s; st: 0x%08lx; to: 0x%08lx\n", descriptor->this_phy & 0xffffffff, descriptor->link_phy & 0xfffffff0, descriptor->link_phy & 0x4 ? "y" : "n", descriptor->link_phy & 0x2 ? "qh" : "td", @@ -301,8 +301,8 @@ Queue::PrintToStream() { #ifdef TRACE_USB dprintf("USB UHCI Queue:\n"); - dprintf("link phy: 0x%08x; link type: %s; terminate: %s\n", fQueueHead->link_phy & 0xfff0, fQueueHead->link_phy & 0x0002 ? "QH" : "TD", fQueueHead->link_phy & 0x0001 ? "yes" : "no"); - dprintf("elem phy: 0x%08x; elem type: %s; terminate: %s\n", fQueueHead->element_phy & 0xfff0, fQueueHead->element_phy & 0x0002 ? "QH" : "TD", fQueueHead->element_phy & 0x0001 ? "yes" : "no"); + dprintf("link phy: 0x%08lx; link type: %s; terminate: %s\n", fQueueHead->link_phy & 0xfff0, fQueueHead->link_phy & 0x0002 ? "QH" : "TD", fQueueHead->link_phy & 0x0001 ? "yes" : "no"); + dprintf("elem phy: 0x%08lx; elem type: %s; terminate: %s\n", fQueueHead->element_phy & 0xfff0, fQueueHead->element_phy & 0x0002 ? "QH" : "TD", fQueueHead->element_phy & 0x0001 ? "yes" : "no"); dprintf("elements:\n"); print_descriptor_chain(fQueueTop); #endif @@ -476,7 +476,7 @@ UHCI::Start() bool running = false; for (int32 i = 0; i < 10; i++) { uint16 status = ReadReg16(UHCI_USBSTS); - TRACE(("usb_uhci: current loop %u, status 0x%04x\n", i, status)); + TRACE(("usb_uhci: current loop %ld, status 0x%04x\n", i, status)); if (status & UHCI_USBSTS_HCHALT) snooze(10000); @@ -515,12 +515,11 @@ UHCI::Start() status_t UHCI::SubmitTransfer(Transfer *transfer) { - TRACE(("usb_uhci: submit transfer called for device %d\n", transfer->TransferPipe()->DeviceAddress())); - // Short circuit the root hub if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress) return fRootHub->ProcessTransfer(this, transfer); + TRACE(("usb_uhci: submit transfer called for device %d\n", transfer->TransferPipe()->DeviceAddress())); if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) return SubmitRequest(transfer); @@ -740,10 +739,16 @@ UHCI::FinishTransfers() if (acquire_sem(fFinishTransfersSem) < B_OK) continue; + // eat up sems that have been released by multiple interrupts + int32 semCount = 0; + get_sem_count(fFinishTransfersSem, &semCount); + if (semCount > 0) + acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); + if (!Lock()) continue; - TRACE(("usb_uhci: finishing transfers (first transfer: 0x%08x; last transfer: 0x%08x)\n", fFirstTransfer, fLastTransfer)); + TRACE(("usb_uhci: finishing transfers (first transfer: 0x%08lx; last transfer: 0x%08lx)\n", (uint32)fFirstTransfer, (uint32)fLastTransfer)); transfer_data *lastTransfer = NULL; transfer_data *transfer = fFirstTransfer; Unlock(); @@ -755,7 +760,7 @@ UHCI::FinishTransfers() while (descriptor) { uint32 status = descriptor->status; if (status & TD_STATUS_ACTIVE) { - TRACE(("usb_uhci: td (0x%08x) still active\n", descriptor->this_phy)); + TRACE(("usb_uhci: td (0x%08lx) still active\n", descriptor->this_phy)); // still in progress break; } @@ -789,7 +794,7 @@ UHCI::FinishTransfers() if (descriptor == transfer->last_descriptor || (descriptor->status & TD_STATUS_ACTLEN_MASK) < (descriptor->token >> TD_TOKEN_MAXLEN_SHIFT)) { - TRACE(("usb_uhci: td (0x%08x) ok\n", descriptor->this_phy)); + TRACE(("usb_uhci: td (0x%08lx) ok\n", descriptor->this_phy)); // we got through without errors so we are finished transfer->queue->RemoveDescriptorChain( transfer->first_descriptor, @@ -1317,7 +1322,7 @@ UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector, size_t length = min_c(current->buffer_size - bufferOffset, vector[vectorIndex].iov_len - vectorOffset); - TRACE(("usb_uhci: copying %d bytes to bufferOffset %d from vectorOffset %d at index %d of %d\n", length, bufferOffset, vectorOffset, vectorIndex, vectorCount)); + TRACE(("usb_uhci: copying %ld bytes to bufferOffset %ld from vectorOffset %ld at index %ld of %ld\n", length, bufferOffset, vectorOffset, vectorIndex, vectorCount)); memcpy((uint8 *)current->buffer_log + bufferOffset, (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length); @@ -1327,7 +1332,7 @@ UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector, if (vectorOffset >= vector[vectorIndex].iov_len) { if (++vectorIndex >= vectorCount) { - TRACE(("usb_uhci: wrote descriptor chain (%d bytes, no more vectors)\n", actualLength)); + TRACE(("usb_uhci: wrote descriptor chain (%ld bytes, no more vectors)\n", actualLength)); return actualLength; } @@ -1346,7 +1351,7 @@ UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector, current = (uhci_td *)current->link_log; } - TRACE(("usb_uhci: wrote descriptor chain (%d bytes)\n", actualLength)); + TRACE(("usb_uhci: wrote descriptor chain (%ld bytes)\n", actualLength)); return actualLength; } @@ -1375,7 +1380,7 @@ UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector, size_t length = min_c(bufferSize - bufferOffset, vector[vectorIndex].iov_len - vectorOffset); - TRACE(("usb_uhci: copying %d bytes to vectorOffset %d from bufferOffset %d at index %d of %d\n", length, vectorOffset, bufferOffset, vectorIndex, vectorCount)); + TRACE(("usb_uhci: copying %ld bytes to vectorOffset %ld from bufferOffset %ld at index %ld of %ld\n", length, vectorOffset, bufferOffset, vectorIndex, vectorCount)); memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset, (uint8 *)current->buffer_log + bufferOffset, length); @@ -1385,7 +1390,7 @@ UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector, if (vectorOffset >= vector[vectorIndex].iov_len) { if (++vectorIndex >= vectorCount) { - TRACE(("usb_uhci: read descriptor chain (%d bytes, no more vectors)\n", actualLength)); + TRACE(("usb_uhci: read descriptor chain (%ld bytes, no more vectors)\n", actualLength)); if (lastDataToggle) *lastDataToggle = dataToggle; return actualLength; @@ -1409,7 +1414,7 @@ UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector, if (lastDataToggle) *lastDataToggle = dataToggle; - TRACE(("usb_uhci: read descriptor chain (%d bytes)\n", actualLength)); + TRACE(("usb_uhci: read descriptor chain (%ld bytes)\n", actualLength)); return actualLength; } @@ -1438,7 +1443,7 @@ UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle) if (lastDataToggle) *lastDataToggle = dataToggle; - TRACE(("usb_uhci: read actual length (%d bytes)\n", actualLength)); + TRACE(("usb_uhci: read actual length (%ld bytes)\n", actualLength)); return actualLength; }