* Renamed some variables
* Reworking the interrupts endpoints tree parts * Added spin_locker, semaphore, finisher thread and interrupt handler (not implemented) * Made fInterruptEndpoints allocation dynamic instead of static * Fixed Start method (it should be correct now) git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22927 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -66,13 +66,18 @@ OHCI::OHCI(pci_info *info, Stack *stack)
|
|||||||
fPCIInfo(info),
|
fPCIInfo(info),
|
||||||
fStack(stack),
|
fStack(stack),
|
||||||
fRegisterArea(-1),
|
fRegisterArea(-1),
|
||||||
|
fSpinLock(0),
|
||||||
fHccaArea(-1),
|
fHccaArea(-1),
|
||||||
fDummyControl(NULL),
|
fDummyControl(NULL),
|
||||||
fDummyBulk(NULL),
|
fDummyBulk(NULL),
|
||||||
fDummyIsochronous(NULL),
|
fDummyIsochronous(NULL),
|
||||||
|
fFirstTransfer(NULL),
|
||||||
|
fFinishTransfer(NULL),
|
||||||
|
fFinishThread(-1),
|
||||||
|
fStopFinishThread(false),
|
||||||
fRootHub(NULL),
|
fRootHub(NULL),
|
||||||
fRootHubAddress(0),
|
fRootHubAddress(0),
|
||||||
fNumPorts(0)
|
fPortCount(0)
|
||||||
{
|
{
|
||||||
if (!fInitOK) {
|
if (!fInitOK) {
|
||||||
TRACE_ERROR(("usb_ohci: bus manager failed to init\n"));
|
TRACE_ERROR(("usb_ohci: bus manager failed to init\n"));
|
||||||
@@ -119,12 +124,13 @@ OHCI::OHCI(pci_info *info, Stack *stack)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set up the Host Controller Communications Area
|
// Set up the Host Controller Communications Area
|
||||||
|
// which is 256 bytes (2048 bits) and must be aligned
|
||||||
void *hccaPhysicalAddress;
|
void *hccaPhysicalAddress;
|
||||||
fHccaArea = fStack->AllocateArea((void **)&fHcca, &hccaPhysicalAddress,
|
fHccaArea = fStack->AllocateArea((void **)&fHcca, &hccaPhysicalAddress,
|
||||||
2048, "USB OHCI Host Controller Communication Area");
|
2048, "USB OHCI Host Controller Communication Area");
|
||||||
|
|
||||||
if (fHccaArea < B_OK) {
|
if (fHccaArea < B_OK) {
|
||||||
TRACE(("usb_ohci: unable to create the HCCA block area\n"));
|
TRACE_ERROR(("usb_ohci: unable to create the HCCA block area\n"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,9 +159,35 @@ OHCI::OHCI(pci_info *info, Stack *stack)
|
|||||||
fDummyIsochronous->flags |= OHCI_ENDPOINT_SKIP;
|
fDummyIsochronous->flags |= OHCI_ENDPOINT_SKIP;
|
||||||
|
|
||||||
// Create the interrupt tree
|
// Create the interrupt tree
|
||||||
// Algorithm kindly borrowed from NetBSD code
|
fInterruptEndpoints = new(std::nothrow)
|
||||||
// TODO: Check it once again
|
ohci_endpoint_descriptor *[OHCI_NUMBER_OF_INTERRUPTS];
|
||||||
ohci_endpoint_descriptor *current, *previous;
|
if (!fInterruptEndpoints) {
|
||||||
|
TRACE_ERROR(("ohci_usb: cannot allocate memory for"
|
||||||
|
" fInterruptEndpoints array\n"));
|
||||||
|
_FreeEndpoint(fDummyControl);
|
||||||
|
_FreeEndpoint(fDummyBulk);
|
||||||
|
_FreeEndpoint(fDummyIsochronous);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static endpoints that get linked in the HCCA
|
||||||
|
for (uint32 i = 0; i < OHCI_NUMBER_OF_INTERRUPTS; i++) {
|
||||||
|
fInterruptEndpoints[i] = _AllocateEndpoint();
|
||||||
|
if (!fInterruptEndpoints[i]) {
|
||||||
|
while (--i >= 0)
|
||||||
|
_FreeEndpoint(fInterruptEndpoints[i]);
|
||||||
|
_FreeEndpoint(fDummyBulk);
|
||||||
|
_FreeEndpoint(fDummyControl);
|
||||||
|
_FreeEndpoint(fDummyIsochronous);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fInterruptEndpoints[i]->flags |= OHCI_ENDPOINT_SKIP;
|
||||||
|
fInterruptEndpoints[i]->next_physical_endpoint
|
||||||
|
= fDummyIsochronous->physical_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
ohci_endpoint_descriptor *current;
|
||||||
for( uint32 i = 0; i < OHCI_NUMBER_OF_ENDPOINTS; i++) {
|
for( uint32 i = 0; i < OHCI_NUMBER_OF_ENDPOINTS; i++) {
|
||||||
current = _AllocateEndpoint();
|
current = _AllocateEndpoint();
|
||||||
if (!current) {
|
if (!current) {
|
||||||
@@ -174,13 +206,14 @@ OHCI::OHCI(pci_info *info, Stack *stack)
|
|||||||
else
|
else
|
||||||
previous = fDummyIsochronous;
|
previous = fDummyIsochronous;
|
||||||
current->next_logical_endpoint = previous;
|
current->next_logical_endpoint = previous;
|
||||||
current->next_physical_endpoint = previous->this_physical;
|
current->next_physical_endpoint = previous->physical_address;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Fill HCCA interrupt table. The bit reversal is to get
|
// Fill HCCA interrupt table. The bit reversal is to get
|
||||||
// the tree set up properly to spread the interrupts.
|
// the tree set up properly to spread the interrupts.
|
||||||
for (uint32 i = 0; i < OHCI_NUMBER_OF_INTERRUPTS; i++)
|
for (uint32 i = 0; i < OHCI_NUMBER_OF_INTERRUPTS; i++)
|
||||||
fHcca->hcca_interrupt_table[revbits[i]] =
|
fHcca->interrupt_table[revbits[i]] =
|
||||||
fInterruptEndpoints[OHCI_NUMBER_OF_ENDPOINTS - OHCI_NUMBER_OF_INTERRUPTS + i]->physical_address;
|
fInterruptEndpoints[OHCI_NUMBER_OF_ENDPOINTS - OHCI_NUMBER_OF_INTERRUPTS + i]->physical_address;
|
||||||
|
|
||||||
|
|
||||||
@@ -230,8 +263,12 @@ OHCI::OHCI(pci_info *info, Stack *stack)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The controller is now in SUSPEND state, we have 2ms to finish
|
// The controller is now in SUSPEND state, we have 2ms to go OPERATIONAL.
|
||||||
// TODO: maybe add spinlock protection???
|
// In order to do so we need a spinlock
|
||||||
|
|
||||||
|
cpu_status former = disable_interrupts();
|
||||||
|
acquire_spinlock(&fSpinLock);
|
||||||
|
|
||||||
// Set up host controller register
|
// Set up host controller register
|
||||||
_WriteReg(OHCI_HCCA, (uint32)hccaPhysicalAddress);
|
_WriteReg(OHCI_HCCA, (uint32)hccaPhysicalAddress);
|
||||||
_WriteReg(OHCI_CONTROL_HEAD_ED, (uint32)fDummyControl->physical_address);
|
_WriteReg(OHCI_CONTROL_HEAD_ED, (uint32)fDummyControl->physical_address);
|
||||||
@@ -248,7 +285,10 @@ OHCI::OHCI(pci_info *info, Stack *stack)
|
|||||||
| OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL;
|
| OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL;
|
||||||
// And finally start the controller
|
// And finally start the controller
|
||||||
_WriteReg(OHCI_CONTROL, control);
|
_WriteReg(OHCI_CONTROL, control);
|
||||||
|
|
||||||
|
release_spinlock(&fSpinLock);
|
||||||
|
restore_interrupts(former);
|
||||||
|
|
||||||
// The controller is now OPERATIONAL.
|
// The controller is now OPERATIONAL.
|
||||||
frameInterval = (_ReadReg(OHCI_FRAME_INTERVAL) & OHCI_FRAME_INTERVAL_TOGGLE)
|
frameInterval = (_ReadReg(OHCI_FRAME_INTERVAL) & OHCI_FRAME_INTERVAL_TOGGLE)
|
||||||
^ OHCI_FRAME_INTERVAL_TOGGLE;
|
^ OHCI_FRAME_INTERVAL_TOGGLE;
|
||||||
@@ -273,11 +313,28 @@ OHCI::OHCI(pci_info *info, Stack *stack)
|
|||||||
uint32 descriptor = _ReadReg(OHCI_RH_DESCRIPTOR_A);
|
uint32 descriptor = _ReadReg(OHCI_RH_DESCRIPTOR_A);
|
||||||
numberOfPorts = OHCI_RH_GET_PORT_COUNT(descriptor);
|
numberOfPorts = OHCI_RH_GET_PORT_COUNT(descriptor);
|
||||||
}
|
}
|
||||||
|
fPortCount = numberOfPorts;
|
||||||
|
|
||||||
// TODO: Add Finisher Thread.
|
// Create semaphore the finisher thread will wait for
|
||||||
|
fFinishTransfersSem = create_sem(0, "OHCI Finish Transfers");
|
||||||
|
if (fFinishTransfersSem < B_OK) {
|
||||||
|
TRACE_ERROR(("usb_ohci: failed to create semaphore\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the finisher service thread
|
||||||
|
fFinishThread = spawn_kernel_thread(_FinishThread, "ohci finish thread",
|
||||||
|
B_URGENT_DISPLAY_PRIORITY, (void *)this);
|
||||||
|
resume_thread(fFinishThread);
|
||||||
|
|
||||||
|
// Install the interrupt handler
|
||||||
|
TRACE(("usb_ohci: installing interrupt handler\n"));
|
||||||
|
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
|
||||||
|
_InterruptHandler, (void *)this, 0);
|
||||||
|
|
||||||
|
// TODO: Enable interrupts. Maybe disable first somewhere before :)
|
||||||
|
|
||||||
TRACE(("usb_ohci: OHCI Host Controller Driver constructed\n"));
|
TRACE(("usb_ohci: OHCI Host Controller Driver constructed\n"));
|
||||||
|
|
||||||
fInitOK = true;
|
fInitOK = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,41 +353,73 @@ OHCI::~OHCI()
|
|||||||
_FreeEndpoint(fDummyIsochronous);
|
_FreeEndpoint(fDummyIsochronous);
|
||||||
if (fRootHub)
|
if (fRootHub)
|
||||||
delete fRootHub;
|
delete fRootHub;
|
||||||
for (int i = 0; i < OHCI_NO_EDS; i++)
|
for (int i = 0; i < OHCI_NUMBER_OF_INTERRUPTS; i++)
|
||||||
if (fInterruptEndpoints[i])
|
if (fInterruptEndpoints[i])
|
||||||
_FreeEndpoint(fInterruptEndpoints[i]);
|
_FreeEndpoint(fInterruptEndpoints[i]);
|
||||||
|
delete [] fInterruptEndpoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
OHCI::_InterruptHandler(void *data)
|
||||||
|
{
|
||||||
|
return ((OHCI *)data)->_Interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
OHCI::_Interrupt()
|
||||||
|
{
|
||||||
|
static spinlock lock = 0;
|
||||||
|
acquire_spinlock(&lock);
|
||||||
|
|
||||||
|
int32 result = B_UNHANDLED_INTERRUPT;
|
||||||
|
|
||||||
|
release_spinlock(&lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
OHCI::_FinishThread(void *data)
|
||||||
|
{
|
||||||
|
((OHCI *)data)->_FinishTransfer();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
OHCI::_FinishTransfer()
|
||||||
|
{
|
||||||
|
// TODO: block on the semaphore
|
||||||
|
}
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
OHCI::Start()
|
OHCI::Start()
|
||||||
{
|
{
|
||||||
TRACE(("usb_ohci::%s()\n", __FUNCTION__));
|
TRACE(("usb_ohci: starting OHCI Host Controller\n"));
|
||||||
if (InitCheck())
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
if (!(_ReadReg(OHCI_CONTROL) & OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL)) {
|
if (!(_ReadReg(OHCI_CONTROL) & OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL)) {
|
||||||
TRACE(("usb_ohci::Start(): Controller not started. TODO: find out what happens.\n"));
|
TRACE_ERROR(("usb_ohci: Controller not started!\n"));
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
fRootHubAddress = AllocateAddress();
|
fRootHubAddress = AllocateAddress();
|
||||||
fNumPorts = OHCI_RH_GET_PORT_COUNT(_ReadReg(OHCI_RH_DESCRIPTOR_A));
|
|
||||||
|
|
||||||
fRootHub = new(std::nothrow) OHCIRootHub(RootObject(), fRootHubAddress);
|
fRootHub = new(std::nothrow) OHCIRootHub(RootObject(), fRootHubAddress);
|
||||||
if (!fRootHub) {
|
if (!fRootHub) {
|
||||||
TRACE_ERROR(("usb_ohci::Start(): no memory to allocate root hub\n"));
|
TRACE_ERROR(("usb_ohci: no memory to allocate root hub\n"));
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fRootHub->InitCheck() < B_OK) {
|
if (fRootHub->InitCheck() < B_OK) {
|
||||||
TRACE_ERROR(("usb_ohci::Start(): root hub failed init check\n"));
|
TRACE_ERROR(("usb_ohci: root hub failed init check\n"));
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetRootHub(fRootHub);
|
SetRootHub(fRootHub);
|
||||||
TRACE(("usb_ohci::Start(): Succesful start\n"));
|
TRACE(("usb_ohci: Host Controller started\n"));
|
||||||
return B_OK;
|
return BusManager::Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -445,7 +534,7 @@ status_t
|
|||||||
OHCI::GetPortStatus(uint8 index, usb_port_status *status)
|
OHCI::GetPortStatus(uint8 index, usb_port_status *status)
|
||||||
{
|
{
|
||||||
TRACE(("usb_ohci::%s(%ud, )\n", __FUNCTION__, index));
|
TRACE(("usb_ohci::%s(%ud, )\n", __FUNCTION__, index));
|
||||||
if (index >= fNumPorts)
|
if (index >= fPortCount)
|
||||||
return B_BAD_INDEX;
|
return B_BAD_INDEX;
|
||||||
|
|
||||||
status->status = status->change = 0;
|
status->status = status->change = 0;
|
||||||
@@ -490,7 +579,7 @@ status_t
|
|||||||
OHCI::SetPortFeature(uint8 index, uint16 feature)
|
OHCI::SetPortFeature(uint8 index, uint16 feature)
|
||||||
{
|
{
|
||||||
TRACE(("OHCI::%s(%ud, %ud)\n", __FUNCTION__, index, feature));
|
TRACE(("OHCI::%s(%ud, %ud)\n", __FUNCTION__, index, feature));
|
||||||
if (index > fNumPorts)
|
if (index > fPortCount)
|
||||||
return B_BAD_INDEX;
|
return B_BAD_INDEX;
|
||||||
|
|
||||||
switch (feature) {
|
switch (feature) {
|
||||||
@@ -511,7 +600,7 @@ status_t
|
|||||||
OHCI::ClearPortFeature(uint8 index, uint16 feature)
|
OHCI::ClearPortFeature(uint8 index, uint16 feature)
|
||||||
{
|
{
|
||||||
TRACE(("OHCI::%s(%ud, %ud)\n", __FUNCTION__, index, feature));
|
TRACE(("OHCI::%s(%ud, %ud)\n", __FUNCTION__, index, feature));
|
||||||
if (index > fNumPorts)
|
if (index > fPortCount)
|
||||||
return B_BAD_INDEX;
|
return B_BAD_INDEX;
|
||||||
|
|
||||||
switch (feature) {
|
switch (feature) {
|
||||||
@@ -534,22 +623,20 @@ OHCI::_AllocateEndpoint()
|
|||||||
ohci_endpoint_descriptor *endpoint;
|
ohci_endpoint_descriptor *endpoint;
|
||||||
void* physicalAddress;
|
void* physicalAddress;
|
||||||
|
|
||||||
//Allocate memory chunk
|
// Allocate memory chunk
|
||||||
if (fStack->AllocateChunk((void **)&endpoint, &physicalAddress,
|
if (fStack->AllocateChunk((void **)&endpoint, &physicalAddress,
|
||||||
sizeof(ohci_endpoint_descriptor)) < B_OK) {
|
sizeof(ohci_endpoint_descriptor)) < B_OK) {
|
||||||
TRACE_ERROR(("usb_ohci: failed to allocate endpoint descriptor\n"));
|
TRACE_ERROR(("usb_ohci: failed to allocate endpoint descriptor\n"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint->this_physical = (addr_t)physicalAddress;
|
endpoint->physical_address = (addr_t)physicalAddress;
|
||||||
|
|
||||||
// Add an empty list by creating a general descriptor
|
endpoint->head_physical_descriptor = NULL;
|
||||||
ohci_general_transfer_descriptor *descriptor = _CreateGeneralDescriptor();
|
endpoint->tail_physical_descriptor = NULL;
|
||||||
endpoint->head_physical_descriptor = descriptor->this_physical;
|
|
||||||
endpoint->tail_physical_descriptor = descriptor->this_physical;
|
|
||||||
|
|
||||||
endpoint->head_logical_descriptor = descriptor;
|
endpoint->head_logical_descriptor = NULL;
|
||||||
endpoint->tail_logical_descriptor = descriptor;
|
endpoint->tail_logical_descriptor = NULL;
|
||||||
|
|
||||||
return endpoint;
|
return endpoint;
|
||||||
}
|
}
|
||||||
@@ -558,46 +645,53 @@ OHCI::_AllocateEndpoint()
|
|||||||
void
|
void
|
||||||
OHCI::_FreeEndpoint(ohci_endpoint_descriptor *endpoint)
|
OHCI::_FreeEndpoint(ohci_endpoint_descriptor *endpoint)
|
||||||
{
|
{
|
||||||
TRACE(("OHCI::%s(%p)\n", __FUNCTION__, end));
|
fStack->FreeChunk((void *)endpoint, (void *)endpoint->physical_address,
|
||||||
fStack->FreeChunk((void *)end->ed, (void *) end->physical_address, sizeof(ohci_endpoint_descriptor));
|
sizeof(ohci_endpoint_descriptor));
|
||||||
delete end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TransferDescriptor *
|
ohci_general_descriptor*
|
||||||
OHCI::_AllocateTransfer()
|
OHCI::_CreateGeneralDescriptor()
|
||||||
{
|
{
|
||||||
TRACE(("OHCI::%s()\n", __FUNCTION__));
|
ohci_general_descriptor *descriptor;
|
||||||
TransferDescriptor *transfer = new TransferDescriptor;
|
void *physicalAddress;
|
||||||
void *phy;
|
|
||||||
if (fStack->AllocateChunk((void **)&transfer->td, &phy, sizeof(ohci_general_transfer_descriptor)) != B_OK) {
|
if (fStack->AllocateChunk((void **)&descriptor, &physicalAddress,
|
||||||
TRACE(("OHCI::AllocateTransfer(): Error Allocating Transfer\n"));
|
sizeof(ohci_general_descriptor)) != B_OK) {
|
||||||
return 0;
|
TRACE_ERROR(("usb_ohci: failed to allocate general descriptor\n"));
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
transfer->physical_address = (addr_t)phy;
|
|
||||||
memset((void *)transfer->td, 0, sizeof(ohci_general_transfer_descriptor));
|
// TODO: Finish methods
|
||||||
return transfer;
|
memset((void *)descriptor, 0, sizeof(ohci_general_descriptor));
|
||||||
|
descriptor->physical_address = (addr_t)physicalAddress;
|
||||||
|
|
||||||
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
OHCI::_FreeTransfer(TransferDescriptor *trans)
|
OHCI::_FreeGeneralDescriptor(ohci_general_descriptor *descriptor)
|
||||||
{
|
{
|
||||||
TRACE(("OHCI::%s(%p)\n", __FUNCTION__, trans));
|
if (!descriptor)
|
||||||
fStack->FreeChunk((void *)trans->td, (void *) trans->physical_address, sizeof(ohci_general_transfer_descriptor));
|
return;
|
||||||
delete trans;
|
|
||||||
|
fStack->FreeChunk((void *)descriptor, (void *)descriptor->physical_address,
|
||||||
|
sizeof(ohci_general_descriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
OHCI::_InsertEndpointForPipe(Pipe *p)
|
OHCI::_InsertEndpointForPipe(Pipe *p)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
TRACE(("OHCI: Inserting Endpoint for device %u function %u\n", p->DeviceAddress(), p->EndpointAddress()));
|
TRACE(("OHCI: Inserting Endpoint for device %u function %u\n", p->DeviceAddress(), p->EndpointAddress()));
|
||||||
|
|
||||||
if (InitCheck())
|
if (InitCheck())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
Endpoint *endpoint = _AllocateEndpoint();
|
//Endpoint *endpoint = _AllocateEndpoint();
|
||||||
|
ohci_endpoint_descriptor *endpoint = _AllocateEndpoint();
|
||||||
if (!endpoint)
|
if (!endpoint)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -677,7 +771,7 @@ OHCI::_InsertEndpointForPipe(Pipe *p)
|
|||||||
tail = tail->next;
|
tail = tail->next;
|
||||||
tail->SetNext(endpoint);
|
tail->SetNext(endpoint);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,13 +18,20 @@ struct pci_info;
|
|||||||
struct pci_module_info;
|
struct pci_module_info;
|
||||||
class OHCIRootHub;
|
class OHCIRootHub;
|
||||||
|
|
||||||
|
typedef struct transfer_data_s {
|
||||||
|
Transfer *transfer;
|
||||||
|
bool incoming;
|
||||||
|
bool canceled;
|
||||||
|
transfer_data_s *link;
|
||||||
|
} transfer_data;
|
||||||
|
|
||||||
// --------------------------------------
|
// --------------------------------------
|
||||||
// OHCI:: Software isonchronous
|
// OHCI:: Software isonchronous
|
||||||
// transfer descriptor
|
// transfer descriptor
|
||||||
// --------------------------------------
|
// --------------------------------------
|
||||||
typedef struct hcd_soft_itransfer
|
typedef struct hcd_soft_itransfer
|
||||||
{
|
{
|
||||||
ohci_isochronous_transfer_descriptor itd;
|
ohci_isochronous_descriptor itd;
|
||||||
struct hcd_soft_itransfer *nextitd; // mirrors nexttd in ITD
|
struct hcd_soft_itransfer *nextitd; // mirrors nexttd in ITD
|
||||||
struct hcd_soft_itransfer *dnext; // next in done list
|
struct hcd_soft_itransfer *dnext; // next in done list
|
||||||
addr_t physaddr; // physical address to the host controller isonchronous transfer
|
addr_t physaddr; // physical address to the host controller isonchronous transfer
|
||||||
@@ -51,6 +58,7 @@ public:
|
|||||||
status_t Start();
|
status_t Start();
|
||||||
virtual status_t SubmitTransfer(Transfer *transfer);
|
virtual status_t SubmitTransfer(Transfer *transfer);
|
||||||
virtual status_t CancelQueuedTransfers(Pipe *pipe);
|
virtual status_t CancelQueuedTransfers(Pipe *pipe);
|
||||||
|
status_t SubmitRequest(Transfer *transfer);
|
||||||
|
|
||||||
virtual status_t NotifyPipeChange(Pipe *pipe,
|
virtual status_t NotifyPipeChange(Pipe *pipe,
|
||||||
usb_change change);
|
usb_change change);
|
||||||
@@ -58,48 +66,73 @@ virtual status_t NotifyPipeChange(Pipe *pipe,
|
|||||||
static status_t AddTo(Stack *stack);
|
static status_t AddTo(Stack *stack);
|
||||||
|
|
||||||
// Port operations
|
// Port operations
|
||||||
|
uint8 PortCount() { return fPortCount; };
|
||||||
status_t GetPortStatus(uint8 index, usb_port_status *status);
|
status_t GetPortStatus(uint8 index, usb_port_status *status);
|
||||||
status_t SetPortFeature(uint8 index, uint16 feature);
|
status_t SetPortFeature(uint8 index, uint16 feature);
|
||||||
status_t ClearPortFeature(uint8 index, uint16 feature);
|
status_t ClearPortFeature(uint8 index, uint16 feature);
|
||||||
|
|
||||||
uint8 PortCount() { return fNumPorts; };
|
status_t ResetPort(uint8 index);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Interrupt functions
|
||||||
|
static int32 _InterruptHandler(void *data);
|
||||||
|
int32 _Interrupt();
|
||||||
|
|
||||||
|
static int32 _FinishThread(void *data);
|
||||||
|
void _FinishTransfer();
|
||||||
|
|
||||||
|
// Endpoint related methods
|
||||||
|
status_t _CreateEndpoint(Pipe *pipe, bool isIsochronous);
|
||||||
|
ohci_endpoint_descriptor *_AllocateEndpoint();
|
||||||
|
void _FreeEndpoint(
|
||||||
|
ohci_endpoint_descriptor *endpoint);
|
||||||
|
status_t _InsertEndpointForPipe(Pipe *pipe);
|
||||||
|
|
||||||
|
// Transfer descriptor related methods
|
||||||
|
ohci_general_descriptor *_CreateGeneralDescriptor();
|
||||||
|
void _FreeGeneralDescriptor(
|
||||||
|
ohci_general_descriptor *descriptor);
|
||||||
|
ohci_isochronous_descriptor *_CreateIsochronousDescriptor();
|
||||||
|
void _FreeIsochronousDescriptor(
|
||||||
|
ohci_isochronous_descriptor *descriptor);
|
||||||
|
|
||||||
// Register functions
|
// Register functions
|
||||||
inline void _WriteReg(uint32 reg, uint32 value);
|
inline void _WriteReg(uint32 reg, uint32 value);
|
||||||
inline uint32 _ReadReg(uint32 reg);
|
inline uint32 _ReadReg(uint32 reg);
|
||||||
|
|
||||||
// Global
|
|
||||||
static pci_module_info *sPCIModule;
|
static pci_module_info *sPCIModule;
|
||||||
|
|
||||||
uint32 *fOperationalRegisters;
|
|
||||||
pci_info *fPCIInfo;
|
pci_info *fPCIInfo;
|
||||||
Stack *fStack;
|
Stack *fStack;
|
||||||
|
|
||||||
|
uint32 *fOperationalRegisters;
|
||||||
area_id fRegisterArea;
|
area_id fRegisterArea;
|
||||||
|
|
||||||
|
spinlock fSpinLock;
|
||||||
|
|
||||||
// Host Controller Communication Area related stuff
|
// Host Controller Communication Area related stuff
|
||||||
area_id fHccaArea;
|
area_id fHccaArea;
|
||||||
struct ohci_hcca *fHcca;
|
ohci_hcca *fHcca;
|
||||||
ohci_endpoint_descriptor *fInterruptEndpoints[OHCI_NUMBER_OF_ENDPOINTS];
|
ohci_endpoint_descriptor **fInterruptEndpoints;
|
||||||
|
|
||||||
// Dummy endpoints
|
// Dummy endpoints
|
||||||
ohci_endpoint_descriptor *fDummyControl;
|
ohci_endpoint_descriptor *fDummyControl;
|
||||||
ohci_endpoint_descriptor *fDummyBulk;
|
ohci_endpoint_descriptor *fDummyBulk;
|
||||||
ohci_endpoint_descriptor *fDummyIsochronous;
|
ohci_endpoint_descriptor *fDummyIsochronous;
|
||||||
|
|
||||||
// Endpoint related methods
|
// Maintain a linked list of transfer
|
||||||
ohci_endpoint_descriptor *_AllocateEndpoint();
|
transfer_data *fFirstTransfer;
|
||||||
void _FreeEndpoint(Endpoint *end);
|
transfer_data *fFinishTransfer;
|
||||||
TransferDescriptor *_AllocateTransfer();
|
sem_id fFinishTransfersSem;
|
||||||
void _FreeTransfer(TransferDescriptor *trans);
|
thread_id fFinishThread;
|
||||||
status_t _InsertEndpointForPipe(Pipe *p);
|
bool fStopFinishThread;
|
||||||
void _SetNext(ohci_endpoint_descriptor *endpoint);
|
|
||||||
|
|
||||||
// Root Hub
|
// Root Hub
|
||||||
OHCIRootHub *fRootHub;
|
OHCIRootHub *fRootHub;
|
||||||
uint8 fRootHubAddress;
|
uint8 fRootHubAddress;
|
||||||
uint8 fNumPorts;
|
|
||||||
|
// Port management
|
||||||
|
uint8 fPortCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -264,27 +264,24 @@
|
|||||||
|
|
||||||
#define OHCI_PERIODIC(i) ((i) * 9 / 10)
|
#define OHCI_PERIODIC(i) ((i) * 9 / 10)
|
||||||
|
|
||||||
// --------------------------------
|
|
||||||
// OHCI physical address
|
|
||||||
// --------------------------------
|
|
||||||
|
|
||||||
typedef uint32 ohci_physaddr_t;
|
|
||||||
|
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
// HCCA structure (section 4.4)
|
// HCCA structure (section 4.4)
|
||||||
|
// 256 bytes aligned
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
|
|
||||||
#define OHCI_NUMBER_OF_INTERRUPTS 32
|
#define OHCI_NUMBER_OF_INTERRUPTS 32
|
||||||
|
|
||||||
typedef struct ohci_hcca
|
typedef struct ohci_hcca
|
||||||
{
|
{
|
||||||
uint32 hcca_interrupt_table[OHCI_NUMBER_OF_INTERRUPTS];
|
uint32 interrupt_table[OHCI_NUMBER_OF_INTERRUPTS];
|
||||||
uint16 hcca_frame_number;
|
uint32 current_frame_number;
|
||||||
uint32 hcca_done_head;
|
uint32 done_head;
|
||||||
uint8 hcca_reserved_for_hc[116];
|
// The following is 120 instead of 116 because the spec
|
||||||
|
// only specifies 252 bytes
|
||||||
|
uint8 reserved_for_hc[120];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OHCI_DONE_INTRS 1
|
#define OHCI_DONE_INTERRUPTS 1
|
||||||
#define OHCI_HCCA_SIZE 256
|
#define OHCI_HCCA_SIZE 256
|
||||||
#define OHCI_HCCA_ALIGN 256
|
#define OHCI_HCCA_ALIGN 256
|
||||||
#define OHCI_PAGE_SIZE 0x1000
|
#define OHCI_PAGE_SIZE 0x1000
|
||||||
@@ -303,7 +300,8 @@ typedef struct ohci_endpoint_descriptor
|
|||||||
uint32 head_physical_descriptor; // Queue head physical pointer
|
uint32 head_physical_descriptor; // Queue head physical pointer
|
||||||
uint32 next_physical_endpoint; // Physical pointer to the next endpoint
|
uint32 next_physical_endpoint; // Physical pointer to the next endpoint
|
||||||
// Software part
|
// Software part
|
||||||
addr_t this_physical; // Physical pointer to this address
|
// TODO: What about type, state and interval (only interrupts) ?
|
||||||
|
addr_t physical_address; // Physical pointer to this address
|
||||||
void *tail_logical_descriptor; // Queue tail logical pointer
|
void *tail_logical_descriptor; // Queue tail logical pointer
|
||||||
void *head_logical_descriptor; // Queue head logical pointer
|
void *head_logical_descriptor; // Queue head logical pointer
|
||||||
void *next_logical_endpoint; // Logical pointer to the next endpoint
|
void *next_logical_endpoint; // Logical pointer to the next endpoint
|
||||||
@@ -334,7 +332,7 @@ typedef struct ohci_endpoint_descriptor
|
|||||||
// General transfer descriptor structure (section 4.3.1)
|
// General transfer descriptor structure (section 4.3.1)
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
|
|
||||||
typedef struct ohci_general_transfer_descriptor
|
typedef struct ohci_general_descriptor
|
||||||
{
|
{
|
||||||
// Hardware part
|
// Hardware part
|
||||||
uint32 flags; // Flags field
|
uint32 flags; // Flags field
|
||||||
@@ -342,7 +340,7 @@ typedef struct ohci_general_transfer_descriptor
|
|||||||
uint32 next_physical_descriptor; // Physical pointer next descriptor
|
uint32 next_physical_descriptor; // Physical pointer next descriptor
|
||||||
uint32 last_physical_byte_address; // Physical pointer to buffer end
|
uint32 last_physical_byte_address; // Physical pointer to buffer end
|
||||||
// Software part
|
// Software part
|
||||||
addr_t this_physical; // Physical pointer to this address
|
addr_t physical_address; // Physical pointer to this address
|
||||||
void *buffer_logical; // Logical pointer to the buffer
|
void *buffer_logical; // Logical pointer to the buffer
|
||||||
void *next_logical_descriptor; // Logical pointer next descriptor
|
void *next_logical_descriptor; // Logical pointer next descriptor
|
||||||
void *last_logical_byte_address; // Logical pointer buffer end
|
void *last_logical_byte_address; // Logical pointer buffer end
|
||||||
@@ -372,7 +370,7 @@ typedef struct ohci_general_transfer_descriptor
|
|||||||
// --------------------------------
|
// --------------------------------
|
||||||
|
|
||||||
#define OHCI_ITD_NOFFSET 8
|
#define OHCI_ITD_NOFFSET 8
|
||||||
typedef struct ohci_isochronous_transfer_descriptor
|
typedef struct ohci_isochronous_descriptor
|
||||||
{
|
{
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
uint32 buffer_page_byte_0; // Physical page number of byte 0
|
uint32 buffer_page_byte_0; // Physical page number of byte 0
|
||||||
|
|||||||
Reference in New Issue
Block a user