Quick merge of my development branch with mainline (for SVN switch).

The OHCI stuff was done by Jixt (thanks)./installusb
All is still very much work in progress

Patches applied:

 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--base-0
   tag of Niels.Reedijk@gmail.com--haiku-2005/usb-busses--mainline--0.1--base-0

 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-1
   Set the PORT_STATUS_LOW_SPEED flag correctly (using the register bitflag for low speed devices, instead of the proper lowspeed flag)

 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-2
   Clean up transfers when they're done

 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-3


 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-4


 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-5


 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-6


 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-7
   Remove obsolete ehci.c

 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-8


 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-9
   Completed memory allocation + initialization

 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-10
   First attempt at performing control transfers - failed miserably

 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-11
   Trying to read a 16bit value into a 8bit integer, stupid

 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-12
   nicer way of getting the base io address

 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-13
   Take over control from BIOS

 * Niels.Reedijk@gmail.com--nielx-2005/usb-busses--development--0.1--patch-14
   Revert change for disabling USB BIOS support


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11743 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Niels Sascha Reedijk 2005-03-14 21:02:03 +00:00
parent 89bdde9df1
commit 5a072ced75
13 changed files with 1464 additions and 185 deletions

View File

@ -3,6 +3,7 @@ SubDir OBOS_TOP src add-ons kernel busses usb ;
SubDirC++Flags -fno-rtti ;
AddResources uhci : uhci.rdef ;
AddResources ohci : ohci.rdef ;
UsePrivateHeaders [ FDirName kernel ] ;
UseHeaders [ FDirName $(OBOS_TOP) src add-ons kernel bus_managers usb ] ;
@ -12,4 +13,10 @@ R5KernelAddon uhci : [ FDirName kernel busses usb ] :
uhci_rh.cpp
;
R5KernelAddon ohci : [ FDirName kernel busses usb ] :
ohci.cpp
ohci_rh.cpp
;
LinkSharedOSLibs uhci : libusb.a ;
LinkSharedOSLibs ohci : libusb.a ;

View File

@ -1,156 +0,0 @@
//------------------------------------------------------------------------------
// Copyright (c) 2003-2004, Niels S. Reedijk
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#include <module.h>
#include <PCI.h>
#define UHCI_DEBUG
#ifdef UHCI_DEBUG
#define TRACE dprintf
#else
#define TRACE silent
void silent( const char * , ... ) {}
#endif
static status_t init_hardware();
/* ++++++++++
This is the implementation of the UHCI controller for the OpenBeOS USB stack
++++++++++ */
static int32
ehci_std_ops( int32 op , ... )
{
switch (op)
{
case B_MODULE_INIT:
TRACE( "ehci_module: init the module\n" );
return init_hardware();
case B_MODULE_UNINIT:
TRACE( "ehci_module: uninit the module\n" );
break;
default:
return EINVAL;
}
return B_OK;
}
struct module_info ehci_module = {
"busses/usb/ehci/nielx",
NULL, // No flag like B_KEEP_LOADED : the usb module does that
ehci_std_ops
};
module_info *modules[] = {
(module_info *)&ehci_module ,
NULL
};
/* ++++++++++
Internal variables
++++++++++ */
typedef struct ehci_properties
{
uint32 reg_base; //Base address of the registers
pci_info *pcii; //pci-info struct
} ehci_properties_t;
static pci_module_info *m_pcimodule = 0;
static pci_info *m_device = 0;
static ehci_properties_t*m_data = 0;
/* ++++++++++
Register/Bit constants
++++++++++ */
enum {
USBCMD = 0x0 //Command register (2byte)
};
enum USBCMD_commands {
RS = 0x1 , //Run=1 Stop=0
HCRESET = 0x2 //Host controller reset
};
/* ++++++++++
The hardware management functions
++++++++++ */
static status_t
init_hardware()
{
status_t status;
pci_info *item;
int i;
// Try if the PCI module is loaded (it would be weird if it wouldn't, but alas)
if( ( status = get_module( B_PCI_MODULE_NAME, (module_info **)&m_pcimodule )) != B_OK)
{
TRACE( "ehci_nielx init_hardware(): Get PCI module failed! %lu \n", status);
return status;
}
// TODO: in the future we might want to support multiple host controllers.
item = (pci_info *)malloc( sizeof( pci_info ) );
for ( i = 0 ; m_pcimodule->get_nth_pci_info( i , item ) == B_OK ; i++ )
{
//class_base = 0C (serial bus) class_sub = 03 (usb) prog_int: 20 (EHCI)
if ( ( item->class_base == 0x0C ) && ( item->class_sub == 0x03 ) &&
( item->class_api == 0x20 ) )
{
if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF))
{
TRACE( "ehci_nielx init_hardware(): found with invalid IRQ - check IRQ assignement\n");
continue;
}
TRACE("ehci_nielx init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line);
m_device = item;
break;
}
}
if ( m_device == 0 )
{
TRACE( "ehci_nielx init hardware(): no devices found\n" );
put_module( B_PCI_MODULE_NAME );
return ENODEV;
}
//Initialise the host controller
m_data = (ehci_properties_t *)malloc( sizeof( ehci_properties_t ) );
m_data->pcii = m_device;
m_data->reg_base = m_device->u.h0.base_registers[0];
{
/* enable pci address access */
unsigned char cmd;
cmd = m_pcimodule->read_pci_config(m_data->pcii->bus, m_data->pcii->device, m_data->pcii->function, PCI_command, 2);
cmd = cmd | PCI_command_io | PCI_command_master | PCI_command_memory;
m_pcimodule->write_pci_config(m_data->pcii->bus, m_data->pcii->device, m_data->pcii->function, PCI_command, 2, cmd );
}
//Do a host reset
//m_pcimodule->write_io_16( data->reg_base + USBCMD , HCRESET );
//usleep(50);
return B_OK;
}

View File

@ -0,0 +1,404 @@
//------------------------------------------------------------------------------
// Copyright (c) 2005, Jan-Rixt Van Hoye
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// explanation of this file:
// -------------------------
//
// This is the implementation of the OHCI module for the Haiku USB stack
// It is bases on the hcir1_0a documentation that can be found on www.usb.org
// Some parts are derive from source-files from openbsd, netbsd and linux.
//
// ------------------------------------------------------------------------
// ---------------------------
// OHCI:: Includes
// ---------------------------
#include <module.h>
#include <PCI.h>
#include <USB.h>
#include <KernelExport.h>
#include <stdlib.h>
// ---------------------------
// OHCI:: Local includes
// ---------------------------
#include "ohci.h"
#include "ohci_hardware.h"
#include <usb_p.h>
//------------------------------------------------------
// OHCI:: Reverse the bits in a value between 0 and 31
// (Section 3.3.2)
//------------------------------------------------------
static uint8 revbits[OHCI_NO_INTRS] =
{ 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c,
0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e,
0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d,
0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f };
//------------------------------------------------------------------------
// OHCI:: These are the OHCI operations that can be done.
//
// parameters:
// - op: operation
//------------------------------------------------------------------------
static int32
ohci_std_ops( int32 op , ... )
{
switch (op)
{
case B_MODULE_INIT:
TRACE( "ohci_module: init the module\n" );
return B_OK;
case B_MODULE_UNINIT:
TRACE( "ohci_module: uninit the module\n" );
break;
default:
return EINVAL;
}
return B_OK;
}
//------------------------------------------------------------------------
// OHCI:: Give an reference of a stack instance to the OHCI module
//
// parameters:
// - &stack: reference to a stack instance form stack.cpp
//------------------------------------------------------------------------
static bool
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
//
// 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);
return status;
}
TRACE( "usb_ohci init_hardware(): Setting up hardware\n" );
//
// 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++ )
{
//
// class_base = 0C (serial bus) class_sub = 03 (usb) prog_int: 10 (OHCI)
//
if ( ( item->class_base == 0x0C ) && ( item->class_sub == 0x03 ) &&
( item->class_api == 0x10 ) )
{
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 )
{
delete bus;
break;
}
stack.AddBusManager( bus );
bus->Start();
found = true;
break;
}
}
if ( found == false )
{
TRACE( "USB OHCI: init hardware(): no devices found\n" );
free( item );
put_module( B_PCI_MODULE_NAME );
return ENODEV;
}
return B_OK; //Hardware found
}
//------------------------------------------------------------------------
// OHCI:: Host controller information
//
// parameters: none
//------------------------------------------------------------------------
host_controller_info ohci_module = {
{
"busses/usb/ohci/jixt",
NULL, // No flag like B_KEEP_LOADED : the usb module does that
ohci_std_ops
},
NULL ,
ohci_add_to
};
//------------------------------------------------------------------------
// OHCI:: Module information
//
// parameters: none
//------------------------------------------------------------------------
module_info *modules[] =
{
(module_info *) &ohci_module,
NULL
};
//------------------------------------------------------------------------
// OHCI:: Constructor/Initialisation
//
// parameters:
// - info: pointer to a pci information structure
// - stack: pointer to a stack instance
//------------------------------------------------------------------------
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 ) ^ 1;
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 );
}
// Get the revision of the controller
OHCI::pci_module->read_io_16( m_opreg_base + OHCI_REVISION );
// 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");
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;
}
// 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++)
{
spin(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);
spin(250000);
}
}
else
{
dprintf("OHCI: cold started\n");
reset:
// Controller was cold started.
spin(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 *sed;
int i;
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);
}
//------------------------------------------------------------------------
// OHCI:: Submit a transfer
//
// parameters:
// - t: pointer to a transfer instance
//------------------------------------------------------------------------
status_t OHCI::SubmitTransfer( Transfer *t )
{
return B_OK;
}
pci_module_info *OHCI::pci_module = 0;

View File

@ -0,0 +1,111 @@
//------------------------------------------------------------------------------
// Copyright (c) 2005, Jan-Rixt Van Hoye
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//-------------------------------------------------------------------------------
#ifndef OHCI_H
#define OHCI_H
// ---------------------------
// OHCI:: Includes
// ---------------------------
#include <usb_p.h>
#include "ohci_software.h"
struct pci_info;
struct pci_module_info;
class OHCIRootHub;
// --------------------------------
// OHCI: The OHCI class derived
// from the BusManager
// --------------------------------
class OHCI : public BusManager
{
friend class OHCIRootHub;
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.
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
};
// --------------------------------
// OHCI: The root hub of the OHCI
// controller derived from
// the Hub class
// --------------------------------
class OHCIRootHub : public Hub
{
public:
OHCIRootHub( OHCI *ohci , int8 devicenum );
status_t SubmitTransfer( Transfer *t );
void UpdatePortStatus();
private:
usb_port_status m_hw_port_status[2]; // the port status (maximum of two)
OHCI *m_ohci; // needed because of internal data
};
#define OHCI_DEBUG
#ifdef OHCI_DEBUG
#define TRACE dprintf
#else
#define TRACE silent
void silent( const char * , ... ) {}
#endif
#endif // OHCI_H

View File

@ -0,0 +1,16 @@
/*
** ohci.rdef
**
*/
resource app_signature "application/x-vnd.haiku-ohci";
resource app_version {
major = 0,
middle = 0,
minor = 1,
variety = 0,
internal = 0,
short_info = "OHCI host controller driver",
long_info = "Haiku - This driver is (c) 2005 Jan-Rixt Van Hoye"
};

View File

@ -0,0 +1,406 @@
//------------------------------------------------------------------------------
// Copyright (c) 2005, Jan-Rixt Van Hoye
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//------------------------------------------------------------------------------
#ifndef OHCI_HARD_H
#define OHCI_HARD_H
// --------------------------------
// The OHCI registers
// --------------------------------
// --------------------------------
// Revision register (section 7.1.1)
// --------------------------------
#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)
// --------------------------------
// Control register (section 7.1.2)
// --------------------------------
#define OHCI_CONTROL 0x04
#define OHCI_CBSR_MASK 0x00000003 // Control-Bulk Service Ratio
#define OHCI_RATIO_1_1 0x00000000
#define OHCI_RATIO_1_2 0x00000001
#define OHCI_RATIO_1_3 0x00000002
#define OHCI_RATIO_1_4 0x00000003
#define OHCI_PLE 0x00000004 // Periodic List Enable
#define OHCI_IE 0x00000008 // Isochronous Enable
#define OHCI_CLE 0x00000010 // Control List Enable
#define OHCI_BLE 0x00000020 // Bulk List Enable
#define OHCI_HCFS_MASK 0x000000c0 // HostControllerFunctionalState
#define OHCI_HCFS_RESET 0x00000000
#define OHCI_HCFS_RESUME 0x00000040
#define OHCI_HCFS_OPERATIONAL 0x00000080
#define OHCI_HCFS_SUSPEND 0x000000c0
#define OHCI_IR 0x00000100 // Interrupt Routing
#define OHCI_RWC 0x00000200 // Remote Wakeup Connected
#define OHCI_RWE 0x00000400 // Remote Wakeup Enabled
// --------------------------------
// Command status register (section 7.1.3)
// --------------------------------
#define OHCI_COMMAND_STATUS 0x08
#define OHCI_HCR 0x00000001 // Host Controller Reset
#define OHCI_CLF 0x00000002 // Control List Filled
#define OHCI_BLF 0x00000004 // Bulk List Filled
#define OHCI_OCR 0x00000008 // Ownership Change Request
#define OHCI_SOC_MASK 0x00030000 // Scheduling Overrun Count
// --------------------------------
// Interupt status register (section 7.1.4)
// --------------------------------
#define OHCI_INTERRUPT_STATUS 0x0c
#define OHCI_SO 0x00000001 // Scheduling Overrun
#define OHCI_WDH 0x00000002 // Writeback Done Head
#define OHCI_SF 0x00000004 // Start of Frame
#define OHCI_RD 0x00000008 // Resume Detected
#define OHCI_UE 0x00000010 // Unrecoverable Error
#define OHCI_FNO 0x00000020 // Frame Number Overflow
#define OHCI_RHSC 0x00000040 // Root Hub Status Change
#define OHCI_OC 0x40000000 // Ownership Change
#define OHCI_MIE 0x80000000 // Master Interrupt Enable
// --------------------------------
// Interupt enable register (section 7.1.5)
// --------------------------------
#define OHCI_INTERRUPT_ENABLE 0x10
// --------------------------------
// Interupt disable register (section 7.1.6)
// --------------------------------
#define OHCI_INTERRUPT_DISABLE 0x14
// -------------------------------------
// Memory Pointer Partition (section 7.2)
// -------------------------------------
// --------------------------------
// HCCA register (section 7.2.1)
// --------------------------------
#define OHCI_HCCA 0x18
// --------------------------------
// Period current ED register (section 7.2.2)
// --------------------------------
#define OHCI_PERIOD_CURRENT_ED 0x1c
// --------------------------------
// Control head ED register (section 7.2.3)
// --------------------------------
#define OHCI_CONTROL_HEAD_ED 0x20
// --------------------------------
// Current control ED register (section 7.2.4)
// --------------------------------
#define OHCI_CONTROL_CURRENT_ED 0x24
// --------------------------------
// Bulk head ED register (section 7.2.5)
// --------------------------------
#define OHCI_BULK_HEAD_ED 0x28
// --------------------------------
// Current bulk ED register (section 7.2.6)
// --------------------------------
#define OHCI_BULK_CURRENT_ED 0x2c
// --------------------------------
// Done head register (section 7.2.7)
// --------------------------------
#define OHCI_DONE_HEAD 0x30
// --------------------------------
// Frame Counter partition (section 7.3)
// --------------------------------
// --------------------------------
// Frame interval register (section 7.3.1)
// --------------------------------
#define OHCI_FM_INTERVAL 0x34
#define OHCI_GET_IVAL(s) ((s) & 0x3fff)
#define OHCI_GET_FSMPS(s) (((s) >> 16) & 0x7fff)
#define OHCI_FIT 0x80000000
// --------------------------------
// Frame remaining register (section 7.3.2)
// --------------------------------
#define OHCI_FM_REMAINING 0x38
// --------------------------------
// Frame number register (section 7.3.3)
// --------------------------------
#define OHCI_FM_NUMBER 0x3c
// --------------------------------
// Periodic start register (section 7.3.4)
// --------------------------------
#define OHCI_PERIODIC_START 0x40
// --------------------------------
// LS treshold register (section 7.3.5)
// --------------------------------
#define OHCI_LS_THRESHOLD 0x44
// --------------------------------
// Root Hub Partition (section 7.4)
// --------------------------------
// --------------------------------
// Root Hub Descriptor A register (section 7.4.1)
// --------------------------------
#define OHCI_RH_DESCRIPTOR_A 0x48
#define OHCI_GET_NDP(s) ((s) & 0xff)
#define OHCI_PSM 0x0100 // Power Switching Mode
#define OHCI_NPS 0x0200 // No Power Switching
#define OHCI_DT 0x0400 // Device Type
#define OHCI_OCPM 0x0800 // Overcurrent Protection Mode
#define OHCI_NOCP 0x1000 // No Overcurrent Protection
#define OHCI_GET_POTPGT(s) ((s) >> 24)
// --------------------------------
// Root Hub Descriptor B register (section 7.4.2)
// --------------------------------
#define OHCI_RH_DESCRIPTOR_B 0x4c
// --------------------------------
// Root Hub status register (section 7.4.3)
// --------------------------------
#define OHCI_RH_STATUS 0x50
#define OHCI_LPS 0x00000001 // Local Power Status
#define OHCI_OCI 0x00000002 // OverCurrent Indicator
#define OHCI_DRWE 0x00008000 // Device Remote Wakeup Enable
#define OHCI_LPSC 0x00010000 // Local Power Status Change
#define OHCI_CCIC 0x00020000 // OverCurrent Indicator Change
#define OHCI_CRWE 0x80000000 // Clear Remote Wakeup Enable
// --------------------------------
// Root Hub port status (n) register (section 7.4.4)
// --------------------------------
#define OHCI_RH_PORT_STATUS(n) (0x50 + (n)*4) // 1 based indexing
// --------------------------------
// ????
// --------------------------------
#define OHCI_LES (OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE)
// --------------------------------
// All interupts
// --------------------------------
#define OHCI_ALL_INTRS (OHCI_SO | OHCI_WDH | OHCI_SF | OHCI_RD | OHCI_UE | OHCI_FNO | OHCI_RHSC | OHCI_OC)
// --------------------------------
// All normal interupts
// --------------------------------
#define OHCI_NORMAL_INTRS (OHCI_SO | OHCI_WDH | OHCI_RD | OHCI_UE | OHCI_RHSC)
// --------------------------------
// FSMPS
// --------------------------------
#define OHCI_FSMPS(i) (((i-210)*6/7) << 16)
// --------------------------------
// Periodic
// --------------------------------
#define OHCI_PERIODIC(i) ((i)*9/10)
// --------------------------------
// OHCI physical address
// --------------------------------
typedef uint32 ohci_physaddr_t;
// --------------------------------
// HCCA structure (section 4.4)
// --------------------------------
#define OHCI_NO_INTRS 32
struct hc_hcca
{
addr_t hcca_interrupt_table[OHCI_NO_INTRS];
uint32 hcca_frame_number;
addr_t hcca_done_head;
uint8 hcca_reserved_for_hc[116];
};
#define OHCI_DONE_INTRS 1
#define OHCI_HCCA_SIZE 256
#define OHCI_HCCA_ALIGN 256
#define OHCI_PAGE_SIZE 0x1000
#define OHCI_PAGE(x) ((x) &~ 0xfff)
#define OHCI_PAGE_OFFSET(x) ((x) & 0xfff)
// --------------------------------
// Endpoint descriptor structure (section 4.2)
// --------------------------------
typedef struct hc_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
};
#define OHCI_ED_GET_FA(s) ((s) & 0x7f)
#define OHCI_ED_ADDRMASK 0x0000007f
#define OHCI_ED_SET_FA(s) (s)
#define OHCI_ED_GET_EN(s) (((s) >> 7) & 0xf)
#define OHCI_ED_SET_EN(s) ((s) << 7)
#define OHCI_ED_DIR_MASK 0x00001800
#define OHCI_ED_DIR_TD 0x00000000
#define OHCI_ED_DIR_OUT 0x00000800
#define OHCI_ED_DIR_IN 0x00001000
#define OHCI_ED_SPEED 0x00002000
#define OHCI_ED_SKIP 0x00004000
#define OHCI_ED_FORMAT_GEN 0x00000000
#define OHCI_ED_FORMAT_ISO 0x00008000
#define OHCI_ED_GET_MAXP(s) (((s) >> 16) & 0x07ff)
#define OHCI_ED_SET_MAXP(s) ((s) << 16)
#define OHCI_ED_MAXPMASK (0x7ff << 16)
#define OHCI_HALTED 0x00000001
#define OHCI_TOGGLECARRY 0x00000002
#define OHCI_HEADMASK 0xfffffffc
#define OHCI_ED_ALIGN 16
// --------------------------------
// General transfer descriptor structure (section 4.3.1)
// --------------------------------
typedef struct hc_transfer_descriptor
{
uint32 td_flags;
addr_t td_cbp; // Current Buffer Pointer
addr_t td_nexttd; // Next Transfer Descriptor
addr_t td_be; // Buffer End
} ;
#define OHCI_TD_R 0x00040000 // Buffer Rounding
#define OHCI_TD_DP_MASK 0x00180000 // Direction / PID
#define OHCI_TD_SETUP 0x00000000
#define OHCI_TD_OUT 0x00080000
#define OHCI_TD_IN 0x00100000
#define OHCI_TD_GET_DI(x) (((x) >> 21) & 7) // Delay Interrupt
#define OHCI_TD_SET_DI(x) ((x) << 21)
#define OHCI_TD_NOINTR 0x00e00000
#define OHCI_TD_INTR_MASK 0x00e00000
#define OHCI_TD_TOGGLE_CARRY 0x00000000
#define OHCI_TD_TOGGLE_0 0x02000000
#define OHCI_TD_TOGGLE_1 0x03000000
#define OHCI_TD_TOGGLE_MASK 0x03000000
#define OHCI_TD_GET_EC(x) (((x) >> 26) & 3) // Error Count
#define OHCI_TD_GET_CC(x) ((x) >> 28) // Condition Code
#define OHCI_TD_NOCC 0xf0000000
#define OHCI_TD_ALIGN 16
// --------------------------------
// Isonchronous transfer descriptor structure (section 4.3.2)
// --------------------------------
#define OHCI_ITD_NOFFSET 8
typedef struct hc_itransfer_descriptor
{
uint32 itd_flags;
addr_t itd_bp0; // Buffer Page 0
addr_t itd_nextitd; // Next Isochronous Transfer Descriptor
addr_t itd_be; // Buffer End
uint16 itd_offset[OHCI_ITD_NOFFSET]; // Buffer offsets
};
#define OHCI_ITD_GET_SF(x) ((x) & 0x0000ffff)
#define OHCI_ITD_SET_SF(x) ((x) & 0xffff)
#define OHCI_ITD_GET_DI(x) (((x) >> 21) & 7) // Delay Interrupt
#define OHCI_ITD_SET_DI(x) ((x) << 21)
#define OHCI_ITD_NOINTR 0x00e00000
#define OHCI_ITD_GET_FC(x) ((((x) >> 24) & 7)+1) // Frame Count
#define OHCI_ITD_SET_FC(x) (((x)-1) << 24)
#define OHCI_ITD_GET_CC(x) ((x) >> 28) // Condition Code
#define OHCI_ITD_NOCC 0xf0000000
#define itd_pswn itd_offset // Packet Status Word
#define OHCI_ITD_PAGE_SELECT 0x00001000
#define OHCI_ITD_MK_OFFS(len) (0xe000 | ((len) & 0x1fff))
#define OHCI_ITD_PSW_LENGTH(x) ((x) & 0xfff) // Transfer length
#define OHCI_ITD_PSW_GET_CC(x) ((x) >> 12) // Condition Code
#define OHCI_ITD_ALIGN 32
// --------------------------------
// Completion Codes (section 4.3.3)
// --------------------------------
#define OHCI_CC_NO_ERROR 0
#define OHCI_CC_CRC 1
#define OHCI_CC_BIT_STUFFING 2
#define OHCI_CC_DATA_TOGGLE_MISMATCH 3
#define OHCI_CC_STALL 4
#define OHCI_CC_DEVICE_NOT_RESPONDING 5
#define OHCI_CC_PID_CHECK_FAILURE 6
#define OHCI_CC_UNEXPECTED_PID 7
#define OHCI_CC_DATA_OVERRUN 8
#define OHCI_CC_DATA_UNDERRUN 9
#define OHCI_CC_BUFFER_OVERRUN 12
#define OHCI_CC_BUFFER_UNDERRUN 13
#define OHCI_CC_NOT_ACCESSED 15
// --------------------------------
// Some delay needed when changing
// certain registers.
// --------------------------------
#define OHCI_ENABLE_POWER_DELAY 5
#define OHCI_READ_DESC_DELAY 5
#endif // OHCI_HARD_H

View File

@ -0,0 +1,104 @@
//------------------------------------------------------------------------------
// Copyright (c) 2005, Jan-Rixt Van Hoye
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//------------------------------------------------------------------------------
#include "ohci.h"
#include <PCI.h>
usb_device_descriptor ohci_devd =
{
0x12, //Descriptor size
USB_DESCRIPTOR_DEVICE , //Type of descriptor
0x110, //USB 1.1
0x09 , //Hub type
0 , //Subclass
0 , //Protocol
64 , //Max packet size
0 , //Vendor
0 , //Product
0x110 , //Version
1 , 2 , 0 , //Other data
1 //Number of configurations
};
usb_configuration_descriptor ohci_confd =
{
0x09, //Size
USB_DESCRIPTOR_CONFIGURATION ,
25 , //Total size (taken from BSD source)
1 , //Number interfaces
1 , //Value of configuration
0 , //Number of configuration
0x40 , //Self powered
0 //Max power (0, because of self power)
};
usb_interface_descriptor ohci_intd =
{
0x09 , //Size
USB_DESCRIPTOR_INTERFACE ,
0 , //Interface number
0 , //Alternate setting
1 , //Num endpoints
0x09 , //Interface class
0 , //Interface subclass
0 , //Interface protocol
0 , //Interface
};
usb_endpoint_descriptor ohci_endd =
{
0x07 , //Size
USB_DESCRIPTOR_ENDPOINT,
USB_REQTYPE_DEVICE_IN | 1, //1 from freebsd driver
0x3 , // Interrupt
8 , // Max packet size
0xFF // Interval 256
};
usb_hub_descriptor ohci_hubd =
{
0x09 , //Including deprecated powerctrlmask
USB_DESCRIPTOR_HUB,
1, //Number of ports
0x02 | 0x01 , //Hub characteristics FIXME
50 , //Power on to power good
0, // Current
0x00 //Both ports are removable
};
//Implementation
OHCIRootHub::OHCIRootHub( OHCI *ohci , int8 devicenum )
: Hub( ohci , NULL , ohci_devd , devicenum , false )
{
m_ohci = ohci;
}
status_t OHCIRootHub::SubmitTransfer( Transfer *t )
{
return B_OK;
}
void OHCIRootHub::UpdatePortStatus(void)
{
// nothing yet
}

View File

@ -0,0 +1,149 @@
//------------------------------------------------------------------------------
// Copyright (c) 2005, Jan-Rixt Van Hoye
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//-------------------------------------------------------------------------------
#ifndef OHCI_SOFT_H
#define OHCI_SOFT_H
// ---------------------------
// OHCI:: Includes
// ---------------------------
#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
// transfer descriptor
// ------------------------------------
typedef struct hcd_soft_transfer
{
hc_transfer_descriptor td;
struct hcd_soft_transfer *nexttd; // mirrors nexttd in TD
struct hcd_soft_trasfer *dnext; // next in done list
addr_t physaddr; // physical address to the host controller transfer
//LIST_ENTRY(hcd_soft_transfer) hnext;
uint16 len; // the lenght
uint16 flags; // flags
}hcd_soft_transfer;
#define OHCI_CALL_DONE 0x0001
#define OHCI_ADD_LEN 0x0002
#define OHCI_STD_SIZE ((sizeof (struct hcd_soft_transfer) + OHCI_TD_ALIGN - 1) / OHCI_TD_ALIGN * OHCI_TD_ALIGN)
#define OHCI_STD_CHUNK 128
// --------------------------------------
// OHCI:: Software isonchronous
// transfer descriptor
// --------------------------------------
typedef struct hcd_soft_itransfer
{
hc_itransfer_descriptor itd;
struct hcd_soft_itransfer *nextitd; // mirrors nexttd in ITD
struct hcd_soft_itransfer *dnext; // next in done list
addr_t physaddr; // physical address to the host controller isonchronous transfer
//LIST_ENTRY(hcd_soft_itransfer) hnext;
uint16 flags; // flags
#ifdef DIAGNOSTIC
char isdone; // is the transfer done?
#endif
}hcd_soft_itransfer;
#define OHCI_SITD_SIZE ((sizeof (struct hcd_soft_itransfer) + OHCI_ITD_ALIGN - 1) / OHCI_ITD_ALIGN * OHCI_ITD_ALIGN)
#define OHCI_SITD_CHUNK 64
// ------------------------------------------
// OHCI:: Number of enpoint descriptors (63)
// ------------------------------------------
#define OHCI_NO_EDS (2*OHCI_NO_INTRS-1)
// --------------------------
// OHCI:: Hash size for the
// --------------------------
#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

View File

@ -90,6 +90,7 @@ uhci_add_to( Stack &stack )
UHCI *bus = new UHCI( item , &stack );
if ( bus->InitCheck() != B_OK )
{
TRACE( "USB UHCI::InitCheck() failed, error %li\n" , bus->InitCheck() );
delete bus;
break;
}
@ -134,26 +135,41 @@ module_info *modules[] =
This is the implementation of the UHCI controller for the OpenBeOS USB stack
++++++++++ */
int32 uhci_interrupt_handler( void *data )
{
int32 retval;
spinlock slock = 0;
cpu_status status = disable_interrupts();
acquire_spinlock( &slock );
retval = ((UHCI*)data)->Interrupt();
release_spinlock( &slock );
restore_interrupts( status );
return retval;
}
UHCI::UHCI( pci_info *info , Stack *stack )
{
//Do nothing yet
dprintf( "UHCI: constructing new BusManager\n" );
m_pcii = info;
m_stack = stack;
m_reg_base = UHCI::pci_module->read_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, 0x20 , 4 ) ^ 1;
m_reg_base = UHCI::pci_module->read_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_memory_base , 4 ) & PCI_address_io_mask ;
TRACE( "USB UHCI: iospace offset: %lx\n" , m_reg_base );
m_rh_address = 255; //Invalidate the RH address
{
/* enable pci address access */
unsigned char cmd;
uint16 cmd;
cmd = UHCI::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;
UHCI::pci_module->write_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_command, 2, cmd );
/* make sure we gain controll of the UHCI controller instead of the BIOS */
// TRACE( "pcii->function %u", m_pcii->function );
// UHCI::pci_module->write_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN );
}
//Do a host reset
GlobalReset();
if ( Reset() == B_ERROR )
if ( Reset() != B_ERROR )
{
TRACE( "USB UHCI: init_hardare(): host failed to reset\n" );
m_initok = false;
@ -189,7 +205,7 @@ UHCI::UHCI( pci_info *info , Stack *stack )
void *phy;
//Must be aligned on 16-byte boundaries
if ( m_stack->AllocateChunk( (void **)&(m_qh_virtual[i]) ,
&phy , 16 ) != B_OK )
&phy , 32 ) != B_OK )
{
dprintf( "USB UHCI: init_hardware(): failed allocation of skeleton qh %i, aborting\n", i );
delete_area( m_framearea );
@ -199,10 +215,14 @@ UHCI::UHCI( pci_info *info , Stack *stack )
//chunk allocated
m_qh_virtual[i]->this_phy = reinterpret_cast<addr_t>(phy);
m_qh_virtual[i]->element_phy = QH_TERMINATE;
m_qh_virtual[i]->element_log = 0;
//Link this qh to its previous qh
if ( i != 0 )
{
m_qh_virtual[i-1]->link_phy = m_qh_virtual[i]->this_phy | QH_NEXT_IS_QH ;
m_qh_virtual[i-1]->link_log = m_qh_virtual[i];
}
}
// Make sure the qh_terminate terminates
m_qh_virtual[11]->link_phy = QH_TERMINATE;
@ -213,7 +233,7 @@ UHCI::UHCI( pci_info *info , Stack *stack )
// (or do I know how I should do that), instead, I just take the frame
// number and determine where it should begin
//NOTE, in c++ this is butt-ugly. We have a addr_t *array (because with
/* //NOTE, in c++ this is butt-ugly. We have a addr_t *array (because with
//an addr_t *array we can apply pointer arithmetic), uhci_qh *pointers
//that need to be put through the logical | to make sure the pointer is
//invalid for the hc. The result of that needs to be converted into a
@ -240,23 +260,64 @@ UHCI::UHCI( pci_info *info , Stack *stack )
else
m_framelist[i] = reinterpret_cast<addr_t*>( reinterpret_cast<addr_t>(m_qh_interrupt_1) | FRAMELIST_NEXT_IS_QH );
}
*/
for ( int i = 0 ; i < 1024 ; i++ )
m_framelist[i] = reinterpret_cast<addr_t*>( reinterpret_cast<addr_t>(m_qh_control) | FRAMELIST_NEXT_IS_QH );
//Set base pointer
UHCI::pci_module->write_io_32( m_reg_base + UHCI_FRBASEADD , (int32)(m_framelist_phy) );
UHCI::pci_module->write_io_16( m_reg_base + UHCI_FRNUM , 0 );
//Set up the root hub
m_rh_address = AllocateAddress();
m_rh = new UHCIRootHub( this , m_rh_address );
SetRootHub( m_rh );
//Install the interrupt handler
install_io_interrupt_handler( m_pcii->u.h0.interrupt_line , uhci_interrupt_handler , (void *)this , 0 );
UHCI::pci_module->write_io_16( m_reg_base + UHCI_USBINTR , UHCI_USBINTR_CRC | UHCI_USBINTR_RESUME | UHCI_USBINTR_IOC | UHCI_USBINTR_SHORT );
}
status_t UHCI::SubmitTransfer( Transfer &t )
status_t UHCI::Start()
{
//Start the host controller, then start the Busmanager
TRACE("USB UCHI::STart() usbcmd reg %u, usbsts reg %u\n" , UHCI::pci_module->read_io_16( m_reg_base + UHCI_USBCMD ) , UHCI::pci_module->read_io_16( m_reg_base + UHCI_USBSTS ) );
UHCI::pci_module->write_io_16( m_reg_base + UHCI_USBCMD , UHCI_USBCMD_RS );
bool running = false;
for ( int i = 0 ; i <= 10 ; i++ )
{
if ( ( UHCI::pci_module->read_io_16( m_reg_base + UHCI_USBSTS ) & UHCI_USBSTS_HCHALT ) == 0 )
snooze( 1 );
else
{
running = true;
break;
}
}
if (!running)
{
TRACE( "UHCI::Start() Controller won't start running\n" );
return B_ERROR;
}
TRACE( "UHCI::Start() Controller is started\n" );
return BusManager::Start();
}
status_t UHCI::SubmitTransfer( Transfer *t )
{
dprintf( "UHCI::SubmitPacket( Transfer &t ) called!!!\n" );
//Short circuit the root hub
if ( m_rh_address == t.GetPipe()->GetDeviceAddress() )
if ( m_rh_address == t->GetPipe()->GetDeviceAddress() )
return m_rh->SubmitTransfer( t );
if ( t->GetPipe()->GetType() == Pipe::Control )
return InsertControl( t );
return B_ERROR;
}
@ -276,4 +337,147 @@ status_t UHCI::Reset()
return B_OK;
}
int32 UHCI::Interrupt()
{
uint16 status = UHCI::pci_module->read_io_16( m_reg_base + UHCI_USBSTS );
TRACE( "USB UHCI::Interrupt()\n" );
//Check if we really had an interrupt
if ( !( status | UHCI_INTERRUPT_MASK ) )
return B_UNHANDLED_INTERRUPT;
//Get funky
if ( status | UHCI_USBSTS_USBINT )
{
//A transfer finished
TRACE( "USB UHCI::Interrupt() transfer finished! [party]\n" );
}
else if ( status | UHCI_USBSTS_ERRINT )
{
TRACE( "USB UHCI::Interrupt() transfer error! [cry]\n" );
}
return B_HANDLED_INTERRUPT;
}
status_t UHCI::InsertControl( Transfer *t )
{
TRACE("USB UCHI::InsertControl() frnum %u , usbsts reg %u\n" , UHCI::pci_module->read_io_16( m_reg_base + UHCI_FRNUM ), UHCI::pci_module->read_io_16( m_reg_base + UHCI_USBSTS ) );
//HACK: this one is to prevent rogue transfers from happening
if ( t->GetBuffer() != 0 )
return B_ERROR;
//Please note that any data structures must be aligned on a 16 byte boundary
//Also, due to the strange ways of C++' void* handling, this code is much messier
//than it actually should be. Forgive me. Or blame the compiler.
//First, set up a Queue Head for the transfer
uhci_qh *topqh;
void *topqh_phy;
if ( m_stack->AllocateChunk( (void **)&topqh , &topqh_phy , 32 ) < B_OK )
{
TRACE( "UHCI::InsertControl(): Failed to allocate a QH\n" );
return ENOMEM;
}
topqh->link_phy = QH_TERMINATE;
topqh->link_log = 0;
topqh->this_phy = (addr_t)topqh_phy;
//Allocate the transfer descriptor for the transfer
uhci_td *firsttd;
void *firsttd_phy;
if ( m_stack->AllocateChunk( (void**)&firsttd , &firsttd_phy , 32 ) < B_OK )
{
TRACE( "UHCI::InsertControl(): Failed to allocate the first TD\n" );
m_stack->FreeChunk( topqh , topqh_phy , 32 );
return ENOMEM;
}
firsttd->this_phy = (addr_t)firsttd_phy;
//Set the 'status' field of the td
if ( t->GetPipe()->GetSpeed() == Pipe::LowSpeed )
firsttd->status = TD_STATUS_LOWSPEED | TD_STATUS_ACTIVE;
else
firsttd->status = TD_STATUS_ACTIVE;
//Set the 'token' field of the td
firsttd->token = ( ( sizeof(usb_request_data) - 1 ) << 21 ) | ( t->GetPipe()->GetEndpointAddress() << 15 )
| ( t->GetPipe()->GetDeviceAddress() << 8 ) | ( 0x2D );
//Create a physical space for the setup request
if ( m_stack->AllocateChunk( &(firsttd->buffer_log) , &(firsttd->buffer_phy) , sizeof (usb_request_data) ) )
{
TRACE( "UHCI::InsertControl(): Unable to allocate space for the SETUP buffer\n" );
m_stack->FreeChunk( topqh , topqh_phy , 32 );
m_stack->FreeChunk( firsttd , firsttd_phy , 32 );
return ENOMEM;
}
memcpy( t->GetRequestData() , firsttd->buffer_log , sizeof(usb_request_data) );
//Link this thing in the queue head
topqh->element_phy = (addr_t)firsttd_phy;
topqh->element_log = firsttd;
//TODO: split the buffer into max transfer sizes
//Finally, create a status td
uhci_td *statustd;
void *statustd_phy;
if ( m_stack->AllocateChunk( (void **)&statustd , &statustd_phy , 32 ) < B_OK )
{
TRACE( "UHCI::InsertControl(): Failed to allocate the status TD\n" );
return ENOMEM;
}
//Set the 'status' field of the td to interrupt on complete
if ( t->GetPipe()->GetSpeed() == Pipe::LowSpeed )
statustd->status = TD_STATUS_LOWSPEED | TD_STATUS_IOC;
else
statustd->status = TD_STATUS_IOC;
//Set the 'token' field of the td (always DATA1) and a null buffer
statustd->token = TD_TOKEN_NULL | TD_TOKEN_DATA1 | ( t->GetPipe()->GetEndpointAddress() << 15 )
| ( t->GetPipe()->GetDeviceAddress() << 8 ) | 0x69 ;
//Invalidate the buffer field
statustd->buffer_phy = statustd->buffer_log = 0;
//Link into the previous transfer descriptor
firsttd->link_phy = (addr_t)statustd_phy | TD_DEPTH_FIRST;
firsttd->link_log = statustd;
//This is the end of this chain, so don't link to any next QH/TD
statustd->link_phy = QH_TERMINATE;
statustd->link_log = 0;
//First, add the transfer to the list of transfers
t->SetHostPrivate( new hostcontroller_priv );
t->GetHostPrivate()->topqh = topqh;
t->GetHostPrivate()->firsttd = firsttd;
t->GetHostPrivate()->lasttd = statustd;
m_transfers.PushBack( t );
//Secondly, append the qh to the control list
//a) if the control queue is empty, make this the first element
if ( ( m_qh_control->element_phy & QH_TERMINATE ) != 0 )
{
m_qh_control->element_phy = topqh->this_phy;
m_qh_control->link_log = (void *)topqh;
TRACE( "USB UHCI::InsertControl() First transfer in QUeue\n" );
}
//b) there are control transfers linked, append to the queue
else
{
uhci_qh *qh = (uhci_qh *)(m_qh_control->link_log);
while ( ( qh->link_phy & QH_TERMINATE ) == 0 )
{
TRACE( "USB UHCI::InsertControl() Looping\n" );
qh = (uhci_qh *)(qh->link_log);
}
qh->link_phy = topqh->this_phy;
qh->link_log = (void *)topqh;
TRACE( "USB UHCI::InsertControl() Appended transfers in queue\n" );
}
return EINPROGRESS;
}
pci_module_info *UHCI::pci_module = 0;

View File

@ -32,11 +32,13 @@ class UHCIRootHub;
class UHCI : public BusManager
{
friend class UHCIRootHub;
friend int32 uhci_interrupt_handler( void *data );
public:
UHCI( pci_info *info , Stack *stack );
//Override from BusManager
status_t SubmitTransfer( Transfer &t );
status_t Start();
status_t SubmitTransfer( Transfer *t );
// Global data for the module.
static pci_module_info *pci_module;
@ -44,6 +46,10 @@ private:
//Utility functions
void GlobalReset();
status_t Reset();
int32 Interrupt();
//Functions for the actual functioning of transfers
status_t InsertControl( Transfer *t );
uint32 m_reg_base; //Base address of the registers
pci_info *m_pcii; //pci-info struct
@ -69,6 +75,9 @@ private:
#define m_qh_bulk m_qh_virtual[10]
#define m_qh_terminate m_qh_virtual[11]
//Maintain a list of transfers
Vector<Transfer *> m_transfers;
//Root hub:
UHCIRootHub *m_rh; // the root hub
uint8 m_rh_address; // the address of the root hub
@ -78,13 +87,20 @@ class UHCIRootHub : public Hub
{
public:
UHCIRootHub( UHCI *uhci , int8 devicenum );
status_t SubmitTransfer( Transfer &t );
status_t SubmitTransfer( Transfer *t );
void UpdatePortStatus();
private:
usb_port_status m_hw_port_status[2]; // the port status (maximum of two)
UHCI *m_uhci; // needed because of internal data
};
struct hostcontroller_priv
{
uhci_qh *topqh;
uhci_td *firsttd;
uhci_td *lasttd;
};
#define UHCI_DEBUG
#ifdef UHCI_DEBUG
#define TRACE dprintf

View File

@ -12,5 +12,5 @@ resource app_version {
variety = 0,
internal = 0,
short_info = "UHCI host controller driver",
long_info = "OpenBeOS - This driver is (c) 2003-2004 Niels Sascha Reedijk"
long_info = "OpenBeOS - This driver is (c) 2003-2005 Niels Sascha Reedijk"
};

View File

@ -31,6 +31,9 @@
// R/WC -- Read/Write Clear
// ** -- Only writable with words!
// PCI register
#define PCI_LEGSUP 0xC0
#define PCI_LEGSUP_USBPIRQDEN 0x2000
// Registers
#define UHCI_USBCMD 0x0 // USB Command - word - R/W
@ -58,6 +61,7 @@
#define UHCI_USBSTS_HOSTERR 0x8 // Host System Error
#define UHCI_USBSTS_HCPRERR 0x10// Host Controller Process error
#define UHCI_USBSTS_HCHALT 0x20 // HCHalted
#define UHCI_INTERRUPT_MASK 0x1F //Mask for all the interrupts
//USBINTR
#define UHCI_USBINTR_CRC 0x1 // Timeout/ CRC interrupt enable
@ -96,12 +100,22 @@ typedef struct
addr_t link_phy; // Link to the next TD/QH
uint32 status; // Status field
uint32 token; // Contains the packet header (where it needs to be sent)
addr_t buffer_phy; // A pointer to the buffer with the actual packet
void * buffer_phy; // A pointer to the buffer with the actual packet
// Software part
addr_t this_phy; // A physical pointer to this address
void * link_log; // Link to the next logical TD/QT
void * buffer_log; // Link to the buffer
} uhci_td;
#define TD_STATUS_LOWSPEED ( 1 << 26 )
#define TD_STATUS_IOS ( 1 << 25 )
#define TD_STATUS_IOC ( 1 << 24 )
#define TD_STATUS_ACTIVE ( 1 << 23 )
#define TD_TOKEN_DATA1 ( 1 << 19 )
#define TD_TOKEN_NULL (0x7FF << 21 )
#define TD_DEPTH_FIRST 0x4
#define TD_TERMINATE 0x1
//Represents a Queue Head (QH)
typedef struct

View File

@ -92,13 +92,13 @@ UHCIRootHub::UHCIRootHub( UHCI *uhci , int8 devicenum )
m_uhci = uhci;
}
status_t UHCIRootHub::SubmitTransfer( Transfer &t )
status_t UHCIRootHub::SubmitTransfer( Transfer *t )
{
status_t retval;
usb_request_data *request = t.GetRequestData();
usb_request_data *request = t->GetRequestData();
uint16 port; //used in RH_CLEAR/SET_FEATURE
TRACE( "USB UHCI: rh_submit_packet called. Request: %u\n" , t.GetRequestData()->Request );
TRACE( "USB UHCI: rh_submit_packet called. Request: %u\n" , t->GetRequestData()->Request );
switch( request->Request )
{
@ -106,7 +106,7 @@ status_t UHCIRootHub::SubmitTransfer( Transfer &t )
if ( request->Index == 0 )
{
//Get the hub status -- everything as 0 means that it is all-rigth
memset( t.GetBuffer() , NULL , sizeof(get_status_buffer) );
memset( t->GetBuffer() , NULL , sizeof(get_status_buffer) );
retval = B_OK;
break;
}
@ -118,8 +118,8 @@ status_t UHCIRootHub::SubmitTransfer( Transfer &t )
}
//Get port status
UpdatePortStatus();
memcpy( t.GetBuffer() , (void *)&(m_hw_port_status[request->Index - 1]) , t.GetBufferLength());
*(t.GetActualLength()) = t.GetBufferLength();
memcpy( t->GetBuffer() , (void *)&(m_hw_port_status[request->Index - 1]) , t->GetBufferLength());
*(t->GetActualLength()) = t->GetBufferLength();
retval = B_OK;
break;
@ -139,28 +139,28 @@ status_t UHCIRootHub::SubmitTransfer( Transfer &t )
switch ( request->Value )
{
case RH_DEVICE_DESCRIPTOR:
memcpy( t.GetBuffer() , (void *)&uhci_devd , t.GetBufferLength());
*(t.GetActualLength()) = t.GetBufferLength();
memcpy( t->GetBuffer() , (void *)&uhci_devd , t->GetBufferLength());
*(t->GetActualLength()) = t->GetBufferLength();
retval = B_OK;
break;
case RH_CONFIG_DESCRIPTOR:
memcpy( t.GetBuffer() , (void *)&uhci_confd , t.GetBufferLength());
*(t.GetActualLength()) = t.GetBufferLength();
memcpy( t->GetBuffer() , (void *)&uhci_confd , t->GetBufferLength());
*(t->GetActualLength()) = t->GetBufferLength();
retval = B_OK;
break;
case RH_INTERFACE_DESCRIPTOR:
memcpy( t.GetBuffer() , (void *)&uhci_intd , t.GetBufferLength());
*(t.GetActualLength()) = t.GetBufferLength();
memcpy( t->GetBuffer() , (void *)&uhci_intd , t->GetBufferLength());
*(t->GetActualLength()) = t->GetBufferLength();
retval = B_OK ;
break;
case RH_ENDPOINT_DESCRIPTOR:
memcpy( t.GetBuffer() , (void *)&uhci_endd , t.GetBufferLength());
*(t.GetActualLength()) = t.GetBufferLength();
memcpy( t->GetBuffer() , (void *)&uhci_endd , t->GetBufferLength());
*(t->GetActualLength()) = t->GetBufferLength();
retval = B_OK ;
break;
case RH_HUB_DESCRIPTOR:
memcpy( t.GetBuffer() , (void *)&uhci_hubd , t.GetBufferLength());
*(t.GetActualLength()) = t.GetBufferLength();
memcpy( t->GetBuffer() , (void *)&uhci_hubd , t->GetBufferLength());
*(t->GetActualLength()) = t->GetBufferLength();
retval = B_OK;
break;
default:
@ -209,7 +209,7 @@ status_t UHCIRootHub::SubmitTransfer( Transfer &t )
default:
retval = EINVAL;
break;
} //switch( t.value)
} //switch( t->value)
break;
default:
@ -217,6 +217,10 @@ status_t UHCIRootHub::SubmitTransfer( Transfer &t )
break;
}
// Clean up the transfer - we own it, so we clean it up
t->Finish();
delete t;
return retval;
}
@ -254,7 +258,7 @@ void UHCIRootHub::UpdatePortStatus(void)
newstatus |= PORT_POWER;
if ( portsc & UHCI_PORTSC_LOWSPEED )
newstatus |= PORT_LOW_SPEED;
newstatus |= PORT_STATUS_LOW_SPEED;
//Update the stored port status
m_hw_port_status[i].status = newstatus;