From 5a072ced7588fd5525ca52d9ce1d45a2d0786b2d Mon Sep 17 00:00:00 2001 From: Niels Sascha Reedijk Date: Mon, 14 Mar 2005 21:02:03 +0000 Subject: [PATCH] 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 --- src/add-ons/kernel/busses/usb/Jamfile | 7 + src/add-ons/kernel/busses/usb/ehci.c | 156 ------- src/add-ons/kernel/busses/usb/ohci.cpp | 404 +++++++++++++++++ src/add-ons/kernel/busses/usb/ohci.h | 111 +++++ src/add-ons/kernel/busses/usb/ohci.rdef | 16 + src/add-ons/kernel/busses/usb/ohci_hardware.h | 406 ++++++++++++++++++ src/add-ons/kernel/busses/usb/ohci_rh.cpp | 104 +++++ src/add-ons/kernel/busses/usb/ohci_software.h | 149 +++++++ src/add-ons/kernel/busses/usb/uhci.cpp | 218 +++++++++- src/add-ons/kernel/busses/usb/uhci.h | 20 +- src/add-ons/kernel/busses/usb/uhci.rdef | 2 +- src/add-ons/kernel/busses/usb/uhci_hardware.h | 16 +- src/add-ons/kernel/busses/usb/uhci_rh.cpp | 40 +- 13 files changed, 1464 insertions(+), 185 deletions(-) delete mode 100644 src/add-ons/kernel/busses/usb/ehci.c create mode 100644 src/add-ons/kernel/busses/usb/ohci.cpp create mode 100644 src/add-ons/kernel/busses/usb/ohci.h create mode 100644 src/add-ons/kernel/busses/usb/ohci.rdef create mode 100644 src/add-ons/kernel/busses/usb/ohci_hardware.h create mode 100644 src/add-ons/kernel/busses/usb/ohci_rh.cpp create mode 100644 src/add-ons/kernel/busses/usb/ohci_software.h diff --git a/src/add-ons/kernel/busses/usb/Jamfile b/src/add-ons/kernel/busses/usb/Jamfile index 10f430db38..2e9a0e7f79 100644 --- a/src/add-ons/kernel/busses/usb/Jamfile +++ b/src/add-ons/kernel/busses/usb/Jamfile @@ -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 ; diff --git a/src/add-ons/kernel/busses/usb/ehci.c b/src/add-ons/kernel/busses/usb/ehci.c deleted file mode 100644 index 83a4ea0f4d..0000000000 --- a/src/add-ons/kernel/busses/usb/ehci.c +++ /dev/null @@ -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 -#include - -#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; -} diff --git a/src/add-ons/kernel/busses/usb/ohci.cpp b/src/add-ons/kernel/busses/usb/ohci.cpp new file mode 100644 index 0000000000..48ead84e2f --- /dev/null +++ b/src/add-ons/kernel/busses/usb/ohci.cpp @@ -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 +#include +#include +#include +#include + +// --------------------------- +// OHCI:: Local includes +// --------------------------- + +#include "ohci.h" +#include "ohci_hardware.h" +#include +//------------------------------------------------------ +// 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(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(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; diff --git a/src/add-ons/kernel/busses/usb/ohci.h b/src/add-ons/kernel/busses/usb/ohci.h new file mode 100644 index 0000000000..2e6f331a4c --- /dev/null +++ b/src/add-ons/kernel/busses/usb/ohci.h @@ -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 +#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 diff --git a/src/add-ons/kernel/busses/usb/ohci.rdef b/src/add-ons/kernel/busses/usb/ohci.rdef new file mode 100644 index 0000000000..648d34a3b2 --- /dev/null +++ b/src/add-ons/kernel/busses/usb/ohci.rdef @@ -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" +}; diff --git a/src/add-ons/kernel/busses/usb/ohci_hardware.h b/src/add-ons/kernel/busses/usb/ohci_hardware.h new file mode 100644 index 0000000000..4e65a66f3b --- /dev/null +++ b/src/add-ons/kernel/busses/usb/ohci_hardware.h @@ -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 diff --git a/src/add-ons/kernel/busses/usb/ohci_rh.cpp b/src/add-ons/kernel/busses/usb/ohci_rh.cpp new file mode 100644 index 0000000000..8346f06f35 --- /dev/null +++ b/src/add-ons/kernel/busses/usb/ohci_rh.cpp @@ -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 + +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 +} diff --git a/src/add-ons/kernel/busses/usb/ohci_software.h b/src/add-ons/kernel/busses/usb/ohci_software.h new file mode 100644 index 0000000000..a16f7a4e83 --- /dev/null +++ b/src/add-ons/kernel/busses/usb/ohci_software.h @@ -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 +#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 diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index 2dd1ac32f4..d1b9b2af55 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -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(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( reinterpret_cast(m_qh_interrupt_1) | FRAMELIST_NEXT_IS_QH ); } +*/ + + for ( int i = 0 ; i < 1024 ; i++ ) + m_framelist[i] = reinterpret_cast( reinterpret_cast(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; diff --git a/src/add-ons/kernel/busses/usb/uhci.h b/src/add-ons/kernel/busses/usb/uhci.h index 54dfdc7d1d..f5cfbad280 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -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 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 diff --git a/src/add-ons/kernel/busses/usb/uhci.rdef b/src/add-ons/kernel/busses/usb/uhci.rdef index 4323d5c447..2d8131da47 100644 --- a/src/add-ons/kernel/busses/usb/uhci.rdef +++ b/src/add-ons/kernel/busses/usb/uhci.rdef @@ -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" }; diff --git a/src/add-ons/kernel/busses/usb/uhci_hardware.h b/src/add-ons/kernel/busses/usb/uhci_hardware.h index dede716828..67418c2cbb 100644 --- a/src/add-ons/kernel/busses/usb/uhci_hardware.h +++ b/src/add-ons/kernel/busses/usb/uhci_hardware.h @@ -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 diff --git a/src/add-ons/kernel/busses/usb/uhci_rh.cpp b/src/add-ons/kernel/busses/usb/uhci_rh.cpp index cb02ba086b..dc992348bb 100644 --- a/src/add-ons/kernel/busses/usb/uhci_rh.cpp +++ b/src/add-ons/kernel/busses/usb/uhci_rh.cpp @@ -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;