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++)
snooze(1000);
if (ReadReg(OHCI_CONTROL) & OHCI_IR)
TRACE(("USB OHCI: SMM doesn't respond... continueing anyway...\n"));
} else if (!(ReadReg(OHCI_CONTROL) & OHCI_HCFS_RESET)) {
TRACE(("USB OHCI: BIOS is in control of the host controller\n"));
if (!(ReadReg(OHCI_CONTROL) & OHCI_HCFS_OPERATIONAL)) {
WriteReg(OHCI_CONTROL, OHCI_HCFS_RESUME);
snooze(USB_DELAY_BUS_RESET);
}
} else if (ReadReg(OHCI_CONTROL) & OHCI_HCFS_RESET) //Only if no BIOS/SMM control
snooze(USB_DELAY_BUS_RESET);
// Determine in what context we are running. // 5.1.1.4 Set Up Host controller
uint32 ctrlmsg,statusmsg; // initialize the data structures for the HCCA
ctrlmsg = OHCI::pci_module->read_io_16( m_opreg_base + OHCI_CONTROL);
if (ctrlmsg & OHCI_IR)
{ uint32 framevalue = ReadReg(OHCI_FM_NUMBER);
/// SMM active, request change
dprintf(("OHCI: SMM active, request owner change\n"));
statusmsg = OHCI::pci_module->read_io_16( m_opreg_base + OHCI_COMMAND_STATUS); m_roothub_base = 255; //Invalidate the Root Hub address
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)
{
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
// without it some controllers do not start.
//
/* +++++++++++++++++++ */
//
// We now own the host controller and the bus has been reset.
//
/* +++++++++++++++++++ */
//
// 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.
private: inline void WriteReg(uint32 reg, uint32 value);
// Global inline uint32 ReadReg(uint32 reg);
pci_info *m_pcii; // pci-info struct
Stack *m_stack; // Pointer to the stack private:
addr_t m_opreg_base; // Base address of the operational registers // Global
uint32 m_revision; // The revision of the host controller pci_info *m_pcii; // pci-info struct
char *m_product_descr; // The product description (can be moved to the Busmanager Class) Stack *m_stack; // Pointer to the stack
// HCCA uint8 *m_registers; // Base address of the operational registers
area_id m_hcca_area; area_id m_register_area; // Area id of the
struct hc_hcca *hcca; // The HCCA structure for the interupt communication // HCCA
addr_t m_hcca_base; // Base address of the HCCA area_id m_hcca_area;
hcd_soft_endpoint *sc_eds[OHCI_NO_EDS]; // number of interupt endpiont descriptors struct hc_hcca *m_hcca; // The HCCA structure for the interupt communication
// 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)