* 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:
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user