This is just an outline of the USB stack: what it is going to look like. It is definately not

ready for testing. Also the documentation is far from complete (it's in it's early phases).
Unfortunately I don't have enough experience in hardware programming to prototype
it first, so I'll be testing the things that I design in the document.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4275 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Niels Sascha Reedijk 2003-08-12 20:36:24 +00:00
parent e8d1b6e166
commit 1501c2bf3e
15 changed files with 1073 additions and 0 deletions

View File

@ -0,0 +1,33 @@
THE USB STACK
==========
The USB stack will follow the same design as the BeOS R5 stack. This implies that:
- There's a bus manager called the 'usb' manager - this file also contains the usb module
- This usb module will control other modules that implement the communication with the host controller
- These modules are the UHCI, EHCI and OHCI modules
- There will be support for RAW usb device handling in later stages of development
- The public API (for drivers) will be compatible with the API of BeOS R5
THE CORE OF THE MATTER: THE USB BUS MODULE
==============================
I'm a little confused whether or not to make the internals of the USB stack in C++, but eventually
I decided to do that, because it makes the whole thing clearer. This does mean that there still needs
to be some C-glue between the modules of the stack, because the OBOS kernel doesn't support
dynamic libraries. The core data of the USB stack is stored in a class called 'Stack'. On init of the
stack one global variable is created with the name 'data'.
The data struct is protected by one master lock called 'master'. This lock should be gained by
every thread that reads or writes in the 'data' struct.
The USB stack will support only host controller. The USB specification says this is enough, however, there will possibly systems with more controllers. If needed, I'll implement support for multiple host controllers, however, that's currently not the idea. Between the usb core and the host controller driver (essentially another module), is a private api (that will be documented for future additions of host controllers).
THE INITIALISATION PHASE
As soon as a device driver calls the usb module, and the module isn't loaded before, a single instance
of the stack class is made. The constructor initialises the object, and it starts the search for host
controllers. All the host controller modules are called, and if there is no hardware present, or the
hardware corresponding to that host controller is malfunctioning, the controller returns B_ERROR. If
there is no controller that works, the USB module will fail to initialise.
If a controller succeeds in initialising the hardware, and the module initialisation succeeds, the
USB Stack class will call the hw_start() call. In this call it supplies a structure with some pointers to
functions that the host controller needs.
THE UHCI CONTROLLER
==============
BASIC THEORY OF OPERATION

189
headers/os/drivers/USB.h Normal file
View File

@ -0,0 +1,189 @@
/*
** USB.h - Version 2 USB Device Driver API
**
** Copyright 1999, Be Incorporated. All Rights Reserved.
**
*/
#ifndef _USB_H
#define _USB_H
#include <KernelExport.h>
#include <bus_manager.h>
#include <USB_spec.h>
#include <USB_rle.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct usb_module_info usb_module_info;
/* these are opaque handles to internal stack objects */
typedef struct usb_device usb_device;
typedef struct usb_interface usb_interface;
typedef struct usb_pipe usb_pipe;
typedef struct usb_endpoint_info usb_endpoint_info;
typedef struct usb_interface_info usb_interface_info;
typedef struct usb_interface_list usb_interface_list;
typedef struct usb_configuration_info usb_configuration_info;
typedef struct usb_notify_hooks {
status_t (*device_added)(const usb_device *device, void **cookie);
status_t (*device_removed)(void *cookie);
} usb_notify_hooks;
typedef struct usb_support_descriptor {
uint8 dev_class;
uint8 dev_subclass;
uint8 dev_protocol;
uint16 vendor;
uint16 product;
} usb_support_descriptor;
/* ie, I support any hub device:
** usb_support_descriptor hub_devs = { 9, 0, 0, 0, 0 };
*/
struct usb_endpoint_info {
usb_endpoint_descriptor *descr; /* descriptor and handle */
usb_pipe *handle; /* of this endpoint/pipe */
};
struct usb_interface_info {
usb_interface_descriptor *descr; /* descriptor and handle */
usb_interface *handle; /* of this interface */
size_t endpoint_count; /* count and list of endpoints */
usb_endpoint_info *endpoint; /* in this interface */
size_t generic_count; /* unparsed descriptors in this */
usb_descriptor **generic; /* interface */
};
struct usb_interface_list {
size_t alt_count; /* count and list of alternate */
usb_interface_info *alt; /* interfaces available */
usb_interface_info *active; /* currently active alternate */
};
struct usb_configuration_info {
usb_configuration_descriptor *descr; /* descriptor of this config */
size_t interface_count; /* interfaces in this config */
usb_interface_list *interface;
};
typedef void (*usb_callback_func)(void *cookie, uint32 status,
void *data, uint32 actual_len);
struct usb_module_info {
bus_manager_info binfo;
/* inform the bus manager of our intent to support a set of devices */
status_t (*register_driver)(const char *driver_name,
const usb_support_descriptor *descriptors,
size_t count,
const char *optional_republish_driver_name);
/* request notification from the bus manager for add/remove of devices we
support */
status_t (*install_notify)(const char *driver_name,
const usb_notify_hooks *hooks);
status_t (*uninstall_notify)(const char *driver_name);
/* get the device descriptor */
const usb_device_descriptor *(*get_device_descriptor)(const usb_device *dev);
/* get the nth supported configuration */
const usb_configuration_info *(*get_nth_configuration)(const usb_device *dev, uint index);
/* get the active configuration */
const usb_configuration_info *(*get_configuration)(const usb_device *dev);
/* set the active configuration */
status_t (*set_configuration)(const usb_device *dev,
const usb_configuration_info *configuration);
status_t (*set_alt_interface)(const usb_device *dev,
const usb_interface_info *ifc);
/* standard device requests -- convenience functions */
/* obj may be a usb_device*, usb_pipe*, or usb_interface* */
status_t (*set_feature)(const void *object, uint16 selector);
status_t (*clear_feature)(const void *object, uint16 selector);
status_t (*get_status)(const void *object, uint16 *status);
status_t (*get_descriptor)(const usb_device *d,
uint8 type, uint8 index, uint16 lang,
void *data, size_t len, size_t *actual_len);
/* generic device request function */
status_t (*send_request)(const usb_device *d,
uint8 request_type, uint8 request,
uint16 value, uint16 index, uint16 length,
void *data, size_t data_len, size_t *actual_len);
/* async request queueing */
status_t (*queue_interrupt)(const usb_pipe *handle,
void *data, size_t len,
usb_callback_func notify, void *cookie);
status_t (*queue_bulk)(const usb_pipe *handle,
void *data, size_t len,
usb_callback_func notify, void *cookie);
status_t (*queue_isochronous)(const usb_pipe *handle,
void *data, size_t len,
rlea* rle_array, uint16 buffer_duration_ms,
usb_callback_func notify, void *cookie);
status_t (*queue_request)(const usb_device *d,
uint8 request_type, uint8 request,
uint16 value, uint16 index, uint16 length,
void *data, size_t data_len,
usb_callback_func notify, void *cookie);
status_t (*set_pipe_policy)(const usb_pipe *handle, uint8 max_num_queued_packets,
uint16 max_buffer_duration_ms, uint16 sample_size);
/* cancel pending async requests to an endpoint */
status_t (*cancel_queued_transfers)(const usb_pipe *handle);
/* tuning, timeouts, etc */
status_t (*usb_ioctl)(uint32 opcode, void* buf, size_t buf_size);
};
/* status code for usb callback functions */
#define B_USB_STATUS_SUCCESS 0x0000
#define B_USB_STATUS_DEVICE_CRC_ERROR 0x0002
#define B_USB_STATUS_DEVICE_TIMEOUT 0x0004
#define B_USB_STATUS_DEVICE_STALLED 0x0008
#define B_USB_STATUS_IRP_CANCELLED_BY_REQUEST 0x0010
#define B_USB_STATUS_DRIVER_INTERNAL_ERROR 0x0020
#define B_USB_STATUS_ADAPTER_HARDWARE_ERROR 0x0040
#define B_USB_STATUS_ISOCH_IRP_ABORTED 0x0080
/* result codes for usb bus manager functions */
#define B_USBD_SUCCESS 0
#define B_USBD_BAD_HANDLE 1
#define B_USBD_BAD_ARGS 2
#define B_USBD_NO_DATA 3
#define B_USBD_DEVICE_FAILURE 4
#define B_USBD_COMMAND_FAILED 5
#define B_USBD_PIPE_NOT_CONFIGURED 6
#define B_USBD_DEVICE_ERROR 7
#define B_USBD_PIPE_ERROR 8
#define B_USBD_NO_MEMORY 9
#define B_USB_MODULE_NAME "bus_managers/usb/v2"
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,91 @@
/*
** USB_rle.h
**
** Copyright 1999, Be Incorporated. All Rights Reserved.
**
*/
#ifndef _USB_RLE_H
#define _USB_RLE_H
#ifdef __cplusplus
extern "C" {
#endif
struct _usbd_param_hdr;
/*
Run Length encoding records for isochronous IN transfers.
Run Length encoding records are used to identify which samples in
the buffer are good which are bad and which are missing.
Bad bytes are not extracted from the buffer, but are padded to next
nearest sample boundary. The ultimate consumer of the buffer
should also receive the RLE array.
RLE records are constructed based on the following rules:
1. an RLE record contains a sample count and a status
(good, bad, missing or unknown). A buffer has
associated with it an array of rle records. The number of
rle records available is specified in the RLE header. The
number used is also in the RLE header.
2. Within the scope of a buffer, successive packets with the
same completion status are represented with (1) rle record.
For example, after three transactions which have completion
status of success, the byte count in the rle record for this
position in the data stream represents the bytes received in
all three packets.
3. New rle records are initialized each time the status for a
given packet differs from that of the previous packet.
*/
#define RLE_GOOD 1
#define RLE_BAD 2
#define RLE_MISSING 3
#define RLE_UNKNOWN 4
/*
Name: rle
Purpose: used to represent the state of a portion of a data buffer
Fields:
rle_status will contain only the values: RLE_GOOD, RLE_BAD, RLE_MISSING
sample_count the number of usb samples in the buffer associated with this rle
record.
Notes:
If the buffer length field in queue_buffer_single structure changes to an
uint32 from uin16, then the sample_count data type must
track this change.
*/
typedef struct rle {
uint16 rle_status;
uint16 sample_count;
} rle;
/*
Name: rlea
Purpose: used as the primary rle information data structure between the
USB driver stack and a consuming client.
Fields:
length the number of rle records available in this structure.
num_valid filled in by the USB driver. indicates the number of valid
records filled.
rles[] unconstrained array of rle records.
*/
typedef struct rlea {
uint16 length;
uint16 num_valid;
rle rles[1];
} rlea;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,144 @@
/*
** USB_spec.h
**
** Copyright 1999, Be Incorporated. All Rights Reserved.
**
** This file contains structures and constants based on the USB Specification 1.1
**
*/
#ifndef _USB_SPEC_H
#define _USB_SPEC_H
#ifdef __cplusplus
extern "C" {
#endif
/* request types (target & direction) for send_request() */
/* cf USB Spec Rev 1.1, table 9-2, p 183 */
#define USB_REQTYPE_DEVICE_IN 0x80
#define USB_REQTYPE_DEVICE_OUT 0x00
#define USB_REQTYPE_INTERFACE_IN 0x81
#define USB_REQTYPE_INTERFACE_OUT 0x01
#define USB_REQTYPE_ENDPOINT_IN 0x82
#define USB_REQTYPE_ENDPOINT_OUT 0x02
#define USB_REQTYPE_OTHER_OUT 0x03
#define USB_REQTYPE_OTHER_IN 0x83
/* request types for send_request() */
/* cf USB Spec Rev 1.1, table 9-2, p 183 */
#define USB_REQTYPE_STANDARD 0x00
#define USB_REQTYPE_CLASS 0x20
#define USB_REQTYPE_VENDOR 0x40
#define USB_REQTYPE_RESERVED 0x60
#define USB_REQTYPE_MASK 0x9F
/* standard request values for send_request() */
/* cf USB Spec Rev 1.1, table 9-4, p 187 */
#define USB_REQUEST_GET_STATUS 0
#define USB_REQUEST_CLEAR_FEATURE 1
#define USB_REQUEST_SET_FEATURE 3
#define USB_REQUEST_SET_ADDRESS 5
#define USB_REQUEST_GET_DESCRIPTOR 6
#define USB_REQUEST_SET_DESCRIPTOR 7
#define USB_REQUEST_GET_CONFIGURATION 8
#define USB_REQUEST_SET_CONFIGURATION 9
#define USB_REQUEST_GET_INTERFACE 10
#define USB_REQUEST_SET_INTERFACE 11
#define USB_REQUEST_SYNCH_FRAME 12
/* used by {set,get}_descriptor() */
/* cf USB Spec Rev 1.1, table 9-5, p 187 */
#define USB_DESCRIPTOR_DEVICE 1
#define USB_DESCRIPTOR_CONFIGURATION 2
#define USB_DESCRIPTOR_STRING 3
#define USB_DESCRIPTOR_INTERFACE 4
#define USB_DESCRIPTOR_ENDPOINT 5
/* used by {set,clear}_feature() */
/* cf USB Spec Rev 1.1, table 9-6, p 188 */
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1
#define USB_FEATURE_ENDPOINT_HALT 0
typedef struct {
/* cf USB Spec Rev 1.1, table 9-7, p 197 */
uint8 length;
uint8 descriptor_type; /* USB_DESCRIPTOR_DEVICE */
uint16 usb_version; /* USB_DESCRIPTOR_DEVICE_LENGTH */
uint8 device_class;
uint8 device_subclass;
uint8 device_protocol;
uint8 max_packet_size_0;
uint16 vendor_id;
uint16 product_id;
uint16 device_version;
uint8 manufacturer;
uint8 product;
uint8 serial_number;
uint8 num_configurations;
} _PACKED usb_device_descriptor;
typedef struct {
/* cf USB Spec Rev 1.1, table 9-8, p 199 */
uint8 length;
uint8 descriptor_type; /* USB_DESCRIPTOR_CONFIGURATION */
uint16 total_length; /* USB_DESCRIPTOR_CONFIGURATION_LENGTH */
uint8 number_interfaces;
uint8 configuration_value;
uint8 configuration;
uint8 attributes;
uint8 max_power;
} _PACKED usb_configuration_descriptor;
typedef struct {
/* cf USB Spec Rev 1.1, table 9-9, p 202 */
uint8 length;
uint8 descriptor_type; /* USB_DESCRIPTOR_INTERFACE */
uint8 interface_number; /* USB_DESCRIPTOR_INTERFACE_LENGTH */
uint8 alternate_setting;
uint8 num_endpoints;
uint8 interface_class;
uint8 interface_subclass;
uint8 interface_protocol;
uint8 interface;
} _PACKED usb_interface_descriptor;
typedef struct {
/* cf USB Spec Rev 1.1, table 9-10, p 203 */
uint8 length;
uint8 descriptor_type; /* USB_DESCRIPTOR_ENDPOINT */
uint8 endpoint_address; /* USB_DESCRIPTOR_ENDPOINT_LENGTH */
uint8 attributes;
uint16 max_packet_size;
uint8 interval;
} _PACKED usb_endpoint_descriptor;
typedef struct {
/* cf USB Spec Rev 1.1, table 9-12, p 205 */
uint8 length; /* USB_DESCRIPTOR_STRING */
uint8 descriptor_type;
uchar string[1];
} _PACKED usb_string_descriptor;
typedef struct {
uint8 length;
uint8 descriptor_type;
uint8 data[1];
} _PACKED usb_generic_descriptor;
typedef union {
usb_generic_descriptor generic;
usb_device_descriptor device;
usb_interface_descriptor interface;
usb_endpoint_descriptor endpoint;
usb_configuration_descriptor configuration;
usb_string_descriptor string;
} usb_descriptor;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,6 +1,7 @@
SubDir OBOS_TOP src add-ons kernel ;
SubInclude OBOS_TOP src add-ons kernel bus_managers ;
SubInclude OBOS_TOP src add-ons kernel busses ;
SubInclude OBOS_TOP src add-ons kernel disk_scanner ;
SubInclude OBOS_TOP src add-ons kernel drivers ;
SubInclude OBOS_TOP src add-ons kernel file_systems ;

View File

@ -19,4 +19,5 @@ KernelLd
:
addons/kernel/config_manager
;
SubInclude OBOS_TOP src add-ons kernel bus_managers usb ;

View File

@ -0,0 +1,8 @@
SubDir OBOS_TOP src add-ons kernel bus_managers usb ;
UsePrivateHeaders kernel ;
R5KernelAddon usb : [ FDirName kernel bus_managers ] :
usb.cpp
Stack.cpp
;

View File

@ -0,0 +1,67 @@
//------------------------------------------------------------------------------
// 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 <module.h>
#include <util/kernel_cpp.h>
#include "usb_p.h"
Stack::Stack()
{
//Init the master lock
m_master = create_sem( 0 , "usb master lock" );
set_sem_owner( m_master , B_SYSTEM_TEAM );
//Check for host controller modules
void *list = open_module_list( "busses/usb" );
char modulename[B_PATH_NAME_LENGTH];
size_t buffersize = sizeof(modulename);
dprintf( "USB: Looking for host controller modules\n" );
while( read_next_module_name( list , modulename , &buffersize ) == B_OK )
{
dprintf( "USB: Found module %s\n" , modulename );
module_info *module = 0;
if ( get_module( modulename , &module ) != B_OK )
continue;
m_busmodules.Insert( module , 0 );
dprintf( "USB: module %s successfully loaded\n" , modulename );
}
if( m_busmodules.Count() == 0 )
return;
}
Stack::~Stack()
{
//Release the bus modules
for( Vector<module_info *>::Iterator i = m_busmodules.Begin() ; i != m_busmodules.End() ; i++ )
put_module( (*i)->name );
}
status_t Stack::InitCheck()
{
if ( m_busmodules.Count() == 0 )
return ENODEV;
return B_OK;
}
Stack *data = 0;

View File

@ -0,0 +1,104 @@
//------------------------------------------------------------------------------
// 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 <USB.h>
#include <util/kernel_cpp.h>
#include "usb_p.h"
#define USB_DEBUG
#ifdef USB_DEBUG
#define TRACE dprintf
#else
#define TRACE silent
void silent( const char * , ... ) {}
#endif
/* ++++++++++
Loading/unloading the module
++++++++++ */
static int32
bus_std_ops(int32 op, ...)
{
switch(op) {
case B_MODULE_INIT:
TRACE(("usb_nielx: bus module: init\n"));
data = new Stack();
if( data->InitCheck() != B_OK )
{
delete data;
return ENODEV;
}
break;
case B_MODULE_UNINIT:
TRACE(("usb_nielx: bus module: uninit\n"));
delete data;
break;
default:
return EINVAL;
}
return B_OK;
}
/* ++++++++++
This module exports the USB API
++++++++++ */
struct usb_module_info m_module_info =
{
// First the bus_manager_info:
{
//module_info
{
"bus_managers/usb/nielx" ,
B_KEEP_LOADED , // Keep loaded, even if no driver requires it
bus_std_ops
} ,
NULL // the rescan function
} ,
NULL , // register_driver
NULL , // install_notify
NULL , // uninstall_notify
NULL , // get_device_descriptor
NULL , // get_nth_configuration_info
NULL , // get_configuration
NULL , // set_configuration
NULL , // set_alt_interface
NULL , // set_feature
NULL , // clear_feature
NULL , // get_status
NULL , // get_descriptor
NULL , // send_request
NULL , // queue_interrupt
NULL , // queue_bulk
NULL , // queue_isochronous
NULL , // queue_request
NULL , // set_pipe_policy
NULL , // cancel_queued_transfers
NULL // usb_ioctl
};
module_info *modules[] = {
(module_info *)&m_module_info ,
NULL
};

View File

@ -0,0 +1,42 @@
//------------------------------------------------------------------------------
// 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.
#ifndef USB_P
#define USB_P
#include <KernelExport.h>
#include <util/Vector.h>
class Stack
{
public:
Stack();
~Stack();
status_t InitCheck();
private:
Vector<module_info *> m_busmodules; //Stores all the bus modules
sem_id m_master; //The master lock
};
extern "C" Stack *data;
#endif

View File

@ -0,0 +1,3 @@
SubDir OBOS_TOP src add-ons kernel busses ;
SubInclude OBOS_TOP src add-ons kernel busses usb ;

View File

@ -0,0 +1,9 @@
SubDir OBOS_TOP src add-ons kernel busses usb ;
R5KernelAddon uhci : [ FDirName kernel busses usb ] :
uhci.c
;
R5KernelAddon ehci : [ FDirName kernel busses usb ] :
ehci.c
;

View File

@ -0,0 +1,156 @@
//------------------------------------------------------------------------------
// 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 <module.h>
#include <PCI.h>
#define UHCI_DEBUG
#ifdef UHCI_DEBUG
#define TRACE dprintf
#else
#define TRACE silent
void silent( const char * , ... ) {}
#endif
static status_t init_hardware();
/* ++++++++++
This is the implementation of the UHCI controller for the OpenBeOS USB stack
++++++++++ */
static int32
ehci_std_ops( int32 op , ... )
{
switch (op)
{
case B_MODULE_INIT:
TRACE( "ehci_module: init the module\n" );
return init_hardware();
case B_MODULE_UNINIT:
TRACE( "ehci_module: uninit the module\n" );
break;
default:
return EINVAL;
}
return B_OK;
}
struct module_info ehci_module = {
"busses/usb/ehci/nielx",
NULL, // No flag like B_KEEP_LOADED : the usb module does that
ehci_std_ops
};
module_info *modules[] = {
(module_info *)&ehci_module ,
NULL
};
/* ++++++++++
Internal variables
++++++++++ */
typedef struct ehci_properties
{
uint32 reg_base; //Base address of the registers
pci_info *pcii; //pci-info struct
} ehci_properties_t;
static pci_module_info *m_pcimodule = 0;
static pci_info *m_device = 0;
static ehci_properties_t*m_data = 0;
/* ++++++++++
Register/Bit constants
++++++++++ */
enum {
USBCMD = 0x0 //Command register (2byte)
};
enum USBCMD_commands {
RS = 0x1 , //Run=1 Stop=0
HCRESET = 0x2 //Host controller reset
};
/* ++++++++++
The hardware management functions
++++++++++ */
static status_t
init_hardware()
{
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( "ehci_nielx init_hardware(): Get PCI module failed! %lu \n", status);
return status;
}
// 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: 20 (EHCI)
if ( ( item->class_base == 0x0C ) && ( item->class_sub == 0x03 ) &&
( item->class_api == 0x20 ) )
{
if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF))
{
TRACE( "ehci_nielx init_hardware(): found with invalid IRQ - check IRQ assignement\n");
continue;
}
TRACE("ehci_nielx init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line);
m_device = item;
break;
}
}
if ( m_device == 0 )
{
TRACE( "ehci_nielx init hardware(): no devices found\n" );
put_module( B_PCI_MODULE_NAME );
return ENODEV;
}
//Initialise the host controller
m_data = (ehci_properties_t *)malloc( sizeof( ehci_properties_t ) );
m_data->pcii = m_device;
m_data->reg_base = m_device->u.h0.base_registers[0];
{
/* 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
//m_pcimodule->write_io_16( data->reg_base + USBCMD , HCRESET );
//usleep(50);
return B_OK;
}

View File

@ -0,0 +1,157 @@
//------------------------------------------------------------------------------
// 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 <module.h>
#include <PCI.h>
#include "uhci.h"
#define UHCI_DEBUG
#ifdef UHCI_DEBUG
#define TRACE dprintf
#else
#define TRACE silent
void silent( const char * , ... ) {}
#endif
static status_t init_hardware();
/* ++++++++++
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;
}
struct module_info uhci_module = {
"busses/usb/uhci/nielx",
NULL, // No flag like B_KEEP_LOADED : the usb module does that
uhci_std_ops
};
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
} uhci_properties_t;
static pci_module_info *m_pcimodule = 0;
static pci_info *m_device = 0;
static uhci_properties_t*m_data = 0;
/* ++++++++++
Register/Bit constants
++++++++++ */
enum {
USBCMD = 0x0 //Command register (2byte)
};
enum USBCMD_commands {
RS = 0x1 , //Run=1 Stop=0
HCRESET = 0x2 //Host controller reset
};
/* ++++++++++
The hardware management functions
++++++++++ */
static status_t
init_hardware()
{
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( "uhci_nielx init_hardware(): Get PCI module failed! %lu \n", status);
return status;
}
// 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( "uhci_nielx 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);
m_device = item;
break;
}
}
if ( m_device == 0 )
{
TRACE( "uhci_nielx init hardware(): no devices found\n" );
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_device->u.h0.base_registers[0];
{
/* 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
// m_pcimodule->write_io_16( m_data->reg_base + UHCI_USBCMD , UHCI_USBCMD_HCRESET );
// spin(50);
return B_OK;
}

View File

@ -0,0 +1,68 @@
//------------------------------------------------------------------------------
// 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.
#ifndef UHCI_H
#define UHCI_H
// 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
#endif