* Fixed spinlock usage in EHCI and UHCI drivers

* Fixed UHCI to allow for empty transfer buffers
* Extended the check for still linked transfer descriptors when removing a chain

There remain UHCI bugs that will cause transfers outgoing transfers to fail. I'll have to review / rewrite the UHCI driver.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19730 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2007-01-06 18:05:05 +00:00
parent 41f9e82cd1
commit 955dc88f0c
2 changed files with 18 additions and 18 deletions
+1 -1
View File
@@ -762,7 +762,7 @@ EHCI::InterruptHandler(void *data)
int32 int32
EHCI::Interrupt() EHCI::Interrupt()
{ {
spinlock lock = 0; static spinlock lock = 0;
acquire_spinlock(&lock); acquire_spinlock(&lock);
// check if any interrupt was generated // check if any interrupt was generated
+17 -17
View File
@@ -226,6 +226,8 @@ Queue::AppendDescriptorChain(uhci_td *descriptor)
element->link_log = descriptor; element->link_log = descriptor;
element->link_phy = descriptor->this_phy | TD_DEPTH_FIRST; element->link_phy = descriptor->this_phy | TD_DEPTH_FIRST;
if (fQueueHead->element_phy & QH_TERMINATE)
fQueueHead->element_phy = descriptor->this_phy;
TRACE(("usb_uhci: appended transfer to queue\n")); TRACE(("usb_uhci: appended transfer to queue\n"));
} }
@@ -247,11 +249,9 @@ Queue::RemoveDescriptorChain(uhci_td *firstDescriptor, uhci_td *lastDescriptor)
if ((lastDescriptor->link_phy & TD_TERMINATE) > 0) { if ((lastDescriptor->link_phy & TD_TERMINATE) > 0) {
// it is the only chain in this queue // it is the only chain in this queue
fQueueTop = NULL; fQueueTop = NULL;
fQueueHead->element_phy = QH_TERMINATE;
} else { } else {
// there are still linked transfers // there are still linked transfers
fQueueTop = (uhci_td *)lastDescriptor->link_log; fQueueTop = (uhci_td *)lastDescriptor->link_log;
fQueueHead->element_phy = fQueueTop->this_phy & TD_LINK_MASK;
} }
} else { } else {
// unlink the chain // unlink the chain
@@ -265,16 +265,17 @@ Queue::RemoveDescriptorChain(uhci_td *firstDescriptor, uhci_td *lastDescriptor)
element = (uhci_td *)element->link_log; element = (uhci_td *)element->link_log;
} }
}
element = firstDescriptor; uhci_td *element = firstDescriptor;
while (element && element != lastDescriptor) { while (element && element != lastDescriptor->link_log) {
if ((fQueueHead->element_phy & TD_LINK_MASK) == element->this_phy) { if ((fQueueHead->element_phy & TD_LINK_MASK) == element->this_phy) {
fQueueHead->element_phy = lastDescriptor->link_phy; fQueueHead->element_phy = lastDescriptor->link_phy;
break; TRACE_ERROR(("uhci: queue element pointer still pointing to removed chain\n"));
} break;
element = (uhci_td *)element->link_log;
} }
element = (uhci_td *)element->link_log;
} }
lastDescriptor->link_log = NULL; lastDescriptor->link_log = NULL;
@@ -357,8 +358,8 @@ UHCI::UHCI(pci_info *info, Stack *stack)
fPCIInfo->function, PCI_command, 2, command); fPCIInfo->function, PCI_command, 2, command);
// make sure we gain control of the UHCI controller instead of the BIOS // make sure we gain control of the UHCI controller instead of the BIOS
sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function, sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN); fPCIInfo->function, PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN);
// disable interrupts // disable interrupts
WriteReg16(UHCI_USBINTR, 0); WriteReg16(UHCI_USBINTR, 0);
@@ -523,9 +524,6 @@ UHCI::SubmitTransfer(Transfer *transfer)
if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE)
return SubmitRequest(transfer); return SubmitRequest(transfer);
if (transfer->VectorCount() == 0)
return B_BAD_VALUE;
Pipe *pipe = transfer->TransferPipe(); Pipe *pipe = transfer->TransferPipe();
bool directionIn = (pipe->Direction() == Pipe::In); bool directionIn = (pipe->Direction() == Pipe::In);
@@ -714,7 +712,7 @@ UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue,
if (fLastTransfer) if (fLastTransfer)
fLastTransfer->link = data; fLastTransfer->link = data;
else if (!fFirstTransfer)
fFirstTransfer = data; fFirstTransfer = data;
fLastTransfer = data; fLastTransfer = data;
@@ -1073,7 +1071,7 @@ UHCI::InterruptHandler(void *data)
int32 int32
UHCI::Interrupt() UHCI::Interrupt()
{ {
spinlock lock = 0; static spinlock lock = 0;
acquire_spinlock(&lock); acquire_spinlock(&lock);
// Check if we really had an interrupt // Check if we really had an interrupt
@@ -1259,6 +1257,8 @@ UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
{ {
size_t packetSize = pipe->MaxPacketSize(); size_t packetSize = pipe->MaxPacketSize();
int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize; int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
if (descriptorCount == 0)
descriptorCount = 1;
bool dataToggle = pipe->DataToggle(); bool dataToggle = pipe->DataToggle();
uhci_td *firstDescriptor = NULL; uhci_td *firstDescriptor = NULL;