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
+140 -68
View File
@@ -88,23 +88,22 @@ ohci_std_ops( int32 op , ... )
//------------------------------------------------------------------------
static status_t
ohci_add_to( Stack *stack )
ohci_add_to(Stack *stack)
{
status_t status;
pci_info *item;
bool found = false;
int i;
#ifdef OHCI_DEBUG
set_dprintf_enabled( true );
load_driver_symbols( "ohci" );
#endif
#ifdef TRACE_USB
set_dprintf_enabled(true);
load_driver_symbols("ohci");
#endif
//
// 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));
return status;
}
@@ -113,20 +112,17 @@ ohci_add_to( Stack *stack )
// TODO: in the future we might want to support multiple host controllers.
//
item = new pci_info;
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 ) &&
( item->class_api == PCI_usb_ohci ) )
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 )
&& ( 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"));
continue;
}
TRACE(("USB OHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line));
OHCI *bus = new OHCI( item , stack );
if ( bus->InitCheck() != B_OK )
{
if ( bus->InitCheck() != B_OK ) {
delete bus;
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"));
free( item );
put_module( B_PCI_MODULE_NAME );
@@ -156,7 +151,7 @@ ohci_add_to( Stack *stack )
host_controller_info ohci_module = {
{
"busses/usb/ohci/jixt",
"busses/usb/ohci",
NULL, // No flag like B_KEEP_LOADED : the usb module does that
ohci_std_ops
},
@@ -170,8 +165,7 @@ host_controller_info ohci_module = {
// parameters: none
//------------------------------------------------------------------------
module_info *modules[] =
{
module_info *modules[] = {
(module_info *) &ohci_module,
NULL
};
@@ -184,59 +178,67 @@ module_info *modules[] =
// - stack: pointer to a stack instance
//------------------------------------------------------------------------
OHCI::OHCI( pci_info *info , Stack *stack )
: BusManager(stack)
OHCI::OHCI(pci_info *info, Stack *stack)
: BusManager(stack),
fRegisterArea(-1),
fHccaArea(-1),
fDummyControl(0),
fDummyBulk(0),
fDummyIsochronous(0)
{
m_pcii = info;
m_stack = stack;
fPcii = info;
fStack = stack;
int i;
hcd_soft_endpoint *sed, *psed;
TRACE(("USB OHCI: constructing new BusManager\n"));
fInitOK = false;
for(i = 0; i < OHCI_NO_EDS; i++) //Clear the interrupt list
fInterruptEndpoints[i] = 0;
// 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_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
//
addr_t registeroffset = pci_module->read_pci_config(info->bus,
info->device, info->function, PCI_base_registers, 4);
registeroffset &= PCI_address_memory_32_mask;
TRACE(("OHCI: iospace offset: %lx\n" , registeroffset));
m_register_area = 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);
if (m_register_area < B_OK) {
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 **)&fRegisters);
if (fRegisterArea < B_OK) {
TRACE(("USB OHCI: error mapping the registers\n"));
return;
}
// Get the revision of the controller
uint32 rev = ReadReg(OHCI_REVISION) & 0xff;
// 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" : ""));
if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) {
TRACE(("USB OHCI: Unsupported OHCI revision of the ohci device\n"));
delete_area(m_register_area);
return;
}
// Set up the Host Controller Communications Area
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");
if (m_hcca_area < B_OK) {
if (fHccaArea < B_OK) {
TRACE(("USB OHCI: Error allocating HCCA block\n"));
delete_area(m_register_area);
return;
}
memset((void*)fHcca, 0, sizeof(ohci_hcca));
//
// 5.1.1.3 Take control of the host controller
//
if (ReadReg(OHCI_CONTROL) & OHCI_IR) {
TRACE(("USB OHCI: SMM is in control of the host controller\n"));
WriteReg(OHCI_COMMAND_STATUS, OHCI_OCR);
@@ -252,44 +254,114 @@ OHCI::OHCI( pci_info *info , Stack *stack )
}
} else if (ReadReg(OHCI_CONTROL) & OHCI_HCFS_RESET) //Only if no BIOS/SMM control
snooze(USB_DELAY_BUS_RESET);
//
// 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);
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));
uint32 framevalue = ReadReg(OHCI_FM_NUMBER);
m_roothub_base = 255; //Invalidate the Root Hub address
}
hcd_soft_endpoint * OHCI::ohci_alloc_soft_endpoint()
OHCI::~OHCI()
{
hcd_soft_endpoint *sed;
int i;
if (fHccaArea > 0)
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;
if (sc_freeeds == NULL)
{
dprintf("OHCI: ohci_alloc_soft_endpoint(): allocating chunk\n");
for(i = 0; i < OHCI_SED_CHUNK; i++)
{
if(m_stack->AllocateChunk( (void **)&(sed) ,&phy , OHCI_ED_ALIGN )!= B_OK)
{
dprintf( "USB OHCI: ohci_alloc_soft_endpoint(): failed allocation of skeleton qh %i, aborting\n", i );
return (0);
}
// chunk has been allocated
sed->physaddr = reinterpret_cast<addr_t>(phy);
sed->next = sc_freeeds;
sc_freeeds = sed;
}
}
sed = sc_freeeds;
sc_freeeds = sed->next;
memset(&sed->ed, 0, sizeof(hc_endpoint_descriptor));
sed->next = 0;
return (sed);
if (fStack->AllocateChunk((void **)&endpoint->ed, &phy, sizeof(ohci_endpoint_descriptor)) != B_OK)
return 0;
endpoint->physicaladdress = (addr_t)phy;
memset((void *)endpoint->ed, 0, sizeof(ohci_endpoint_descriptor));
endpoint->ed->ed_flags = OHCI_ED_SKIP;
return endpoint;
}
void
OHCI::FreeEndpoint(Endpoint *end)
{
fStack->FreeChunk((void *)end->ed, (void *) end->physicaladdress, sizeof(ohci_endpoint_descriptor));
delete end;
}
//------------------------------------------------------------------------
@@ -309,11 +381,11 @@ pci_module_info *OHCI::pci_module = 0;
void
OHCI::WriteReg(uint32 reg, uint32 value)
{
*(volatile uint32 *)(m_registers + reg) = value;
*(volatile uint32 *)(fRegisters + reg) = value;
}
uint32
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_module_info;
class OHCIRootHub;
class Endpoint;
// --------------------------------
// OHCI: The OHCI class derived
@@ -45,8 +46,9 @@ class OHCI : public BusManager
friend class OHCIRootHub;
public:
OHCI( pci_info *info , Stack *stack );
status_t SubmitTransfer( Transfer *t ); //Override from BusManager.
OHCI(pci_info *info, Stack *stack);
~OHCI();
status_t SubmitTransfer(Transfer *t); //Override from BusManager.
static pci_module_info *pci_module; // Global data for the module.
inline void WriteReg(uint32 reg, uint32 value);
@@ -54,34 +56,24 @@ public:
private:
// Global
pci_info *m_pcii; // pci-info struct
Stack *m_stack; // Pointer to the stack
uint8 *m_registers; // Base address of the operational registers
area_id m_register_area; // Area id of the
pci_info *fPcii; // pci-info struct
Stack *fStack; // Pointer to the stack
uint8 *fRegisters; // Base address of the operational registers
area_id fRegisterArea; // Area id of the
// HCCA
area_id m_hcca_area;
struct hc_hcca *m_hcca; // The HCCA structure for the interupt communication
hcd_soft_endpoint *sc_eds[OHCI_NO_EDS]; // number of interupt endpiont descriptors
// Registers
struct hcd_soft_endpoint *ed_bulk_tail; // last in the bulk list
struct hcd_soft_endpoint *ed_control_tail; // last in the control list
struct hcd_soft_endpoint *ed_isoch_tail; // lest in the isochrnonous list
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];
area_id fHccaArea;
struct ohci_hcca *fHcca; // The HCCA structure for the interupt communication
Endpoint *fInterruptEndpoints[OHCI_NO_EDS]; // The interrupt endpoint list
// Dummy endpoints
Endpoint *fDummyControl;
Endpoint *fDummyBulk;
Endpoint *fDummyIsochronous;
// Root Hub
OHCIRootHub *m_roothub; // the root hub
addr_t m_roothub_base; // Base address of the root hub
OHCIRootHub *m_roothub; // the root hub
addr_t m_roothub_base; // Base address of the root hub
// 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
};
//
// 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
#endif // OHCI_H
@@ -263,7 +263,7 @@ typedef uint32 ohci_physaddr_t;
#define OHCI_NO_INTRS 32
struct hc_hcca
struct ohci_hcca
{
addr_t hcca_interrupt_table[OHCI_NO_INTRS];
uint32 hcca_frame_number;
@@ -282,12 +282,12 @@ struct hc_hcca
// Endpoint descriptor structure (section 4.2)
// --------------------------------
typedef struct hc_endpoint_descriptor
typedef struct ohci_endpoint_descriptor
{
uint32 ed_flags;
addr_t ed_qtailp; // Queue tail pointer
addr_t ed_qheadp; // Queue head pointer
addr_t ed_nexted; // Next endpoint in the list
addr_t ed_qtailp; // Queue tail pointer
addr_t ed_qheadp; // Queue head pointer
addr_t next_endpoint; // Next endpoint in the list
};
#define OHCI_ED_GET_FA(s) ((s) & 0x7f)
@@ -31,19 +31,6 @@
#include "usb_p.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
@@ -99,51 +86,4 @@ typedef struct hcd_soft_itransfer
#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