Implemented most of the roothub.

There remains only one issue: reading the Port registers seem to return a bogus value (0). I need to find out what's causing it.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18918 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Niels Sascha Reedijk 2006-09-25 14:26:22 +00:00
parent 36020a912d
commit 2159acc7d9
4 changed files with 388 additions and 92 deletions

View File

@ -108,9 +108,6 @@ ohci_add_to(Stack *stack)
return status;
}
TRACE(("usb_ohci 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 ; OHCI::pci_module->get_nth_pci_info( i , item ) == B_OK ; i++ ) {
if ( ( item->class_base == PCI_serial_bus ) && ( item->class_sub == PCI_usb )
@ -121,20 +118,28 @@ ohci_add_to(Stack *stack)
continue;
}
TRACE(("USB OHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line));
OHCI *bus = new OHCI( item , stack );
if ( bus->InitCheck() != B_OK ) {
delete bus;
break;
OHCI *bus = new(std::nothrow) OHCI(item, stack);
if (!bus) {
delete item;
OHCI::pci_module = NULL;
put_module(B_PCI_MODULE_NAME);
return B_NO_MEMORY;
}
if (bus->InitCheck() != B_OK) {
TRACE(("usb_ohci: bus failed to initialize...\n"));
delete bus;
continue;
}
bus->Start();
stack->AddBusManager( bus );
bus->Start();
found = true;
break;
}
}
if ( found == false ) {
if (!found) {
TRACE(("USB OHCI: init hardware(): no devices found\n"));
free( item );
put_module( B_PCI_MODULE_NAME );
@ -184,7 +189,10 @@ OHCI::OHCI(pci_info *info, Stack *stack)
fHccaArea(-1),
fDummyControl(0),
fDummyBulk(0),
fDummyIsochronous(0)
fDummyIsochronous(0),
fRootHub(0),
fRootHubAddress(0),
fNumPorts(0)
{
fPcii = info;
fStack = stack;
@ -321,9 +329,7 @@ OHCI::OHCI(pci_info *info, Stack *stack)
uint32 interval = OHCI_GET_IVAL(frameinterval);
WriteReg(OHCI_PERIODIC_START, OHCI_PERIODIC(interval));
m_roothub_base = 255; //Invalidate the Root Hub address
fInitOK = true;
}
OHCI::~OHCI()
@ -338,18 +344,140 @@ OHCI::~OHCI()
FreeEndpoint(fDummyBulk);
if (fDummyIsochronous)
FreeEndpoint(fDummyIsochronous);
if (fRootHub)
delete fRootHub;
for (int i = 0; i < OHCI_NO_EDS; i++)
if (fInterruptEndpoints[i])
FreeEndpoint(fInterruptEndpoints[i]);
}
status_t
OHCI::Start()
{
if (!(ReadReg(OHCI_CONTROL) & OHCI_HCFS_OPERATIONAL)) {
TRACE(("USB OHCI::Start(): Controller not started. TODO: find out what happens.\n"));
return B_ERROR;
}
fRootHubAddress = AllocateAddress();
fNumPorts = OHCI_GET_PORT_COUNT(ReadReg(OHCI_RH_DESCRIPTOR_A));
fRootHub = new(std::nothrow) OHCIRootHub(this, fRootHubAddress);
if (!fRootHub) {
TRACE_ERROR(("USB OHCI::Start(): no memory to allocate root hub\n"));
return B_NO_MEMORY;
}
if (fRootHub->InitCheck() < B_OK) {
TRACE_ERROR(("USB OHCI::Start(): root hub failed init check\n"));
return B_ERROR;
}
SetRootHub(fRootHub);
TRACE(("USB OHCI::Start(): Succesful start\n"));
return B_OK;
}
status_t OHCI::SubmitTransfer( Transfer *t )
{
TRACE(("usb OHCI::SubmitTransfer: called for device %d\n", t->TransferPipe()->DeviceAddress()));
if (t->TransferPipe()->DeviceAddress() == fRootHubAddress)
return fRootHub->ProcessTransfer(t, this);
return B_ERROR;
}
status_t
OHCI::GetPortStatus(uint8 index, usb_port_status *status)
{
if (index > fNumPorts)
return B_BAD_INDEX;
status->status = status->change = 0;
uint32 portStatus = ReadReg(OHCI_RH_PORT_STATUS(index));
TRACE(("OHCIRootHub::GetPortStatus: Port %i Value 0x%lx\n", OHCI_RH_PORT_STATUS(index), portStatus));
// status
if (portStatus & OHCI_PORTSTATUS_CCS)
status->status |= PORT_STATUS_CONNECTION;
if (portStatus & OHCI_PORTSTATUS_PES)
status->status |= PORT_STATUS_ENABLE;
if (portStatus & OHCI_PORTSTATUS_PRS)
status->status |= PORT_STATUS_RESET;
if (portStatus & OHCI_PORTSTATUS_LSDA)
status->status |= PORT_STATUS_LOW_SPEED;
if (portStatus & OHCI_PORTSTATUS_PSS)
status->status |= PORT_STATUS_SUSPEND;
if (portStatus & OHCI_PORTSTATUS_POCI)
status->status |= PORT_STATUS_OVER_CURRENT;
if (portStatus & OHCI_PORTSTATUS_PPS)
status->status |= PORT_STATUS_POWER;
// change
if (portStatus & OHCI_PORTSTATUS_CSC)
status->change |= PORT_STATUS_CONNECTION;
if (portStatus & OHCI_PORTSTATUS_PESC)
status->change |= PORT_STATUS_ENABLE;
if (portStatus & OHCI_PORTSTATUS_PSSC)
status->change |= PORT_STATUS_SUSPEND;
if (portStatus & OHCI_PORTSTATUS_OCIC)
status->change |= PORT_STATUS_OVER_CURRENT;
if (portStatus & OHCI_PORTSTATUS_PRSC)
status->change |= PORT_STATUS_RESET;
return B_OK;
}
status_t
OHCI::SetPortFeature(uint8 index, uint16 feature)
{
if (index > fNumPorts)
return B_BAD_INDEX;
switch (feature) {
case PORT_RESET:
WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_PORTSTATUS_PRS);
return B_OK;
case PORT_POWER:
WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_PORTSTATUS_PPS);
return B_OK;
}
return B_BAD_VALUE;
}
status_t
OHCI::ClearPortFeature(uint8 index, uint16 feature)
{
if (index > fNumPorts)
return B_BAD_INDEX;
switch (feature) {
case C_PORT_RESET:
WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_PORTSTATUS_CSC);
return B_OK;
case C_PORT_CONNECTION:
WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_PORTSTATUS_CSC);
return B_OK;
}
return B_BAD_VALUE;
}
Endpoint *
OHCI::AllocateEndpoint()
{
Endpoint *endpoint = new Endpoint;
void *phy;
if (fStack->AllocateChunk((void **)&endpoint->ed, &phy, sizeof(ohci_endpoint_descriptor)) != B_OK)
if (fStack->AllocateChunk((void **)&endpoint->ed, &phy, sizeof(ohci_endpoint_descriptor)) != B_OK) {
TRACE(("OHCI::AllocateEndpoint(): Error Allocating Endpoint\n"));
return 0;
}
endpoint->physicaladdress = (addr_t)phy;
memset((void *)endpoint->ed, 0, sizeof(ohci_endpoint_descriptor));
@ -364,17 +492,6 @@ OHCI::FreeEndpoint(Endpoint *end)
delete end;
}
//------------------------------------------------------------------------
// OHCI:: Submit a transfer
//
// parameters:
// - t: pointer to a transfer instance
//------------------------------------------------------------------------
status_t OHCI::SubmitTransfer( Transfer *t )
{
return B_OK;
}
pci_module_info *OHCI::pci_module = 0;

View File

@ -48,13 +48,20 @@ public:
OHCI(pci_info *info, Stack *stack);
~OHCI();
status_t Start();
status_t SubmitTransfer(Transfer *t); //Override from BusManager.
static pci_module_info *pci_module; // Global data for the module.
status_t GetPortStatus(uint8 index, usb_port_status *status);
status_t ClearPortFeature(uint8 index, uint16 feature);
status_t SetPortFeature(uint8 index, uint16 feature);
uint8 PortCount() { return fNumPorts; };
private:
inline void WriteReg(uint32 reg, uint32 value);
inline uint32 ReadReg(uint32 reg);
private:
// Global
pci_info *fPcii; // pci-info struct
Stack *fStack; // Pointer to the stack
@ -69,8 +76,9 @@ private:
Endpoint *fDummyBulk;
Endpoint *fDummyIsochronous;
// Root Hub
OHCIRootHub *m_roothub; // the root hub
addr_t m_roothub_base; // Base address of the root hub
OHCIRootHub *fRootHub; // the root hub
uint8 fRootHubAddress; // the usb address of the roothub
uint8 fNumPorts; // the number of ports
// functions
Endpoint *AllocateEndpoint(); // allocate memory for an endpoint
void FreeEndpoint(Endpoint *end); //Free endpoint
@ -85,12 +93,8 @@ private:
class OHCIRootHub : public Hub
{
public:
OHCIRootHub( OHCI *ohci , int8 devicenum );
status_t SubmitTransfer( Transfer *t );
void UpdatePortStatus();
private:
usb_port_status m_hw_port_status[2]; // the port status (maximum of two)
OHCI *m_ohci; // needed because of internal data
OHCIRootHub(OHCI *ohci, int8 deviceAddress);
status_t ProcessTransfer(Transfer *t, OHCI *ohci);
};
//
@ -110,6 +114,4 @@ struct Endpoint
};
};
#define OHCI_DEBUG
#endif // OHCI_H

View File

@ -189,7 +189,7 @@
// --------------------------------
#define OHCI_RH_DESCRIPTOR_A 0x48
#define OHCI_GET_NDP(s) ((s) & 0xff)
#define OHCI_GET_PORT_COUNT(s) ((s) & 0xff)
#define OHCI_PSM 0x0100 // Power Switching Mode
#define OHCI_NPS 0x0200 // No Power Switching
#define OHCI_DT 0x0400 // Device Type
@ -220,6 +220,18 @@
// --------------------------------
#define OHCI_RH_PORT_STATUS(n) (0x50 + (n)*4) // 1 based indexing
#define OHCI_PORTSTATUS_CCS 0x00000001 // Current Connection Status
#define OHCI_PORTSTATUS_PES 0x00000002 // Port Enable Status
#define OHCI_PORTSTATUS_PSS 0x00000004 // Port Suspend Status
#define OHCI_PORTSTATUS_POCI 0x00000008 // Port Overcurrent Indicator
#define OHCI_PORTSTATUS_PRS 0x00000010 // Port Reset Status
#define OHCI_PORTSTATUS_PPS 0x00000100 // Port Power Status
#define OHCI_PORTSTATUS_LSDA 0x00000200 // Low Speed Device Attached
#define OHCI_PORTSTATUS_CSC 0x00010000 // Connection Status Change
#define OHCI_PORTSTATUS_PESC 0x00020000 // Port Enable Status Change
#define OHCI_PORTSTATUS_PSSC 0x00040000 // Port Suspend Status change
#define OHCI_PORTSTATUS_OCIC 0x00080000 // Port Overcurrent Change
#define OHCI_PORTSTATUS_PRSC 0x00100000 // Port Reset Status Change
// --------------------------------
// ????

View File

@ -22,9 +22,8 @@
#include "ohci.h"
#include <PCI.h>
usb_device_descriptor ohci_devd =
static usb_device_descriptor sOHCIRootHubDevice =
{
0x12, //Descriptor size
USB_DESCRIPTOR_DEVICE , //Type of descriptor
@ -40,65 +39,231 @@ usb_device_descriptor ohci_devd =
1 //Number of configurations
};
usb_configuration_descriptor ohci_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)
struct ohci_root_hub_configuration_s {
usb_configuration_descriptor configuration;
usb_interface_descriptor interface;
usb_endpoint_descriptor endpoint;
usb_hub_descriptor hub;
} _PACKED;
static ohci_root_hub_configuration_s sOHCIRootHubConfig = {
{ // configuration descriptor
9, //Size
USB_DESCRIPTOR_CONFIGURATION,
34, //Total size of the configuration
1, //Number interfaces
1, //Value of configuration
0, //Number of configuration
0x40, //Self powered
0 //Max power (0, because of self power)
},
{ // interface descriptor
9, //Size
USB_DESCRIPTOR_INTERFACE,
0, //Interface number
0, //Alternate setting
1, //Num endpoints
0x09, //Interface class
0, //Interface subclass
0, //Interface protocol
0 //Interface
},
{ // endpoint descriptor
7, //Size
USB_DESCRIPTOR_ENDPOINT,
USB_REQTYPE_DEVICE_IN | 1, //1 from freebsd driver
0x3, // Interrupt
8, // Max packet size
0xFF // Interval 256
},
{
9, //Including deprecated powerctrlmask
USB_DESCRIPTOR_HUB,
0, //Number of ports
0x0000, //Hub characteristics FIXME
50, //Power on to power good
0, // Current
0x00, //Both ports are removable
0xff // Depricated power control mask
}
};
usb_interface_descriptor ohci_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
struct ohci_root_hub_string_s {
uint8 length;
uint8 descriptor_type;
uint16 unicode_string[12];
} _PACKED;
static ohci_root_hub_string_s sOHCIRootHubStrings[3] = {
{
4, // Descriptor length
USB_DESCRIPTOR_STRING, // Descriptor type
{
0x0409 // Supported language IDs (English US)
}
},
{
22, // Descriptor length
USB_DESCRIPTOR_STRING, // Descriptor type
{
'H', 'A', 'I', 'K', 'U', // Characters
' ', 'I', 'n', 'c', '.'
}
},
{
26, // Descriptor length
USB_DESCRIPTOR_STRING, // Descriptor type
{
'O', 'H', 'C', 'I', ' ', // Characters
'R', 'o', 'o', 't', 'H',
'u', 'b'
}
}
};
usb_endpoint_descriptor ohci_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 ohci_hubd =
OHCIRootHub::OHCIRootHub(OHCI *ohci, int8 deviceAddress)
: Hub(ohci->RootObject(), sOHCIRootHubDevice, deviceAddress , USB_SPEED_FULLSPEED )
{
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
OHCIRootHub::OHCIRootHub( OHCI *ohci , int8 devicenum )
: Hub( ohci->RootObject() , ohci_devd , devicenum , USB_SPEED_FULLSPEED )
{
m_ohci = ohci;
}
status_t OHCIRootHub::SubmitTransfer( Transfer *t )
status_t
OHCIRootHub::ProcessTransfer(Transfer *t, OHCI *ohci)
{
if ((t->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
return B_ERROR;
usb_request_data *request = t->RequestData();
TRACE(("OHCIRootHub::ProcessTransfer(): request: %d\n", request->Request));
uint32 status = B_USB_STATUS_DEVICE_TIMEOUT;
size_t actualLength = 0;
switch (request->Request) {
case USB_REQUEST_GET_STATUS: {
if (request->Index == 0) {
// get hub status
actualLength = MIN(sizeof(usb_port_status),
t->DataLength());
// the hub reports whether the local power failed (bit 0)
// and if there is a over-current condition (bit 1).
// everything as 0 means all is ok.
// TODO (?) actually check for the value
memset(t->Data(), 0, actualLength);
status = B_USB_STATUS_SUCCESS;
break;
}
usb_port_status portStatus;
if (ohci->GetPortStatus(request->Index, &portStatus) >= B_OK) {
actualLength = MIN(sizeof(usb_port_status), t->DataLength());
memcpy(t->Data(), (void *)&portStatus, actualLength);
status = B_USB_STATUS_SUCCESS;
}
break;
}
case USB_REQUEST_SET_ADDRESS:
if (request->Value >= 128) {
status = B_USB_STATUS_DEVICE_TIMEOUT;
break;
}
TRACE(("OHCIRootHub::ProcessTransfer(): set address: %d\n", request->Value));
status = B_USB_STATUS_SUCCESS;
break;
case USB_REQUEST_GET_DESCRIPTOR:
TRACE(("OHCIRootHub::ProcessTransfer(): get descriptor: %d\n", request->Value >> 8));
switch (request->Value >> 8) {
case USB_DESCRIPTOR_DEVICE: {
actualLength = MIN(sizeof(usb_device_descriptor),
t->DataLength());
memcpy(t->Data(), (void *)&sOHCIRootHubDevice,
actualLength);
status = B_USB_STATUS_SUCCESS;
break;
}
case USB_DESCRIPTOR_CONFIGURATION: {
//Make sure we have the correct number of ports
sOHCIRootHubConfig.hub.num_ports = ohci->PortCount();
actualLength = MIN(sizeof(sOHCIRootHubConfig),
t->DataLength());
memcpy(t->Data(), (void *)&(sOHCIRootHubConfig),
actualLength);
status = B_USB_STATUS_SUCCESS;
break;
}
case USB_DESCRIPTOR_STRING: {
uint8 index = request->Value & 0x00ff;
if (index > 2)
break;
actualLength = MIN(sOHCIRootHubStrings[index].length,
t->DataLength());
memcpy(t->Data(), (void *)&sOHCIRootHubStrings[index],
actualLength);
status = B_USB_STATUS_SUCCESS;
break;
}
case USB_DESCRIPTOR_HUB: {
//Make sure we have the correct number of ports
sOHCIRootHubConfig.hub.num_ports = ohci->PortCount();
actualLength = MIN(sizeof(usb_hub_descriptor),
t->DataLength());
memcpy(t->Data(), (void *)&sOHCIRootHubConfig.hub,
actualLength);
status = B_USB_STATUS_SUCCESS;
break;
}
}
break;
case USB_REQUEST_SET_CONFIGURATION:
status = B_USB_STATUS_SUCCESS;
break;
case USB_REQUEST_CLEAR_FEATURE: {
if (request->Index == 0) {
// we don't support any hub changes
TRACE_ERROR(("OHCIRootHub::ProcessTransfer(): clear feature: no hub changes\n"));
break;
}
TRACE(("OHCIRootHub::ProcessTransfer(): clear feature: %d\n", request->Value));
if (ohci->ClearPortFeature(request->Index, request->Value) >= B_OK)
status = B_USB_STATUS_SUCCESS;
break;
}
case USB_REQUEST_SET_FEATURE: {
if (request->Index == 0) {
// we don't support any hub changes
TRACE_ERROR(("OHCIRootHub::ProcessTransfer(): set feature: no hub changes\n"));
break;
}
TRACE(("OHCIRootHub::ProcessTransfer(): set feature: %d\n", request->Value));
if (ohci->SetPortFeature(request->Index, request->Value) >= B_OK)
status = B_USB_STATUS_SUCCESS;
break;
}
}
t->Finished(status, actualLength);
delete t;
return B_OK;
}
}
void OHCIRootHub::UpdatePortStatus(void)
{
// nothing yet
}