* Cleaned up / applied style to the BusManager class

* Fixed some copy&paste errors I introduced earlier
* Removed the "one UHCI bus only" limit
* Other fixes

The hub now sees when a new device is connected but failes when getting its descriptor.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17611 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2006-05-27 19:33:30 +00:00
parent 76e69839f7
commit 26f34d1c06
5 changed files with 210 additions and 207 deletions

View File

@ -1,186 +1,200 @@
//------------------------------------------------------------------------------
// 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.
/*
* Copyright 2003-2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Niels S. Reedijk
*/
#include "usb_p.h"
/* +++++++++
This is the 'main' function of the explore thread, which keeps track of
the hub statuses.
+++++++++ */
int32 usb_explore_thread( void *data )
{
Hub *roothub = (Hub *)data;
if ( roothub == 0 )
return B_ERROR;
while ( true )
{
//Go to the hubs
roothub->Explore();
snooze(1000000); //Wait one second before continueing
}
return B_OK;
}
#define TRACE_BUSMANAGER
#ifdef TRACE_BUSMANAGER
#define TRACE(x) dprintf(x)
#else
#define TRACE(x) /* nothing */
#endif
BusManager::BusManager()
{
m_initok = false;
m_roothub = 0;
// Set up the semaphore
m_lock = create_sem( 1 , "buslock" );
if( m_lock < B_OK )
return;
set_sem_owner( B_SYSTEM_TEAM , m_lock );
// Clear the device map
memset( &m_devicemap , 0 , 128 );
// Set up the default pipes
m_defaultPipe = new ControlPipe( this , 0 , Pipe::Default , Pipe::NormalSpeed , 0 );
m_defaultLowSpeedPipe = new ControlPipe( this , 0 , Pipe::Default , Pipe::LowSpeed , 0 );
// Clear the 'explore thread'
m_explore_thread = 0;
fInitOK = false;
fRootHub = NULL;
m_initok = true;
// Set up the semaphore
fLock = create_sem(1, "bus manager lock");
if (fLock < B_OK)
return;
set_sem_owner(B_SYSTEM_TEAM, fLock);
// Clear the device map
for (int32 i = 0; i < 128; i++)
fDeviceMap[i] = false;
// Set up the default pipes
fDefaultPipe = new ControlPipe(this, 0, Pipe::Default, Pipe::NormalSpeed, 0);
fDefaultPipeLowSpeed = new ControlPipe(this, 0, Pipe::Default,
Pipe::LowSpeed, 0);
fExploreThread = -1;
fInitOK = true;
}
BusManager::~BusManager()
{
}
status_t BusManager::InitCheck()
status_t
BusManager::InitCheck()
{
if ( m_initok == true )
if (fInitOK)
return B_OK;
else
return B_ERROR;
return B_ERROR;
}
Device * BusManager::AllocateNewDevice( Device *parent , bool lowspeed )
/*
This is the 'main' function of the explore thread, which keeps track of
the hub states.
*/
int32
BusManager::ExploreThread(void *data)
{
int8 devicenum;
status_t retval;
usb_device_descriptor device_descriptor;
//1. Check if there is a free entry in the device map (for the device number)
devicenum = AllocateAddress();
if ( devicenum < 0 )
{
dprintf( "usb Busmanager [new device]: could not get a new address\n" );
return 0;
Hub *rootHub = (Hub *)data;
if (!rootHub)
return B_ERROR;
while (true) {
rootHub->Explore();
snooze(1000000);
}
//2. Set the address of the device USB 1.1 spec p202 (bepdf)
retval = m_defaultPipe->SendRequest( USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD , //host->device
USB_REQUEST_SET_ADDRESS , //request
devicenum , //value
0 , //index
0 , //length
NULL , //data
0 , //data_len
0 ); //actual len
if ( retval < B_OK )
{
dprintf( "usb busmanager [new device]: error with commmunicating the right address\n" );
return 0;
return B_OK;
}
Device *
BusManager::AllocateNewDevice(Device *parent, bool lowSpeed)
{
// Check if there is a free entry in the device map (for the device number)
int8 deviceNum = AllocateAddress();
if (deviceNum < 0) {
TRACE(("usb BusManager::AllocateNewDevice(): could not get a new address\n"));
return NULL;
}
//Create a temporary pipe
ControlPipe pipe( this , devicenum , Pipe::Default , Pipe::LowSpeed , 0 );
//3. Get the device descriptor
// Set the address of the device USB 1.1 spec p202
status_t result = fDefaultPipeLowSpeed->SendRequest(
USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD, // type
USB_REQUEST_SET_ADDRESS, // request
deviceNum, // value
0, // index
0, // length
NULL, // buffer
0, // buffer length
NULL); // actual length
if (result < B_OK) {
TRACE(("usb BusManager::AllocateNewDevice(): error while setting device address\n"));
return NULL;
}
// Create a temporary pipe
ControlPipe pipe(this, deviceNum, Pipe::Default, Pipe::LowSpeed, 0);
// Get the device descriptor
// Just retrieve the first 8 bytes of the descriptor -> minimum supported
// size of any device, plus it is enough, because the device type is in
// there too
size_t actual_length;
pipe.SendRequest( USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD , //Type
USB_REQUEST_GET_DESCRIPTOR , //Request
( USB_DESCRIPTOR_DEVICE << 8 ), //Value
0 , //Index
8 , //Length
(void *)&device_descriptor , //Buffer
8 , //Bufferlength
&actual_length ); //length
if ( actual_length != 8 )
{
dprintf( "usb busmanager [new device]: error while getting the device descriptor\n" );
return 0;
// there too
size_t actualLength = 0;
usb_device_descriptor deviceDescriptor;
pipe.SendRequest(
USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD, // type
USB_REQUEST_GET_DESCRIPTOR, // request
USB_DESCRIPTOR_DEVICE << 8, // value
0, // index
8, // length
(void *)&deviceDescriptor, // buffer
8, // buffer length
&actualLength); // actual length
if (actualLength != 8) {
TRACE(("usb BusManager::AllocateNewDevice(): error while getting the device descriptor\n"));
return NULL;
}
//4. Create a new instant based on the type (Hub or Device);
if ( device_descriptor.device_class == 0x09 )
{
dprintf( "usb Busmanager [new device]: New hub\n" );
Device *ret = new Hub( this , parent , device_descriptor , devicenum , lowspeed );
if ( parent == 0 ) //root hub!!
m_roothub = ret;
return 0;
// Create a new instance based on the type (Hub or Device)
if (deviceDescriptor.device_class == 0x09) {
TRACE(("usb BusManager::AllocateNewDevice(): creating new hub\n"));
Device *ret = new Hub(this, parent, deviceDescriptor, deviceNum,
lowSpeed);
if (parent == NULL) {
// root hub
fRootHub = ret;
}
return ret;
}
dprintf( "usb Busmanager [new device]: New normal device\n" );
return new Device( this , parent , device_descriptor , devicenum , lowspeed);
TRACE(("usb BusManager::AllocateNewDevice(): creating new device\n"));
return new Device(this, parent, deviceDescriptor, deviceNum, lowSpeed);
}
int8 BusManager::AllocateAddress()
int8
BusManager::AllocateAddress()
{
acquire_sem_etc( m_lock , 1 , B_CAN_INTERRUPT , 0 );
int8 devicenum = -1;
for( int i = 1 ; i < 128 ; i++ )
{
if ( m_devicemap[i] == false )
{
devicenum = i;
m_devicemap[i] = true;
acquire_sem_etc(fLock, 1, B_CAN_INTERRUPT, 0);
int8 deviceNum = -1;
for (int32 i = 1; i < 128; i++) {
if (fDeviceMap[i] == false) {
deviceNum = i;
fDeviceMap[i] = true;
break;
}
}
release_sem( m_lock );
return devicenum;
release_sem(fLock);
return deviceNum;
}
status_t BusManager::Start()
status_t
BusManager::Start()
{
dprintf( "USB: BusManager::Start()\n" );
if ( InitCheck() != B_OK )
TRACE(("usb BusManager::Start()\n"));
if (InitCheck() != B_OK)
return InitCheck();
if ( m_explore_thread == 0 )
m_explore_thread = spawn_kernel_thread( usb_explore_thread , "usb_busmanager_explore" ,
B_LOW_PRIORITY , (void *)m_roothub );
// Start the 'explore thread'
return resume_thread( m_explore_thread );
if (fExploreThread < 0) {
fExploreThread = spawn_kernel_thread(ExploreThread,
"usb busmanager explore", B_LOW_PRIORITY, (void *)fRootHub);
}
return resume_thread(fExploreThread);
}
status_t BusManager::SubmitTransfer( Transfer *t )
status_t
BusManager::Stop()
{
// ToDo: implement (should end the explore thread)
return B_OK;
}
status_t
BusManager::SubmitTransfer(Transfer *transfer)
{
// virtual function to be overridden
return B_ERROR;
};
}

View File

@ -128,37 +128,42 @@ private:
* after a host controller gives positive feedback on whether the hardware
* is found.
*/
class BusManager
{
friend class Device;
friend class ControlPipe;
class BusManager {
public:
BusManager();
virtual ~BusManager();
virtual status_t InitCheck();
Device *AllocateNewDevice( Device *parent , bool speed );
int8 AllocateAddress();
virtual status_t Start();
// virtual status_t Stop();
virtual status_t SubmitTransfer( Transfer *t );
protected:
void SetRootHub( Hub *hub ) { m_roothub = hub; };
Device* GetRootHub() { return m_roothub; };
bool m_initok;
private:
bool m_devicemap[128];
ControlPipe *m_defaultLowSpeedPipe;
ControlPipe *m_defaultPipe;
sem_id m_lock;
Device *m_roothub;
thread_id m_explore_thread;
};
BusManager();
virtual ~BusManager();
// Located in the BusManager.cpp
int32 usb_explore_thread( void *data );
virtual status_t InitCheck();
Device *AllocateNewDevice(Device *parent,
bool lowSpeed);
int8 AllocateAddress();
virtual status_t Start();
virtual status_t Stop();
virtual status_t SubmitTransfer(Transfer *transfer);
protected:
void SetRootHub(Hub *hub) { fRootHub = hub; };
Device *GetRootHub() { return fRootHub; };
bool fInitOK;
private:
friend class Device;
friend class ControlPipe;
static int32 ExploreThread(void *data);
sem_id fLock;
bool fDeviceMap[128];
ControlPipe *fDefaultPipe;
ControlPipe *fDefaultPipeLowSpeed;
Device *fRootHub;
thread_id fExploreThread;
};
/*
* The Pipe class is the communication management between the hardware and\

View File

@ -99,7 +99,7 @@ UHCI::UHCI(pci_info *info, Stack *stack)
GlobalReset();
if (Reset() < B_OK) {
TRACE(("usb_uhci: host failed to reset\n"));
m_initok = false;
fInitOK = false;
return;
}
@ -110,7 +110,7 @@ UHCI::UHCI(pci_info *info, Stack *stack)
if (fFrameArea < B_OK) {
TRACE(("usb_uhci: unable to create an area for the frame pointer list\n"));
m_initok = false;
fInitOK = false;
return;
}
@ -126,7 +126,7 @@ UHCI::UHCI(pci_info *info, Stack *stack)
if (fStack->AllocateChunk((void **)&strayDescriptor, &physicalAddress, 32) != B_OK) {
TRACE(("usb_uhci: failed to allocate a stray transfer descriptor\n"));
delete_area(fFrameArea);
m_initok = false;
fInitOK = false;
return;
}
@ -151,7 +151,7 @@ UHCI::UHCI(pci_info *info, Stack *stack)
&physicalAddress, 32) != B_OK) {
TRACE(("usb_uhci: failed allocation of skeleton queue head %i, aborting\n", i));
delete_area(fFrameArea);
m_initok = false;
fInitOK = false;
return;
}
@ -246,22 +246,13 @@ UHCI::Start()
return B_ERROR;
}
TRACE(("usb_uhci: controller is started. status: %u curframe: %u\n",
ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM)));
return BusManager::Start();
}
status_t
UHCI::SetupRootHub()
{
TRACE(("usb_uhci: setting up root hub\n"));
fRootHubAddress = AllocateAddress();
fRootHub = new UHCIRootHub(this, fRootHubAddress);
SetRootHub(fRootHub);
return B_OK;
TRACE(("usb_uhci: controller is started. status: %u curframe: %u\n",
ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM)));
return BusManager::Start();
}
@ -377,10 +368,6 @@ UHCI::InsertControl(Transfer *transfer)
TRACE(("usb_uhci: InsertControl() frnum %u, usbsts reg %u\n",
ReadReg16(UHCI_FRNUM), ReadReg16(UHCI_USBSTS)));
// HACK: this one is to prevent rogue transfers from happening
if (!transfer->GetBuffer())
return B_ERROR;
// Please note that any data structures must be aligned on a 16 byte boundary
// Also, due to the strange ways of C++' void* handling, this code is much messier
// than it actually should be. Forgive me. Or blame the compiler.
@ -423,7 +410,8 @@ UHCI::InsertControl(Transfer *transfer)
return ENOMEM;
}
memcpy(transferDescriptor->buffer_log, transfer->GetRequestData(), sizeof(usb_request_data));
memcpy(transferDescriptor->buffer_log, transfer->GetRequestData(),
sizeof(usb_request_data));
// Link this to the queue head
topQueueHead->element_phy = transferDescriptor->this_phy;
@ -470,11 +458,11 @@ UHCI::InsertControl(Transfer *transfer)
transfer->GetHostPrivate()->lasttd = statusDescriptor;
fTransfers.PushBack(transfer);
// Secondly, append the qh to the control list
// Secondly, append the queue head to the control list
if (fQueueHeadControl->element_phy & QH_TERMINATE) {
// the control queue is empty, make this the first element
fQueueHeadControl->element_phy = topQueueHead->this_phy;
fQueueHeadControl->link_log = (void *)topQueueHead;
fQueueHeadControl->link_log = topQueueHead;
TRACE(("usb_uhci: first transfer in queue\n"));
} else {
// there are control transfers linked, append to the queue
@ -483,7 +471,7 @@ UHCI::InsertControl(Transfer *transfer)
queueHead = (uhci_qh *)queueHead->link_log;
queueHead->link_phy = topQueueHead->this_phy;
queueHead->link_log = (void *)topQueueHead;
queueHead->link_log = topQueueHead;
TRACE(("usb_uhci: appended transfer to queue\n"));
}
@ -510,7 +498,6 @@ UHCI::AddTo(Stack &stack)
TRACE(("usb_uhci: AddTo(): setting up hardware\n"));
// TODO: in the future we might want to support multiple host controllers.
bool found = false;
pci_info *item = new pci_info;
for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) {
@ -532,10 +519,8 @@ UHCI::AddTo(Stack &stack)
}
bus->Start();
bus->SetupRootHub();
stack.AddBusManager(bus);
found = true;
break;
}
}

View File

@ -22,7 +22,6 @@ public:
UHCI(pci_info *info, Stack *stack);
status_t Start();
status_t SetupRootHub();
status_t SubmitTransfer(Transfer *transfer);
static bool AddTo(Stack &stack);

View File

@ -77,7 +77,7 @@ usb_hub_descriptor uhci_hubd =
{
0x09, //Including deprecated powerctrlmask
USB_DESCRIPTOR_HUB,
1, //Number of ports
2, //Number of ports
0x02 | 0x01, //Hub characteristics FIXME
50, //Power on to power good
0, // Current
@ -228,25 +228,25 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
void
UHCIRootHub::UpdatePortStatus()
{
for (int32 i = 0; i < 2; i++) {
for (int32 i = 0; i < uhci_hubd.bNbrPorts; 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));
TRACE(("usb_uhci_roothub: port: %d status: 0x%04x\n", i, portStatus));
// Set all individual bits
if (portStatus & UHCI_PORTSC_CURSTAT)
newStatus |= PORT_STATUS_CONNECTION;
if (portStatus & UHCI_PORTSC_STATCHA)
newStatus |= PORT_STATUS_CONNECTION;
newChange |= PORT_STATUS_CONNECTION;
if (portStatus & UHCI_PORTSC_ENABLED)
newStatus |= PORT_STATUS_ENABLE;
if (portStatus & UHCI_PORTSC_ENABCHA)
newStatus |= PORT_STATUS_ENABLE;
newChange |= PORT_STATUS_ENABLE;
// TODO: work out suspended/resume