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

View File

@ -3,8 +3,9 @@
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Jan-Rixt Van Hoye * Jan-Rixt Van Hoye
* Salvatore Benedetto <salvatore.benedetto@gmail.com> * Salvatore Benedetto <salvatore.benedetto@gmail.com>
* Michael Lotz <mmlr@mlotz.ch>
*/ */
#ifndef OHCI_H #ifndef OHCI_H
@ -28,49 +29,14 @@ typedef struct transfer_data_s {
transfer_data_s *link; transfer_data_s *link;
} transfer_data; } 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) class OHCI : public BusManager {
#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
{
public: public:
OHCI(pci_info *info, Stack *stack); OHCI(pci_info *info, Stack *stack);
~OHCI(); ~OHCI();
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,
bool force); bool force);
@ -80,8 +46,8 @@ 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; }; uint8 PortCount() { return fPortCount; };
status_t GetPortStatus(uint8 index, status_t GetPortStatus(uint8 index,
usb_port_status *status); 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);
@ -152,31 +118,15 @@ static int32 _FinishThread(void *data);
void _FreeIsochronousDescriptor( void _FreeIsochronousDescriptor(
ohci_isochronous_td *descriptor); 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 // 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);
static pci_module_info *sPCIModule; static pci_module_info *sPCIModule;
pci_info *fPCIInfo; pci_info *fPCIInfo;
Stack *fStack; Stack *fStack;
uint32 *fOperationalRegisters; uint8 *fOperationalRegisters;
area_id fRegisterArea; area_id fRegisterArea;
// Host Controller Communication Area related stuff // Host Controller Communication Area related stuff
@ -196,12 +146,8 @@ static pci_module_info *sPCIModule;
thread_id fFinishThread; thread_id fFinishThread;
bool fStopFinishThread; bool fStopFinishThread;
// Hash table
ohci_general_td **fHashGenericTable;
ohci_isochronous_td **fHashIsochronousTable;
// Root Hub // Root Hub
OHCIRootHub *fRootHub; OHCIRootHub *fRootHub;
uint8 fRootHubAddress; uint8 fRootHubAddress;
// Port management // Port management
@ -214,7 +160,7 @@ public:
OHCIRootHub(Object *rootObject, OHCIRootHub(Object *rootObject,
int8 deviceAddress); int8 deviceAddress);
static status_t ProcessTransfer(OHCI *ohci, static status_t ProcessTransfer(OHCI *ohci,
Transfer *transfer); Transfer *transfer);
}; };

View File

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