diff --git a/src/add-ons/kernel/busses/usb/Jamfile b/src/add-ons/kernel/busses/usb/Jamfile index e732580e26..9078b859a2 100644 --- a/src/add-ons/kernel/busses/usb/Jamfile +++ b/src/add-ons/kernel/busses/usb/Jamfile @@ -4,6 +4,3 @@ R5KernelAddon uhci : [ FDirName kernel busses usb ] : uhci.c ; -R5KernelAddon ehci : [ FDirName kernel busses usb ] : - ehci.c - ; \ No newline at end of file diff --git a/src/add-ons/kernel/busses/usb/host_controller.h b/src/add-ons/kernel/busses/usb/host_controller.h new file mode 100644 index 0000000000..b609737599 --- /dev/null +++ b/src/add-ons/kernel/busses/usb/host_controller.h @@ -0,0 +1,36 @@ +#ifndef HOST_CONTROLLER_INFO_H +#define HOST_CONTROLLER_INFO_H + +/* ++++++++++ +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 internal organs of an usb packet +typedef struct usb_packet_t +{ + uint16 pipe; + uint8 *requestdata; + uint8 *buffer; + int16 bufferlength; + size_t *actual_length; + int16 address; //!!!! TEMPORARY ... or is it? +} usb_packet_t; + +typedef struct host_controller_info +{ + module_info info; + status_t (*hwstart)(void); + status_t (*SubmitPacket)(usb_packet_t *); +} host_controller_info; + +#endif //HOST_CONTROLLER_INFO_H \ No newline at end of file diff --git a/src/add-ons/kernel/busses/usb/uhci.c b/src/add-ons/kernel/busses/usb/uhci.c index 9010de1e9b..e247b853db 100644 --- a/src/add-ons/kernel/busses/usb/uhci.c +++ b/src/add-ons/kernel/busses/usb/uhci.c @@ -21,8 +21,12 @@ #include #include +#include +#include +#include #include "uhci.h" +#include "host_controller.h" #define UHCI_DEBUG #ifdef UHCI_DEBUG @@ -33,8 +37,9 @@ void silent( const char * , ... ) {} #endif -static status_t init_hardware(); - +static status_t init_hardware(void); +static status_t submit_packet( usb_packet_t *packet ); +static status_t rh_submit_packet( usb_packet_t *packet ); /* ++++++++++ This is the implementation of the UHCI controller for the OpenBeOS USB stack @@ -56,15 +61,20 @@ uhci_std_ops( int32 op , ... ) return B_OK; } -struct module_info uhci_module = { - "busses/usb/uhci/nielx", - NULL, // No flag like B_KEEP_LOADED : the usb module does that - uhci_std_ops +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 +module_info *modules[] = +{ + (module_info *) &uhci_module, + NULL }; /* ++++++++++ @@ -74,6 +84,14 @@ 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 } uhci_properties_t; static pci_module_info *m_pcimodule = 0; @@ -81,23 +99,32 @@ static pci_info *m_device = 0; static uhci_properties_t*m_data = 0; /* ++++++++++ -Register/Bit constants +Utility functions ++++++++++ */ -enum { - USBCMD = 0x0 //Command register (2byte) -}; +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 ); +} -enum USBCMD_commands { - RS = 0x1 , //Run=1 Stop=0 - HCRESET = 0x2 //Host controller reset -}; +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() +init_hardware(void) { status_t status; pci_info *item; @@ -106,10 +133,12 @@ init_hardware() // 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( "uhci_nielx init_hardware(): Get PCI module failed! %lu \n", status); + 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++ ) @@ -120,10 +149,10 @@ init_hardware() { if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF)) { - TRACE( "uhci_nielx init_hardware(): found with invalid IRQ - check IRQ assignement\n"); + TRACE( "USB UHCI: init_hardware(): found with invalid IRQ - check IRQ assignement\n"); continue; } - TRACE("uhci_nielx init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line); + TRACE("USB UHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line); m_device = item; break; } @@ -131,7 +160,8 @@ init_hardware() if ( m_device == 0 ) { - TRACE( "uhci_nielx init hardware(): no devices found\n" ); + TRACE( "USB UHCI: init hardware(): no devices found\n" ); + free( item ); put_module( B_PCI_MODULE_NAME ); return ENODEV; } @@ -140,7 +170,7 @@ init_hardware() m_data = (uhci_properties_t *)malloc( sizeof( uhci_properties_t ) ); m_data->pcii = m_device; m_data->reg_base = m_device->u.h0.base_registers[0]; - + m_data->rh_address = 255; //Invalidate the RH address { /* enable pci address access */ unsigned char cmd; @@ -150,8 +180,151 @@ init_hardware() } //Do a host reset -// m_pcimodule->write_io_16( m_data->reg_base + UHCI_USBCMD , UHCI_USBCMD_HCRESET ); -// spin(50); + 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; + } + //Set up the frame list + m_data->framearea = map_physical_memory( "uhci framelist" , m_data->framelist_phy , + 4096 , B_ANY_KERNEL_BLOCK_ADDRESS , + B_WRITE_AREA , m_data->framelist ); + + //!!!!!!!!!!!!!! Check the area + + //This is enough for now, the most time consuming hardware tasks have been done now return B_OK; } + +/* ++++++++++ +Inserting packets in the queue +++++++++++ */ +status_t submit_packet( usb_packet_t *packet ) +{ + 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 ( packet->address == 0 ) //First device of a bus has address 0 per definition + { + rh_submit_packet( packet ); + goto out; + } + //4. Determine the type of transfer and send it to the proper function + //5. Release the spinlock +out: +} + +/* ++++++++++ +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 +}; + + + +status_t rh_submit_packet( usb_packet_t *packet ) +{ + usb_request_data *request = (usb_request_data *)packet->requestdata; + status_t retval; + + TRACE( "USB UHCI: rh_submit_packet called\n" ); + + switch( request->Request ) + { + 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( packet->buffer , (void *)&uhci_devd , packet->bufferlength ); + *(packet->actual_length) = packet->bufferlength; + retval = B_OK; + break; + case RH_CONFIG_DESCRIPTOR: + memcpy( packet->buffer , (void *)&uhci_confd , packet->bufferlength ); + *(packet->actual_length) = packet->bufferlength; + retval = B_OK; + break; + case RH_SET_CONFIG: + retval = B_OK; + break; + default: + retval = EINVAL; + break; + } + break; + } + default: + retval = EINVAL; + break; + } + + return retval; +} + + diff --git a/src/add-ons/kernel/busses/usb/uhci.h b/src/add-ons/kernel/busses/usb/uhci.h index 0019e8d8ea..b3b2e7f18a 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -22,6 +22,11 @@ #ifndef UHCI_H #define UHCI_H +/************************************************************ + * The Registers * + ************************************************************/ + + // R/W -- Read/Write // R/WC -- Read/Write Clear // ** -- Only writable with words! @@ -65,4 +70,37 @@ #define UHCI_PORTSC_STATCHA 0x2 // Current connect status change #define UHCI_PORTSC_ENABLED 0x4 // Port enabled/disabled +/************************************************************ + * Hardware structs * + ************************************************************/ + +//Represents a Transfer Descriptor (TD) + +struct uhci_td +{ + 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 +}; + +//Represents a Queue Head (QH) + +struct uhci_qh +{ + void * link; //Link to the next TD/QH + void * element; //Link to the first element pointer in the queue +}; + +/************************************************************ + * Roothub Emulation * + ************************************************************/ +#define RH_GET_DESCRIPTOR 6 +#define RH_SET_ADDRESS 5 +#define RH_SET_CONFIG 9 + +//Descriptors (in usb_request_data->Value) +#define RH_DEVICE_DESCRIPTOR ( 1 << 8 ) +#define RH_CONFIG_DESCRIPTOR ( 2 << 8 ) + #endif