* Make the operational register memory a uint8 * instead of a uint32 * so the

driver has at least a chance of working (it previously always used wrong
  offsets for register access).
* Remove the hash approach for now (I'm going to explore a few other ways of
  doing that first).
* Reorder some stuff and check for errors in some more places.
* More cleanup (mostly whitespace again).

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25538 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2008-05-18 09:23:29 +00:00
parent 2b9cc6d877
commit 20bbb1bf28
3 changed files with 52 additions and 161 deletions

View File

@ -77,8 +77,6 @@ OHCI::OHCI(pci_info *info, Stack *stack)
fFinishTransfersSem(-1),
fFinishThread(-1),
fStopFinishThread(false),
fHashGenericTable(NULL),
fHashIsochronousTable(NULL),
fRootHub(NULL),
fRootHubAddress(0),
fPortCount(0)
@ -138,35 +136,17 @@ OHCI::OHCI(pci_info *info, Stack *stack)
memset(fHcca, 0, sizeof(ohci_hcca));
// Allocate hash tables
fHashGenericTable = (ohci_general_td **)
malloc(sizeof(ohci_general_td *) * OHCI_HASH_SIZE);
if (fHashGenericTable == NULL) {
TRACE_ERROR(("usb_ohci: unable to allocate hash generic table\n"));
return;
}
fHashIsochronousTable = (ohci_isochronous_td **)
malloc(sizeof(ohci_isochronous_td *) * OHCI_HASH_SIZE);
if (fHashIsochronousTable == NULL) {
free(fHashGenericTable);
TRACE_ERROR(("usb_ohci: unable to allocate hash isochronous table\n"));
return;
}
// Set Up Host controller
// Dummy endpoints
fDummyControl = _AllocateEndpoint();
if (!fDummyControl)
return;
fDummyControl->flags |= OHCI_ENDPOINT_SKIP;
fDummyBulk = _AllocateEndpoint();
if (!fDummyBulk) {
_FreeEndpoint(fDummyControl);
return;
}
fDummyBulk->flags |= OHCI_ENDPOINT_SKIP;
fDummyIsochronous = _AllocateEndpoint();
if (!fDummyIsochronous) {
@ -174,7 +154,6 @@ OHCI::OHCI(pci_info *info, Stack *stack)
_FreeEndpoint(fDummyBulk);
return;
}
fDummyIsochronous->flags |= OHCI_ENDPOINT_SKIP;
// Static endpoints that get linked in the HCCA
fInterruptEndpoints = new(std::nothrow)
@ -202,7 +181,6 @@ OHCI::OHCI(pci_info *info, Stack *stack)
}
// Make them point all to the dummy isochronous endpoint
fInterruptEndpoints[i]->flags |= OHCI_ENDPOINT_SKIP;
fInterruptEndpoints[i]->next_physical_endpoint
= fDummyIsochronous->physical_address;
}
@ -341,9 +319,6 @@ OHCI::~OHCI()
if (fRegisterArea >= B_OK)
delete_area(fRegisterArea);
free(fHashGenericTable);
free(fHashIsochronousTable);
_FreeEndpoint(fDummyControl);
_FreeEndpoint(fDummyBulk);
_FreeEndpoint(fDummyIsochronous);
@ -365,9 +340,11 @@ OHCI::Start()
{
TRACE(("usb_ohci: starting OHCI Host Controller\n"));
if ((_ReadReg(OHCI_CONTROL) & OHCI_HC_FUNCTIONAL_STATE_MASK)
uint32 control = _ReadReg(OHCI_CONTROL);
if ((control & OHCI_HC_FUNCTIONAL_STATE_MASK)
!= OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL) {
TRACE_ERROR(("usb_ohci: Controller not started!\n"));
TRACE_ERROR(("usb_ohci: Controller not started (0x%08lx)!\n",
control));
return B_ERROR;
} else
TRACE(("usb_ohci: Controller is operational!\n"));
@ -578,7 +555,7 @@ OHCI::AddTo(Stack *stack)
status_t
OHCI::GetPortStatus(uint8 index, usb_port_status *status)
{
TRACE(("usb_ohci::%s(%ud, )\n", __FUNCTION__, index));
TRACE(("usb_ohci: get port status %ud\n", index));
if (index >= fPortCount)
return B_BAD_INDEX;
@ -857,7 +834,7 @@ OHCI::_FinishTransfers()
ohci_isochronous_td *isoCurrent = NULL;
ohci_isochronous_td *isoTop = NULL;
while (doneList != 0) {
current = _FindDescriptorInHash(doneList);
current = NULL; //_FindDescriptorInHash(doneList);
if (current != NULL) {
doneList = current->next_physical_descriptor;
current->next_done_descriptor = (void *)top;
@ -865,7 +842,7 @@ OHCI::_FinishTransfers()
continue;
}
isoCurrent = _FindIsoDescriptorInHash(doneList);
isoCurrent = NULL; //_FindIsoDescriptorInHash(doneList);
if (isoCurrent != NULL) {
doneList = isoCurrent->next_physical_descriptor;
isoCurrent->next_done_descriptor = (void *)isoTop;
@ -1135,11 +1112,14 @@ OHCI::_AllocateEndpoint()
return NULL;
}
endpoint->flags = OHCI_ENDPOINT_SKIP;
endpoint->physical_address = (addr_t)physicalAddress;
endpoint->head_logical_descriptor = NULL;
endpoint->head_physical_descriptor = 0;
endpoint->tail_logical_descriptor = NULL;
endpoint->tail_physical_descriptor = 0;
endpoint->next_logical_endpoint = NULL;
endpoint->next_physical_endpoint = 0;
return endpoint;
}
@ -1214,27 +1194,32 @@ OHCI::_InsertEndpointForPipe(Pipe *pipe)
endpoint->flags = flags;
// Add the endpoint to the appropriate list
ohci_endpoint_descriptor *head = NULL;
uint32 type = pipe->Type();
ohci_endpoint_descriptor *head = NULL;
if (type & USB_OBJECT_CONTROL_PIPE)
head = fDummyControl;
else if (type & USB_OBJECT_BULK_PIPE)
head = fDummyBulk;
else if (type & USB_OBJECT_INTERRUPT_PIPE)
head = _FindInterruptEndpoint(pipe->Interval());
else if (type & USB_OBJECT_ISO_PIPE) {
// Set the isochronous bit format
endpoint->flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT;
else if (type & USB_OBJECT_ISO_PIPE)
head = fDummyIsochronous;
} else {
else
TRACE_ERROR(("usb_ohci: unknown pipe type\n"));
if (head == NULL) {
TRACE_ERROR(("usb_ohci: no list found for endpoint\n"));
_FreeEndpoint(endpoint);
return B_BAD_VALUE;
return B_ERROR;
}
// Create (necessary) dummy descriptor
if (pipe->Type() & USB_OBJECT_ISO_PIPE) {
// Set the isochronous bit format
endpoint->flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT;
// TODO
_FreeEndpoint(endpoint);
return B_ERROR;
} else {
ohci_general_td *dummy = _CreateGeneralDescriptor(0);
dummy->next_logical_descriptor = NULL;
@ -1245,15 +1230,23 @@ OHCI::_InsertEndpointForPipe(Pipe *pipe)
endpoint->tail_physical_descriptor = dummy->physical_address;
}
// TODO: Change lock lo LockEndpoint()
Lock();
if (!Lock()) {
if (endpoint->head_logical_descriptor) {
_FreeGeneralDescriptor(
(ohci_general_td *)endpoint->head_logical_descriptor);
}
_FreeEndpoint(endpoint);
return B_ERROR;
}
pipe->SetControllerCookie((void *)endpoint);
endpoint->next_logical_endpoint = head->next_logical_endpoint;
endpoint->next_physical_endpoint = head->next_physical_endpoint;
head->next_logical_endpoint = (void *)endpoint;
head->next_physical_endpoint = (uint32)endpoint->physical_address;
Unlock();
Unlock();
return B_OK;
}
@ -1422,50 +1415,6 @@ OHCI::_FreeIsochronousDescriptor(ohci_isochronous_td *descriptor)
}
void
OHCI::_AddDescriptorToHash(ohci_general_td *descriptor)
{
// TODO
}
void
OHCI::_RemoveDescriptorFromHash(ohci_general_td *descriptor)
{
// TODO
}
ohci_general_td*
OHCI::_FindDescriptorInHash(uint32 physicalAddress)
{
// TODO
return NULL;
}
void
OHCI::_AddIsoDescriptorToHash(ohci_isochronous_td *descriptor)
{
// TODO
}
void
OHCI::_RemoveIsoDescriptorFromHash(ohci_isochronous_td *descriptor)
{
// TODO
}
ohci_isochronous_td*
OHCI::_FindIsoDescriptorInHash(uint32 physicalAddress)
{
// TODO
return NULL;
}
inline void
OHCI::_WriteReg(uint32 reg, uint32 value)
{

View File

@ -3,8 +3,9 @@
* Distributed under the terms of the MIT License.
*
* Authors:
* Jan-Rixt Van Hoye
* Salvatore Benedetto <salvatore.benedetto@gmail.com>
* Jan-Rixt Van Hoye
* Salvatore Benedetto <salvatore.benedetto@gmail.com>
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef OHCI_H
@ -28,49 +29,14 @@ typedef struct transfer_data_s {
transfer_data_s *link;
} transfer_data;
// --------------------------------------
// OHCI:: Software isonchronous
// transfer descriptor
// --------------------------------------
typedef struct hcd_soft_itransfer
{
ohci_isochronous_td itd;
struct hcd_soft_itransfer *nextitd; // mirrors nexttd in ITD
struct hcd_soft_itransfer *dnext; // next in done list
addr_t physaddr; // physical address to the host controller isonchronous transfer
//LIST_ENTRY(hcd_soft_itransfer) hnext;
uint16 flags; // flags
#ifdef DIAGNOSTIC
char isdone; // is the transfer done?
#endif
}hcd_soft_itransfer;
#define OHCI_SITD_SIZE ((sizeof (struct hcd_soft_itransfer) + OHCI_ITD_ALIGN - 1) / OHCI_ITD_ALIGN * OHCI_ITD_ALIGN)
#define OHCI_SITD_CHUNK 64
#define OHCI_NUMBER_OF_ENDPOINTS (2 * OHCI_NUMBER_OF_INTERRUPTS - 1)
// Note: the controller returns only the physical
// address of the first processed descriptor of
// an heterogeneous list (isochronous + generic). Unfortunately
// we don't have a way to know whether the descriptor is
// generic or isochronous, either way to translate the address back to
// kernel address. The physical address is used as the hash value.
// (Kindly borrowed from *BSD)
#define OHCI_HASH_SIZE 128
#define HASH(x) (((x) >> 4) % OHCI_HASH_SIZE)
class OHCI : public BusManager
{
class OHCI : public BusManager {
public:
OHCI(pci_info *info, Stack *stack);
~OHCI();
status_t Start();
virtual status_t SubmitTransfer(Transfer *transfer);
virtual status_t SubmitTransfer(Transfer *transfer);
virtual status_t CancelQueuedTransfers(Pipe *pipe,
bool force);
@ -80,8 +46,8 @@ virtual status_t NotifyPipeChange(Pipe *pipe,
static status_t AddTo(Stack *stack);
// Port operations
uint8 PortCount() { return fPortCount; };
status_t GetPortStatus(uint8 index,
uint8 PortCount() { return fPortCount; };
status_t GetPortStatus(uint8 index,
usb_port_status *status);
status_t SetPortFeature(uint8 index, uint16 feature);
status_t ClearPortFeature(uint8 index, uint16 feature);
@ -152,31 +118,15 @@ static int32 _FinishThread(void *data);
void _FreeIsochronousDescriptor(
ohci_isochronous_td *descriptor);
// Hash tables related methods
void _AddDescriptorToHash(
ohci_general_td *descriptor);
void _RemoveDescriptorFromHash(
ohci_general_td *descriptor);
ohci_general_td *_FindDescriptorInHash(
uint32 physicalAddress);
void _AddIsoDescriptorToHash(
ohci_isochronous_td *descriptor);
void _RemoveIsoDescriptorFromHash(
ohci_isochronous_td *descriptor);
ohci_isochronous_td *_FindIsoDescriptorInHash(
uint32 physicalAddress);
// Register functions
inline void _WriteReg(uint32 reg, uint32 value);
inline uint32 _ReadReg(uint32 reg);
static pci_module_info *sPCIModule;
pci_info *fPCIInfo;
pci_info *fPCIInfo;
Stack *fStack;
uint32 *fOperationalRegisters;
uint8 *fOperationalRegisters;
area_id fRegisterArea;
// Host Controller Communication Area related stuff
@ -196,12 +146,8 @@ static pci_module_info *sPCIModule;
thread_id fFinishThread;
bool fStopFinishThread;
// Hash table
ohci_general_td **fHashGenericTable;
ohci_isochronous_td **fHashIsochronousTable;
// Root Hub
OHCIRootHub *fRootHub;
OHCIRootHub *fRootHub;
uint8 fRootHubAddress;
// Port management
@ -214,7 +160,7 @@ public:
OHCIRootHub(Object *rootObject,
int8 deviceAddress);
static status_t ProcessTransfer(OHCI *ohci,
static status_t ProcessTransfer(OHCI *ohci,
Transfer *transfer);
};

View File

@ -5,6 +5,7 @@
* Authors:
* Jan-Rixt Van Hoye
* Salvatore Benedetto <salvatore.benedetto@gmail.com>
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef OHCI_HARDWARE_H
@ -271,15 +272,14 @@
#define OHCI_NUMBER_OF_INTERRUPTS 32
typedef struct ohci_hcca
{
typedef struct {
uint32 interrupt_table[OHCI_NUMBER_OF_INTERRUPTS];
uint32 current_frame_number;
uint32 done_head;
// The following is 120 instead of 116 because the spec
// only specifies 252 bytes
uint8 reserved_for_hc[120];
};
} ohci_hcca;
#define OHCI_DONE_INTERRUPTS 1
#define OHCI_HCCA_SIZE 256
@ -292,20 +292,18 @@ typedef struct ohci_hcca
// Endpoint descriptor structure (section 4.2)
// --------------------------------
typedef struct ohci_endpoint_descriptor
{
typedef struct {
// Hardware part
uint32 flags; // Flags field
uint32 tail_physical_descriptor; // Queue tail physical pointer
uint32 head_physical_descriptor; // Queue head physical pointer
uint32 next_physical_endpoint; // Physical pointer to the next endpoint
// Software part
// 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 *head_logical_descriptor; // Queue head logical pointer
void *next_logical_endpoint; // Logical pointer to the next endpoint
};
} ohci_endpoint_descriptor;
#define OHCI_ENDPOINT_ADDRESS_MASK 0x0000007f
#define OHCI_ENDPOINT_GET_DEVICE_ADDRESS(s) ((s) & 0x7f)
@ -333,8 +331,7 @@ typedef struct ohci_endpoint_descriptor
// General transfer descriptor structure (section 4.3.1)
// --------------------------------
typedef struct ohci_general_td
{
typedef struct {
// Hardware part 16 bytes
uint32 flags; // Flags field
uint32 buffer_physical; // Physical buffer pointer
@ -348,7 +345,7 @@ typedef struct ohci_general_td
size_t buffer_size; // Size of the buffer
void *transfer; // Pointer to the transfer_data
bool is_last; // Last descriptor of the transfer
};
} ohci_general_td;
#define OHCI_BUFFER_ROUNDING 0x00040000
#define OHCI_TD_DIRECTION_PID_MASK 0x00180000
@ -374,8 +371,7 @@ typedef struct ohci_general_td
// --------------------------------
#define OHCI_ITD_NOFFSET 8
typedef struct ohci_isochronous_td
{
typedef struct {
// Hardware part 32 byte
uint32 flags;
uint32 buffer_page_byte_0; // Physical page number of byte 0
@ -386,7 +382,7 @@ typedef struct ohci_isochronous_td
addr_t physical_address; // Physical address of this descriptor
void *next_logical_descriptor; // Logical pointer next descriptor
void *next_done_descriptor; // Used for collision in the hash table
};
} ohci_isochronous_td;
#define OHCI_ITD_GET_STARTING_FRAME(x) ((x) & 0x0000ffff)
#define OHCI_ITD_SET_STARTING_FRAME(x) ((x) & 0xffff)