Summary: Merge in recent changes
Keywords: Patches applied: * [email protected]/usb-busses--development--0.1--patch-12 Update/add license header * [email protected]/usb-busses--development--0.1--patch-13 Changes to init routine and memory management * [email protected]/usb-busses--development--0.1--patch-14 Move uhci_properties_t into its own header -- cleans up the implementation * [email protected]/usb-busses--development--0.1--patch-15 Add a virtual schedule that can be used to hook in all kinds of transfers * [email protected]/usb-busses--development--0.1--patch-16 Improve rh handling * [email protected]/usb-busses--development--0.1--patch-17 Change module to be subclass of BusManager * [email protected]/usb-busses--development--0.1--patch-18 Reimplemented the uhci root hub * [email protected]/usb-busses--development--0.1--patch-19 merge with mainline git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8422 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -2,8 +2,12 @@ SubDir OBOS_TOP src add-ons kernel busses usb ;
|
|||||||
|
|
||||||
AddResources uhci : uhci.rdef ;
|
AddResources uhci : uhci.rdef ;
|
||||||
|
|
||||||
|
UsePrivateHeaders [ FDirName kernel ] ;
|
||||||
|
UseHeaders [ FDirName $(OBOS_TOP) src add-ons kernel bus_managers usb ] ;
|
||||||
|
|
||||||
R5KernelAddon uhci : [ FDirName kernel busses usb ] :
|
R5KernelAddon uhci : [ FDirName kernel busses usb ] :
|
||||||
uhci.c
|
uhci.cpp
|
||||||
util.c
|
uhci_rh.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
|
LinkSharedOSLibs uhci : libusb.a ;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Copyright (c) 2003, Niels S. Reedijk
|
// Copyright (c) 2003-2004, Niels S. Reedijk
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
// copy of this software and associated documentation files (the "Software"),
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
#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
|
|
||||||
++++++++++ */
|
|
||||||
|
|
||||||
//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 internals of a pipe
|
|
||||||
enum Direction { In , Out , Default };
|
|
||||||
enum Speed { LowSpeed , NormalSpeed };
|
|
||||||
|
|
||||||
typedef struct usb_pipe_t
|
|
||||||
{
|
|
||||||
enum Direction direction;
|
|
||||||
enum Speed speed;
|
|
||||||
int8 deviceid;
|
|
||||||
uint8 endpoint;
|
|
||||||
} usb_pipe_t;
|
|
||||||
|
|
||||||
|
|
||||||
// Describes the internal organs of an usb packet
|
|
||||||
typedef struct usb_transfer_t
|
|
||||||
{
|
|
||||||
//Data that is related to the transfer
|
|
||||||
usb_pipe_t *pipe;
|
|
||||||
uint8 *buffer;
|
|
||||||
size_t bufferlength;
|
|
||||||
size_t *actual_length;
|
|
||||||
bigtime_t timeout;
|
|
||||||
status_t status;
|
|
||||||
|
|
||||||
//For control transfers
|
|
||||||
usb_request_data *request;
|
|
||||||
} usb_transfer_t;
|
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
typedef struct host_controller_info
|
|
||||||
{
|
|
||||||
module_info info;
|
|
||||||
status_t (*hwstart)(void);
|
|
||||||
status_t (*SubmitPacket)(usb_transfer_t *);
|
|
||||||
} host_controller_info;
|
|
||||||
|
|
||||||
#endif //HOST_CONTROLLER_INFO_H
|
|
||||||
@@ -1,487 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 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 <USB.h>
|
|
||||||
#include <KernelExport.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "uhci.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "host_controller.h"
|
|
||||||
|
|
||||||
#define UHCI_DEBUG
|
|
||||||
#ifdef UHCI_DEBUG
|
|
||||||
#define TRACE dprintf
|
|
||||||
#else
|
|
||||||
#define TRACE silent
|
|
||||||
void silent( const char * , ... ) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static status_t init_hardware(void);
|
|
||||||
static status_t submit_packet( usb_transfer_t *transfer );
|
|
||||||
static status_t rh_submit_packet( usb_transfer_t *transfer );
|
|
||||||
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
|
|
||||||
++++++++++ */
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ++++++++++
|
|
||||||
Internal variables
|
|
||||||
++++++++++ */
|
|
||||||
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
|
|
||||||
usb_port_status port_status[2]; // the port status (maximum of two)
|
|
||||||
} uhci_properties_t;
|
|
||||||
|
|
||||||
static pci_module_info *m_pcimodule = 0;
|
|
||||||
static pci_info *m_device = 0;
|
|
||||||
static uhci_properties_t*m_data = 0;
|
|
||||||
|
|
||||||
/* ++++++++++
|
|
||||||
Utility functions
|
|
||||||
++++++++++ */
|
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
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(void)
|
|
||||||
{
|
|
||||||
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( "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++ )
|
|
||||||
{
|
|
||||||
//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( "USB UHCI: init_hardware(): found with invalid IRQ - check IRQ assignement\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
TRACE("USB UHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line);
|
|
||||||
m_device = item;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( m_device == 0 )
|
|
||||||
{
|
|
||||||
TRACE( "USB UHCI: init hardware(): no devices found\n" );
|
|
||||||
free( item );
|
|
||||||
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_pcimodule->read_pci_config(m_data->pcii->bus, m_data->pcii->device, m_data->pcii->function, 0x20 , 4 ) ^ 1;
|
|
||||||
TRACE( "USB UHCI: iospace offset: %lx\n" , m_data->reg_base );
|
|
||||||
m_data->rh_address = 255; //Invalidate the RH address
|
|
||||||
{
|
|
||||||
/* 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
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 = alloc_mem( &(m_data->framelist[0]) , &(m_data->framelist_phy) ,
|
|
||||||
4096 , "uhci framelist" );
|
|
||||||
if ( m_data->framearea < B_OK )
|
|
||||||
{
|
|
||||||
TRACE( "USB UHCI: init_hardware(): unable to create an area for the frame pointer list\n" );
|
|
||||||
free( item );
|
|
||||||
put_module( B_PCI_MODULE_NAME );
|
|
||||||
return ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Make all frame list entries invalid
|
|
||||||
for( i = 0 ; i < 1024 ; i++ )
|
|
||||||
(int32)(m_data->framelist[i]) = 0x1;
|
|
||||||
|
|
||||||
//Set base pointer
|
|
||||||
m_pcimodule->write_io_32( m_data->reg_base + UHCI_FRBASEADD , (int32)(m_data->framelist_phy) );
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ++++++++++
|
|
||||||
Inserting transfers in the queue
|
|
||||||
++++++++++ */
|
|
||||||
status_t submit_packet( usb_transfer_t *transfer )
|
|
||||||
{
|
|
||||||
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 ( transfer->pipe->deviceid == 1 ) //First device of a bus has address 1 per definition
|
|
||||||
{
|
|
||||||
rh_submit_packet( transfer );
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
//4. Determine the type of transfer and send it to the proper function
|
|
||||||
//5. Release the spinlock
|
|
||||||
out:
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ++++++++++
|
|
||||||
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 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_transfer_t *transfer )
|
|
||||||
{
|
|
||||||
usb_request_data *request = transfer->request;
|
|
||||||
status_t retval;
|
|
||||||
|
|
||||||
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( transfer->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( transfer->buffer , (void *)&(m_data->port_status[request->Index - 1]) , transfer->bufferlength );
|
|
||||||
*(transfer->actual_length) = transfer->bufferlength;
|
|
||||||
retval = B_OK;
|
|
||||||
break;
|
|
||||||
|
|
||||||
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( transfer->buffer , (void *)&uhci_devd , transfer->bufferlength );
|
|
||||||
*(transfer->actual_length) = transfer->bufferlength;
|
|
||||||
retval = B_OK;
|
|
||||||
break;
|
|
||||||
case RH_CONFIG_DESCRIPTOR:
|
|
||||||
memcpy( transfer->buffer , (void *)&uhci_confd , transfer->bufferlength );
|
|
||||||
*(transfer->actual_length) = transfer->bufferlength;
|
|
||||||
retval = B_OK;
|
|
||||||
break;
|
|
||||||
case RH_INTERFACE_DESCRIPTOR:
|
|
||||||
memcpy( transfer->buffer , (void *)&uhci_intd , transfer->bufferlength );
|
|
||||||
*(transfer->actual_length) = transfer->bufferlength;
|
|
||||||
retval = B_OK ;
|
|
||||||
break;
|
|
||||||
case RH_ENDPOINT_DESCRIPTOR:
|
|
||||||
memcpy( transfer->buffer , (void *)&uhci_endd , transfer->bufferlength );
|
|
||||||
*(transfer->actual_length) = transfer->bufferlength;
|
|
||||||
retval = B_OK ;
|
|
||||||
break;
|
|
||||||
case RH_HUB_DESCRIPTOR:
|
|
||||||
memcpy( transfer->buffer , (void *)&uhci_hubd , transfer->bufferlength );
|
|
||||||
*(transfer->actual_length) = transfer->bufferlength;
|
|
||||||
retval = B_OK;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
retval = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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 PORT_RESET:
|
|
||||||
port = m_pcimodule->read_io_16( m_data->reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 );
|
|
||||||
port &= ~UHCI_PORTSC_RESET;
|
|
||||||
TRACE( "UHCI rh: port %x Clear RESET\n" , port );
|
|
||||||
m_pcimodule->write_io_16( m_data->reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 , port );
|
|
||||||
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( transfer->value)
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
retval = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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: %x status: 0x%x\n" , UHCI_PORTSC1 + i * 2 , 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2004, 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 <USB.h>
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "uhci.h"
|
||||||
|
#include "uhci_hardware.h"
|
||||||
|
#include <usb_p.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* ++++++++++
|
||||||
|
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 B_OK;
|
||||||
|
case B_MODULE_UNINIT:
|
||||||
|
TRACE( "uhci_module: uninit the module\n" );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
uhci_add_to( Stack &stack )
|
||||||
|
{
|
||||||
|
status_t status;
|
||||||
|
pci_info *item;
|
||||||
|
bool found = false;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
#ifdef UHCI_DEBUG
|
||||||
|
set_dprintf_enabled( true );
|
||||||
|
load_driver_symbols( "uhci" );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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 **)&( UHCI::pci_module ) ) ) != B_OK)
|
||||||
|
{
|
||||||
|
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 = new pci_info;
|
||||||
|
for ( i = 0 ; UHCI::pci_module->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( "USB UHCI: init_hardware(): found with invalid IRQ - check IRQ assignement\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TRACE("USB UHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line);
|
||||||
|
UHCI *bus = new UHCI( item , &stack );
|
||||||
|
if ( bus->InitCheck() != B_OK )
|
||||||
|
{
|
||||||
|
delete bus;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.AddBusManager( bus );
|
||||||
|
bus->Start();
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( found == false )
|
||||||
|
{
|
||||||
|
TRACE( "USB UHCI: init hardware(): no devices found\n" );
|
||||||
|
free( item );
|
||||||
|
put_module( B_PCI_MODULE_NAME );
|
||||||
|
return ENODEV;
|
||||||
|
}
|
||||||
|
return B_OK; //Hardware found
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 ,
|
||||||
|
uhci_add_to
|
||||||
|
};
|
||||||
|
|
||||||
|
module_info *modules[] =
|
||||||
|
{
|
||||||
|
(module_info *) &uhci_module,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ++++++++++
|
||||||
|
This is the implementation of the UHCI controller for the OpenBeOS USB stack
|
||||||
|
++++++++++ */
|
||||||
|
|
||||||
|
UHCI::UHCI( pci_info *info , Stack *stack )
|
||||||
|
{
|
||||||
|
//Do nothing yet
|
||||||
|
dprintf( "UHCI: constructing new BusManager\n" );
|
||||||
|
m_pcii = info;
|
||||||
|
m_stack = stack;
|
||||||
|
m_reg_base = UHCI::pci_module->read_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, 0x20 , 4 ) ^ 1;
|
||||||
|
TRACE( "USB UHCI: iospace offset: %lx\n" , m_reg_base );
|
||||||
|
m_rh_address = 255; //Invalidate the RH address
|
||||||
|
{
|
||||||
|
/* enable pci address access */
|
||||||
|
unsigned char cmd;
|
||||||
|
cmd = UHCI::pci_module->read_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_command, 2);
|
||||||
|
cmd = cmd | PCI_command_io | PCI_command_master | PCI_command_memory;
|
||||||
|
UHCI::pci_module->write_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_command, 2, cmd );
|
||||||
|
}
|
||||||
|
|
||||||
|
//Do a host reset
|
||||||
|
GlobalReset();
|
||||||
|
if ( Reset() == B_ERROR )
|
||||||
|
{
|
||||||
|
TRACE( "USB UHCI: init_hardare(): host failed to reset\n" );
|
||||||
|
m_initok = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
void *phy;
|
||||||
|
m_framearea = stack->AllocateArea( (void **)&(m_framelist[0]) , &(phy) ,
|
||||||
|
4096 , "uhci framelist" );
|
||||||
|
m_framelist_phy = reinterpret_cast<addr_t>(phy);
|
||||||
|
if ( m_framearea < B_OK )
|
||||||
|
{
|
||||||
|
TRACE( "USB UHCI: init_hardware(): unable to create an area for the frame pointer list\n" );
|
||||||
|
m_initok = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set up the virtual structure. I stole this idea from the linux usb stack,
|
||||||
|
the idea is that for every interrupt interval there is a queue head. These
|
||||||
|
things all link together and eventually point to the control and bulk
|
||||||
|
virtual queue heads.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for( int i = 0 ; i < 12 ; i++ )
|
||||||
|
{
|
||||||
|
void *phy;
|
||||||
|
//Must be aligned on 16-byte boundaries
|
||||||
|
if ( m_stack->AllocateChunk( (void **)&(m_qh_virtual[i]) ,
|
||||||
|
&phy , 16 ) != B_OK )
|
||||||
|
{
|
||||||
|
dprintf( "USB UHCI: init_hardware(): failed allocation of skeleton qh %i, aborting\n", i );
|
||||||
|
delete_area( m_framearea );
|
||||||
|
m_initok = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//chunk allocated
|
||||||
|
m_qh_virtual[i]->this_phy = reinterpret_cast<addr_t>(phy);
|
||||||
|
m_qh_virtual[i]->element_phy = QH_TERMINATE;
|
||||||
|
|
||||||
|
//Link this qh to its previous qh
|
||||||
|
if ( i != 0 )
|
||||||
|
m_qh_virtual[i-1]->link_phy = m_qh_virtual[i]->this_phy | QH_NEXT_IS_QH ;
|
||||||
|
}
|
||||||
|
// Make sure the qh_terminate terminates
|
||||||
|
m_qh_virtual[11]->link_phy = QH_TERMINATE;
|
||||||
|
|
||||||
|
//Insert the queues in the frame list. The linux developers mentioned
|
||||||
|
// in a comment that they used some magic to distribute the elements all
|
||||||
|
// over the place, but I don't really think that it is useful right now
|
||||||
|
// (or do I know how I should do that), instead, I just take the frame
|
||||||
|
// number and determine where it should begin
|
||||||
|
|
||||||
|
//NOTE, in c++ this is butt-ugly. We have a addr_t *array (because with
|
||||||
|
//an addr_t *array we can apply pointer arithmetic), uhci_qh *pointers
|
||||||
|
//that need to be put through the logical | to make sure the pointer is
|
||||||
|
//invalid for the hc. The result of that needs to be converted into a
|
||||||
|
//addr_t. Get it?
|
||||||
|
for( int i = 0 ; i < 1024 ; i++ )
|
||||||
|
{
|
||||||
|
int frame = i+1;
|
||||||
|
if ( ( frame % 256 ) == 0 )
|
||||||
|
m_framelist[i] = reinterpret_cast<addr_t*>( reinterpret_cast<addr_t>(m_qh_interrupt_256) | FRAMELIST_NEXT_IS_QH );
|
||||||
|
else if ( ( frame % 128 ) == 0 )
|
||||||
|
m_framelist[i] = reinterpret_cast<addr_t*>( reinterpret_cast<addr_t>(m_qh_interrupt_128) | FRAMELIST_NEXT_IS_QH );
|
||||||
|
else if ( ( frame % 64 ) == 0 )
|
||||||
|
m_framelist[i] = reinterpret_cast<addr_t*>( reinterpret_cast<addr_t>(m_qh_interrupt_64) | FRAMELIST_NEXT_IS_QH );
|
||||||
|
else if ( ( frame % 32 ) == 0 )
|
||||||
|
m_framelist[i] = reinterpret_cast<addr_t*>( reinterpret_cast<addr_t>(m_qh_interrupt_32) | FRAMELIST_NEXT_IS_QH );
|
||||||
|
else if ( ( frame % 16 ) == 0 )
|
||||||
|
m_framelist[i] = reinterpret_cast<addr_t*>( reinterpret_cast<addr_t>(m_qh_interrupt_16) | FRAMELIST_NEXT_IS_QH );
|
||||||
|
else if ( ( frame % 8 ) == 0 )
|
||||||
|
m_framelist[i] = reinterpret_cast<addr_t*>( reinterpret_cast<addr_t>(m_qh_interrupt_8) | FRAMELIST_NEXT_IS_QH );
|
||||||
|
else if ( ( frame % 4 ) == 0 )
|
||||||
|
m_framelist[i] = reinterpret_cast<addr_t*>( reinterpret_cast<addr_t>(m_qh_interrupt_4) | FRAMELIST_NEXT_IS_QH );
|
||||||
|
else if ( ( frame % 2 ) == 0 )
|
||||||
|
m_framelist[i] = reinterpret_cast<addr_t*>( reinterpret_cast<addr_t>(m_qh_interrupt_2) | FRAMELIST_NEXT_IS_QH );
|
||||||
|
else
|
||||||
|
m_framelist[i] = reinterpret_cast<addr_t*>( reinterpret_cast<addr_t>(m_qh_interrupt_1) | FRAMELIST_NEXT_IS_QH );
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set base pointer
|
||||||
|
UHCI::pci_module->write_io_32( m_reg_base + UHCI_FRBASEADD , (int32)(m_framelist_phy) );
|
||||||
|
|
||||||
|
//Set up the root hub
|
||||||
|
m_rh_address = AllocateAddress();
|
||||||
|
m_rh = new UHCIRootHub( this , m_rh_address );
|
||||||
|
SetRootHub( m_rh );
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t UHCI::SubmitTransfer( Transfer &t )
|
||||||
|
{
|
||||||
|
dprintf( "UHCI::SubmitPacket( Transfer &t ) called!!!\n" );
|
||||||
|
|
||||||
|
//Short circuit the root hub
|
||||||
|
if ( m_rh_address == t.GetPipe()->GetDeviceAddress() )
|
||||||
|
return m_rh->SubmitTransfer( t );
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UHCI::GlobalReset()
|
||||||
|
{
|
||||||
|
UHCI::pci_module->write_io_16( m_reg_base + UHCI_USBCMD , UHCI_USBCMD_GRESET );
|
||||||
|
spin( 100 );
|
||||||
|
UHCI::pci_module->write_io_16( m_reg_base + UHCI_USBCMD , 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t UHCI::Reset()
|
||||||
|
{
|
||||||
|
UHCI::pci_module->write_io_16( m_reg_base + UHCI_USBCMD , UHCI_USBCMD_HCRESET );
|
||||||
|
spin( 100 );
|
||||||
|
if ( UHCI::pci_module->read_io_16( m_reg_base + UHCI_USBCMD ) & UHCI_USBCMD_HCRESET )
|
||||||
|
return B_ERROR;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_module_info *UHCI::pci_module = 0;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Copyright (c) 2003, Niels S. Reedijk
|
// Copyright (c) 2004, Niels S. Reedijk
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
// copy of this software and associated documentation files (the "Software"),
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
@@ -22,107 +22,75 @@
|
|||||||
#ifndef UHCI_H
|
#ifndef UHCI_H
|
||||||
#define UHCI_H
|
#define UHCI_H
|
||||||
|
|
||||||
/************************************************************
|
#include <usb_p.h>
|
||||||
* The Registers *
|
#include "uhci_hardware.h"
|
||||||
************************************************************/
|
|
||||||
|
|
||||||
|
struct pci_info;
|
||||||
|
struct pci_module_info;
|
||||||
|
class UHCIRootHub;
|
||||||
|
|
||||||
// R/W -- Read/Write
|
class UHCI : public BusManager
|
||||||
// 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
|
|
||||||
#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 *
|
|
||||||
************************************************************/
|
|
||||||
|
|
||||||
//Represents a Transfer Descriptor (TD)
|
|
||||||
|
|
||||||
struct uhci_td
|
|
||||||
{
|
{
|
||||||
void * link; // Link to the next TD/QH
|
friend class UHCIRootHub;
|
||||||
uint32 status; // Status field
|
public:
|
||||||
uint32 token; // Contains the packet header (where it needs to be sent)
|
UHCI( pci_info *info , Stack *stack );
|
||||||
void * buffer; // A pointer to the buffer with the actual packet
|
|
||||||
|
//Override from BusManager
|
||||||
|
status_t SubmitTransfer( Transfer &t );
|
||||||
|
|
||||||
|
// Global data for the module.
|
||||||
|
static pci_module_info *pci_module;
|
||||||
|
private:
|
||||||
|
//Utility functions
|
||||||
|
void GlobalReset();
|
||||||
|
status_t Reset();
|
||||||
|
|
||||||
|
uint32 m_reg_base; //Base address of the registers
|
||||||
|
pci_info *m_pcii; //pci-info struct
|
||||||
|
Stack *m_stack; //Pointer to the stack
|
||||||
|
|
||||||
|
//Frame list memory
|
||||||
|
area_id m_framearea;
|
||||||
|
addr_t *m_framelist[1024]; //The frame list struct
|
||||||
|
addr_t m_framelist_phy; //The physical pointer to the frame list
|
||||||
|
|
||||||
|
// Virtual frame
|
||||||
|
uhci_qh *m_qh_virtual[12]; //
|
||||||
|
#define m_qh_interrupt_256 m_qh_virtual[0]
|
||||||
|
#define m_qh_interrupt_128 m_qh_virtual[1]
|
||||||
|
#define m_qh_interrupt_64 m_qh_virtual[2]
|
||||||
|
#define m_qh_interrupt_32 m_qh_virtual[3]
|
||||||
|
#define m_qh_interrupt_16 m_qh_virtual[4]
|
||||||
|
#define m_qh_interrupt_8 m_qh_virtual[5]
|
||||||
|
#define m_qh_interrupt_4 m_qh_virtual[6]
|
||||||
|
#define m_qh_interrupt_2 m_qh_virtual[7]
|
||||||
|
#define m_qh_interrupt_1 m_qh_virtual[8]
|
||||||
|
#define m_qh_control m_qh_virtual[9]
|
||||||
|
#define m_qh_bulk m_qh_virtual[10]
|
||||||
|
#define m_qh_terminate m_qh_virtual[11]
|
||||||
|
|
||||||
|
//Root hub:
|
||||||
|
UHCIRootHub *m_rh; // the root hub
|
||||||
|
uint8 m_rh_address; // the address of the root hub
|
||||||
};
|
};
|
||||||
|
|
||||||
//Represents a Queue Head (QH)
|
class UHCIRootHub : public Hub
|
||||||
|
|
||||||
struct uhci_qh
|
|
||||||
{
|
{
|
||||||
void * link; //Link to the next TD/QH
|
public:
|
||||||
void * element; //Link to the first element pointer in the queue
|
UHCIRootHub( UHCI *uhci , int8 devicenum );
|
||||||
|
status_t SubmitTransfer( Transfer &t );
|
||||||
|
void UpdatePortStatus();
|
||||||
|
private:
|
||||||
|
usb_port_status m_hw_port_status[2]; // the port status (maximum of two)
|
||||||
|
UHCI *m_uhci; // needed because of internal data
|
||||||
};
|
};
|
||||||
|
|
||||||
/************************************************************
|
#define UHCI_DEBUG
|
||||||
* Roothub Emulation *
|
#ifdef UHCI_DEBUG
|
||||||
************************************************************/
|
#define TRACE dprintf
|
||||||
#define RH_GET_STATUS 0
|
#else
|
||||||
#define RH_CLEAR_FEATURE 1
|
#define TRACE silent
|
||||||
#define RH_SET_FEATURE 3
|
void silent( const char * , ... ) {}
|
||||||
#define RH_SET_ADDRESS 5
|
#endif
|
||||||
#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
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2003-2004, 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_HARDWARE_H
|
||||||
|
#define UHCI_HARDWARE_H
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* The Registers *
|
||||||
|
************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
// 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
|
||||||
|
#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 *
|
||||||
|
************************************************************/
|
||||||
|
|
||||||
|
//A framelist thingie
|
||||||
|
#define FRAMELIST_TERMINATE 0x1
|
||||||
|
#define FRAMELIST_NEXT_IS_QH 0x2
|
||||||
|
|
||||||
|
|
||||||
|
//Represents a Transfer Descriptor (TD)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
//Hardware part
|
||||||
|
addr_t link_phy; // Link to the next TD/QH
|
||||||
|
uint32 status; // Status field
|
||||||
|
uint32 token; // Contains the packet header (where it needs to be sent)
|
||||||
|
addr_t buffer_phy; // A pointer to the buffer with the actual packet
|
||||||
|
// Software part
|
||||||
|
void * link_log; // Link to the next logical TD/QT
|
||||||
|
void * buffer_log; // Link to the buffer
|
||||||
|
} uhci_td;
|
||||||
|
|
||||||
|
//Represents a Queue Head (QH)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
// Hardware part
|
||||||
|
addr_t link_phy; //Link to the next TD/QH
|
||||||
|
addr_t element_phy; //Link to the first element pointer in the queue
|
||||||
|
// Software part
|
||||||
|
addr_t this_phy; //The physical pointer to this address
|
||||||
|
void * link_log; //Link to the next TD/QH logical
|
||||||
|
void * element_log; //
|
||||||
|
} uhci_qh;
|
||||||
|
|
||||||
|
#define QH_TERMINATE 0x1
|
||||||
|
#define QH_NEXT_IS_QH 0x2
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Roothub Emulation *
|
||||||
|
************************************************************/
|
||||||
|
#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
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2004, 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 "uhci.h"
|
||||||
|
#include <PCI.h>
|
||||||
|
|
||||||
|
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 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
|
||||||
|
};
|
||||||
|
|
||||||
|
//Implementation
|
||||||
|
UHCIRootHub::UHCIRootHub( UHCI *uhci , int8 devicenum )
|
||||||
|
: Hub( uhci , NULL , uhci_devd , devicenum , false )
|
||||||
|
{
|
||||||
|
m_uhci = uhci;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t UHCIRootHub::SubmitTransfer( Transfer &t )
|
||||||
|
{
|
||||||
|
status_t retval;
|
||||||
|
usb_request_data *request = t.GetRequestData();
|
||||||
|
uint16 port; //used in RH_CLEAR/SET_FEATURE
|
||||||
|
|
||||||
|
TRACE( "USB UHCI: rh_submit_packet called. Request: %u\n" , t.GetRequestData()->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( t.GetBuffer() , 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
|
||||||
|
UpdatePortStatus();
|
||||||
|
memcpy( t.GetBuffer() , (void *)&(m_hw_port_status[request->Index - 1]) , t.GetBufferLength());
|
||||||
|
*(t.GetActualLength()) = t.GetBufferLength();
|
||||||
|
retval = B_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RH_SET_ADDRESS:
|
||||||
|
if ( request->Value >= 128 )
|
||||||
|
{
|
||||||
|
retval = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TRACE( "USB UHCI: rh_submit_packet RH_ADDRESS: %d\n" , 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( t.GetBuffer() , (void *)&uhci_devd , t.GetBufferLength());
|
||||||
|
*(t.GetActualLength()) = t.GetBufferLength();
|
||||||
|
retval = B_OK;
|
||||||
|
break;
|
||||||
|
case RH_CONFIG_DESCRIPTOR:
|
||||||
|
memcpy( t.GetBuffer() , (void *)&uhci_confd , t.GetBufferLength());
|
||||||
|
*(t.GetActualLength()) = t.GetBufferLength();
|
||||||
|
retval = B_OK;
|
||||||
|
break;
|
||||||
|
case RH_INTERFACE_DESCRIPTOR:
|
||||||
|
memcpy( t.GetBuffer() , (void *)&uhci_intd , t.GetBufferLength());
|
||||||
|
*(t.GetActualLength()) = t.GetBufferLength();
|
||||||
|
retval = B_OK ;
|
||||||
|
break;
|
||||||
|
case RH_ENDPOINT_DESCRIPTOR:
|
||||||
|
memcpy( t.GetBuffer() , (void *)&uhci_endd , t.GetBufferLength());
|
||||||
|
*(t.GetActualLength()) = t.GetBufferLength();
|
||||||
|
retval = B_OK ;
|
||||||
|
break;
|
||||||
|
case RH_HUB_DESCRIPTOR:
|
||||||
|
memcpy( t.GetBuffer() , (void *)&uhci_hubd , t.GetBufferLength());
|
||||||
|
*(t.GetActualLength()) = t.GetBufferLength();
|
||||||
|
retval = B_OK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
retval = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
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 PORT_RESET:
|
||||||
|
port = UHCI::pci_module->read_io_16( m_uhci->m_reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 );
|
||||||
|
port &= ~UHCI_PORTSC_RESET;
|
||||||
|
TRACE( "UHCI rh: port %x Clear RESET\n" , port );
|
||||||
|
UHCI::pci_module->write_io_16( m_uhci->m_reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 , port );
|
||||||
|
case C_PORT_CONNECTION:
|
||||||
|
port = UHCI::pci_module->read_io_16( m_uhci->m_reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 );
|
||||||
|
port = port & UHCI_PORTSC_DATAMASK;
|
||||||
|
port |= UHCI_PORTSC_STATCHA;
|
||||||
|
TRACE( "UHCI rh: port: %x\n" , port );
|
||||||
|
UHCI::pci_module->write_io_16( m_uhci->m_reg_base + UHCI_PORTSC1 + (request->Index - 1 ) * 2 , port );
|
||||||
|
retval = B_OK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
retval = EINVAL;
|
||||||
|
break;
|
||||||
|
} //switch( t.value)
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
retval = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UHCIRootHub::UpdatePortStatus(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for ( i = 0; i <= 1 ; i++ )
|
||||||
|
{
|
||||||
|
uint16 newstatus = 0;
|
||||||
|
uint16 newchange = 0;
|
||||||
|
|
||||||
|
uint16 portsc = UHCI::pci_module->read_io_16( m_uhci->m_reg_base + UHCI_PORTSC1 + i * 2 );
|
||||||
|
dprintf( "USB UHCI: port: %x status: 0x%x\n" , UHCI_PORTSC1 + i * 2 , 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_hw_port_status[i].status = newstatus;
|
||||||
|
m_hw_port_status[i].change = newchange;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* BeOS Driver for Intel ICH AC'97 Link interface
|
|
||||||
*
|
|
||||||
* Copyright (c) 2002, Marcus Overhagen <[email protected]>
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
||||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#include <Errors.h>
|
|
||||||
#include <OS.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
//#define DEBUG 2
|
|
||||||
|
|
||||||
//#include "debug.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
spinlock slock = 0;
|
|
||||||
|
|
||||||
uint32 round_to_pagesize(uint32 size);
|
|
||||||
|
|
||||||
cpu_status lock(void)
|
|
||||||
{
|
|
||||||
cpu_status status = disable_interrupts();
|
|
||||||
acquire_spinlock(&slock);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock(cpu_status status)
|
|
||||||
{
|
|
||||||
release_spinlock(&slock);
|
|
||||||
restore_interrupts(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 round_to_pagesize(uint32 size)
|
|
||||||
{
|
|
||||||
return (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
area_id alloc_mem(void **log, void **phy, size_t size, const char *name)
|
|
||||||
{
|
|
||||||
physical_entry pe;
|
|
||||||
void * logadr;
|
|
||||||
area_id areaid;
|
|
||||||
status_t rv;
|
|
||||||
|
|
||||||
dprintf("allocating %ld bytes for %s\n",size,name);
|
|
||||||
|
|
||||||
size = round_to_pagesize(size);
|
|
||||||
areaid = create_area(name, &logadr, B_ANY_KERNEL_ADDRESS,size,B_FULL_LOCK | B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
|
|
||||||
if (areaid < B_OK) {
|
|
||||||
dprintf("couldn't allocate area %s\n",name);
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
rv = get_memory_map(logadr,size,&pe,1);
|
|
||||||
if (rv < B_OK) {
|
|
||||||
delete_area(areaid);
|
|
||||||
dprintf("couldn't map %s\n",name);
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
memset(logadr,0,size);
|
|
||||||
if (log)
|
|
||||||
*log = logadr;
|
|
||||||
if (phy)
|
|
||||||
*phy = pe.address;
|
|
||||||
dprintf("area = %ld, size = %ld, log = %#08lX, phy = %#08lX\n",areaid,size,(uint32)logadr,(uint32)(pe.address));
|
|
||||||
return areaid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is not the most advanced method to map physical memory for io access.
|
|
||||||
* Perhaps using B_ANY_KERNEL_ADDRESS instead of B_ANY_KERNEL_BLOCK_ADDRESS
|
|
||||||
* makes the whole offset calculation and relocation obsolete. But the code
|
|
||||||
* below does work, and I can't test if using B_ANY_KERNEL_ADDRESS also works.
|
|
||||||
*/
|
|
||||||
area_id map_mem(void **log, void *phy, size_t size, const char *name)
|
|
||||||
{
|
|
||||||
uint32 offset;
|
|
||||||
void *phyadr;
|
|
||||||
void *mapadr;
|
|
||||||
area_id area;
|
|
||||||
|
|
||||||
dprintf("mapping physical address %p with %#lx bytes for %s\n",phy,size,name);
|
|
||||||
|
|
||||||
offset = (uint32)phy & (B_PAGE_SIZE - 1);
|
|
||||||
phyadr = (char *)phy - offset;
|
|
||||||
size = round_to_pagesize(size + offset);
|
|
||||||
area = map_physical_memory(name, phyadr, size, B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA, &mapadr);
|
|
||||||
*log = (char *)mapadr + offset;
|
|
||||||
|
|
||||||
dprintf("physical = %p, logical = %p, offset = %#lx, phyadr = %p, mapadr = %p, size = %#lx, area = %#lx\n",
|
|
||||||
phy, *log, offset, phyadr, mapadr, size, area);
|
|
||||||
|
|
||||||
return area;
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* BeOS Driver for Intel ICH AC'97 Link interface
|
|
||||||
*
|
|
||||||
* Copyright (c) 2002, Marcus Overhagen <[email protected]>
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
||||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef _UTIL_H_
|
|
||||||
#define _UTIL_H_
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
|
||||||
|
|
||||||
area_id alloc_mem(void **log, void **phy, size_t size, const char *name);
|
|
||||||
area_id map_mem(void **log, void *phy, size_t size, const char *name);
|
|
||||||
|
|
||||||
cpu_status lock(void);
|
|
||||||
void unlock(cpu_status status);
|
|
||||||
|
|
||||||
extern spinlock slock;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Reference in New Issue
Block a user