* [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
|
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 <module.h>
|
||||||
#include <PCI.h>
|
#include <PCI.h>
|
||||||
|
#include <USB.h>
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "uhci.h"
|
#include "uhci.h"
|
||||||
|
#include "host_controller.h"
|
||||||
|
|
||||||
#define UHCI_DEBUG
|
#define UHCI_DEBUG
|
||||||
#ifdef UHCI_DEBUG
|
#ifdef UHCI_DEBUG
|
||||||
@@ -33,8 +37,9 @@ void silent( const char * , ... ) {}
|
|||||||
#endif
|
#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
|
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct module_info uhci_module = {
|
host_controller_info uhci_module = {
|
||||||
"busses/usb/uhci/nielx",
|
{
|
||||||
NULL, // No flag like B_KEEP_LOADED : the usb module does that
|
"busses/usb/uhci/nielx",
|
||||||
uhci_std_ops
|
NULL, // No flag like B_KEEP_LOADED : the usb module does that
|
||||||
|
uhci_std_ops
|
||||||
|
},
|
||||||
|
NULL ,
|
||||||
|
submit_packet
|
||||||
};
|
};
|
||||||
|
|
||||||
module_info *modules[] = {
|
module_info *modules[] =
|
||||||
(module_info *)&uhci_module ,
|
{
|
||||||
NULL
|
(module_info *) &uhci_module,
|
||||||
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ++++++++++
|
/* ++++++++++
|
||||||
@@ -74,6 +84,14 @@ typedef struct uhci_properties
|
|||||||
{
|
{
|
||||||
uint32 reg_base; //Base address of the registers
|
uint32 reg_base; //Base address of the registers
|
||||||
pci_info *pcii; //pci-info struct
|
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;
|
} uhci_properties_t;
|
||||||
|
|
||||||
static pci_module_info *m_pcimodule = 0;
|
static pci_module_info *m_pcimodule = 0;
|
||||||
@@ -81,23 +99,32 @@ static pci_info *m_device = 0;
|
|||||||
static uhci_properties_t*m_data = 0;
|
static uhci_properties_t*m_data = 0;
|
||||||
|
|
||||||
/* ++++++++++
|
/* ++++++++++
|
||||||
Register/Bit constants
|
Utility functions
|
||||||
++++++++++ */
|
++++++++++ */
|
||||||
|
|
||||||
enum {
|
static void
|
||||||
USBCMD = 0x0 //Command register (2byte)
|
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 {
|
static status_t
|
||||||
RS = 0x1 , //Run=1 Stop=0
|
uhci_reset( uhci_properties_t *data )
|
||||||
HCRESET = 0x2 //Host controller reset
|
{
|
||||||
};
|
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
|
The hardware management functions
|
||||||
++++++++++ */
|
++++++++++ */
|
||||||
static status_t
|
static status_t
|
||||||
init_hardware()
|
init_hardware(void)
|
||||||
{
|
{
|
||||||
status_t status;
|
status_t status;
|
||||||
pci_info *item;
|
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)
|
// 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)
|
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;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRACE( "usb_uhci init_hardware(): Setting up hardware\n" );
|
||||||
|
|
||||||
// TODO: in the future we might want to support multiple host controllers.
|
// TODO: in the future we might want to support multiple host controllers.
|
||||||
item = (pci_info *)malloc( sizeof( pci_info ) );
|
item = (pci_info *)malloc( sizeof( pci_info ) );
|
||||||
for ( i = 0 ; m_pcimodule->get_nth_pci_info( i , item ) == B_OK ; i++ )
|
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))
|
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;
|
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;
|
m_device = item;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -131,7 +160,8 @@ init_hardware()
|
|||||||
|
|
||||||
if ( m_device == 0 )
|
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 );
|
put_module( B_PCI_MODULE_NAME );
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
}
|
}
|
||||||
@@ -140,7 +170,7 @@ init_hardware()
|
|||||||
m_data = (uhci_properties_t *)malloc( sizeof( uhci_properties_t ) );
|
m_data = (uhci_properties_t *)malloc( sizeof( uhci_properties_t ) );
|
||||||
m_data->pcii = m_device;
|
m_data->pcii = m_device;
|
||||||
m_data->reg_base = m_device->u.h0.base_registers[0];
|
m_data->reg_base = m_device->u.h0.base_registers[0];
|
||||||
|
m_data->rh_address = 255; //Invalidate the RH address
|
||||||
{
|
{
|
||||||
/* enable pci address access */
|
/* enable pci address access */
|
||||||
unsigned char cmd;
|
unsigned char cmd;
|
||||||
@@ -150,8 +180,151 @@ init_hardware()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Do a host reset
|
//Do a host reset
|
||||||
// m_pcimodule->write_io_16( m_data->reg_base + UHCI_USBCMD , UHCI_USBCMD_HCRESET );
|
uhci_globalreset( m_data );
|
||||||
// spin(50);
|
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;
|
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
|
#ifndef UHCI_H
|
||||||
#define UHCI_H
|
#define UHCI_H
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* The Registers *
|
||||||
|
************************************************************/
|
||||||
|
|
||||||
|
|
||||||
// R/W -- Read/Write
|
// R/W -- Read/Write
|
||||||
// R/WC -- Read/Write Clear
|
// R/WC -- Read/Write Clear
|
||||||
// ** -- Only writable with words!
|
// ** -- Only writable with words!
|
||||||
@@ -65,4 +70,37 @@
|
|||||||
#define UHCI_PORTSC_STATCHA 0x2 // Current connect status change
|
#define UHCI_PORTSC_STATCHA 0x2 // Current connect status change
|
||||||
#define UHCI_PORTSC_ENABLED 0x4 // Port enabled/disabled
|
#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
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user