* [email protected]/usb-busses--development--0.1--patch-1
Fix things up before big changes * [email protected]/usb-busses--development--0.1--patch-2 Continued development on device initialisation * [email protected]/usb-busses--development--0.1--patch-3 Finished Driver initialisation git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5831 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -4,6 +4,3 @@ R5KernelAddon uhci : [ FDirName kernel busses usb ] :
|
||||
uhci.c
|
||||
;
|
||||
|
||||
R5KernelAddon ehci : [ FDirName kernel busses usb ] :
|
||||
ehci.c
|
||||
;
|
||||
@@ -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
|
||||
@@ -21,8 +21,12 @@
|
||||
|
||||
#include <module.h>
|
||||
#include <PCI.h>
|
||||
#include <USB.h>
|
||||
#include <KernelExport.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user