* Copyright 2003-2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
* Niels S. Reedijk
*/
#include "usb_private.h"
BusManager::BusManager(Stack *stack, device_node* node)
: fInitOK(false),
fStack(stack),
fRootHub(NULL),
fStackIndex((uint32)-1),
fNode(node)
{
mutex_init(&fLock, "usb busmanager lock");
fRootObject = new(std::nothrow) Object(stack, this);
if (!fRootObject)
return;
for (int32 i = 0; i < 128; i++)
fDeviceMap[i] = false;
fDeviceIndex = 0;
for (int32 i = 0; i <= USB_SPEED_MAX; i++)
fDefaultPipes[i] = NULL;
fInitOK = true;
}
BusManager::~BusManager()
{
Lock();
mutex_destroy(&fLock);
for (int32 i = 0; i <= USB_SPEED_MAX; i++)
delete fDefaultPipes[i];
delete fRootObject;
}
status_t
BusManager::InitCheck()
{
if (fInitOK)
return B_OK;
return B_ERROR;
}
bool
BusManager::Lock()
{
return (mutex_lock(&fLock) == B_OK);
}
void
BusManager::Unlock()
{
mutex_unlock(&fLock);
}
int8
BusManager::AllocateAddress()
{
if (!Lock())
return -1;
int8 tries = 127;
int8 address = fDeviceIndex;
while (tries-- > 0) {
if (fDeviceMap[address] == false) {
fDeviceIndex = (address + 1) % 127;
fDeviceMap[address] = true;
Unlock();
return address + 1;
}
address = (address + 1) % 127;
}
TRACE_ERROR("the busmanager has run out of device addresses\n");
Unlock();
return -1;
}
void
BusManager::FreeAddress(int8 address)
{
address--;
if (address < 0)
return;
if (!Lock())
return;
if (!fDeviceMap[address]) {
TRACE_ERROR("freeing address %d which was not allocated\n", address);
}
fDeviceMap[address] = false;
Unlock();
}
Device *
BusManager::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
usb_speed speed)
{
int8 deviceAddress = AllocateAddress();
if (deviceAddress < 0) {
TRACE_ERROR("could not allocate an address\n");
return NULL;
}
TRACE("setting device address to %d\n", deviceAddress);
ControlPipe *defaultPipe = _GetDefaultPipe(speed);
if (!defaultPipe) {
TRACE_ERROR("error getting the default pipe for speed %d\n", speed);
FreeAddress(deviceAddress);
return NULL;
}
defaultPipe->SetHubInfo(hubAddress, hubPort);
status_t result = B_ERROR;
for (int32 i = 0; i < 3; i++) {
result = defaultPipe->SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
USB_REQUEST_SET_ADDRESS,
deviceAddress,
0,
0,
NULL,
0,
NULL);
if (result >= B_OK)
break;
snooze(USB_DELAY_SET_ADDRESS_RETRY);
}
if (result < B_OK) {
TRACE_ERROR("error while setting device address\n");
FreeAddress(deviceAddress);
return NULL;
}
snooze(USB_DELAY_SET_ADDRESS);
ControlPipe pipe(fRootObject);
pipe.InitCommon(deviceAddress, 0, speed, Pipe::Default, 8, 0, hubAddress,
hubPort);
size_t actualLength = 0;
usb_device_descriptor deviceDescriptor;
TRACE("getting the device descriptor\n");
pipe.SendRequest(
USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD,
USB_REQUEST_GET_DESCRIPTOR,
USB_DESCRIPTOR_DEVICE << 8,
0,
8,
(void *)&deviceDescriptor,
8,
&actualLength);
if (actualLength != 8) {
TRACE_ERROR("error while getting the device descriptor\n");
FreeAddress(deviceAddress);
return NULL;
}
TRACE("short device descriptor for device %d:\n", deviceAddress);
TRACE("\tlength:..............%d\n", deviceDescriptor.length);
TRACE("\tdescriptor_type:.....0x%04x\n", deviceDescriptor.descriptor_type);
TRACE("\tusb_version:.........0x%04x\n", deviceDescriptor.usb_version);
TRACE("\tdevice_class:........0x%02x\n", deviceDescriptor.device_class);
TRACE("\tdevice_subclass:.....0x%02x\n", deviceDescriptor.device_subclass);
TRACE("\tdevice_protocol:.....0x%02x\n", deviceDescriptor.device_protocol);
TRACE("\tmax_packet_size_0:...%d\n", deviceDescriptor.max_packet_size_0);
if (deviceDescriptor.device_class == 0x09) {
TRACE("creating new hub\n");
Hub *hub = new(std::nothrow) Hub(parent, hubAddress, hubPort,
deviceDescriptor, deviceAddress, speed, false);
if (!hub) {
TRACE_ERROR("no memory to allocate hub\n");
FreeAddress(deviceAddress);
return NULL;
}
if (hub->InitCheck() < B_OK) {
TRACE_ERROR("hub failed init check\n");
FreeAddress(deviceAddress);
delete hub;
return NULL;
}
hub->RegisterNode();
return (Device *)hub;
}
TRACE("creating new device\n");
Device *device = new(std::nothrow) Device(parent, hubAddress, hubPort,
deviceDescriptor, deviceAddress, speed, false);
if (!device) {
TRACE_ERROR("no memory to allocate device\n");
FreeAddress(deviceAddress);
return NULL;
}
if (device->InitCheck() < B_OK) {
TRACE_ERROR("device failed init check\n");
FreeAddress(deviceAddress);
delete device;
return NULL;
}
device->RegisterNode();
return device;
}
void
BusManager::FreeDevice(Device *device)
{
FreeAddress(device->DeviceAddress());
delete device;
}
status_t
BusManager::Start()
{
fStack->AddBusManager(this);
fStackIndex = fStack->IndexOfBusManager(this);
fStack->Explore();
return B_OK;
}
status_t
BusManager::Stop()
{
return B_OK;
}
status_t
BusManager::StartDebugTransfer(Transfer *transfer)
{
return B_UNSUPPORTED;
}
status_t
BusManager::CheckDebugTransfer(Transfer *transfer)
{
return B_UNSUPPORTED;
}
void
BusManager::CancelDebugTransfer(Transfer *transfer)
{
}
status_t
BusManager::SubmitTransfer(Transfer *transfer)
{
return B_ERROR;
}
status_t
BusManager::CancelQueuedTransfers(Pipe *pipe, bool force)
{
return B_ERROR;
}
status_t
BusManager::NotifyPipeChange(Pipe *pipe, usb_change change)
{
return B_ERROR;
}
ControlPipe *
BusManager::_GetDefaultPipe(usb_speed speed)
{
if (!Lock())
return NULL;
if (fDefaultPipes[speed] == NULL) {
fDefaultPipes[speed] = new(std::nothrow) ControlPipe(fRootObject);
fDefaultPipes[speed]->InitCommon(0, 0, speed, Pipe::Default, 8, 0, 0, 0);
}
if (!fDefaultPipes[speed]) {
TRACE_ERROR("failed to allocate default pipe for speed %d\n", speed);
}
Unlock();
return fDefaultPipes[speed];
}