Picking up work on the USB stack. First of all adapting the style of the UHCI driver. Not yet working any more than until now.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17607 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2006-05-27 13:07:11 +00:00
parent 848b89034e
commit 12b0511534
4 changed files with 798 additions and 751 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +1,10 @@
//------------------------------------------------------------------------------
// 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.
/*
* Copyright 2004-2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Niels S. Reedijk
*/
#ifndef UHCI_H
#define UHCI_H
@ -29,84 +16,88 @@ struct pci_info;
struct pci_module_info;
class UHCIRootHub;
class UHCI : public BusManager
{
friend class UHCIRootHub;
friend int32 uhci_interrupt_handler( void *data );
public:
UHCI( pci_info *info , Stack *stack );
//Override from BusManager
status_t Start();
status_t SubmitTransfer( Transfer *t );
// Global data for the module.
static pci_module_info *pci_module;
private:
//Utility functions
void GlobalReset();
status_t Reset();
int32 Interrupt();
//Functions for the actual functioning of transfers
status_t InsertControl( Transfer *t );
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]
//Maintain a list of transfers
Vector<Transfer *> m_transfers;
//Root hub:
UHCIRootHub *m_rh; // the root hub
uint8 m_rh_address; // the address of the root hub
class UHCI : public BusManager {
public:
UHCI(pci_info *info, Stack *stack);
status_t Start();
status_t SubmitTransfer(Transfer *transfer);
static bool AddTo(Stack &stack);
private:
friend class UHCIRootHub;
// Utility functions
void GlobalReset();
status_t Reset();
static int32 InterruptHandler(void *data);
int32 Interrupt();
// Register functions
inline void WriteReg16(uint32 reg, uint16 value);
inline void WriteReg32(uint32 reg, uint32 value);
inline uint16 ReadReg16(uint32 reg);
inline uint32 ReadReg32(uint32 reg);
// Functions for the actual functioning of transfers
status_t InsertControl(Transfer *transfer);
static pci_module_info *sPCIModule;
uint32 fRegisterBase;
pci_info *fPCIInfo;
Stack *fStack;
// Frame list memory
area_id fFrameArea;
addr_t fFrameList[1024];
addr_t fPhysicalFrameList;
// Virtual frame
uhci_qh *fVirtualQueueHead[12];
#define fQueueHeadInterrupt256 fVirtualQueueHead[0]
#define fQueueHeadInterrupt128 fVirtualQueueHead[1]
#define fQueueHeadInterrupt64 fVirtualQueueHead[2]
#define fQueueHeadInterrupt32 fVirtualQueueHead[3]
#define fQueueHeadInterrupt16 fVirtualQueueHead[4]
#define fQueueHeadInterrupt8 fVirtualQueueHead[5]
#define fQueueHeadInterrupt4 fVirtualQueueHead[6]
#define fQueueHeadInterrupt2 fVirtualQueueHead[7]
#define fQueueHeadInterrupt1 fVirtualQueueHead[8]
#define fQueueHeadControl fVirtualQueueHead[9]
#define fQueueHeadBulk fVirtualQueueHead[10]
#define fQueueHeadTerminate fVirtualQueueHead[11]
// Maintain a list of transfers
Vector<Transfer *> fTransfers;
// Root hub
UHCIRootHub *fRootHub;
uint8 fRootHubAddress;
};
class UHCIRootHub : public Hub
{
class UHCIRootHub : public Hub {
public:
UHCIRootHub( UHCI *uhci , int8 devicenum );
status_t SubmitTransfer( Transfer *t );
void UpdatePortStatus();
UHCIRootHub(UHCI *uhci, int8 deviceNum);
status_t SubmitTransfer(Transfer *transfer);
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
usb_port_status fPortStatus[2];
UHCI *fUHCI;
};
struct hostcontroller_priv
{
struct hostcontroller_priv {
uhci_qh *topqh;
uhci_td *firsttd;
uhci_td *lasttd;
};
#define UHCI_DEBUG
#ifdef UHCI_DEBUG
#define TRACE dprintf
#else
#define TRACE silent
void silent( const char * , ... ) {}
#endif
#endif

View File

@ -61,7 +61,7 @@
#define UHCI_USBSTS_HOSTERR 0x8 // Host System Error
#define UHCI_USBSTS_HCPRERR 0x10// Host Controller Process error
#define UHCI_USBSTS_HCHALT 0x20 // HCHalted
#define UHCI_INTERRUPT_MASK 0x1F //Mask for all the interrupts
#define UHCI_INTERRUPT_MASK 0x3F //Mask for all the interrupts
//USBINTR
#define UHCI_USBINTR_CRC 0x1 // Timeout/ CRC interrupt enable

View File

@ -1,267 +1,268 @@
//------------------------------------------------------------------------------
// 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.
/*
* Copyright 2004-2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Niels S. Reedijk
*/
#include "uhci.h"
#include <PCI.h>
#define TRACE_UHCI_ROOT_HUB
#ifdef TRACE_UHCI_ROOT_HUB
#define TRACE(x) dprintf x
#else
#define TRACE(x) /* nothing */
#endif
usb_device_descriptor uhci_devd =
{
0x12, //Descriptor size
USB_DESCRIPTOR_DEVICE , //Type of descriptor
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
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
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
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
0x07, //Size
USB_DESCRIPTOR_ENDPOINT,
USB_REQTYPE_DEVICE_IN | 1, //1 from freebsd driver
0x3 , // Interrupt
8 , // Max packet size
0x3, // Interrupt
8, // Max packet size
0xFF // Interval 256
};
usb_hub_descriptor uhci_hubd =
{
0x09 , //Including deprecated powerctrlmask
0x09, //Including deprecated powerctrlmask
USB_DESCRIPTOR_HUB,
1, //Number of ports
0x02 | 0x01 , //Hub characteristics FIXME
50 , //Power on to power good
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 )
UHCIRootHub::UHCIRootHub(UHCI *uhci, int8 devicenum)
: Hub(uhci, NULL, uhci_devd, devicenum, false)
{
m_uhci = uhci;
fUHCI = 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;
status_t
UHCIRootHub::SubmitTransfer(Transfer *transfer)
{
usb_request_data *request = transfer->GetRequestData();
TRACE(("usb_uhci_roothub: rh_submit_packet called. request: %u\n", request->Request));
status_t result = B_ERROR;
switch(request->Request) {
case RH_GET_STATUS:
if (request->Index == 0) {
// Get the hub status -- everything as 0 means all-right
memset(transfer->GetBuffer(), 0, sizeof(get_status_buffer));
result = 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;
} else if (request->Index > uhci_hubd.bNbrPorts) {
// This port doesn't exist
result = EINVAL;
break;
}
break;
}
case RH_SET_CONFIG:
retval = B_OK;
break;
// Get port status
UpdatePortStatus();
memcpy(transfer->GetBuffer(),
(void *)&fPortStatus[request->Index - 1],
transfer->GetBufferLength());
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;
*(transfer->GetActualLength()) = transfer->GetBufferLength();
result = B_OK;
break;
}
else if ( request->Index > uhci_hubd.bNbrPorts )
{
//Invalid port number
TRACE( "UHCI: RH_CLEAR_FEATURE invalid port!\n" );
retval = EINVAL;
case RH_SET_ADDRESS:
if (request->Value >= 128) {
result = EINVAL;
break;
}
TRACE(("usb_uhci_roothub: rh_submit_packet RH_ADDRESS: %d\n", request->Value));
result = B_OK;
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;
case RH_GET_DESCRIPTOR:
TRACE(("usb_uhci_roothub: rh_submit_packet GET_DESC: %d\n", request->Value));
switch (request->Value) {
case RH_DEVICE_DESCRIPTOR:
memcpy(transfer->GetBuffer(), (void *)&uhci_devd,
transfer->GetBufferLength());
*(transfer->GetActualLength()) = transfer->GetBufferLength();
result = B_OK;
break;
case RH_CONFIG_DESCRIPTOR:
memcpy(transfer->GetBuffer(), (void *)&uhci_confd,
transfer->GetBufferLength());
*(transfer->GetActualLength()) = transfer->GetBufferLength();
result = B_OK;
break;
case RH_INTERFACE_DESCRIPTOR:
memcpy(transfer->GetBuffer(), (void *)&uhci_intd,
transfer->GetBufferLength());
*(transfer->GetActualLength()) = transfer->GetBufferLength();
result = B_OK ;
break;
case RH_ENDPOINT_DESCRIPTOR:
memcpy(transfer->GetBuffer(), (void *)&uhci_endd,
transfer->GetBufferLength());
*(transfer->GetActualLength()) = transfer->GetBufferLength();
result = B_OK ;
break;
case RH_HUB_DESCRIPTOR:
memcpy(transfer->GetBuffer(), (void *)&uhci_hubd,
transfer->GetBufferLength());
*(transfer->GetActualLength()) = transfer->GetBufferLength();
result = B_OK;
break;
default:
result = EINVAL;
break;
}
break;
default:
retval = EINVAL;
case RH_SET_CONFIG:
result = B_OK;
break;
case RH_CLEAR_FEATURE:
if (request->Index == 0) {
// We don't support any hub changes
TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE no hub changes!\n"));
result = EINVAL;
break;
} else if (request->Index > uhci_hubd.bNbrPorts) {
// Invalid port number
TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE invalid port!\n"));
result = EINVAL;
break;
}
TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE called. Feature: %u!\n", request->Value));
uint16 port;
switch(request->Value) {
case PORT_RESET:
port = UHCI::sPCIModule->read_io_16(fUHCI->fRegisterBase + UHCI_PORTSC1 + (request->Index - 1) * 2);
port &= ~UHCI_PORTSC_RESET;
TRACE(("usb_uhci_roothub: port %x Clear RESET\n", port));
UHCI::sPCIModule->write_io_16(fUHCI->fRegisterBase + UHCI_PORTSC1 + (request->Index - 1) * 2, port);
break;
case C_PORT_CONNECTION:
port = UHCI::sPCIModule->read_io_16(fUHCI->fRegisterBase + UHCI_PORTSC1 + (request->Index - 1) * 2);
port = port & UHCI_PORTSC_DATAMASK;
port |= UHCI_PORTSC_STATCHA;
TRACE(("usb_uhci_roothub: port: %x\n", port));
UHCI::sPCIModule->write_io_16(fUHCI->fRegisterBase + UHCI_PORTSC1 + (request->Index - 1) * 2, port);
result = B_OK;
break;
default:
result = EINVAL;
break;
}
break;
default:
result = EINVAL;
break;
} //switch( t->value)
break;
default:
retval = EINVAL;
break;
}
// Clean up the transfer - we own it, so we clean it up
t->Finish();
delete t;
return retval;
transfer->Finish();
delete transfer;
return result;
}
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;
void
UHCIRootHub::UpdatePortStatus()
{
for (int32 i = 0; i < 2; i++) {
uint16 newStatus = 0;
uint16 newChange = 0;
uint16 portStatus = UHCI::sPCIModule->read_io_16(fUHCI->fRegisterBase + UHCI_PORTSC1 + i * 2);
TRACE(("usb_uhci_roothub: port: %d status: 0x%04x\n", UHCI_PORTSC1 + i * 2, portStatus));
// Set all individual bits
if (portStatus & UHCI_PORTSC_CURSTAT)
newStatus |= PORT_STATUS_CONNECTION;
if (portStatus & UHCI_PORTSC_STATCHA)
newStatus |= PORT_STATUS_CONNECTION;
if (portStatus & UHCI_PORTSC_ENABLED)
newStatus |= PORT_STATUS_ENABLE;
if (portStatus & UHCI_PORTSC_ENABCHA)
newStatus |= PORT_STATUS_ENABLE;
// TODO: work out suspended/resume
if ( portsc & UHCI_PORTSC_RESET )
newstatus |= PORT_STATUS_RESET;
if (portStatus & 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_STATUS_LOW_SPEED;
newStatus |= PORT_POWER;
if (portStatus & UHCI_PORTSC_LOWSPEED)
newStatus |= PORT_STATUS_LOW_SPEED;
//Update the stored port status
m_hw_port_status[i].status = newstatus;
m_hw_port_status[i].change = newchange;
fPortStatus[i].status = newStatus;
fPortStatus[i].change = newChange;
}
}