Wrote the initialisation routine of the host controller

* Started cleaning up the style (WIP)
* I'll slowly phase out ohci_software.h, since it is BSD legacy
* Cleanup other BSD inspired naming. I like full names.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18723 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Niels Sascha Reedijk
2006-08-31 11:58:27 +00:00
parent 2c9ae83ff9
commit 915367e31a
4 changed files with 181 additions and 160 deletions
+136 -64
View File
@@ -88,23 +88,22 @@ ohci_std_ops( int32 op , ... )
//------------------------------------------------------------------------ //------------------------------------------------------------------------
static status_t static status_t
ohci_add_to( Stack *stack ) ohci_add_to(Stack *stack)
{ {
status_t status; status_t status;
pci_info *item; pci_info *item;
bool found = false; bool found = false;
int i; int i;
#ifdef OHCI_DEBUG #ifdef TRACE_USB
set_dprintf_enabled( true ); set_dprintf_enabled(true);
load_driver_symbols( "ohci" ); load_driver_symbols("ohci");
#endif #endif
// //
// Try if the PCI module is loaded // Try if the PCI module is loaded
// //
if( ( status = get_module( B_PCI_MODULE_NAME, (module_info **)&( OHCI::pci_module ) ) ) != B_OK) if( ( status = get_module( B_PCI_MODULE_NAME, (module_info **)&( OHCI::pci_module ) ) ) != B_OK) {
{
TRACE(("USB_ OHCI: init_hardware(): Get PCI module failed! %lu \n", status)); TRACE(("USB_ OHCI: init_hardware(): Get PCI module failed! %lu \n", status));
return status; return status;
} }
@@ -113,20 +112,17 @@ ohci_add_to( Stack *stack )
// TODO: in the future we might want to support multiple host controllers. // TODO: in the future we might want to support multiple host controllers.
// //
item = new pci_info; item = new pci_info;
for ( i = 0 ; OHCI::pci_module->get_nth_pci_info( i , item ) == B_OK ; i++ ) for ( i = 0 ; OHCI::pci_module->get_nth_pci_info( i , item ) == B_OK ; i++ ) {
{ if ( ( item->class_base == PCI_serial_bus ) && ( item->class_sub == PCI_usb )
if ( ( item->class_base == PCI_serial_bus ) && ( item->class_sub == PCI_usb ) && && ( item->class_api == PCI_usb_ohci ) )
( item->class_api == PCI_usb_ohci ) )
{ {
if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF)) if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF)) {
{
TRACE(("USB OHCI: init_hardware(): found with invalid IRQ - check IRQ assignement\n")); TRACE(("USB OHCI: init_hardware(): found with invalid IRQ - check IRQ assignement\n"));
continue; continue;
} }
TRACE(("USB OHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line)); TRACE(("USB OHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line));
OHCI *bus = new OHCI( item , stack ); OHCI *bus = new OHCI( item , stack );
if ( bus->InitCheck() != B_OK ) if ( bus->InitCheck() != B_OK ) {
{
delete bus; delete bus;
break; break;
} }
@@ -138,8 +134,7 @@ ohci_add_to( Stack *stack )
} }
} }
if ( found == false ) if ( found == false ) {
{
TRACE(("USB OHCI: init hardware(): no devices found\n")); TRACE(("USB OHCI: init hardware(): no devices found\n"));
free( item ); free( item );
put_module( B_PCI_MODULE_NAME ); put_module( B_PCI_MODULE_NAME );
@@ -156,7 +151,7 @@ ohci_add_to( Stack *stack )
host_controller_info ohci_module = { host_controller_info ohci_module = {
{ {
"busses/usb/ohci/jixt", "busses/usb/ohci",
NULL, // No flag like B_KEEP_LOADED : the usb module does that NULL, // No flag like B_KEEP_LOADED : the usb module does that
ohci_std_ops ohci_std_ops
}, },
@@ -170,8 +165,7 @@ host_controller_info ohci_module = {
// parameters: none // parameters: none
//------------------------------------------------------------------------ //------------------------------------------------------------------------
module_info *modules[] = module_info *modules[] = {
{
(module_info *) &ohci_module, (module_info *) &ohci_module,
NULL NULL
}; };
@@ -184,59 +178,67 @@ module_info *modules[] =
// - stack: pointer to a stack instance // - stack: pointer to a stack instance
//------------------------------------------------------------------------ //------------------------------------------------------------------------
OHCI::OHCI( pci_info *info , Stack *stack ) OHCI::OHCI(pci_info *info, Stack *stack)
: BusManager(stack) : BusManager(stack),
fRegisterArea(-1),
fHccaArea(-1),
fDummyControl(0),
fDummyBulk(0),
fDummyIsochronous(0)
{ {
m_pcii = info; fPcii = info;
m_stack = stack; fStack = stack;
int i; int i;
hcd_soft_endpoint *sed, *psed;
TRACE(("USB OHCI: constructing new BusManager\n")); TRACE(("USB OHCI: constructing new BusManager\n"));
fInitOK = false; fInitOK = false;
for(i = 0; i < OHCI_NO_EDS; i++) //Clear the interrupt list
fInterruptEndpoints[i] = 0;
// enable busmaster and memory mapped access // enable busmaster and memory mapped access
uint16 cmd = OHCI::pci_module->read_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_command, 2); uint16 cmd = OHCI::pci_module->read_pci_config(fPcii->bus, fPcii->device, fPcii->function, PCI_command, 2);
cmd &= ~PCI_command_io; cmd &= ~PCI_command_io;
cmd |= PCI_command_master | PCI_command_memory; cmd |= PCI_command_master | PCI_command_memory;
OHCI::pci_module->write_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_command, 2, cmd ); OHCI::pci_module->write_pci_config(fPcii->bus, fPcii->device, fPcii->function, PCI_command, 2, cmd );
//
// 5.1.1.2 map the registers // 5.1.1.2 map the registers
//
addr_t registeroffset = pci_module->read_pci_config(info->bus, addr_t registeroffset = pci_module->read_pci_config(info->bus,
info->device, info->function, PCI_base_registers, 4); info->device, info->function, PCI_base_registers, 4);
registeroffset &= PCI_address_memory_32_mask; registeroffset &= PCI_address_memory_32_mask;
TRACE(("OHCI: iospace offset: %lx\n" , registeroffset)); TRACE(("OHCI: iospace offset: %lx\n" , registeroffset));
m_register_area = map_physical_memory("OHCI base registers", (void *)registeroffset, fRegisterArea = map_physical_memory("OHCI base registers", (void *)registeroffset,
B_PAGE_SIZE, B_ANY_KERNEL_BLOCK_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, (void **)&m_registers); B_PAGE_SIZE, B_ANY_KERNEL_BLOCK_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, (void **)&fRegisters);
if (m_register_area < B_OK) { if (fRegisterArea < B_OK) {
TRACE(("USB OHCI: error mapping the registers\n")); TRACE(("USB OHCI: error mapping the registers\n"));
return; return;
} }
// Get the revision of the controller // Get the revision of the controller
uint32 rev = ReadReg(OHCI_REVISION) & 0xff; uint32 rev = ReadReg(OHCI_REVISION) & 0xff;
// Check the revision of the controller. The revision should be 10xh // Check the revision of the controller. The revision should be 10xh
TRACE((" OHCI: Version %ld.%ld%s\n", OHCI_REV_HI(rev), OHCI_REV_LO(rev),OHCI_REV_LEGACY(rev) ? ", legacy support" : "")); TRACE((" OHCI: Version %ld.%ld%s\n", OHCI_REV_HI(rev), OHCI_REV_LO(rev),OHCI_REV_LEGACY(rev) ? ", legacy support" : ""));
if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) { if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) {
TRACE(("USB OHCI: Unsupported OHCI revision of the ohci device\n")); TRACE(("USB OHCI: Unsupported OHCI revision of the ohci device\n"));
delete_area(m_register_area);
return; return;
} }
// Set up the Host Controller Communications Area // Set up the Host Controller Communications Area
void *hcca_phy; void *hcca_phy;
m_hcca_area = m_stack->AllocateArea((void**)&m_hcca, &hcca_phy, fHccaArea = fStack->AllocateArea((void**)&fHcca, &hcca_phy,
B_PAGE_SIZE, "OHCI HCCA"); B_PAGE_SIZE, "OHCI HCCA");
if (m_hcca_area < B_OK) { if (fHccaArea < B_OK) {
TRACE(("USB OHCI: Error allocating HCCA block\n")); TRACE(("USB OHCI: Error allocating HCCA block\n"));
delete_area(m_register_area);
return; return;
} }
memset((void*)fHcca, 0, sizeof(ohci_hcca));
//
// 5.1.1.3 Take control of the host controller // 5.1.1.3 Take control of the host controller
//
if (ReadReg(OHCI_CONTROL) & OHCI_IR) { if (ReadReg(OHCI_CONTROL) & OHCI_IR) {
TRACE(("USB OHCI: SMM is in control of the host controller\n")); TRACE(("USB OHCI: SMM is in control of the host controller\n"));
WriteReg(OHCI_COMMAND_STATUS, OHCI_OCR); WriteReg(OHCI_COMMAND_STATUS, OHCI_OCR);
@@ -253,43 +255,113 @@ OHCI::OHCI( pci_info *info , Stack *stack )
} else if (ReadReg(OHCI_CONTROL) & OHCI_HCFS_RESET) //Only if no BIOS/SMM control } else if (ReadReg(OHCI_CONTROL) & OHCI_HCFS_RESET) //Only if no BIOS/SMM control
snooze(USB_DELAY_BUS_RESET); snooze(USB_DELAY_BUS_RESET);
//
// 5.1.1.4 Set Up Host controller // 5.1.1.4 Set Up Host controller
// initialize the data structures for the HCCA //
// Dummy endpoints
fDummyControl = AllocateEndpoint();
if (!fDummyControl)
return;
fDummyBulk = AllocateEndpoint();
if (!fDummyBulk)
return;
fDummyIsochronous = AllocateEndpoint();
if (!fDummyIsochronous)
return;
//Create the interrupt tree
//Algorhythm kindly borrowed from NetBSD code
for(i = 0; i < OHCI_NO_EDS; i++) {
fInterruptEndpoints[i] = AllocateEndpoint();
if (!fInterruptEndpoints[i])
return;
if (i != 0)
fInterruptEndpoints[i]->SetNext(fInterruptEndpoints[(i-1) / 2]);
else
fInterruptEndpoints[i]->SetNext(fDummyIsochronous);
}
for (i = 0; i < OHCI_NO_INTRS; i++)
fHcca->hcca_interrupt_table[revbits[i]] =
fInterruptEndpoints[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physicaladdress;
//Go to the hardware part of the initialisation
uint32 frameinterval = ReadReg(OHCI_FM_INTERVAL);
uint32 framevalue = ReadReg(OHCI_FM_NUMBER); WriteReg(OHCI_COMMAND_STATUS, OHCI_HCR);
for (i = 0; i < 10; i++){
snooze(10); //Should be okay in one run: 10 microseconds for reset
if (!(ReadReg(OHCI_COMMAND_STATUS) & OHCI_HCR))
break;
}
if (ReadReg(OHCI_COMMAND_STATUS) & OHCI_HCR) {
TRACE(("USB OHCI: Error resetting the host controller\n"));
return;
}
WriteReg(OHCI_FM_INTERVAL, frameinterval);
//We now have 2 ms to finish the following sequence.
//TODO: maybe add spinlock protection???
WriteReg(OHCI_CONTROL_HEAD_ED, (uint32)fDummyControl->physicaladdress);
WriteReg(OHCI_BULK_HEAD_ED, (uint32)fDummyBulk->physicaladdress);
WriteReg(OHCI_HCCA, (uint32)hcca_phy);
WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
WriteReg(OHCI_INTERRUPT_ENABLE, OHCI_NORMAL_INTRS);
//
// 5.1.1.5 Begin Sending SOFs
//
uint32 control = ReadReg(OHCI_CONTROL);
control &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR);
control |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE |
OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL;
WriteReg(OHCI_CONTROL, control);
//The controller is now operational, end of 2ms block.
uint32 interval = OHCI_GET_IVAL(frameinterval);
WriteReg(OHCI_PERIODIC_START, OHCI_PERIODIC(interval));
m_roothub_base = 255; //Invalidate the Root Hub address m_roothub_base = 255; //Invalidate the Root Hub address
} }
hcd_soft_endpoint * OHCI::ohci_alloc_soft_endpoint() OHCI::~OHCI()
{ {
hcd_soft_endpoint *sed; if (fHccaArea > 0)
int i; delete_area(fHccaArea);
if (fRegisterArea > 0)
delete_area(fRegisterArea);
if (fDummyControl)
FreeEndpoint(fDummyControl);
if (fDummyBulk)
FreeEndpoint(fDummyBulk);
if (fDummyIsochronous)
FreeEndpoint(fDummyIsochronous);
for (int i = 0; i < OHCI_NO_EDS; i++)
if (fInterruptEndpoints[i])
FreeEndpoint(fInterruptEndpoints[i]);
}
Endpoint *
OHCI::AllocateEndpoint()
{
Endpoint *endpoint = new Endpoint;
void *phy; void *phy;
if (sc_freeeds == NULL) if (fStack->AllocateChunk((void **)&endpoint->ed, &phy, sizeof(ohci_endpoint_descriptor)) != B_OK)
{ return 0;
dprintf("OHCI: ohci_alloc_soft_endpoint(): allocating chunk\n"); endpoint->physicaladdress = (addr_t)phy;
for(i = 0; i < OHCI_SED_CHUNK; i++)
{ memset((void *)endpoint->ed, 0, sizeof(ohci_endpoint_descriptor));
if(m_stack->AllocateChunk( (void **)&(sed) ,&phy , OHCI_ED_ALIGN )!= B_OK) endpoint->ed->ed_flags = OHCI_ED_SKIP;
{ return endpoint;
dprintf( "USB OHCI: ohci_alloc_soft_endpoint(): failed allocation of skeleton qh %i, aborting\n", i ); }
return (0);
} void
// chunk has been allocated OHCI::FreeEndpoint(Endpoint *end)
sed->physaddr = reinterpret_cast<addr_t>(phy); {
sed->next = sc_freeeds; fStack->FreeChunk((void *)end->ed, (void *) end->physicaladdress, sizeof(ohci_endpoint_descriptor));
sc_freeeds = sed; delete end;
}
}
sed = sc_freeeds;
sc_freeeds = sed->next;
memset(&sed->ed, 0, sizeof(hc_endpoint_descriptor));
sed->next = 0;
return (sed);
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
@@ -309,11 +381,11 @@ pci_module_info *OHCI::pci_module = 0;
void void
OHCI::WriteReg(uint32 reg, uint32 value) OHCI::WriteReg(uint32 reg, uint32 value)
{ {
*(volatile uint32 *)(m_registers + reg) = value; *(volatile uint32 *)(fRegisters + reg) = value;
} }
uint32 uint32
OHCI::ReadReg(uint32 reg) OHCI::ReadReg(uint32 reg)
{ {
return *(volatile uint32 *)(m_registers + reg); return *(volatile uint32 *)(fRegisters + reg);
} }
+36 -27
View File
@@ -34,6 +34,7 @@
struct pci_info; struct pci_info;
struct pci_module_info; struct pci_module_info;
class OHCIRootHub; class OHCIRootHub;
class Endpoint;
// -------------------------------- // --------------------------------
// OHCI: The OHCI class derived // OHCI: The OHCI class derived
@@ -45,8 +46,9 @@ class OHCI : public BusManager
friend class OHCIRootHub; friend class OHCIRootHub;
public: public:
OHCI( pci_info *info , Stack *stack ); OHCI(pci_info *info, Stack *stack);
status_t SubmitTransfer( Transfer *t ); //Override from BusManager. ~OHCI();
status_t SubmitTransfer(Transfer *t); //Override from BusManager.
static pci_module_info *pci_module; // Global data for the module. static pci_module_info *pci_module; // Global data for the module.
inline void WriteReg(uint32 reg, uint32 value); inline void WriteReg(uint32 reg, uint32 value);
@@ -54,34 +56,24 @@ public:
private: private:
// Global // Global
pci_info *m_pcii; // pci-info struct pci_info *fPcii; // pci-info struct
Stack *m_stack; // Pointer to the stack Stack *fStack; // Pointer to the stack
uint8 *m_registers; // Base address of the operational registers uint8 *fRegisters; // Base address of the operational registers
area_id m_register_area; // Area id of the area_id fRegisterArea; // Area id of the
// HCCA // HCCA
area_id m_hcca_area; area_id fHccaArea;
struct hc_hcca *m_hcca; // The HCCA structure for the interupt communication struct ohci_hcca *fHcca; // The HCCA structure for the interupt communication
hcd_soft_endpoint *sc_eds[OHCI_NO_EDS]; // number of interupt endpiont descriptors Endpoint *fInterruptEndpoints[OHCI_NO_EDS]; // The interrupt endpoint list
// Registers // Dummy endpoints
struct hcd_soft_endpoint *ed_bulk_tail; // last in the bulk list Endpoint *fDummyControl;
struct hcd_soft_endpoint *ed_control_tail; // last in the control list Endpoint *fDummyBulk;
struct hcd_soft_endpoint *ed_isoch_tail; // lest in the isochrnonous list Endpoint *fDummyIsochronous;
struct hcd_soft_endpoint *ed_periodic[32]; // shadow of the interupt table
// free list structures
struct hcd_soft_endpoint *sc_freeeds; // list of free endpoint descriptors
struct hcd_soft_transfer *sc_freetds; // list of free general transfer descriptors
struct hcd_soft_itransfer *sc_freeitds; // list of free isonchronous transfer descriptors
// Done queue
struct hcd_soft_transfer *sc_sdone; // list of done general transfer descriptors
struct hcd_soft_itransfer *sc_sidone; // list of done isonchronous transefer descriptors
// memory management for queue data structures.
struct hcd_soft_transfer sc_hash_tds[OHCI_HASH_SIZE];
struct hcd_soft_itransfer sc_hash_itds[OHCI_HASH_SIZE];
// Root Hub // Root Hub
OHCIRootHub *m_roothub; // the root hub OHCIRootHub *m_roothub; // the root hub
addr_t m_roothub_base; // Base address of the root hub addr_t m_roothub_base; // Base address of the root hub
// functions // functions
hcd_soft_endpoint *ohci_alloc_soft_endpoint(); // allocate memory for an endpoint Endpoint *AllocateEndpoint(); // allocate memory for an endpoint
void FreeEndpoint(Endpoint *end); //Free endpoint
}; };
// -------------------------------- // --------------------------------
@@ -101,6 +93,23 @@ class OHCIRootHub : public Hub
OHCI *m_ohci; // needed because of internal data OHCI *m_ohci; // needed because of internal data
}; };
//
// Endpoint: wrapper around the hardware endpoints
//
struct Endpoint
{
addr_t physicaladdress;//Point to the physical address
ohci_endpoint_descriptor *ed; //Logical 'endpoint'
Endpoint *next; //Pointer to the 'next' endpoint
//Utility functions
void SetNext(Endpoint *end) {
next = end;
ed->next_endpoint = end->physicaladdress;
};
};
#define OHCI_DEBUG #define OHCI_DEBUG
#endif // OHCI_H #endif // OHCI_H
@@ -263,7 +263,7 @@ typedef uint32 ohci_physaddr_t;
#define OHCI_NO_INTRS 32 #define OHCI_NO_INTRS 32
struct hc_hcca struct ohci_hcca
{ {
addr_t hcca_interrupt_table[OHCI_NO_INTRS]; addr_t hcca_interrupt_table[OHCI_NO_INTRS];
uint32 hcca_frame_number; uint32 hcca_frame_number;
@@ -282,12 +282,12 @@ struct hc_hcca
// Endpoint descriptor structure (section 4.2) // Endpoint descriptor structure (section 4.2)
// -------------------------------- // --------------------------------
typedef struct hc_endpoint_descriptor typedef struct ohci_endpoint_descriptor
{ {
uint32 ed_flags; uint32 ed_flags;
addr_t ed_qtailp; // Queue tail pointer addr_t ed_qtailp; // Queue tail pointer
addr_t ed_qheadp; // Queue head pointer addr_t ed_qheadp; // Queue head pointer
addr_t ed_nexted; // Next endpoint in the list addr_t next_endpoint; // Next endpoint in the list
}; };
#define OHCI_ED_GET_FA(s) ((s) & 0x7f) #define OHCI_ED_GET_FA(s) ((s) & 0x7f)
@@ -31,19 +31,6 @@
#include "usb_p.h" #include "usb_p.h"
#include "ohci_hardware.h" #include "ohci_hardware.h"
// ------------------------------------
// OHCI:: Software endpoint descriptor
// ------------------------------------
typedef struct hcd_soft_endpoint
{
addr_t physaddr; // physical address of the host controller endpoint
hc_endpoint_descriptor ed; // host controller endpoint descriptor
struct hcd_soft_endpoint *next; // next software endpoint descriptor
}hcd_soft_endpoint;
#define OHCI_SED_SIZE ((sizeof (struct hcd_soft_endpoint) + OHCI_ED_ALIGN - 1) / OHCI_ED_ALIGN * OHCI_ED_ALIGN)
#define OHCI_SED_CHUNK 128
// ------------------------------------ // ------------------------------------
// OHCI:: Software general // OHCI:: Software general
@@ -99,51 +86,4 @@ typedef struct hcd_soft_itransfer
#define OHCI_HASH_SIZE 128 #define OHCI_HASH_SIZE 128
// ------------------------------
// OHCI:: OHCI device structure
// ------------------------------
/*
typedef struct
{
usb_dma_t sc_hccadma;
struct ohci_hcca *sc_hcca;
ohci_soft_endpoint *sc_eds[OHCI_NO_EDS];
int sc_bws[OHCI_NO_INTRS];
uint32 sc_eintrs;
ohci_soft_endpoint *sc_isoc_head;
ohci_soft_endpoint *sc_ctrl_head;
ohci_soft_endpoint *sc_bulk_head;
LIST_HEAD(, ohci_soft_transfer) sc_hash_tds[OHCI_HASH_SIZE];
LIST_HEAD(, ohci_soft_itransfer) sc_hash_itds[OHCI_HASH_SIZE];
int sc_noport;
uint8 sc_addr; // device address
uint8 sc_conf; // device configuration
#ifdef USB_USE_SOFTINTR
char sc_softwake;
#endif // USB_USE_SOFTINTR
ohci_soft_endpoint *sc_freeeds;
ohci_soft_transfer *sc_freetds;
ohci_soft_itransfer *sc_freeitds;
usbd_xfer_handle sc_intrxfer;
ohci_soft_itransfer *sc_sidone;
ohci_soft_transfer *sc_sdone;
char sc_vendor[16];
int sc_id_vendor;
void *sc_powerhook; // cookie from power hook
void *sc_shutdownhook; // cookie from shutdown hook
uint32 sc_control; // Preserved during suspend/standby
uint32 sc_intre;
} ohci_soft;
*/
#endif // OHCI_SOFT #endif // OHCI_SOFT