* 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 * Copyright 2003-2006, Haiku Inc. All rights reserved.
// * Distributed under the terms of the MIT License.
// Permission is hereby granted, free of charge, to any person obtaining a *
// copy of this software and associated documentation files (the "Software"), * Authors:
// to deal in the Software without restriction, including without limitation * Niels S. Reedijk
// the rights to use, copy, modify, merge, publish, distribute, sublicense, */
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#include "usb_p.h" #include "usb_p.h"
/* +++++++++ #define TRACE_BUSMANAGER
This is the 'main' function of the explore thread, which keeps track of #ifdef TRACE_BUSMANAGER
the hub statuses. #define TRACE(x) dprintf(x)
+++++++++ */ #else
int32 usb_explore_thread( void *data ) #define TRACE(x) /* nothing */
{ #endif
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;
}
BusManager::BusManager() BusManager::BusManager()
{ {
m_initok = false; fInitOK = false;
m_roothub = 0; fRootHub = NULL;
// 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;
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() BusManager::~BusManager()
{ {
} }
status_t BusManager::InitCheck()
status_t
BusManager::InitCheck()
{ {
if ( m_initok == true ) if (fInitOK)
return B_OK; 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; Hub *rootHub = (Hub *)data;
status_t retval; if (!rootHub)
usb_device_descriptor device_descriptor; return B_ERROR;
//1. Check if there is a free entry in the device map (for the device number) while (true) {
devicenum = AllocateAddress(); rootHub->Explore();
if ( devicenum < 0 ) snooze(1000000);
{
dprintf( "usb Busmanager [new device]: could not get a new address\n" );
return 0;
} }
return B_OK;
//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 Device *
0 , //index BusManager::AllocateNewDevice(Device *parent, bool lowSpeed)
0 , //length {
NULL , //data // Check if there is a free entry in the device map (for the device number)
0 , //data_len int8 deviceNum = AllocateAddress();
0 ); //actual len if (deviceNum < 0) {
TRACE(("usb BusManager::AllocateNewDevice(): could not get a new address\n"));
if ( retval < B_OK ) return NULL;
{
dprintf( "usb busmanager [new device]: error with commmunicating the right address\n" );
return 0;
} }
//Create a temporary pipe // Set the address of the device USB 1.1 spec p202
ControlPipe pipe( this , devicenum , Pipe::Default , Pipe::LowSpeed , 0 ); status_t result = fDefaultPipeLowSpeed->SendRequest(
USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD, // type
//3. Get the device descriptor 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 // 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 // size of any device, plus it is enough, because the device type is in
// there too // there too
size_t actual_length; size_t actualLength = 0;
usb_device_descriptor deviceDescriptor;
pipe.SendRequest( USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD , //Type
USB_REQUEST_GET_DESCRIPTOR , //Request pipe.SendRequest(
( USB_DESCRIPTOR_DEVICE << 8 ), //Value USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD, // type
0 , //Index USB_REQUEST_GET_DESCRIPTOR, // request
8 , //Length USB_DESCRIPTOR_DEVICE << 8, // value
(void *)&device_descriptor , //Buffer 0, // index
8 , //Bufferlength 8, // length
&actual_length ); //length (void *)&deviceDescriptor, // buffer
8, // buffer length
if ( actual_length != 8 ) &actualLength); // actual length
{
dprintf( "usb busmanager [new device]: error while getting the device descriptor\n" ); if (actualLength != 8) {
return 0; 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); // Create a new instance based on the type (Hub or Device)
if ( device_descriptor.device_class == 0x09 ) if (deviceDescriptor.device_class == 0x09) {
{ TRACE(("usb BusManager::AllocateNewDevice(): creating new hub\n"));
dprintf( "usb Busmanager [new device]: New hub\n" ); Device *ret = new Hub(this, parent, deviceDescriptor, deviceNum,
Device *ret = new Hub( this , parent , device_descriptor , devicenum , lowspeed ); lowSpeed);
if ( parent == 0 ) //root hub!!
m_roothub = ret; if (parent == NULL) {
return 0; // root hub
fRootHub = ret;
}
return ret;
} }
dprintf( "usb Busmanager [new device]: New normal device\n" ); TRACE(("usb BusManager::AllocateNewDevice(): creating new device\n"));
return new Device( this , parent , device_descriptor , devicenum , lowspeed); return new Device(this, parent, deviceDescriptor, deviceNum, lowSpeed);
} }
int8 BusManager::AllocateAddress()
int8
BusManager::AllocateAddress()
{ {
acquire_sem_etc( m_lock , 1 , B_CAN_INTERRUPT , 0 ); acquire_sem_etc(fLock, 1, B_CAN_INTERRUPT, 0);
int8 devicenum = -1;
for( int i = 1 ; i < 128 ; i++ ) int8 deviceNum = -1;
{ for (int32 i = 1; i < 128; i++) {
if ( m_devicemap[i] == false ) if (fDeviceMap[i] == false) {
{ deviceNum = i;
devicenum = i; fDeviceMap[i] = true;
m_devicemap[i] = true;
break; 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" ); TRACE(("usb BusManager::Start()\n"));
if ( InitCheck() != B_OK ) if (InitCheck() != B_OK)
return InitCheck(); return InitCheck();
if ( m_explore_thread == 0 ) if (fExploreThread < 0) {
m_explore_thread = spawn_kernel_thread( usb_explore_thread , "usb_busmanager_explore" , fExploreThread = spawn_kernel_thread(ExploreThread,
B_LOW_PRIORITY , (void *)m_roothub ); "usb busmanager explore", B_LOW_PRIORITY, (void *)fRootHub);
}
// Start the 'explore thread'
return resume_thread( m_explore_thread ); 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; return B_ERROR;
}; }

View File

@ -128,37 +128,42 @@ private:
* after a host controller gives positive feedback on whether the hardware * after a host controller gives positive feedback on whether the hardware
* is found. * is found.
*/ */
class BusManager class BusManager {
{
friend class Device;
friend class ControlPipe;
public: public:
BusManager(); BusManager();
virtual ~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;
};
// Located in the BusManager.cpp virtual status_t InitCheck();
int32 usb_explore_thread( void *data );
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\ * 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(); GlobalReset();
if (Reset() < B_OK) { if (Reset() < B_OK) {
TRACE(("usb_uhci: host failed to reset\n")); TRACE(("usb_uhci: host failed to reset\n"));
m_initok = false; fInitOK = false;
return; return;
} }
@ -110,7 +110,7 @@ UHCI::UHCI(pci_info *info, Stack *stack)
if (fFrameArea < B_OK) { if (fFrameArea < B_OK) {
TRACE(("usb_uhci: unable to create an area for the frame pointer list\n")); TRACE(("usb_uhci: unable to create an area for the frame pointer list\n"));
m_initok = false; fInitOK = false;
return; return;
} }
@ -126,7 +126,7 @@ UHCI::UHCI(pci_info *info, Stack *stack)
if (fStack->AllocateChunk((void **)&strayDescriptor, &physicalAddress, 32) != B_OK) { if (fStack->AllocateChunk((void **)&strayDescriptor, &physicalAddress, 32) != B_OK) {
TRACE(("usb_uhci: failed to allocate a stray transfer descriptor\n")); TRACE(("usb_uhci: failed to allocate a stray transfer descriptor\n"));
delete_area(fFrameArea); delete_area(fFrameArea);
m_initok = false; fInitOK = false;
return; return;
} }
@ -151,7 +151,7 @@ UHCI::UHCI(pci_info *info, Stack *stack)
&physicalAddress, 32) != B_OK) { &physicalAddress, 32) != B_OK) {
TRACE(("usb_uhci: failed allocation of skeleton queue head %i, aborting\n", i)); TRACE(("usb_uhci: failed allocation of skeleton queue head %i, aborting\n", i));
delete_area(fFrameArea); delete_area(fFrameArea);
m_initok = false; fInitOK = false;
return; return;
} }
@ -246,22 +246,13 @@ UHCI::Start()
return B_ERROR; 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(); fRootHubAddress = AllocateAddress();
fRootHub = new UHCIRootHub(this, fRootHubAddress); fRootHub = new UHCIRootHub(this, fRootHubAddress);
SetRootHub(fRootHub); 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", TRACE(("usb_uhci: InsertControl() frnum %u, usbsts reg %u\n",
ReadReg16(UHCI_FRNUM), ReadReg16(UHCI_USBSTS))); 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 // 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 // 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. // than it actually should be. Forgive me. Or blame the compiler.
@ -423,7 +410,8 @@ UHCI::InsertControl(Transfer *transfer)
return ENOMEM; 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 // Link this to the queue head
topQueueHead->element_phy = transferDescriptor->this_phy; topQueueHead->element_phy = transferDescriptor->this_phy;
@ -470,11 +458,11 @@ UHCI::InsertControl(Transfer *transfer)
transfer->GetHostPrivate()->lasttd = statusDescriptor; transfer->GetHostPrivate()->lasttd = statusDescriptor;
fTransfers.PushBack(transfer); 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) { if (fQueueHeadControl->element_phy & QH_TERMINATE) {
// the control queue is empty, make this the first element // the control queue is empty, make this the first element
fQueueHeadControl->element_phy = topQueueHead->this_phy; fQueueHeadControl->element_phy = topQueueHead->this_phy;
fQueueHeadControl->link_log = (void *)topQueueHead; fQueueHeadControl->link_log = topQueueHead;
TRACE(("usb_uhci: first transfer in queue\n")); TRACE(("usb_uhci: first transfer in queue\n"));
} else { } else {
// there are control transfers linked, append to the queue // there are control transfers linked, append to the queue
@ -483,7 +471,7 @@ UHCI::InsertControl(Transfer *transfer)
queueHead = (uhci_qh *)queueHead->link_log; queueHead = (uhci_qh *)queueHead->link_log;
queueHead->link_phy = topQueueHead->this_phy; queueHead->link_phy = topQueueHead->this_phy;
queueHead->link_log = (void *)topQueueHead; queueHead->link_log = topQueueHead;
TRACE(("usb_uhci: appended transfer to queue\n")); TRACE(("usb_uhci: appended transfer to queue\n"));
} }
@ -510,7 +498,6 @@ UHCI::AddTo(Stack &stack)
TRACE(("usb_uhci: AddTo(): setting up hardware\n")); TRACE(("usb_uhci: AddTo(): setting up hardware\n"));
// TODO: in the future we might want to support multiple host controllers.
bool found = false; bool found = false;
pci_info *item = new pci_info; pci_info *item = new pci_info;
for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) { 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->Start();
bus->SetupRootHub();
stack.AddBusManager(bus); stack.AddBusManager(bus);
found = true; found = true;
break;
} }
} }

View File

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

View File

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