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:
parent
89bdde9df1
commit
5a072ced75
@ -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 ;
|
||||
|
@ -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;
|
||||
}
|
404
src/add-ons/kernel/busses/usb/ohci.cpp
Normal file
404
src/add-ons/kernel/busses/usb/ohci.cpp
Normal 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;
|
111
src/add-ons/kernel/busses/usb/ohci.h
Normal file
111
src/add-ons/kernel/busses/usb/ohci.h
Normal 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
|
16
src/add-ons/kernel/busses/usb/ohci.rdef
Normal file
16
src/add-ons/kernel/busses/usb/ohci.rdef
Normal 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"
|
||||
};
|
406
src/add-ons/kernel/busses/usb/ohci_hardware.h
Normal file
406
src/add-ons/kernel/busses/usb/ohci_hardware.h
Normal 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
|
104
src/add-ons/kernel/busses/usb/ohci_rh.cpp
Normal file
104
src/add-ons/kernel/busses/usb/ohci_rh.cpp
Normal 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
|
||||
}
|
149
src/add-ons/kernel/busses/usb/ohci_software.h
Normal file
149
src/add-ons/kernel/busses/usb/ohci_software.h
Normal 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
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user