diff --git a/src/add-ons/kernel/busses/usb/Jamfile b/src/add-ons/kernel/busses/usb/Jamfile index 25996a45b9..4ee80db655 100644 --- a/src/add-ons/kernel/busses/usb/Jamfile +++ b/src/add-ons/kernel/busses/usb/Jamfile @@ -2,8 +2,12 @@ SubDir OBOS_TOP src add-ons kernel busses usb ; AddResources uhci : uhci.rdef ; +UsePrivateHeaders [ FDirName kernel ] ; +UseHeaders [ FDirName $(OBOS_TOP) src add-ons kernel bus_managers usb ] ; + R5KernelAddon uhci : [ FDirName kernel busses usb ] : - uhci.c - util.c + uhci.cpp + uhci_rh.cpp ; +LinkSharedOSLibs uhci : libusb.a ; diff --git a/src/add-ons/kernel/busses/usb/ehci.c b/src/add-ons/kernel/busses/usb/ehci.c index ab0cfd3261..83a4ea0f4d 100644 --- a/src/add-ons/kernel/busses/usb/ehci.c +++ b/src/add-ons/kernel/busses/usb/ehci.c @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// Copyright (c) 2003, Niels S. Reedijk +// 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"), diff --git a/src/add-ons/kernel/busses/usb/host_controller.h b/src/add-ons/kernel/busses/usb/host_controller.h deleted file mode 100644 index 677c929232..0000000000 --- a/src/add-ons/kernel/busses/usb/host_controller.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef HOST_CONTROLLER_INFO_H -#define HOST_CONTROLLER_INFO_H - -/* +++++++++ -USB Spec definitions (not interesting for the outside world -+++++++++ */ -typedef struct -{ - uint8 bDescLength; - uint8 bDescriptorType; - uint8 bNbrPorts; - uint16 wHubCharacteristics; - uint8 bPwrOn2PwrGood; - uint8 bHucContrCurrent; - uint8 DeviceRemovable; //Should be variable!!! - uint8 PortPwrCtrlMask; //Deprecated -} usb_hub_descriptor; - -#define USB_DESCRIPTOR_HUB 0x29 - -// USB Spec 1.1 page 273 -typedef struct -{ - uint16 status; - uint16 change; -} usb_port_status; - -//The bits in the usb_port_status struct -// USB 1.1 spec page 274 -#define PORT_STATUS_CONNECTION 0x1 -#define PORT_STATUS_ENABLE 0x2 -#define PORT_STATUS_SUSPEND 0x4 -#define PORT_STATUS_OVER_CURRENT 0x8 -#define PORT_STATUS_RESET 0x10 -#define PORT_STATUS_POWER 0x100 -#define PORT_STATUS_LOW_SPEED 0x200 - -//The feature requests with ports -// USB 1.1 spec page 268 -#define PORT_CONNECTION 0 -#define PORT_ENABLE 1 -#define PORT_SUSPEND 2 -#define PORT_OVER_CURRENT 3 -#define PORT_RESET 4 -#define PORT_POWER 8 -#define PORT_LOW_SPEED 9 -#define C_PORT_CONNECTION 16 -#define C_PORT_ENABLE 17 -#define C_PORT_SUSPEND 18 -#define C_PORT_OVER_CURRENT 19 -#define C_PORT_RESET 20 - -/* ++++++++++ -Internally used types -++++++++++ */ - -//This embodies a request that can be send -typedef struct -{ - uint8 RequestType; - uint8 Request; - uint16 Value; - uint16 Index; - uint16 Length; -} usb_request_data; - -// Describes the internals of a pipe -enum Direction { In , Out , Default }; -enum Speed { LowSpeed , NormalSpeed }; - -typedef struct usb_pipe_t -{ - enum Direction direction; - enum Speed speed; - int8 deviceid; - uint8 endpoint; -} usb_pipe_t; - - -// Describes the internal organs of an usb packet -typedef struct usb_transfer_t -{ - //Data that is related to the transfer - usb_pipe_t *pipe; - uint8 *buffer; - size_t bufferlength; - size_t *actual_length; - bigtime_t timeout; - status_t status; - - //For control transfers - usb_request_data *request; -} usb_transfer_t; - -// -// -typedef struct host_controller_info -{ - module_info info; - status_t (*hwstart)(void); - status_t (*SubmitPacket)(usb_transfer_t *); -} host_controller_info; - -#endif //HOST_CONTROLLER_INFO_H diff --git a/src/add-ons/kernel/busses/usb/uhci.c b/src/add-ons/kernel/busses/usb/uhci.c deleted file mode 100644 index 93e949ed31..0000000000 --- a/src/add-ons/kernel/busses/usb/uhci.c +++ /dev/null @@ -1,487 +0,0 @@ -//------------------------------------------------------------------------------ -// Copyright (c) 2003, 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 -#include -#include -#include - -#include "uhci.h" -#include "util.h" -#include "host_controller.h" - -#define UHCI_DEBUG -#ifdef UHCI_DEBUG -#define TRACE dprintf -#else -#define TRACE silent -void silent( const char * , ... ) {} -#endif - - -static status_t init_hardware(void); -static status_t submit_packet( usb_transfer_t *transfer ); -static status_t rh_submit_packet( usb_transfer_t *transfer ); -static void rh_update_port_status(void); -//static int32 uhci_interrupt( void *d ); - -/* ++++++++++ -This is the implementation of the UHCI controller for the OpenBeOS USB stack -++++++++++ */ -static int32 -uhci_std_ops( int32 op , ... ) -{ - switch (op) - { - case B_MODULE_INIT: - TRACE( "uhci_module: init the module\n" ); - return init_hardware(); - case B_MODULE_UNINIT: - TRACE( "uhci_module: uninit the module\n" ); - break; - default: - return EINVAL; - } - return B_OK; -} - -host_controller_info uhci_module = { - { - "busses/usb/uhci/nielx", - NULL, // No flag like B_KEEP_LOADED : the usb module does that - uhci_std_ops - }, - NULL , - submit_packet -}; - -module_info *modules[] = -{ - (module_info *) &uhci_module, - NULL -}; - -/* ++++++++++ -Internal variables -++++++++++ */ -typedef struct uhci_properties -{ - uint32 reg_base; //Base address of the registers - pci_info *pcii; //pci-info struct - - //Frame list memory - area_id framearea; - void *framelist[1024]; //The frame list struct - void *framelist_phy; //The physical pointer to the frame list - - //Root hub: - uint8 rh_address; // the address of the root hub - usb_port_status port_status[2]; // the port status (maximum of two) -} uhci_properties_t; - -static pci_module_info *m_pcimodule = 0; -static pci_info *m_device = 0; -static uhci_properties_t*m_data = 0; - -/* ++++++++++ -Utility functions -++++++++++ */ - -static void -uhci_globalreset( uhci_properties_t *data ) -{ - m_pcimodule->write_io_16( data->reg_base + UHCI_USBCMD , UHCI_USBCMD_GRESET ); - spin( 100 ); - m_pcimodule->write_io_16( data->reg_base + UHCI_USBCMD , 0 ); -} - -static status_t -uhci_reset( uhci_properties_t *data ) -{ - m_pcimodule->write_io_16( data->reg_base + UHCI_USBCMD , UHCI_USBCMD_HCRESET ); - spin( 100 ); - if ( m_pcimodule->read_io_16( data->reg_base + UHCI_USBCMD ) & UHCI_USBCMD_HCRESET ) - return B_ERROR; - return B_OK; -} - -/* ++++++++++ -The hardware management functions -++++++++++ */ -static status_t -init_hardware(void) -{ - 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( "USB_ UHCI: init_hardware(): Get PCI module failed! %lu \n", status); - return status; - } - - TRACE( "usb_uhci init_hardware(): Setting up hardware\n" ); - - // 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: 00 (UHCI) - if ( ( item->class_base == 0x0C ) && ( item->class_sub == 0x03 ) && - ( item->class_api == 0x00 ) ) - { - if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF)) - { - TRACE( "USB UHCI: init_hardware(): found with invalid IRQ - check IRQ assignement\n"); - continue; - } - TRACE("USB UHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line); - m_device = item; - break; - } - } - - if ( m_device == 0 ) - { - TRACE( "USB UHCI: init hardware(): no devices found\n" ); - free( item ); - put_module( B_PCI_MODULE_NAME ); - return ENODEV; - } - - //Initialise the host controller - m_data = (uhci_properties_t *)malloc( sizeof( uhci_properties_t ) ); - m_data->pcii = m_device; - m_data->reg_base = m_pcimodule->read_pci_config(m_data->pcii->bus, m_data->pcii->device, m_data->pcii->function, 0x20 , 4 ) ^ 1; - TRACE( "USB UHCI: iospace offset: %lx\n" , m_data->reg_base ); - m_data->rh_address = 255; //Invalidate the RH address - { - /* 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 - uhci_globalreset( m_data ); - if ( uhci_reset( m_data ) == B_ERROR ) - { - TRACE( "USB UHCI: init_hardare(): host failed to reset\n" ); - free( item ); - put_module( B_PCI_MODULE_NAME ); - return ENODEV; - } - - // Poll the status of the two ports - rh_update_port_status(); - TRACE( "USB UHCI: init_hardware(): port1: %x port2: %x\n", - m_data->port_status[0].status , m_data->port_status[1].status ); - - //Set up the frame list - m_data->framearea = alloc_mem( &(m_data->framelist[0]) , &(m_data->framelist_phy) , - 4096 , "uhci framelist" ); - if ( m_data->framearea < B_OK ) - { - TRACE( "USB UHCI: init_hardware(): unable to create an area for the frame pointer list\n" ); - free( item ); - put_module( B_PCI_MODULE_NAME ); - return ENODEV; - } - - //Make all frame list entries invalid - for( i = 0 ; i < 1024 ; i++ ) - (int32)(m_data->framelist[i]) = 0x1; - - //Set base pointer - m_pcimodule->write_io_32( m_data->reg_base + UHCI_FRBASEADD , (int32)(m_data->framelist_phy) ); - - // Install the interrupt handler - //install_io_interrupt_handler( m_data->pcii->h0.interrupt_line , - // uhci_interrupt , m_data , NULL ); - //m_pcimodule->write_io_16( m_data->reg_base + USBINTR , - - //This is enough for now, the most time consuming hardware tasks have been done now - return B_OK; -} - -/* ++++++++++ -Inserting transfers in the queue -++++++++++ */ -status_t submit_packet( usb_transfer_t *transfer ) -{ - dprintf( "uhci submit_packet(): CALLED\n"); - //Do the following: - //1. Check if the packet really belongs to this bus -- no way of doing that now - //2. Acquire the spinlock of the packet -- still needs to be fixed - - if ( transfer->pipe->deviceid == 1 ) //First device of a bus has address 1 per definition - { - rh_submit_packet( transfer ); - goto out; - } - //4. Determine the type of transfer and send it to the proper function - //5. Release the spinlock -out: - return B_OK; -} - -/* ++++++++++ -Root hub emulation -++++++++++ */ -usb_device_descriptor uhci_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 uhci_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 uhci_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 uhci_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 uhci_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 -}; - -status_t -rh_submit_packet( usb_transfer_t *transfer ) -{ - usb_request_data *request = transfer->request; - status_t retval; - - uint16 port; //used in RH_CLEAR/SET_FEATURE - - TRACE( "USB UHCI: rh_submit_packet called. Request: %u\n" , request->Request ); - - switch( request->Request ) - { - case RH_GET_STATUS: - if ( request->Index == 0 ) - { - //Get the hub status -- everything as 0 means that it is all-rigth - memset( transfer->buffer , NULL , sizeof(get_status_buffer) ); - retval = B_OK; - break; - } - else if (request->Index > uhci_hubd.bNbrPorts ) - { - //This port doesn't exist - retval = EINVAL; - break; - } - //Get port status - rh_update_port_status(); - memcpy( transfer->buffer , (void *)&(m_data->port_status[request->Index - 1]) , transfer->bufferlength ); - *(transfer->actual_length) = transfer->bufferlength; - retval = B_OK; - break; - - case RH_SET_ADDRESS: - if ( request->Value >= 128 ) - { - retval = EINVAL; - break; - } - TRACE( "USB UHCI: rh_submit_packet RH_ADDRESS: %d\n" , request->Value ); - m_data->rh_address = request->Value; - retval = B_OK; - break; - - case RH_GET_DESCRIPTOR: - { - TRACE( "USB UHCI: rh_submit_packet GET_DESC: %d\n" , request->Value ); - switch ( request->Value ) - { - case RH_DEVICE_DESCRIPTOR: - memcpy( transfer->buffer , (void *)&uhci_devd , transfer->bufferlength ); - *(transfer->actual_length) = transfer->bufferlength; - retval = B_OK; - break; - case RH_CONFIG_DESCRIPTOR: - memcpy( transfer->buffer , (void *)&uhci_confd , transfer->bufferlength ); - *(transfer->actual_length) = transfer->bufferlength; - retval = B_OK; - break; - case RH_INTERFACE_DESCRIPTOR: - memcpy( transfer->buffer , (void *)&uhci_intd , transfer->bufferlength ); - *(transfer->actual_length) = transfer->bufferlength; - retval = B_OK ; - break; - case RH_ENDPOINT_DESCRIPTOR: - memcpy( transfer->buffer , (void *)&uhci_endd , transfer->bufferlength ); - *(transfer->actual_length) = transfer->bufferlength; - retval = B_OK ; - break; - case RH_HUB_DESCRIPTOR: - memcpy( transfer->buffer , (void *)&uhci_hubd , transfer->bufferlength ); - *(transfer->actual_length) = transfer->bufferlength; - retval = B_OK; - break; - default: - retval = EINVAL; - break; - } - break; - } - - case RH_SET_CONFIG: - retval = B_OK; - break; - - case RH_CLEAR_FEATURE: - if ( request->Index == 0 ) - { - //We don't support any hub changes - TRACE( "UHCI: RH_CLEAR_FEATURE no hub changes!\n" ); - retval = EINVAL; - break; - } - else if ( request->Index > uhci_hubd.bNbrPorts ) - { - //Invalid port number - TRACE( "UHCI: RH_CLEAR_FEATURE invalid port!\n" ); - retval = EINVAL; - break; - } - - TRACE("UHCI: RH_CLEAR_FEATURE called. Feature: %u!\n" , request->Value ); - switch( request->Value ) - { - case PORT_RESET: - port = m_pcimodule->read_io_16( m_data->reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 ); - port &= ~UHCI_PORTSC_RESET; - TRACE( "UHCI rh: port %x Clear RESET\n" , port ); - m_pcimodule->write_io_16( m_data->reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 , port ); - case C_PORT_CONNECTION: - port = m_pcimodule->read_io_16( m_data->reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 ); - port = port & UHCI_PORTSC_DATAMASK; - port |= UHCI_PORTSC_STATCHA; - TRACE( "UHCI rh: port: %x\n" , port ); - m_pcimodule->write_io_16( m_data->reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 , port ); - retval = B_OK; - break; - default: - retval = EINVAL; - break; - } //switch( transfer->value) - break; - - default: - retval = EINVAL; - break; - } - - return retval; -} - -void -rh_update_port_status(void) -{ - int i; - for ( i = 0; i <= 1 ; i++ ) - { - uint16 newstatus = 0; - uint16 newchange = 0; - - uint16 portsc = m_pcimodule->read_io_16( m_data->reg_base + UHCI_PORTSC1 + i * 2 ); - dprintf( "USB UHCI: port: %x status: 0x%x\n" , UHCI_PORTSC1 + i * 2 , portsc ); - //Set all individual bits - if ( portsc & UHCI_PORTSC_CURSTAT ) - newstatus |= PORT_STATUS_CONNECTION; - - if ( portsc & UHCI_PORTSC_STATCHA ) - newchange |= PORT_STATUS_CONNECTION; - - if ( portsc & UHCI_PORTSC_ENABLED ) - newstatus |= PORT_STATUS_ENABLE; - - if ( portsc & UHCI_PORTSC_ENABCHA ) - newchange |= PORT_STATUS_ENABLE; - - // TODO: work out suspended/resume - - if ( portsc & UHCI_PORTSC_RESET ) - newstatus |= PORT_STATUS_RESET; - - //TODO: work out reset change... - - //The port is automagically powered on - newstatus |= PORT_POWER; - - if ( portsc & UHCI_PORTSC_LOWSPEED ) - newstatus |= PORT_LOW_SPEED; - - //Update the stored port status - m_data->port_status[i].status = newstatus; - m_data->port_status[i].change = newchange; - } -} diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp new file mode 100644 index 0000000000..2dd1ac32f4 --- /dev/null +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -0,0 +1,279 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 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 +#include +#include +#include + +#include "uhci.h" +#include "uhci_hardware.h" +#include + + +/* ++++++++++ +This is the implementation of the UHCI controller for the OpenBeOS USB stack +++++++++++ */ + +static int32 +uhci_std_ops( int32 op , ... ) +{ + switch (op) + { + case B_MODULE_INIT: + TRACE( "uhci_module: init the module\n" ); + return B_OK; + case B_MODULE_UNINIT: + TRACE( "uhci_module: uninit the module\n" ); + break; + default: + return EINVAL; + } + return B_OK; +} + +static bool +uhci_add_to( Stack &stack ) +{ + status_t status; + pci_info *item; + bool found = false; + int i; + + #ifdef UHCI_DEBUG + set_dprintf_enabled( true ); + load_driver_symbols( "uhci" ); + #endif + + // 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 **)&( UHCI::pci_module ) ) ) != B_OK) + { + TRACE( "USB_ UHCI: init_hardware(): Get PCI module failed! %lu \n", status); + return status; + } + + TRACE( "usb_uhci 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 ; UHCI::pci_module->get_nth_pci_info( i , item ) == B_OK ; i++ ) + { + //class_base = 0C (serial bus) class_sub = 03 (usb) prog_int: 00 (UHCI) + if ( ( item->class_base == 0x0C ) && ( item->class_sub == 0x03 ) && + ( item->class_api == 0x00 ) ) + { + if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF)) + { + TRACE( "USB UHCI: init_hardware(): found with invalid IRQ - check IRQ assignement\n"); + continue; + } + TRACE("USB UHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line); + UHCI *bus = new UHCI( item , &stack ); + if ( bus->InitCheck() != B_OK ) + { + delete bus; + break; + } + + stack.AddBusManager( bus ); + bus->Start(); + found = true; + break; + } + } + + if ( found == false ) + { + TRACE( "USB UHCI: init hardware(): no devices found\n" ); + free( item ); + put_module( B_PCI_MODULE_NAME ); + return ENODEV; + } + return B_OK; //Hardware found +} + + + + +host_controller_info uhci_module = { + { + "busses/usb/uhci/nielx", + NULL, // No flag like B_KEEP_LOADED : the usb module does that + uhci_std_ops + }, + NULL , + uhci_add_to +}; + +module_info *modules[] = +{ + (module_info *) &uhci_module, + NULL +}; + +/* ++++++++++ +This is the implementation of the UHCI controller for the OpenBeOS USB stack +++++++++++ */ + +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; + 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; + 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 ); + } + + //Do a host reset + GlobalReset(); + if ( Reset() == B_ERROR ) + { + TRACE( "USB UHCI: init_hardare(): host failed to reset\n" ); + m_initok = false; + return; + } + + // Poll the status of the two ports +// rh_update_port_status(); +// TRACE( "USB UHCI: init_hardware(): port1: %x port2: %x\n", +// m_data->port_status[0].status , m_data->port_status[1].status ); + + //Set up the frame list + void *phy; + m_framearea = stack->AllocateArea( (void **)&(m_framelist[0]) , &(phy) , + 4096 , "uhci framelist" ); + m_framelist_phy = reinterpret_cast(phy); + if ( m_framearea < B_OK ) + { + TRACE( "USB UHCI: init_hardware(): unable to create an area for the frame pointer list\n" ); + m_initok = false; + return; + } + + /* + Set up the virtual structure. I stole this idea from the linux usb stack, + the idea is that for every interrupt interval there is a queue head. These + things all link together and eventually point to the control and bulk + virtual queue heads. + */ + + for( int i = 0 ; i < 12 ; i++ ) + { + void *phy; + //Must be aligned on 16-byte boundaries + if ( m_stack->AllocateChunk( (void **)&(m_qh_virtual[i]) , + &phy , 16 ) != B_OK ) + { + dprintf( "USB UHCI: init_hardware(): failed allocation of skeleton qh %i, aborting\n", i ); + delete_area( m_framearea ); + m_initok = false; + return; + } + //chunk allocated + m_qh_virtual[i]->this_phy = reinterpret_cast(phy); + m_qh_virtual[i]->element_phy = QH_TERMINATE; + + //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 ; + } + // Make sure the qh_terminate terminates + m_qh_virtual[11]->link_phy = QH_TERMINATE; + + //Insert the queues in the frame list. The linux developers mentioned + // in a comment that they used some magic to distribute the elements all + // over the place, but I don't really think that it is useful right now + // (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 + //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 + //addr_t. Get it? + for( int i = 0 ; i < 1024 ; i++ ) + { + int frame = i+1; + if ( ( frame % 256 ) == 0 ) + m_framelist[i] = reinterpret_cast( reinterpret_cast(m_qh_interrupt_256) | FRAMELIST_NEXT_IS_QH ); + else if ( ( frame % 128 ) == 0 ) + m_framelist[i] = reinterpret_cast( reinterpret_cast(m_qh_interrupt_128) | FRAMELIST_NEXT_IS_QH ); + else if ( ( frame % 64 ) == 0 ) + m_framelist[i] = reinterpret_cast( reinterpret_cast(m_qh_interrupt_64) | FRAMELIST_NEXT_IS_QH ); + else if ( ( frame % 32 ) == 0 ) + m_framelist[i] = reinterpret_cast( reinterpret_cast(m_qh_interrupt_32) | FRAMELIST_NEXT_IS_QH ); + else if ( ( frame % 16 ) == 0 ) + m_framelist[i] = reinterpret_cast( reinterpret_cast(m_qh_interrupt_16) | FRAMELIST_NEXT_IS_QH ); + else if ( ( frame % 8 ) == 0 ) + m_framelist[i] = reinterpret_cast( reinterpret_cast(m_qh_interrupt_8) | FRAMELIST_NEXT_IS_QH ); + else if ( ( frame % 4 ) == 0 ) + m_framelist[i] = reinterpret_cast( reinterpret_cast(m_qh_interrupt_4) | FRAMELIST_NEXT_IS_QH ); + else if ( ( frame % 2 ) == 0 ) + m_framelist[i] = reinterpret_cast( reinterpret_cast(m_qh_interrupt_2) | FRAMELIST_NEXT_IS_QH ); + else + m_framelist[i] = reinterpret_cast( reinterpret_cast(m_qh_interrupt_1) | FRAMELIST_NEXT_IS_QH ); + } + + //Set base pointer + UHCI::pci_module->write_io_32( m_reg_base + UHCI_FRBASEADD , (int32)(m_framelist_phy) ); + + //Set up the root hub + m_rh_address = AllocateAddress(); + m_rh = new UHCIRootHub( this , m_rh_address ); + SetRootHub( m_rh ); +} + +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() ) + return m_rh->SubmitTransfer( t ); + return B_ERROR; +} + +void UHCI::GlobalReset() +{ + UHCI::pci_module->write_io_16( m_reg_base + UHCI_USBCMD , UHCI_USBCMD_GRESET ); + spin( 100 ); + UHCI::pci_module->write_io_16( m_reg_base + UHCI_USBCMD , 0 ); +} + +status_t UHCI::Reset() +{ + UHCI::pci_module->write_io_16( m_reg_base + UHCI_USBCMD , UHCI_USBCMD_HCRESET ); + spin( 100 ); + if ( UHCI::pci_module->read_io_16( m_reg_base + UHCI_USBCMD ) & UHCI_USBCMD_HCRESET ) + return B_ERROR; + return B_OK; +} + +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 6aa1bcdea6..54dfdc7d1d 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// Copyright (c) 2003, Niels S. Reedijk +// Copyright (c) 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"), @@ -22,107 +22,75 @@ #ifndef UHCI_H #define UHCI_H -/************************************************************ - * The Registers * - ************************************************************/ +#include +#include "uhci_hardware.h" +struct pci_info; +struct pci_module_info; +class UHCIRootHub; -// R/W -- Read/Write -// R/WC -- Read/Write Clear -// ** -- Only writable with words! - - -// Registers -#define UHCI_USBCMD 0x0 // USB Command - word - R/W -#define UHCI_USBSTS 0x2 // USB Status - word - R/WC -#define UHCI_USBINTR 0x4 // USB Interrupt Enable - word - R/W -#define UHCI_FRNUM 0x6 // Frame number - word - R/W** -#define UHCI_FRBASEADD 0x08 // Frame List BAse Address - dword - R/W -#define UHCI_SOFMOD 0xC // Start of Frame Modify - byte - R/W -#define UHCI_PORTSC1 0x10 // Port 1 Status/Control - word - R/WC** -#define UHCI_PORTSC2 0x12 // Port 2 Status/Control - word - R/WC** - -// USBCMD -#define UHCI_USBCMD_RS 0x1 // Run/Stop -#define UHCI_USBCMD_HCRESET 0x2 // Host Controller Reset -#define UHCI_USBCMD_GRESET 0x4 // Global Reset -#define UHCI_USBCMD_EGSM 0x8 // Enter Global Suspensd mode -#define UHCI_USBCMD_FGR 0x10 // Force Global resume -#define UHCI_USBCMD_SWDBG 0x20 // Software Debug -#define UHCI_USBCMD_CF 0x40 // Configure Flag - -//USBSTS -#define UHCI_USBSTS_USBINT 0x1 // USB interrupt -#define UHCI_USBSTS_ERRINT 0x2 // USB error interrupt -#define UHCI_USBSTS_RESDET 0x4 // Resume Detect -#define UHCI_USBSTS_HOSTERR 0x8 // Host System Error -#define UHCI_USBSTS_HCPRERR 0x10// Host Controller Process error -#define UHCI_USBSTS_HCHALT 0x20 // HCHalted - -//USBINTR -#define UHCI_USBINTR_CRC 0x1 // Timeout/ CRC interrupt enable -#define UHCI_USBINTR_RESUME 0x2 // Resume interrupt enable -#define UHCI_USBINTR_IOC 0x4 // Interrupt on complete enable -#define UHCI_USBINTR_SHORT 0x8 // Short packet interrupt enable - -//PORTSC -#define UHCI_PORTSC_CURSTAT 0x1 // Current connect status -#define UHCI_PORTSC_STATCHA 0x2 // Current connect status change -#define UHCI_PORTSC_ENABLED 0x4 // Port enabled/disabled -#define UHCI_PORTSC_ENABCHA 0x8 // Change in enabled/disabled -#define UHCI_PORTSC_LINE_0 0x10 // The status of D+ /D- -#define UHCI_PORTSC_LINE_1 0x20 -#define UHCI_PORTSC_RESUME 0x40 // Something with the suspend state ??? -#define UHCI_PORTSC_LOWSPEED 0x100// Low speed device attached? -#define UHCI_PORTSC_RESET 0x200// Port is in reset -#define UHCI_PORTSC_SUSPEND 0x1000//Set port in suspend state - -#define UHCI_PORTSC_DATAMASK 0x13F5 //Mask that excludes the change bits of portsc - -/************************************************************ - * Hardware structs * - ************************************************************/ - -//Represents a Transfer Descriptor (TD) - -struct uhci_td +class UHCI : public BusManager { - void * link; // Link to the next TD/QH - uint32 status; // Status field - uint32 token; // Contains the packet header (where it needs to be sent) - void * buffer; // A pointer to the buffer with the actual packet + friend class UHCIRootHub; +public: + UHCI( pci_info *info , Stack *stack ); + + //Override from BusManager + status_t SubmitTransfer( Transfer &t ); + + // Global data for the module. + static pci_module_info *pci_module; +private: + //Utility functions + void GlobalReset(); + status_t Reset(); + + uint32 m_reg_base; //Base address of the registers + pci_info *m_pcii; //pci-info struct + Stack *m_stack; //Pointer to the stack + + //Frame list memory + area_id m_framearea; + addr_t *m_framelist[1024]; //The frame list struct + addr_t m_framelist_phy; //The physical pointer to the frame list + + // Virtual frame + uhci_qh *m_qh_virtual[12]; // +#define m_qh_interrupt_256 m_qh_virtual[0] +#define m_qh_interrupt_128 m_qh_virtual[1] +#define m_qh_interrupt_64 m_qh_virtual[2] +#define m_qh_interrupt_32 m_qh_virtual[3] +#define m_qh_interrupt_16 m_qh_virtual[4] +#define m_qh_interrupt_8 m_qh_virtual[5] +#define m_qh_interrupt_4 m_qh_virtual[6] +#define m_qh_interrupt_2 m_qh_virtual[7] +#define m_qh_interrupt_1 m_qh_virtual[8] +#define m_qh_control m_qh_virtual[9] +#define m_qh_bulk m_qh_virtual[10] +#define m_qh_terminate m_qh_virtual[11] + + //Root hub: + UHCIRootHub *m_rh; // the root hub + uint8 m_rh_address; // the address of the root hub }; -//Represents a Queue Head (QH) - -struct uhci_qh +class UHCIRootHub : public Hub { - void * link; //Link to the next TD/QH - void * element; //Link to the first element pointer in the queue +public: + UHCIRootHub( UHCI *uhci , int8 devicenum ); + 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 }; -/************************************************************ - * Roothub Emulation * - ************************************************************/ -#define RH_GET_STATUS 0 -#define RH_CLEAR_FEATURE 1 -#define RH_SET_FEATURE 3 -#define RH_SET_ADDRESS 5 -#define RH_GET_DESCRIPTOR 6 -#define RH_SET_CONFIG 9 - -//Descriptors (in usb_request_data->Value) -#define RH_DEVICE_DESCRIPTOR ( 1 << 8 ) -#define RH_CONFIG_DESCRIPTOR ( 2 << 8 ) -#define RH_INTERFACE_DESCRIPTOR ( 4 << 8 ) -#define RH_ENDPOINT_DESCRIPTOR ( 5 << 8 ) -#define RH_HUB_DESCRIPTOR ( 0x29 << 8 ) - -//Hub/Portstatus buffer -typedef struct -{ - uint16 status; - uint16 change; -} get_status_buffer; +#define UHCI_DEBUG +#ifdef UHCI_DEBUG +#define TRACE dprintf +#else +#define TRACE silent +void silent( const char * , ... ) {} +#endif #endif diff --git a/src/add-ons/kernel/busses/usb/uhci_hardware.h b/src/add-ons/kernel/busses/usb/uhci_hardware.h new file mode 100644 index 0000000000..dede716828 --- /dev/null +++ b/src/add-ons/kernel/busses/usb/uhci_hardware.h @@ -0,0 +1,145 @@ +//------------------------------------------------------------------------------ +// 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. + +#ifndef UHCI_HARDWARE_H +#define UHCI_HARDWARE_H + +/************************************************************ + * The Registers * + ************************************************************/ + + +// R/W -- Read/Write +// R/WC -- Read/Write Clear +// ** -- Only writable with words! + + +// Registers +#define UHCI_USBCMD 0x0 // USB Command - word - R/W +#define UHCI_USBSTS 0x2 // USB Status - word - R/WC +#define UHCI_USBINTR 0x4 // USB Interrupt Enable - word - R/W +#define UHCI_FRNUM 0x6 // Frame number - word - R/W** +#define UHCI_FRBASEADD 0x08 // Frame List BAse Address - dword - R/W +#define UHCI_SOFMOD 0xC // Start of Frame Modify - byte - R/W +#define UHCI_PORTSC1 0x10 // Port 1 Status/Control - word - R/WC** +#define UHCI_PORTSC2 0x12 // Port 2 Status/Control - word - R/WC** + +// USBCMD +#define UHCI_USBCMD_RS 0x1 // Run/Stop +#define UHCI_USBCMD_HCRESET 0x2 // Host Controller Reset +#define UHCI_USBCMD_GRESET 0x4 // Global Reset +#define UHCI_USBCMD_EGSM 0x8 // Enter Global Suspensd mode +#define UHCI_USBCMD_FGR 0x10 // Force Global resume +#define UHCI_USBCMD_SWDBG 0x20 // Software Debug +#define UHCI_USBCMD_CF 0x40 // Configure Flag + +//USBSTS +#define UHCI_USBSTS_USBINT 0x1 // USB interrupt +#define UHCI_USBSTS_ERRINT 0x2 // USB error interrupt +#define UHCI_USBSTS_RESDET 0x4 // Resume Detect +#define UHCI_USBSTS_HOSTERR 0x8 // Host System Error +#define UHCI_USBSTS_HCPRERR 0x10// Host Controller Process error +#define UHCI_USBSTS_HCHALT 0x20 // HCHalted + +//USBINTR +#define UHCI_USBINTR_CRC 0x1 // Timeout/ CRC interrupt enable +#define UHCI_USBINTR_RESUME 0x2 // Resume interrupt enable +#define UHCI_USBINTR_IOC 0x4 // Interrupt on complete enable +#define UHCI_USBINTR_SHORT 0x8 // Short packet interrupt enable + +//PORTSC +#define UHCI_PORTSC_CURSTAT 0x1 // Current connect status +#define UHCI_PORTSC_STATCHA 0x2 // Current connect status change +#define UHCI_PORTSC_ENABLED 0x4 // Port enabled/disabled +#define UHCI_PORTSC_ENABCHA 0x8 // Change in enabled/disabled +#define UHCI_PORTSC_LINE_0 0x10 // The status of D+ /D- +#define UHCI_PORTSC_LINE_1 0x20 +#define UHCI_PORTSC_RESUME 0x40 // Something with the suspend state ??? +#define UHCI_PORTSC_LOWSPEED 0x100// Low speed device attached? +#define UHCI_PORTSC_RESET 0x200// Port is in reset +#define UHCI_PORTSC_SUSPEND 0x1000//Set port in suspend state + +#define UHCI_PORTSC_DATAMASK 0x13F5 //Mask that excludes the change bits of portsc + +/************************************************************ + * Hardware structs * + ************************************************************/ + +//A framelist thingie +#define FRAMELIST_TERMINATE 0x1 +#define FRAMELIST_NEXT_IS_QH 0x2 + + +//Represents a Transfer Descriptor (TD) + +typedef struct +{ + //Hardware part + 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 + // Software part + void * link_log; // Link to the next logical TD/QT + void * buffer_log; // Link to the buffer +} uhci_td; + +//Represents a Queue Head (QH) + +typedef struct +{ + // Hardware part + addr_t link_phy; //Link to the next TD/QH + addr_t element_phy; //Link to the first element pointer in the queue + // Software part + addr_t this_phy; //The physical pointer to this address + void * link_log; //Link to the next TD/QH logical + void * element_log; // +} uhci_qh; + +#define QH_TERMINATE 0x1 +#define QH_NEXT_IS_QH 0x2 + +/************************************************************ + * Roothub Emulation * + ************************************************************/ +#define RH_GET_STATUS 0 +#define RH_CLEAR_FEATURE 1 +#define RH_SET_FEATURE 3 +#define RH_SET_ADDRESS 5 +#define RH_GET_DESCRIPTOR 6 +#define RH_SET_CONFIG 9 + +//Descriptors (in usb_request_data->Value) +#define RH_DEVICE_DESCRIPTOR ( 1 << 8 ) +#define RH_CONFIG_DESCRIPTOR ( 2 << 8 ) +#define RH_INTERFACE_DESCRIPTOR ( 4 << 8 ) +#define RH_ENDPOINT_DESCRIPTOR ( 5 << 8 ) +#define RH_HUB_DESCRIPTOR ( 0x29 << 8 ) + +//Hub/Portstatus buffer +typedef struct +{ + uint16 status; + uint16 change; +} get_status_buffer; + +#endif diff --git a/src/add-ons/kernel/busses/usb/uhci_rh.cpp b/src/add-ons/kernel/busses/usb/uhci_rh.cpp new file mode 100644 index 0000000000..cb02ba086b --- /dev/null +++ b/src/add-ons/kernel/busses/usb/uhci_rh.cpp @@ -0,0 +1,263 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 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 "uhci.h" +#include + +usb_device_descriptor uhci_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 uhci_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 uhci_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 uhci_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 uhci_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 +UHCIRootHub::UHCIRootHub( UHCI *uhci , int8 devicenum ) + : Hub( uhci , NULL , uhci_devd , devicenum , false ) +{ + m_uhci = uhci; +} + +status_t UHCIRootHub::SubmitTransfer( Transfer &t ) +{ + status_t retval; + 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 ); + + switch( request->Request ) + { + case RH_GET_STATUS: + 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) ); + retval = B_OK; + break; + } + else if (request->Index > uhci_hubd.bNbrPorts ) + { + //This port doesn't exist + retval = EINVAL; + break; + } + //Get port status + UpdatePortStatus(); + memcpy( t.GetBuffer() , (void *)&(m_hw_port_status[request->Index - 1]) , t.GetBufferLength()); + *(t.GetActualLength()) = t.GetBufferLength(); + retval = B_OK; + break; + + case RH_SET_ADDRESS: + if ( request->Value >= 128 ) + { + retval = EINVAL; + break; + } + TRACE( "USB UHCI: rh_submit_packet RH_ADDRESS: %d\n" , request->Value ); + retval = B_OK; + break; + + case RH_GET_DESCRIPTOR: + { + TRACE( "USB UHCI: rh_submit_packet GET_DESC: %d\n" , request->Value ); + switch ( request->Value ) + { + case RH_DEVICE_DESCRIPTOR: + 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(); + retval = B_OK; + break; + case RH_INTERFACE_DESCRIPTOR: + 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(); + retval = B_OK ; + break; + case RH_HUB_DESCRIPTOR: + memcpy( t.GetBuffer() , (void *)&uhci_hubd , t.GetBufferLength()); + *(t.GetActualLength()) = t.GetBufferLength(); + retval = B_OK; + break; + default: + retval = EINVAL; + break; + } + break; + } + + case RH_SET_CONFIG: + retval = B_OK; + break; + + case RH_CLEAR_FEATURE: + if ( request->Index == 0 ) + { + //We don't support any hub changes + TRACE( "UHCI: RH_CLEAR_FEATURE no hub changes!\n" ); + retval = EINVAL; + break; + } + else if ( request->Index > uhci_hubd.bNbrPorts ) + { + //Invalid port number + TRACE( "UHCI: RH_CLEAR_FEATURE invalid port!\n" ); + retval = EINVAL; + break; + } + + TRACE("UHCI: RH_CLEAR_FEATURE called. Feature: %u!\n" , request->Value ); + switch( request->Value ) + { + case PORT_RESET: + port = UHCI::pci_module->read_io_16( m_uhci->m_reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 ); + port &= ~UHCI_PORTSC_RESET; + TRACE( "UHCI rh: port %x Clear RESET\n" , port ); + UHCI::pci_module->write_io_16( m_uhci->m_reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 , port ); + case C_PORT_CONNECTION: + port = UHCI::pci_module->read_io_16( m_uhci->m_reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 ); + port = port & UHCI_PORTSC_DATAMASK; + port |= UHCI_PORTSC_STATCHA; + TRACE( "UHCI rh: port: %x\n" , port ); + UHCI::pci_module->write_io_16( m_uhci->m_reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 , port ); + retval = B_OK; + break; + default: + retval = EINVAL; + break; + } //switch( t.value) + break; + + default: + retval = EINVAL; + break; + } + + return retval; +} + +void UHCIRootHub::UpdatePortStatus(void) +{ + int i; + for ( i = 0; i <= 1 ; i++ ) + { + uint16 newstatus = 0; + uint16 newchange = 0; + + uint16 portsc = UHCI::pci_module->read_io_16( m_uhci->m_reg_base + UHCI_PORTSC1 + i * 2 ); + dprintf( "USB UHCI: port: %x status: 0x%x\n" , UHCI_PORTSC1 + i * 2 , portsc ); + //Set all individual bits + if ( portsc & UHCI_PORTSC_CURSTAT ) + newstatus |= PORT_STATUS_CONNECTION; + + if ( portsc & UHCI_PORTSC_STATCHA ) + newchange |= PORT_STATUS_CONNECTION; + + if ( portsc & UHCI_PORTSC_ENABLED ) + newstatus |= PORT_STATUS_ENABLE; + + if ( portsc & UHCI_PORTSC_ENABCHA ) + newchange |= PORT_STATUS_ENABLE; + + // TODO: work out suspended/resume + + if ( portsc & UHCI_PORTSC_RESET ) + newstatus |= PORT_STATUS_RESET; + + //TODO: work out reset change... + + //The port is automagically powered on + newstatus |= PORT_POWER; + + if ( portsc & UHCI_PORTSC_LOWSPEED ) + newstatus |= PORT_LOW_SPEED; + + //Update the stored port status + m_hw_port_status[i].status = newstatus; + m_hw_port_status[i].change = newchange; + } +} diff --git a/src/add-ons/kernel/busses/usb/util.c b/src/add-ons/kernel/busses/usb/util.c deleted file mode 100644 index 4c8de3d577..0000000000 --- a/src/add-ons/kernel/busses/usb/util.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * BeOS Driver for Intel ICH AC'97 Link interface - * - * Copyright (c) 2002, Marcus Overhagen - * - * All rights reserved. - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -#include -#include -#include - -//#define DEBUG 2 - -//#include "debug.h" -#include "util.h" - -spinlock slock = 0; - -uint32 round_to_pagesize(uint32 size); - -cpu_status lock(void) -{ - cpu_status status = disable_interrupts(); - acquire_spinlock(&slock); - return status; -} - -void unlock(cpu_status status) -{ - release_spinlock(&slock); - restore_interrupts(status); -} - -uint32 round_to_pagesize(uint32 size) -{ - return (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); -} - -area_id alloc_mem(void **log, void **phy, size_t size, const char *name) -{ - physical_entry pe; - void * logadr; - area_id areaid; - status_t rv; - - dprintf("allocating %ld bytes for %s\n",size,name); - - size = round_to_pagesize(size); - areaid = create_area(name, &logadr, B_ANY_KERNEL_ADDRESS,size,B_FULL_LOCK | B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA); - if (areaid < B_OK) { - dprintf("couldn't allocate area %s\n",name); - return B_ERROR; - } - rv = get_memory_map(logadr,size,&pe,1); - if (rv < B_OK) { - delete_area(areaid); - dprintf("couldn't map %s\n",name); - return B_ERROR; - } - memset(logadr,0,size); - if (log) - *log = logadr; - if (phy) - *phy = pe.address; - dprintf("area = %ld, size = %ld, log = %#08lX, phy = %#08lX\n",areaid,size,(uint32)logadr,(uint32)(pe.address)); - return areaid; -} - -/* This is not the most advanced method to map physical memory for io access. - * Perhaps using B_ANY_KERNEL_ADDRESS instead of B_ANY_KERNEL_BLOCK_ADDRESS - * makes the whole offset calculation and relocation obsolete. But the code - * below does work, and I can't test if using B_ANY_KERNEL_ADDRESS also works. - */ -area_id map_mem(void **log, void *phy, size_t size, const char *name) -{ - uint32 offset; - void *phyadr; - void *mapadr; - area_id area; - - dprintf("mapping physical address %p with %#lx bytes for %s\n",phy,size,name); - - offset = (uint32)phy & (B_PAGE_SIZE - 1); - phyadr = (char *)phy - offset; - size = round_to_pagesize(size + offset); - area = map_physical_memory(name, phyadr, size, B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA, &mapadr); - *log = (char *)mapadr + offset; - - dprintf("physical = %p, logical = %p, offset = %#lx, phyadr = %p, mapadr = %p, size = %#lx, area = %#lx\n", - phy, *log, offset, phyadr, mapadr, size, area); - - return area; -} diff --git a/src/add-ons/kernel/busses/usb/util.h b/src/add-ons/kernel/busses/usb/util.h deleted file mode 100644 index 2bc87c062f..0000000000 --- a/src/add-ons/kernel/busses/usb/util.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * BeOS Driver for Intel ICH AC'97 Link interface - * - * Copyright (c) 2002, Marcus Overhagen - * - * All rights reserved. - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -#ifndef _UTIL_H_ -#define _UTIL_H_ - -#include - -area_id alloc_mem(void **log, void **phy, size_t size, const char *name); -area_id map_mem(void **log, void *phy, size_t size, const char *name); - -cpu_status lock(void); -void unlock(cpu_status status); - -extern spinlock slock; - -#endif