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_DELAY_BUS_RESET 100000
#define USB_DELAY_DEVICE_POWER_UP 300000
#define USB_DELAY_HUB_POWER_UP 200000
#define USB_DELAY_PORT_RESET 50000

View File

@ -69,10 +69,10 @@ ohci_std_ops( int32 op , ... )
switch (op)
{
case B_MODULE_INIT:
TRACE( "ohci_module: init the module\n" );
TRACE(("ohci_module: init the module\n"));
return B_OK;
case B_MODULE_UNINIT:
TRACE( "ohci_module: uninit the module\n" );
TRACE(("ohci_module: uninit the module\n"));
break;
default:
return EINVAL;
@ -99,15 +99,16 @@ ohci_add_to( Stack *stack )
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)
{
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;
}
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.
//
@ -122,10 +123,10 @@ ohci_add_to( Stack *stack )
{
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;
}
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 );
if ( bus->InitCheck() != B_OK )
{
@ -142,7 +143,7 @@ ohci_add_to( Stack *stack )
if ( found == false )
{
TRACE( "USB OHCI: init hardware(): no devices found\n" );
TRACE(("USB OHCI: init hardware(): no devices found\n"));
free( item );
put_module( B_PCI_MODULE_NAME );
return ENODEV;
@ -191,178 +192,79 @@ OHCI::OHCI( pci_info *info , Stack *stack )
{
m_pcii = info;
m_stack = stack;
uint32 rev=0;
int i;
hcd_soft_endpoint *sed, *psed;
dprintf( "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;
TRACE( "OHCI: iospace offset: %lx\n" , m_opreg_base );
m_roothub_base = 255; //Invalidate the Root Hub address
{
// enable pci address access
unsigned char cmd;
cmd = OHCI::pci_module->read_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_command, 2);
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 );
TRACE(("USB OHCI: constructing new BusManager\n"));
fInitOK = false;
// 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);
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 );
// 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
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
dprintf(" 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)
{
dprintf("OHCI: Unsupported OHCI revision of the ohci device\n");
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 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.
ed_control_tail = ohci_alloc_soft_endpoint();
ed_control_tail->ed.ed_flags |= OHCI_ED_SKIP;
// Allocate dummy Endpoint Descriptor that starts the bulk list.
ed_bulk_tail = ohci_alloc_soft_endpoint();
ed_bulk_tail->ed.ed_flags |= OHCI_ED_SKIP;
// 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;
// Set up the Host Controller Communications Area
void *hcca_phy;
m_hcca_area = m_stack->AllocateArea((void**)&m_hcca, &hcca_phy,
B_PAGE_SIZE, "OHCI HCCA");
if (m_hcca_area < B_OK) {
TRACE(("USB OHCI: Error allocating HCCA block\n"));
delete_area(m_register_area);
return;
}
// Fill HCCA interrupt table. The bit reversal is to get
// the tree set up properly to spread the interrupts.
for (i = 0; i < OHCI_NO_INTRS; i++)
hcca->hcca_interrupt_table[revbits[i]] = sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr;
// Determine in what context we are running.
uint32 ctrlmsg,statusmsg;
ctrlmsg = OHCI::pci_module->read_io_16( m_opreg_base + OHCI_CONTROL);
if (ctrlmsg & OHCI_IR)
{
/// 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);
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);
// 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);
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);
}
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);
}
} else if (ReadReg(OHCI_CONTROL) & OHCI_HCFS_RESET) //Only if no BIOS/SMM control
snooze(USB_DELAY_BUS_RESET);
// 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;
// 5.1.1.4 Set Up Host controller
// initialize the data structures for the HCCA
uint32 framevalue = ReadReg(OHCI_FM_NUMBER);
m_roothub_base = 255; //Invalidate the Root Hub address
}
hcd_soft_endpoint * OHCI::ohci_alloc_soft_endpoint()
@ -404,4 +306,17 @@ status_t OHCI::SubmitTransfer( Transfer *t )
{
return B_OK;
}
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
{
friend class OHCIRootHub;
public:
public:
OHCI( pci_info *info , Stack *stack );
status_t SubmitTransfer( Transfer *t ); //Override from BusManager.
static pci_module_info *pci_module; // Global data for the module.
OHCI( pci_info *info , Stack *stack );
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);
inline uint32 ReadReg(uint32 reg);
private:
// Global
pci_info *m_pcii; // pci-info struct
Stack *m_stack; // Pointer to the stack
addr_t m_opreg_base; // Base address of the operational registers
uint32 m_revision; // The revision of the host controller
char *m_product_descr; // The product description (can be moved to the Busmanager Class)
// HCCA
area_id m_hcca_area;
struct hc_hcca *hcca; // The HCCA structure for the interupt communication
addr_t m_hcca_base; // Base address of the HCCA
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];
// 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
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
// 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];
// 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
};
// --------------------------------
@ -101,11 +102,5 @@ class OHCIRootHub : public Hub
};
#define OHCI_DEBUG
#ifdef OHCI_DEBUG
#define TRACE dprintf
#else
#define TRACE silent
void silent( const char * , ... ) {}
#endif
#endif // OHCI_H

View File

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