diff --git a/src/add-ons/kernel/busses/usb/Jamfile b/src/add-ons/kernel/busses/usb/Jamfile index 9078b859a2..e5c3967836 100644 --- a/src/add-ons/kernel/busses/usb/Jamfile +++ b/src/add-ons/kernel/busses/usb/Jamfile @@ -1,5 +1,7 @@ SubDir OBOS_TOP src add-ons kernel busses usb ; +AddResources uhci : uhci.rdef ; + R5KernelAddon uhci : [ FDirName kernel busses usb ] : uhci.c ; diff --git a/src/add-ons/kernel/busses/usb/host_controller.h b/src/add-ons/kernel/busses/usb/host_controller.h index b609737599..fe600fdbc3 100644 --- a/src/add-ons/kernel/busses/usb/host_controller.h +++ b/src/add-ons/kernel/busses/usb/host_controller.h @@ -1,6 +1,55 @@ #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 ++++++++++ */ diff --git a/src/add-ons/kernel/busses/usb/uhci.c b/src/add-ons/kernel/busses/usb/uhci.c index e247b853db..c441ae7796 100644 --- a/src/add-ons/kernel/busses/usb/uhci.c +++ b/src/add-ons/kernel/busses/usb/uhci.c @@ -40,6 +40,8 @@ void silent( const char * , ... ) {} 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 ); +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 @@ -92,6 +94,7 @@ typedef struct uhci_properties //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; @@ -189,12 +192,23 @@ init_hardware(void) 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 = map_physical_memory( "uhci framelist" , m_data->framelist_phy , + /*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 + */ + + // 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; @@ -271,20 +285,53 @@ usb_endpoint_descriptor uhci_endd = USB_REQTYPE_DEVICE_IN | 1, //1 from freebsd driver 0x3 , // Interrupt 8 , // Max packet size - 0xFF // Interval + 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_packet_t *packet ) +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" ); + 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( packet->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( packet->buffer , (void *)&(m_data->port_status[request->Index - 1]) , packet->bufferlength ); + *(packet->actual_length) = packet->bufferlength; + retval = B_OK; + break; + case RH_SET_ADDRESS: if ( request->Value >= 128 ) { @@ -295,6 +342,7 @@ status_t rh_submit_packet( usb_packet_t *packet ) 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 ); @@ -310,7 +358,19 @@ status_t rh_submit_packet( usb_packet_t *packet ) *(packet->actual_length) = packet->bufferlength; retval = B_OK; break; - case RH_SET_CONFIG: + case RH_INTERFACE_DESCRIPTOR: + memcpy( packet->buffer , (void *)&uhci_intd , packet->bufferlength ); + *(packet->actual_length) = packet->bufferlength; + retval = B_OK ; + break; + case RH_ENDPOINT_DESCRIPTOR: + memcpy( packet->buffer , (void *)&uhci_endd , packet->bufferlength ); + *(packet->actual_length) = packet->bufferlength; + retval = B_OK ; + break; + case RH_HUB_DESCRIPTOR: + memcpy( packet->buffer , (void *)&uhci_hubd , packet->bufferlength ); + *(packet->actual_length) = packet->bufferlength; retval = B_OK; break; default: @@ -319,6 +379,44 @@ status_t rh_submit_packet( usb_packet_t *packet ) } 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 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( packet->value) + break; + default: retval = EINVAL; break; @@ -327,4 +425,45 @@ status_t rh_submit_packet( usb_packet_t *packet ) 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 status: 0x%x\n" , 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; + } +} \ No newline at end of file diff --git a/src/add-ons/kernel/busses/usb/uhci.h b/src/add-ons/kernel/busses/usb/uhci.h index b3b2e7f18a..6aa1bcdea6 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -66,9 +66,18 @@ #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_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 * @@ -95,12 +104,25 @@ struct uhci_qh /************************************************************ * Roothub Emulation * ************************************************************/ -#define RH_GET_DESCRIPTOR 6 +#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