/* * Copyright 2003-2006, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Michael Lotz * 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; // Clear the device map for (int32 i = 0; i < 128; i++) fDeviceMap[i] = false; fDeviceIndex = 0; // Set the default pipes to NULL (these will be created when needed) 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) { // Check if there is a free entry in the device map (for the device number) 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++) { // Set the address of the device USB 1.1 spec p202 result = defaultPipe->SendRequest( USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT, // type USB_REQUEST_SET_ADDRESS, // request deviceAddress, // value 0, // index 0, // length NULL, // buffer 0, // buffer length NULL); // actual length 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; } // Wait a bit for the device to complete addressing snooze(USB_DELAY_SET_ADDRESS); // Create a temporary pipe with the new address ControlPipe pipe(fRootObject); pipe.InitCommon(deviceAddress, 0, speed, Pipe::Default, 8, 0, hubAddress, hubPort); // Get the device descriptor // Just retrieve the first 8 bytes of the descriptor -> minimum supported // size of any device. It is enough because it includes the device type. size_t actualLength = 0; usb_device_descriptor deviceDescriptor; TRACE("getting the device descriptor\n"); 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_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); // Create a new instance based on the type (Hub or Device) 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) { // virtual function to be overridden return B_UNSUPPORTED; } status_t BusManager::CheckDebugTransfer(Transfer *transfer) { // virtual function to be overridden return B_UNSUPPORTED; } void BusManager::CancelDebugTransfer(Transfer *transfer) { // virtual function to be overridden } status_t BusManager::SubmitTransfer(Transfer *transfer) { // virtual function to be overridden return B_ERROR; } status_t BusManager::CancelQueuedTransfers(Pipe *pipe, bool force) { // virtual function to be overridden return B_ERROR; } status_t BusManager::NotifyPipeChange(Pipe *pipe, usb_change change) { // virtual function to be overridden 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]; }