First commit to show that work on the ohci bus has restarted.

It doesn't do anything yet, but it allocates the io registers properly and
now the values that are returned when reading it make sense.

More to come...


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18673 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Niels Sascha Reedijk 2006-08-28 16:57:55 +00:00
parent 32065846ac
commit 34314b9803
4 changed files with 120 additions and 209 deletions

View File

@ -17,6 +17,7 @@
#define USB_MAX_AREAS 8 #define USB_MAX_AREAS 8
#define USB_DELAY_BUS_RESET 100000
#define USB_DELAY_DEVICE_POWER_UP 300000 #define USB_DELAY_DEVICE_POWER_UP 300000
#define USB_DELAY_HUB_POWER_UP 200000 #define USB_DELAY_HUB_POWER_UP 200000
#define USB_DELAY_PORT_RESET 50000 #define USB_DELAY_PORT_RESET 50000

View File

@ -69,10 +69,10 @@ ohci_std_ops( int32 op , ... )
switch (op) switch (op)
{ {
case B_MODULE_INIT: case B_MODULE_INIT:
TRACE( "ohci_module: init the module\n" ); TRACE(("ohci_module: init the module\n"));
return B_OK; return B_OK;
case B_MODULE_UNINIT: case B_MODULE_UNINIT:
TRACE( "ohci_module: uninit the module\n" ); TRACE(("ohci_module: uninit the module\n"));
break; break;
default: default:
return EINVAL; return EINVAL;
@ -99,15 +99,16 @@ ohci_add_to( Stack *stack )
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;
} }
TRACE( "usb_ohci init_hardware(): Setting up hardware\n" ); TRACE(("usb_ohci init_hardware(): Setting up hardware\n"));
// //
// TODO: in the future we might want to support multiple host controllers. // TODO: in the future we might want to support multiple host controllers.
// //
@ -122,10 +123,10 @@ ohci_add_to( Stack *stack )
{ {
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 )
{ {
@ -142,7 +143,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 );
return ENODEV; return ENODEV;
@ -191,178 +192,79 @@ OHCI::OHCI( pci_info *info , Stack *stack )
{ {
m_pcii = info; m_pcii = info;
m_stack = stack; m_stack = stack;
uint32 rev=0;
int i; int i;
hcd_soft_endpoint *sed, *psed; hcd_soft_endpoint *sed, *psed;
dprintf( "OHCI: constructing new BusManager\n" ); TRACE(("USB OHCI: constructing new BusManager\n"));
m_opreg_base = OHCI::pci_module->read_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, 0x20, 4);
m_opreg_base &= PCI_address_io_mask; fInitOK = false;
TRACE( "OHCI: iospace offset: %lx\n" , m_opreg_base );
m_roothub_base = 255; //Invalidate the Root Hub address // 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);
// enable pci address access cmd &= ~PCI_command_io;
unsigned char cmd; cmd |= PCI_command_master | PCI_command_memory;
cmd = OHCI::pci_module->read_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_command, 2); OHCI::pci_module->write_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_command, 2, cmd );
cmd = cmd | PCI_command_io | 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 ); // 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) {
TRACE(("USB OHCI: error mapping the registers\n"));
return;
} }
// Get the revision of the controller // Get the revision of the controller
OHCI::pci_module->read_io_16( m_opreg_base + OHCI_REVISION ); 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
dprintf(" 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"));
{ delete_area(m_register_area);
dprintf("OHCI: Unsupported OHCI revision of the ohci device\n");
return; return;
} }
// Set the revision of the controller
m_revision = rev;
// Set the product description of the controller
m_product_descr = "Open Host Controller Interface";
// Initialize the transfer descriptors and the interupt transfer descriptors
//
/* +++++++++++++++++++ */
//
// Allocate the HCCA area.
void *phy;
m_hcca_area = stack->AllocateArea( (void **)&(hcca) , &(phy) ,OHCI_HCCA_SIZE , "ohci hcca area" );
m_hcca_base = reinterpret_cast<addr_t>(phy);
// Allocate dummy Endpoint Descriptor that starts the control list. // Set up the Host Controller Communications Area
ed_control_tail = ohci_alloc_soft_endpoint(); void *hcca_phy;
ed_control_tail->ed.ed_flags |= OHCI_ED_SKIP; m_hcca_area = m_stack->AllocateArea((void**)&m_hcca, &hcca_phy,
B_PAGE_SIZE, "OHCI HCCA");
// Allocate dummy Endpoint Descriptor that starts the bulk list. if (m_hcca_area < B_OK) {
ed_bulk_tail = ohci_alloc_soft_endpoint(); TRACE(("USB OHCI: Error allocating HCCA block\n"));
ed_bulk_tail->ed.ed_flags |= OHCI_ED_SKIP; delete_area(m_register_area);
return;
// Allocate dummy Endpoint Descriptor that starts the isochronous list.
ed_isoch_tail = ohci_alloc_soft_endpoint();
ed_isoch_tail->ed.ed_flags |= OHCI_ED_SKIP;
// Allocate all the dummy Endpoint Desriptors that make up the interrupt tree.
for (i = 0; i < OHCI_NO_EDS; i++)
{
sed = ohci_alloc_soft_endpoint();
if (sed == NULL)
{
return;
}
/* All ED fields are set to 0. */
sc_eds[i] = sed;
sed->ed.ed_flags |= OHCI_ED_SKIP;
if (i != 0)
psed = sc_eds[(i-1) / 2];
else
psed= ed_isoch_tail;
sed->next = psed;
sed->ed.ed_nexted = psed->physaddr;
} }
// Fill HCCA interrupt table. The bit reversal is to get // 5.1.1.3 Take control of the host controller
// the tree set up properly to spread the interrupts. if (ReadReg(OHCI_CONTROL) & OHCI_IR) {
for (i = 0; i < OHCI_NO_INTRS; i++) TRACE(("USB OHCI: SMM is in control of the host controller\n"));
hcca->hcca_interrupt_table[revbits[i]] = sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr; WriteReg(OHCI_COMMAND_STATUS, OHCI_OCR);
for (int i = 0; i < 100 && (ReadReg(OHCI_CONTROL) & OHCI_IR); i++)
// Determine in what context we are running. snooze(1000);
uint32 ctrlmsg,statusmsg; if (ReadReg(OHCI_CONTROL) & OHCI_IR)
ctrlmsg = OHCI::pci_module->read_io_16( m_opreg_base + OHCI_CONTROL); TRACE(("USB OHCI: SMM doesn't respond... continueing anyway...\n"));
if (ctrlmsg & OHCI_IR) } else if (!(ReadReg(OHCI_CONTROL) & OHCI_HCFS_RESET)) {
{ TRACE(("USB OHCI: BIOS is in control of the host controller\n"));
/// SMM active, request change if (!(ReadReg(OHCI_CONTROL) & OHCI_HCFS_OPERATIONAL)) {
dprintf(("OHCI: SMM active, request owner change\n")); WriteReg(OHCI_CONTROL, OHCI_HCFS_RESUME);
statusmsg = OHCI::pci_module->read_io_16( m_opreg_base + OHCI_COMMAND_STATUS); snooze(USB_DELAY_BUS_RESET);
OHCI::pci_module->write_io_16( m_opreg_base + OHCI_COMMAND_STATUS,statusmsg | OHCI_OCR);
for (i = 0; i < 100 && (ctrlmsg & OHCI_IR); i++)
{
snooze(100);
ctrlmsg = OHCI::pci_module->read_io_16( m_opreg_base + OHCI_CONTROL);
} }
if ((ctrlmsg & OHCI_IR) == 0) } else if (ReadReg(OHCI_CONTROL) & OHCI_HCFS_RESET) //Only if no BIOS/SMM control
{ snooze(USB_DELAY_BUS_RESET);
dprintf("OHCI: SMM does not respond, resetting\n");
OHCI::pci_module->write_io_16( m_opreg_base + OHCI_CONTROL,OHCI_HCFS_RESET);
goto reset;
}
// Don't bother trying to reuse the BIOS init, we'll reset it anyway.
}
else if ((ctrlmsg & OHCI_HCFS_MASK) != OHCI_HCFS_RESET)
{
// BIOS started controller
dprintf("OHCI: BIOS active\n");
if ((ctrlmsg & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL)
{
OHCI::pci_module->write_io_16( m_opreg_base + OHCI_CONTROL,OHCI_HCFS_OPERATIONAL);
snooze(250000);
}
}
else
{
dprintf("OHCI: cold started\n");
reset:
// Controller was cold started.
snooze(100000);
}
// This reset should not be necessary according to the OHCI spec, but // 5.1.1.4 Set Up Host controller
// without it some controllers do not start. // initialize the data structures for the HCCA
//
/* +++++++++++++++++++ */
// uint32 framevalue = ReadReg(OHCI_FM_NUMBER);
// We now own the host controller and the bus has been reset.
//
/* +++++++++++++++++++ */ m_roothub_base = 255; //Invalidate the Root Hub address
//
// Reset the Host Controller
//
/* +++++++++++++++++++ */
//
// Nominal time for a reset is 10 us.
//
/* +++++++++++++++++++ */
//
// The controller is now in SUSPEND state, we have 2ms to finish.
//
// Set up the Host Controler registers.
//
/* +++++++++++++++++++ */
//
// Disable all interrupts and then switch on all desired interrupts.
//
/* +++++++++++++++++++ */
//
// Switch on desired functional features.
//
/* +++++++++++++++++++ */
//
// And finally start it!
//
/* +++++++++++++++++++ */
//
// The controller is now OPERATIONAL. Set a some final
// registers that should be set earlier, but that the
// controller ignores when in the SUSPEND state.
//
/* +++++++++++++++++++ */
//
// Fiddle the No OverCurrent Protection bit to avoid chip bug.
//
/* +++++++++++++++++++ */
//
// The AMD756 requires a delay before re-reading the register,
// otherwise it will occasionally report 0 ports.
//
/* +++++++++++++++++++ */
//
// Set up the bus structure
//
/* +++++++++++++++++++ */
//return B_OK;
} }
hcd_soft_endpoint * OHCI::ohci_alloc_soft_endpoint() hcd_soft_endpoint * OHCI::ohci_alloc_soft_endpoint()
@ -404,4 +306,17 @@ status_t OHCI::SubmitTransfer( Transfer *t )
{ {
return B_OK; return B_OK;
} }
pci_module_info *OHCI::pci_module = 0; pci_module_info *OHCI::pci_module = 0;
void
OHCI::WriteReg(uint32 reg, uint32 value)
{
*(volatile uint32 *)(m_registers + reg) = value;
}
uint32
OHCI::ReadReg(uint32 reg)
{
return *(volatile uint32 *)(m_registers + reg);
}

View File

@ -43,44 +43,45 @@ class OHCIRootHub;
class OHCI : public BusManager 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. 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 uint32 ReadReg(uint32 reg);
private: private:
// Global // Global
pci_info *m_pcii; // pci-info struct pci_info *m_pcii; // pci-info struct
Stack *m_stack; // Pointer to the stack Stack *m_stack; // Pointer to the stack
addr_t m_opreg_base; // Base address of the operational registers uint8 *m_registers; // Base address of the operational registers
uint32 m_revision; // The revision of the host controller area_id m_register_area; // Area id of the
char *m_product_descr; // The product description (can be moved to the Busmanager Class) // HCCA
// HCCA area_id m_hcca_area;
area_id m_hcca_area; struct hc_hcca *m_hcca; // The HCCA structure for the interupt communication
struct hc_hcca *hcca; // The HCCA structure for the interupt communication hcd_soft_endpoint *sc_eds[OHCI_NO_EDS]; // number of interupt endpiont descriptors
addr_t m_hcca_base; // Base address of the HCCA // Registers
hcd_soft_endpoint *sc_eds[OHCI_NO_EDS]; // number of interupt endpiont descriptors struct hcd_soft_endpoint *ed_bulk_tail; // last in the bulk list
// Registers struct hcd_soft_endpoint *ed_control_tail; // last in the control list
struct hcd_soft_endpoint *ed_bulk_tail; // last in the bulk list struct hcd_soft_endpoint *ed_isoch_tail; // lest in the isochrnonous list
struct hcd_soft_endpoint *ed_control_tail; // last in the control list struct hcd_soft_endpoint *ed_periodic[32]; // shadow of the interupt table
struct hcd_soft_endpoint *ed_isoch_tail; // lest in the isochrnonous list // free list structures
struct hcd_soft_endpoint *ed_periodic[32]; // shadow of the interupt table struct hcd_soft_endpoint *sc_freeeds; // list of free endpoint descriptors
// free list structures struct hcd_soft_transfer *sc_freetds; // list of free general transfer descriptors
struct hcd_soft_endpoint *sc_freeeds; // list of free endpoint descriptors struct hcd_soft_itransfer *sc_freeitds; // list of free isonchronous transfer descriptors
struct hcd_soft_transfer *sc_freetds; // list of free general transfer descriptors // Done queue
struct hcd_soft_itransfer *sc_freeitds; // list of free isonchronous transfer descriptors struct hcd_soft_transfer *sc_sdone; // list of done general transfer descriptors
// Done queue struct hcd_soft_itransfer *sc_sidone; // list of done isonchronous transefer descriptors
struct hcd_soft_transfer *sc_sdone; // list of done general transfer descriptors // memory management for queue data structures.
struct hcd_soft_itransfer *sc_sidone; // list of done isonchronous transefer descriptors struct hcd_soft_transfer sc_hash_tds[OHCI_HASH_SIZE];
// memory management for queue data structures. struct hcd_soft_itransfer sc_hash_itds[OHCI_HASH_SIZE];
struct hcd_soft_transfer sc_hash_tds[OHCI_HASH_SIZE]; // Root Hub
struct hcd_soft_itransfer sc_hash_itds[OHCI_HASH_SIZE]; OHCIRootHub *m_roothub; // the root hub
// Root Hub addr_t m_roothub_base; // Base address of the root hub
OHCIRootHub *m_roothub; // the root hub // functions
addr_t m_roothub_base; // Base address of the root hub hcd_soft_endpoint *ohci_alloc_soft_endpoint(); // allocate memory for an endpoint
// functions
hcd_soft_endpoint *ohci_alloc_soft_endpoint(); // allocate memory for an endpoint
}; };
// -------------------------------- // --------------------------------
@ -101,11 +102,5 @@ class OHCIRootHub : public Hub
}; };
#define OHCI_DEBUG #define OHCI_DEBUG
#ifdef OHCI_DEBUG
#define TRACE dprintf
#else
#define TRACE silent
void silent( const char * , ... ) {}
#endif
#endif // OHCI_H #endif // OHCI_H

View File

@ -32,9 +32,9 @@
// -------------------------------- // --------------------------------
#define OHCI_REVISION 0x00 // OHCI revision #define OHCI_REVISION 0x00 // OHCI revision
#define OHCI_REV_LO(rev) ((rev)&0xf) #define OHCI_REV_LO(rev) ((rev)&0x0f)
#define OHCI_REV_HI(rev) (((rev)>>4)&0xf) #define OHCI_REV_HI(rev) (((rev)>>4)&0x03)
#define OHCI_REV_LEGACY(rev) ((rev) & 0x100) #define OHCI_REV_LEGACY(rev) ((rev) & 0x10)
// -------------------------------- // --------------------------------
// Control register (section 7.1.2) // Control register (section 7.1.2)