* Implemented most of the USB module public API (using opaque handles like in R5 will change that to using IDs later)

* Fixed the UHCI root hub and the hub implementation. Interface and endpoint descriptors are part of the configuration descriptor, they cannot be requested individually.
* Added simple support for interrupt and bulk transfers to UHCI. It's enough to get my USB mouse working to a stable and usable degree.
* Cleaned up and reworked some other parts, added allocation checks and such.

Yes, my internet connection is back up :)

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18496 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2006-08-12 12:49:45 +00:00
parent 852c3506f5
commit b8c6a85136
13 changed files with 1628 additions and 446 deletions

View File

@ -35,10 +35,13 @@ BusManager::BusManager()
fDeviceMap[i] = false;
// Set up the default pipes
fDefaultPipe = new ControlPipe(this, 0, Pipe::Default, Pipe::NormalSpeed,
0, 8);
fDefaultPipeLowSpeed = new ControlPipe(this, 0, Pipe::Default,
Pipe::LowSpeed, 0, 8);
fDefaultPipe = new(std::nothrow) ControlPipe(this, 0, Pipe::NormalSpeed, 0, 8);
if (!fDefaultPipe)
return;
fDefaultPipeLowSpeed = new(std::nothrow) ControlPipe(this, 0, Pipe::LowSpeed, 0, 8);
if (!fDefaultPipeLowSpeed)
return;
fExploreThread = -1;
fInitOK = true;
@ -97,7 +100,7 @@ BusManager::AllocateNewDevice(Device *parent, bool lowSpeed)
// Set the address of the device USB 1.1 spec p202
status_t result = defaultPipe->SendRequest(
USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD, // type
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT, // type
USB_REQUEST_SET_ADDRESS, // request
deviceAddress, // value
0, // index
@ -115,7 +118,7 @@ BusManager::AllocateNewDevice(Device *parent, bool lowSpeed)
snooze(10000);
// Create a temporary pipe with the new address
ControlPipe pipe(this, deviceAddress, Pipe::Default,
ControlPipe pipe(this, deviceAddress,
lowSpeed ? Pipe::LowSpeed : Pipe::NormalSpeed, 0, 8);
// Get the device descriptor
@ -153,19 +156,42 @@ BusManager::AllocateNewDevice(Device *parent, bool lowSpeed)
// 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, deviceAddress,
lowSpeed);
Hub *hub = new(std::nothrow) Hub(this, parent, deviceDescriptor,
deviceAddress, lowSpeed);
if (!hub) {
TRACE(("usb BusManager::AllocateNewDevice(): no memory to allocate hub\n"));
return NULL;
}
if (hub->InitCheck() < B_OK) {
TRACE(("usb BusManager::AllocateNewDevice(): hub failed init check\n"));
delete hub;
return NULL;
}
if (parent == NULL) {
// root hub
fRootHub = ret;
fRootHub = hub;
}
return ret;
return (Device *)hub;
}
TRACE(("usb BusManager::AllocateNewDevice(): creating new device\n"));
return new Device(this, parent, deviceDescriptor, deviceAddress, lowSpeed);
Device *device = new(std::nothrow) Device(this, parent, deviceDescriptor,
deviceAddress, lowSpeed);
if (!device) {
TRACE(("usb BusManager::AllocateNewDevice(): no memory to allocate device\n"));
return NULL;
}
if (device->InitCheck() < B_OK) {
TRACE(("usb BusManager::AllocateNewDevice(): device failed init check\n"));
delete device;
return NULL;
}
return device;
}

View File

@ -19,13 +19,20 @@
Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
int8 deviceAddress, bool lowSpeed)
: ControlPipe(bus, deviceAddress,
lowSpeed ? Pipe::LowSpeed : Pipe::NormalSpeed, 0,
desc.max_packet_size_0),
fDeviceDescriptor(desc),
fConfigurations(NULL),
fCurrentConfiguration(NULL),
fInitOK(false),
fLowSpeed(lowSpeed),
fBus(bus),
fParent(parent),
fDeviceAddress(deviceAddress),
fLock(-1),
fNotifyCookie(NULL)
{
fBus = bus;
fParent = parent;
fInitOK = false;
fCurrentConfiguration = NULL;
fDeviceAddress = deviceAddress;
TRACE(("USB Device: new device\n"));
fLock = create_sem(1, "USB Device Lock");
@ -36,18 +43,15 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
set_sem_owner(fLock, B_SYSTEM_TEAM);
fLowSpeed = lowSpeed;
fDeviceDescriptor = desc;
fMaxPacketIn[0] = fMaxPacketOut[0] = fDeviceDescriptor.max_packet_size_0;
fDefaultPipe = new ControlPipe(this, Pipe::Default,
lowSpeed ? Pipe::LowSpeed : Pipe::NormalSpeed, 0, fMaxPacketIn[0]);
// Get the device descriptor
// We already have a part of it, but we want it all
status_t status = GetDescriptor(USB_DESCRIPTOR_DEVICE, 0,
(void *)&fDeviceDescriptor, sizeof(fDeviceDescriptor));
size_t actualLength;
status_t status = GetDescriptor(USB_DESCRIPTOR_DEVICE, 0, 0,
(void *)&fDeviceDescriptor, sizeof(fDeviceDescriptor), &actualLength);
if (status != sizeof(fDeviceDescriptor)) {
if (status < B_OK || actualLength != sizeof(fDeviceDescriptor)) {
TRACE(("USB Device: error while getting the device descriptor\n"));
return;
}
@ -69,28 +73,190 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
TRACE(("\tnum_configurations:..%d\n", fDeviceDescriptor.num_configurations));
// Get the configurations
fConfigurations = (usb_configuration_descriptor *)malloc(fDeviceDescriptor.num_configurations
* sizeof(usb_configuration_descriptor));
fConfigurations = (usb_configuration_info *)malloc(
fDeviceDescriptor.num_configurations * sizeof(usb_configuration_info));
if (fConfigurations == NULL) {
TRACE(("USB Device: out of memory during config creations!\n"));
return;
}
for (int32 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
size_t size = GetDescriptor(USB_DESCRIPTOR_CONFIGURATION, i,
(void *)&fConfigurations[i], sizeof(usb_configuration_descriptor));
usb_configuration_descriptor configDescriptor;
status = GetDescriptor(USB_DESCRIPTOR_CONFIGURATION, i, 0,
(void *)&configDescriptor, sizeof(usb_configuration_descriptor),
&actualLength);
if (size != sizeof(usb_configuration_descriptor)) {
if (status < B_OK || actualLength != sizeof(usb_configuration_descriptor)) {
TRACE(("USB Device %d: error fetching configuration %d\n", fDeviceAddress, i));
return;
}
TRACE(("USB Device %d: configuration %d\n", fDeviceAddress, i));
TRACE(("\tlength:..............%d\n", configDescriptor.length));
TRACE(("\tdescriptor_type:.....0x%02x\n", configDescriptor.descriptor_type));
TRACE(("\ttotal_length:........%d\n", configDescriptor.total_length));
TRACE(("\tnumber_interfaces:...%d\n", configDescriptor.number_interfaces));
TRACE(("\tconfiguration_value:.0x%02x\n", configDescriptor.configuration_value));
TRACE(("\tconfiguration:.......0x%02x\n", configDescriptor.configuration));
TRACE(("\tattributes:..........0x%02x\n", configDescriptor.attributes));
TRACE(("\tmax_power:...........%d\n", configDescriptor.max_power));
uint8 *configData = (uint8 *)malloc(configDescriptor.total_length);
status = GetDescriptor(USB_DESCRIPTOR_CONFIGURATION, i, 0,
(void *)configData, configDescriptor.total_length, &actualLength);
if (status < B_OK || actualLength != configDescriptor.total_length) {
TRACE(("USB Device %d: error fetching full configuration descriptor %d\n", fDeviceAddress, i));
return;
}
usb_configuration_descriptor *configuration = (usb_configuration_descriptor *)configData;
fConfigurations[i].descr = configuration;
fConfigurations[i].interface_count = configuration->number_interfaces;
fConfigurations[i].interface = (usb_interface_list *)malloc(
configuration->number_interfaces * sizeof(usb_interface_list));
memset(fConfigurations[i].interface, 0,
configuration->number_interfaces * sizeof(usb_interface_list));
usb_interface_info *currentInterface = NULL;
uint32 descriptorStart = sizeof(usb_configuration_descriptor);
while (descriptorStart < actualLength) {
switch (configData[descriptorStart + 1]) {
case USB_DESCRIPTOR_INTERFACE: {
TRACE(("USB Device %d: got interface descriptor\n", fDeviceAddress));
usb_interface_descriptor *interfaceDescriptor = (usb_interface_descriptor *)&configData[descriptorStart];
TRACE(("\tlength:.............%d\n", interfaceDescriptor->length));
TRACE(("\tdescriptor_type:....0x%02x\n", interfaceDescriptor->descriptor_type));
TRACE(("\tinterface_number:...%d\n", interfaceDescriptor->interface_number));
TRACE(("\talternate_setting:..%d\n", interfaceDescriptor->alternate_setting));
TRACE(("\tnum_endpoints:......%d\n", interfaceDescriptor->num_endpoints));
TRACE(("\tinterface_class:....0x%02x\n", interfaceDescriptor->interface_class));
TRACE(("\tinterface_subclass:.0x%02x\n", interfaceDescriptor->interface_subclass));
TRACE(("\tinterface_protocol:.0x%02x\n", interfaceDescriptor->interface_protocol));
TRACE(("\tinterface:..........%d\n", interfaceDescriptor->interface));
usb_interface_list *interfaceList =
&fConfigurations[i].interface[interfaceDescriptor->interface_number];
/* allocate this alternate */
interfaceList->alt_count++;
interfaceList->alt = (usb_interface_info *)realloc(
interfaceList->alt, interfaceList->alt_count
* sizeof(usb_interface_info));
interfaceList->active = interfaceList->alt;
/* setup this alternate */
usb_interface_info *interfaceInfo =
&interfaceList->alt[interfaceList->alt_count - 1];
interfaceInfo->descr = interfaceDescriptor;
interfaceInfo->endpoint_count = 0;
interfaceInfo->endpoint = NULL;
interfaceInfo->generic_count = 0;
interfaceInfo->generic = NULL;
Interface *interface = new(std::nothrow) Interface(this);
interfaceInfo->handle = (usb_interface *)interface;
currentInterface = interfaceInfo;
break;
}
case USB_DESCRIPTOR_ENDPOINT: {
TRACE(("USB Device %d: got endpoint descriptor\n", fDeviceAddress));
usb_endpoint_descriptor *endpointDescriptor = (usb_endpoint_descriptor *)&configData[descriptorStart];
TRACE(("\tlength:.............%d\n", endpointDescriptor->length));
TRACE(("\tdescriptor_type:....0x%02x\n", endpointDescriptor->descriptor_type));
TRACE(("\tendpoint_address:...0x%02x\n", endpointDescriptor->endpoint_address));
TRACE(("\tattributes:.........0x%02x\n", endpointDescriptor->attributes));
TRACE(("\tmax_packet_size:....%d\n", endpointDescriptor->max_packet_size));
TRACE(("\tinterval:...........%d\n", endpointDescriptor->interval));
if (!currentInterface)
break;
/* allocate this endpoint */
currentInterface->endpoint_count++;
currentInterface->endpoint = (usb_endpoint_info *)realloc(
currentInterface->endpoint,
currentInterface->endpoint_count
* sizeof(usb_endpoint_info));
/* setup this endpoint */
usb_endpoint_info *endpointInfo =
&currentInterface->endpoint[currentInterface->endpoint_count - 1];
endpointInfo->descr = endpointDescriptor;
Pipe *endpoint = NULL;
switch (endpointDescriptor->attributes & 0x03) {
case 0x00: /* Control Endpoint */
endpoint = new(std::nothrow) ControlPipe(this,
LowSpeed() ? Pipe::LowSpeed : Pipe::NormalSpeed,
endpointDescriptor->endpoint_address & 0x0f,
endpointDescriptor->max_packet_size);
break;
case 0x01: /* Isochronous Endpoint */
endpoint = new(std::nothrow) IsochronousPipe(this,
endpointDescriptor->endpoint_address & 0x80 > 0 ? Pipe::In : Pipe::Out,
LowSpeed() ? Pipe::LowSpeed : Pipe::NormalSpeed,
endpointDescriptor->endpoint_address & 0x0f,
endpointDescriptor->max_packet_size);
break;
case 0x02: /* Bulk Endpoint */
endpoint = new(std::nothrow) BulkPipe(this,
endpointDescriptor->endpoint_address & 0x80 > 0 ? Pipe::In : Pipe::Out,
LowSpeed() ? Pipe::LowSpeed : Pipe::NormalSpeed,
endpointDescriptor->endpoint_address & 0x0f,
endpointDescriptor->max_packet_size);
break;
case 0x03: /* Interrupt Endpoint */
endpoint = new(std::nothrow) InterruptPipe(this,
endpointDescriptor->endpoint_address & 0x80 > 0 ? Pipe::In : Pipe::Out,
LowSpeed() ? Pipe::LowSpeed : Pipe::NormalSpeed,
endpointDescriptor->endpoint_address & 0x0f,
endpointDescriptor->max_packet_size);
break;
}
endpointInfo->handle = (usb_pipe *)endpoint;
break;
}
default:
TRACE(("USB Device %d: got generic descriptor\n", fDeviceAddress));
usb_generic_descriptor *genericDescriptor = (usb_generic_descriptor *)&configData[descriptorStart];
TRACE(("\tlength:.............%d\n", genericDescriptor->length));
TRACE(("\tdescriptor_type:....0x%02x\n", genericDescriptor->descriptor_type));
if (!currentInterface)
break;
/* allocate this descriptor */
currentInterface->generic_count++;
currentInterface->generic = (usb_descriptor **)realloc(
currentInterface->generic,
currentInterface->generic_count
* sizeof(usb_descriptor *));
/* add this descriptor */
currentInterface->generic[currentInterface->generic_count] =
(usb_descriptor *)genericDescriptor;
break;
}
descriptorStart += configData[descriptorStart];
}
}
// Set default configuration
TRACE(("USB Device %d: setting default configuration\n", fDeviceAddress));
SetConfiguration(0);
if (SetConfigurationAt(0) < B_OK) {
TRACE(("USB Device %d: failed to set default configuration\n", fDeviceAddress));
return;
}
// ToDo: Find drivers for the device
fInitOK = true;
}
@ -105,36 +271,61 @@ Device::InitCheck()
}
// Returns the length that was copied (index gives the number of the config)
size_t
Device::GetDescriptor(uint8 descriptorType, uint16 index, void *buffer,
size_t bufferSize)
status_t
Device::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID,
void *data, size_t dataLength, size_t *actualLength)
{
size_t actualLength = 0;
fDefaultPipe->SendRequest(
return SendRequest(
USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD, // type
USB_REQUEST_GET_DESCRIPTOR, // request
(descriptorType << 8) | index, // value
0, // index
bufferSize, // length
buffer, // buffer
bufferSize, // buffer length
&actualLength); // actual length
return actualLength;
languageID, // index
dataLength, // length
data, // buffer
dataLength, // buffer length
actualLength); // actual length
}
status_t
Device::SetConfiguration(uint8 value)
const usb_configuration_info *
Device::Configuration() const
{
if (value >= fDeviceDescriptor.num_configurations)
return EINVAL;
return fCurrentConfiguration;
}
status_t result = fDefaultPipe->SendRequest(
const usb_configuration_info *
Device::ConfigurationAt(uint8 index) const
{
if (index >= fDeviceDescriptor.num_configurations)
return NULL;
return &fConfigurations[index];
}
status_t
Device::SetConfiguration(const usb_configuration_info *configuration)
{
for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
if (configuration == &fConfigurations[i])
return SetConfigurationAt(i);
}
return B_BAD_VALUE;
}
status_t
Device::SetConfigurationAt(uint8 index)
{
if (index >= fDeviceDescriptor.num_configurations)
return B_BAD_VALUE;
status_t result = SendRequest(
USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD, // type
USB_REQUEST_SET_CONFIGURATION, // request
value, // value
index, // value
0, // index
0, // length
NULL, // buffer
@ -145,6 +336,120 @@ Device::SetConfiguration(uint8 value)
return result;
// Set current configuration
fCurrentConfiguration = &fConfigurations[value];
fCurrentConfiguration = &fConfigurations[index];
// Wait some for the configuration being finished
snooze(10000);
return B_OK;
}
const usb_device_descriptor *
Device::DeviceDescriptor() const
{
return &fDeviceDescriptor;
}
void
Device::ReportDevice(usb_support_descriptor *supportDescriptors,
uint32 supportDescriptorCount, const usb_notify_hooks *hooks, bool added)
{
TRACE(("USB Device ReportDevice\n"));
if (supportDescriptorCount == 0 || supportDescriptors == NULL) {
if (added && hooks->device_added != NULL)
hooks->device_added((const usb_device *)this, &fNotifyCookie);
else if (!added && hooks->device_removed != NULL)
hooks->device_removed(fNotifyCookie);
return;
}
for (uint32 i = 0; i < supportDescriptorCount; i++) {
if ((supportDescriptors[i].vendor != 0
&& fDeviceDescriptor.vendor_id != supportDescriptors[i].vendor)
|| (supportDescriptors[i].product != 0
&& fDeviceDescriptor.product_id != supportDescriptors[i].product))
continue;
if ((supportDescriptors[i].dev_class == 0
|| fDeviceDescriptor.device_class == supportDescriptors[i].dev_class)
&& (supportDescriptors[i].dev_subclass == 0
|| fDeviceDescriptor.device_subclass == supportDescriptors[i].dev_subclass)
&& (supportDescriptors[i].dev_protocol == 0
|| fDeviceDescriptor.device_protocol == supportDescriptors[i].dev_protocol)) {
if (added && hooks->device_added != NULL)
hooks->device_added((const usb_device *)this, &fNotifyCookie);
else if (!added && hooks->device_removed != NULL)
hooks->device_removed(fNotifyCookie);
return;
}
// we have to check all interfaces for matching class/subclass/protocol
for (uint32 j = 0; j < fDeviceDescriptor.num_configurations; j++) {
for (uint32 k = 0; k < fConfigurations[j].interface_count; k++) {
for (uint32 l = 0; l < fConfigurations[j].interface[k].alt_count; l++) {
usb_interface_descriptor *descriptor = fConfigurations[j].interface[k].alt[l].descr;
if ((supportDescriptors[i].dev_class == 0
|| descriptor->interface_class == supportDescriptors[i].dev_class)
&& (supportDescriptors[i].dev_subclass == 0
|| descriptor->interface_subclass == supportDescriptors[i].dev_subclass)
&& (supportDescriptors[i].dev_protocol == 0
|| descriptor->interface_protocol == supportDescriptors[i].dev_protocol)) {
if (added && hooks->device_added != NULL)
hooks->device_added((const usb_device *)this, &fNotifyCookie);
else if (!added && hooks->device_removed != NULL)
hooks->device_removed(fNotifyCookie);
return;
}
}
}
}
}
}
status_t
Device::SetFeature(uint16 selector)
{
return SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
USB_REQUEST_SET_FEATURE,
selector,
0,
0,
NULL,
0,
NULL);
}
status_t
Device::ClearFeature(uint16 selector)
{
return SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
USB_REQUEST_CLEAR_FEATURE,
selector,
0,
0,
NULL,
0,
NULL);
}
status_t
Device::GetStatus(uint16 *status)
{
return SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_IN,
USB_REQUEST_GET_STATUS,
0,
0,
2,
(void *)status,
2,
NULL);
}

View File

@ -31,50 +31,45 @@ Hub::Hub(BusManager *bus, Device *parent, usb_device_descriptor &desc,
// Set to false again for the hub init.
fInitOK = false;
if (fDeviceDescriptor.device_subclass != 0
for (int32 i = 0; i < 8; i++)
fChildren[i] = NULL;
if (fDeviceDescriptor.device_class != 9
|| fDeviceDescriptor.device_subclass != 0
|| fDeviceDescriptor.device_protocol != 0) {
TRACE(("USB Hub: wrong class/subclass/protocol! Bailing out\n"));
return;
}
if (fCurrentConfiguration->number_interfaces > 1) {
if (Configuration()->descr->number_interfaces > 1) {
TRACE(("USB Hub: too many interfaces\n"));
return;
}
size_t actualLength;
if (GetDescriptor(USB_DESCRIPTOR_INTERFACE, 0, (void *)&fInterruptInterface,
sizeof(usb_interface_descriptor)) != sizeof(usb_interface_descriptor)) {
TRACE(("USB Hub: error getting the interrupt interface\n"));
return;
}
if (fInterruptInterface.num_endpoints > 1) {
fInterruptInterface = Configuration()->interface->active->descr;
if (fInterruptInterface->num_endpoints > 1) {
TRACE(("USB Hub: too many endpoints\n"));
return;
}
if (GetDescriptor(USB_DESCRIPTOR_ENDPOINT, 0, (void *)&fInterruptEndpoint,
sizeof(usb_endpoint_descriptor)) != sizeof(usb_endpoint_descriptor)) {
TRACE(("USB Hub: Error getting the endpoint\n"));
return;
}
if (fInterruptEndpoint.attributes != 0x03) { // interrupt transfer
fInterruptEndpoint = Configuration()->interface->active->endpoint[0].descr;
if (fInterruptEndpoint->attributes != 0x03) { // interrupt endpoint
TRACE(("USB Hub: Not an interrupt endpoint\n"));
return;
}
TRACE(("USB Hub: Getting hub descriptor...\n"));
if (GetDescriptor(USB_DESCRIPTOR_HUB, 0, (void *)&fHubDescriptor,
sizeof(usb_hub_descriptor)) != sizeof(usb_hub_descriptor)) {
size_t actualLength;
status_t status = GetDescriptor(USB_DESCRIPTOR_HUB, 0, 0,
(void *)&fHubDescriptor, sizeof(usb_hub_descriptor), &actualLength);
if (status < B_OK || actualLength != sizeof(usb_hub_descriptor)) {
TRACE(("USB Hub: Error getting hub descriptor\n"));
return;
}
// Enable port power on all ports
for (int32 i = 0; i < fHubDescriptor.bNbrPorts; i++) {
fDefaultPipe->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
USB_REQUEST_SET_FEATURE,
PORT_POWER,
i + 1,
@ -85,7 +80,7 @@ Hub::Hub(BusManager *bus, Device *parent, usb_device_descriptor &desc,
}
// Wait for power to stabilize
snooze(fHubDescriptor.bPwrOn2PwrGood * 2);
snooze(fHubDescriptor.bPwrOn2PwrGood * 2000);
fInitOK = true;
TRACE(("USB Hub: initialised ok\n"));
@ -99,7 +94,7 @@ Hub::Explore()
size_t actualLength;
// Get the current port status
fDefaultPipe->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_IN,
SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_IN,
USB_REQUEST_GET_STATUS,
0,
i + 1,
@ -117,7 +112,7 @@ Hub::Explore()
// We need to test the port change against a number of things
if (fPortStatus[i].status & PORT_RESET) {
fDefaultPipe->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
USB_REQUEST_CLEAR_FEATURE,
PORT_RESET,
i + 1,
@ -133,7 +128,7 @@ Hub::Explore()
if ((fPortStatus[i].status & PORT_STATUS_ENABLE) == 0) {
// enable the port if it isn't
fDefaultPipe->SendRequest(
SendRequest(
USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
USB_REQUEST_SET_FEATURE,
PORT_ENABLE,
@ -146,22 +141,25 @@ Hub::Explore()
TRACE(("USB Hub: Explore(): New device connected\n"));
Device *newDevice;
if (fPortStatus[i].status & PORT_STATUS_LOW_SPEED)
newDevice = fBus->AllocateNewDevice(this, true);
else
newDevice = fBus->AllocateNewDevice(this, false);
Device *newDevice = fBus->AllocateNewDevice(this,
(fPortStatus[i].status & PORT_STATUS_LOW_SPEED) > 0);
if (newDevice)
if (newDevice) {
fChildren[i] = newDevice;
Manager()->GetStack()->NotifyDeviceChange(fChildren[i], true);
}
} else {
// Device removed...
// ToDo: do something
TRACE(("USB Hub Explore(): Device removed\n"));
if (fChildren[i]) {
Manager()->GetStack()->NotifyDeviceChange(fChildren[i], false);
delete fChildren[i];
fChildren[i] = NULL;
}
}
// Clear status change
fDefaultPipe->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
USB_REQUEST_CLEAR_FEATURE,
C_PORT_CONNECTION,
i + 1,
@ -172,3 +170,39 @@ Hub::Explore()
}
}
}
status_t
Hub::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID,
void *data, size_t dataLength, size_t *actualLength)
{
return SendRequest(
USB_REQTYPE_DEVICE_IN | USB_REQTYPE_CLASS, // type
USB_REQUEST_GET_DESCRIPTOR, // request
(descriptorType << 8) | index, // value
languageID, // index
dataLength, // length
data, // buffer
dataLength, // buffer length
actualLength); // actual length
}
void
Hub::ReportDevice(usb_support_descriptor *supportDescriptors,
uint32 supportDescriptorCount, const usb_notify_hooks *hooks, bool added)
{
TRACE(("USB Hub ReportDevice\n"));
// Report ourselfs first
Device::ReportDevice(supportDescriptors, supportDescriptorCount, hooks, added);
// Then report all of our children
for (int32 i = 0; i < fHubDescriptor.bNbrPorts; i++) {
if (!fChildren[i])
continue;
fChildren[i]->ReportDevice(supportDescriptors,
supportDescriptorCount, hooks, added);
}
}

View File

@ -12,6 +12,7 @@ KernelStaticLibrary libusb.a :
BusManager.cpp
Transfer.cpp
Pipe.cpp
Interface.cpp
: -fno-pic
;

View File

@ -3,21 +3,23 @@
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
* Niels S. Reedijk
*/
#include "usb_p.h"
Pipe::Pipe(Device *device, pipeDirection direction, uint8 endpointAddress,
uint32 maxPacketSize)
Pipe::Pipe(Device *device, pipeDirection direction, pipeSpeed speed,
uint8 endpointAddress, uint32 maxPacketSize)
: fDevice(device),
fBus(NULL),
fDirection(direction),
fSpeed(speed),
fEndpoint(endpointAddress),
fMaxPacketSize(maxPacketSize),
fDataToggle(false)
{
fDirection = direction;
fDevice = device;
fEndpoint = endpointAddress;
fMaxPacketSize = maxPacketSize;
fBus = NULL;
if (fDevice)
fBus = fDevice->Manager();
}
@ -38,27 +40,124 @@ Pipe::DeviceAddress()
}
status_t
Pipe::SubmitTransfer(Transfer *transfer)
{
// ToDo: keep track of all submited transfers to be able to cancel them
return fBus->SubmitTransfer(transfer);
}
status_t
Pipe::CancelQueuedTransfers()
{
return B_ERROR;
}
//
// #pragma mark -
//
ControlPipe::ControlPipe(Device *device, pipeDirection direction,
InterruptPipe::InterruptPipe(Device *device, pipeDirection direction,
pipeSpeed speed, uint8 endpointAddress, uint32 maxPacketSize)
: Pipe(device, direction, endpointAddress, maxPacketSize)
: Pipe(device, direction, speed, endpointAddress, maxPacketSize)
{
fSpeed = speed;
}
ControlPipe::ControlPipe(BusManager *bus, int8 deviceAddress,
pipeDirection direction, pipeSpeed speed, uint8 endpointAddress,
uint32 maxPacketSize)
: Pipe(NULL, direction, endpointAddress, maxPacketSize)
status_t
InterruptPipe::QueueInterrupt(void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie)
{
Transfer *transfer = new(std::nothrow) Transfer(this, false);
if (!transfer)
return B_NO_MEMORY;
transfer->SetData((uint8 *)data, dataLength);
transfer->SetCallback(callback, callbackCookie);
status_t result = SubmitTransfer(transfer);
if (result == B_OK || result == EINPROGRESS)
return B_OK;
delete transfer;
return result;
}
//
// #pragma mark -
//
BulkPipe::BulkPipe(Device *device, pipeDirection direction,
pipeSpeed speed, uint8 endpointAddress, uint32 maxPacketSize)
: Pipe(device, direction, speed, endpointAddress, maxPacketSize)
{
}
status_t
BulkPipe::QueueBulk(void *data, size_t dataLength, usb_callback_func callback,
void *callbackCookie)
{
Transfer *transfer = new(std::nothrow) Transfer(this, false);
if (!transfer)
return B_NO_MEMORY;
transfer->SetData((uint8 *)data, dataLength);
transfer->SetCallback(callback, callbackCookie);
status_t result = SubmitTransfer(transfer);
if (result == B_OK || result == EINPROGRESS)
return B_OK;
delete transfer;
return result;
}
//
// #pragma mark -
//
IsochronousPipe::IsochronousPipe(Device *device, pipeDirection direction,
pipeSpeed speed, uint8 endpointAddress, uint32 maxPacketSize)
: Pipe(device, direction, speed, endpointAddress, maxPacketSize)
{
}
status_t
IsochronousPipe::QueueIsochronous(void *data, size_t dataLength,
rlea *rleArray, uint16 bufferDurationMS, usb_callback_func callback,
void *callbackCookie)
{
return B_ERROR;
}
//
// #pragma mark -
//
ControlPipe::ControlPipe(Device *device, pipeSpeed speed,
uint8 endpointAddress, uint32 maxPacketSize)
: Pipe(device, Pipe::Default, speed, endpointAddress, maxPacketSize)
{
}
ControlPipe::ControlPipe(BusManager *bus, int8 deviceAddress, pipeSpeed speed,
uint8 endpointAddress, uint32 maxPacketSize)
: Pipe(NULL, Pipe::Default, speed, endpointAddress, maxPacketSize),
fDeviceAddress(deviceAddress)
{
fBus = bus;
fDeviceAddress = deviceAddress;
fSpeed = speed;
}
@ -78,30 +177,104 @@ ControlPipe::SendRequest(uint8 requestType, uint8 request, uint16 value,
size_t *actualLength)
{
usb_request_data requestData;
requestData.RequestType = requestType;
requestData.Request = request;
requestData.Value = value;
requestData.Index = index;
requestData.Length = length;
return SendControlMessage(&requestData, data, dataLength, actualLength,
3 * 1000 * 1000);
Transfer *transfer = new(std::nothrow) Transfer(this, true);
if (!transfer)
return B_NO_MEMORY;
transfer->SetRequestData(&requestData);
transfer->SetData((uint8 *)data, dataLength);
transfer->SetActualLength(actualLength);
status_t result = SubmitTransfer(transfer);
if (result == EINPROGRESS)
return transfer->WaitForFinish();
if (result < B_OK)
delete transfer;
return result;
}
status_t
ControlPipe::SendControlMessage(usb_request_data *command, void *data,
size_t dataLength, size_t *actualLength, bigtime_t timeout)
ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value,
uint16 index, uint16 length, void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie)
{
// builds an usb packet with the needed data
Transfer transfer(this, true);
usb_request_data *requestData = new(std::nothrow) usb_request_data;
if (!requestData)
return B_NO_MEMORY;
transfer.SetRequestData(command);
transfer.SetBuffer((uint8 *)data);
transfer.SetBufferLength(dataLength);
transfer.SetActualLength(actualLength);
requestData->RequestType = requestType;
requestData->Request = request;
requestData->Value = value;
requestData->Index = index;
requestData->Length = length;
fBus->SubmitTransfer(&transfer);
return transfer.WaitForFinish();
Transfer *transfer = new(std::nothrow) Transfer(this, false);
if (!transfer) {
delete requestData;
return B_NO_MEMORY;
}
transfer->SetRequestData(requestData);
transfer->SetData((uint8 *)data, dataLength);
transfer->SetCallback(callback, callbackCookie);
status_t result = SubmitTransfer(transfer);
if (result == B_OK || result == EINPROGRESS)
return B_OK;
delete transfer;
return result;
}
status_t
ControlPipe::SetFeature(uint16 selector)
{
return SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT,
USB_REQUEST_SET_FEATURE,
selector,
0,
0,
NULL,
0,
NULL);
}
status_t
ControlPipe::ClearFeature(uint16 selector)
{
return SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT,
USB_REQUEST_CLEAR_FEATURE,
selector,
0,
0,
NULL,
0,
NULL);
}
status_t
ControlPipe::GetStatus(uint16 *status)
{
return SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_IN,
USB_REQUEST_GET_STATUS,
0,
0,
2,
(void *)status,
2,
NULL);
}

View File

@ -20,6 +20,7 @@
Stack::Stack()
: fDriverList(NULL)
{
TRACE(("usb stack: stack init\n"));
@ -31,9 +32,6 @@ Stack::Stack()
fDataLock = create_sem(1, "usb data lock");
set_sem_owner(fDataLock, B_SYSTEM_TEAM);
// Set the global "data" variable to this
usb_stack = this;
// Initialise the memory chunks: create 8, 16 and 32 byte-heaps
// NOTE: This is probably the most ugly code you will see in the
// whole stack. Unfortunately this is needed because of the fact
@ -103,6 +101,27 @@ Stack::Stack()
chunk->next_item = NULL;
}
// 64-byte heap
fAreaFreeCount[3] = 0;
fAreas[3] = AllocateArea(&fLogical[3], &fPhysical[3], B_PAGE_SIZE,
"64-byte chunk area");
if (fAreas[3] < B_OK) {
TRACE(("usb stack: 64-byte chunk area failed to initialise\n"));
return;
}
fListhead64 = (addr_t)fLogical[3];
for (int32 i = 0; i < B_PAGE_SIZE / 64; i++) {
memory_chunk *chunk = (memory_chunk *)((addr_t)fLogical[3] + 64 * i);
chunk->physical = (addr_t)fPhysical[3] + 64 * i;
if (i < B_PAGE_SIZE / 64 - 1)
chunk->next_item = (addr_t)fLogical[3] + 64 * (i + 1);
else
chunk->next_item = NULL;
}
// Check for host controller modules
void *moduleList = open_module_list("busses/usb");
char moduleName[B_PATH_NAME_LENGTH];
@ -152,10 +171,10 @@ Stack::InitCheck()
}
void
bool
Stack::Lock()
{
acquire_sem(fMasterLock);
return (acquire_sem(fMasterLock) == B_OK);
}
@ -185,6 +204,8 @@ Stack::AllocateChunk(void **logicalAddress, void **physicalAddress, uint8 size)
listhead = fListhead16;
else if (size <= 32)
listhead = fListhead32;
else if (size <= 64)
listhead = fListhead64;
else {
TRACE(("usb stack: Chunk size %d to big\n", size));
Unlock();
@ -215,6 +236,8 @@ Stack::AllocateChunk(void **logicalAddress, void **physicalAddress, uint8 size)
fListhead16 = listhead;
else if (size <= 32)
fListhead32 = listhead;
else if (size <= 64)
fListhead64 = listhead;
Unlock();
//TRACE(("usb stack: allocated a new chunk with size %u\n", size));
@ -234,6 +257,8 @@ Stack::FreeChunk(void *logicalAddress, void *physicalAddress, uint8 size)
listhead = fListhead16;
else if (size <= 32)
listhead = fListhead32;
else if (size <= 64)
listhead = fListhead64;
else {
TRACE(("usb stack: Chunk size %d invalid\n", size));
Unlock();
@ -250,6 +275,8 @@ Stack::FreeChunk(void *logicalAddress, void *physicalAddress, uint8 size)
fListhead16 = (addr_t)logicalAddress;
else if (size <= 32)
fListhead32 = (addr_t)logicalAddress;
else if (size <= 64)
fListhead64 = (addr_t)logicalAddress;
Unlock();
return B_OK;
@ -293,4 +320,112 @@ Stack::AllocateArea(void **logicalAddress, void **physicalAddress, size_t size,
}
Stack *usb_stack = NULL;
void
Stack::NotifyDeviceChange(Device *device, bool added)
{
TRACE(("usb stack: device %s\n", added ? "added" : "removed"));
usb_driver_info *element = fDriverList;
while (element) {
if ((added && element->notify_hooks.device_added != NULL)
|| (!added && element->notify_hooks.device_removed != NULL)) {
device->ReportDevice(element->support_descriptors,
element->support_descriptor_count,
&element->notify_hooks, added);
}
element = element->link;
}
}
status_t
Stack::RegisterDriver(const char *driverName,
const usb_support_descriptor *descriptors,
size_t descriptorCount, const char *republishDriverName)
{
TRACE(("usb stack: register driver \"%s\"\n", driverName));
usb_driver_info *info = new(std::nothrow) usb_driver_info;
if (!info)
return B_NO_MEMORY;
info->driver_name = strdup(driverName);
info->republish_driver_name = strdup(republishDriverName);
size_t descriptorsSize = descriptorCount * sizeof(usb_support_descriptor);
info->support_descriptors = (usb_support_descriptor *)malloc(descriptorsSize);
memcpy(info->support_descriptors, descriptors, descriptorsSize);
info->support_descriptor_count = descriptorCount;
info->notify_hooks.device_added = NULL;
info->notify_hooks.device_removed = NULL;
info->link = NULL;
if (!Lock()) {
delete info;
return B_ERROR;
}
if (fDriverList) {
usb_driver_info *element = fDriverList;
while (element->link)
element = element->link;
element->link = info;
} else
fDriverList = info;
Unlock();
return B_OK;
}
status_t
Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks)
{
TRACE(("usb stack: installing notify hooks for driver \"%s\"\n", driverName));
usb_driver_info *element = fDriverList;
while (element) {
if (strcmp(element->driver_name, driverName) == 0) {
// inform driver about any already present devices
for (int32 i = 0; i < fBusManagers.Count(); i++) {
Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub();
if (rootHub) {
// Ensure that all devices are already recognized
rootHub->Explore();
// Report device will recurse down the whole tree
rootHub->ReportDevice(element->support_descriptors,
element->support_descriptor_count, hooks, true);
}
}
element->notify_hooks.device_added = hooks->device_added;
element->notify_hooks.device_removed = hooks->device_removed;
return B_OK;
}
element = element->link;
}
return B_NAME_NOT_FOUND;
}
status_t
Stack::UninstallNotify(const char *driverName)
{
TRACE(("usb stack: uninstalling notify hooks for driver \"%s\"\n", driverName));
usb_driver_info *element = fDriverList;
while (element) {
if (strcmp(element->driver_name, driverName) == 0) {
element->notify_hooks.device_added = NULL;
element->notify_hooks.device_removed = NULL;
return B_OK;
}
element = element->link;
}
return B_NAME_NOT_FOUND;
}

View File

@ -10,16 +10,19 @@
Transfer::Transfer(Pipe *pipe, bool synchronous)
: fPipe(pipe),
fData(NULL),
fDataLength(0),
fActualLength(NULL),
fOwnActualLength(0),
fStatus(B_NO_INIT),
fCallback(NULL),
fCallbackCookie(NULL),
fSem(-1),
fHostPrivate(NULL),
fRequestData(NULL)
{
fPipe = pipe;
fBuffer = NULL;
fBufferLength = 0;
fActualLength = NULL;
fStatus = B_NO_INIT;
fSem = -1;
fHostPrivate = NULL;
fCallback = NULL;
fActualLength = &fOwnActualLength;
if (synchronous) {
fSem = create_sem(0, "USB Transfer");
set_sem_owner(fSem, B_SYSTEM_TEAM);
@ -37,21 +40,15 @@ Transfer::~Transfer()
void
Transfer::SetRequestData(usb_request_data *data)
{
fRequest = data;
fRequestData = data;
}
void
Transfer::SetBuffer(uint8 *buffer)
Transfer::SetData(uint8 *data, size_t dataLength)
{
fBuffer = buffer;
}
void
Transfer::SetBufferLength(size_t length)
{
fBufferLength = length;
fData = data;
fDataLength = dataLength;
}
@ -63,7 +60,7 @@ Transfer::SetActualLength(size_t *actualLength)
void
Transfer::SetCallbackFunction(usb_callback_func callback, void *cookie)
Transfer::SetCallback(usb_callback_func callback, void *cookie)
{
fCallback = callback;
fCallbackCookie = cookie;
@ -98,11 +95,15 @@ Transfer::Finished(status_t result)
{
fStatus = result;
// If we are synchronous, release the sem
if (fSem > B_OK)
release_sem(fSem);
// Call the callback function ...
if (fCallback) {
fCallback(fCallbackCookie, fStatus, fData, *fActualLength);
return;
}
// ToDo: implement callback correctly
if (fCallback)
fCallback(fCallbackCookie, fStatus, fBuffer, 0);
// ... or release the sem
if (fSem > B_OK) {
release_sem(fSem);
return;
}
}

View File

@ -19,6 +19,9 @@
#endif
Stack *gUSBStack = NULL;
static int32
bus_std_ops(int32 op, ...)
{
@ -28,20 +31,25 @@ bus_std_ops(int32 op, ...)
set_dprintf_enabled(true);
load_driver_symbols("usb");
#endif
TRACE(("usb_nielx: bus module: init\n"));
TRACE(("usb_module: init\n"));
Stack *stack = new(std::nothrow) Stack();
if (!stack)
return B_NO_MEMORY;
Stack *stack = new Stack();
if (stack->InitCheck() != B_OK) {
delete stack;
return ENODEV;
}
gUSBStack = stack;
break;
}
case B_MODULE_UNINIT:
TRACE(("usb_nielx: bus module: uninit\n"));
delete usb_stack;
TRACE(("usb_module: bus module: uninit\n"));
delete gUSBStack;
gUSBStack = NULL;
break;
default:
@ -52,6 +60,207 @@ bus_std_ops(int32 op, ...)
}
status_t
register_driver(const char *driverName,
const usb_support_descriptor *descriptors,
size_t count, const char *optionalRepublishDriverName)
{
return gUSBStack->RegisterDriver(driverName, descriptors, count,
optionalRepublishDriverName);
}
status_t
install_notify(const char *driverName, const usb_notify_hooks *hooks)
{
return gUSBStack->InstallNotify(driverName, hooks);
}
status_t
uninstall_notify(const char *driverName)
{
return gUSBStack->UninstallNotify(driverName);
}
const usb_device_descriptor *
get_device_descriptor(const usb_device *device)
{
if (!device)
return NULL;
return ((const Device *)device)->DeviceDescriptor();
}
const usb_configuration_info *
get_nth_configuration(const usb_device *device, uint index)
{
if (!device)
return NULL;
return ((const Device *)device)->ConfigurationAt((int32)index);
}
const usb_configuration_info *
get_configuration(const usb_device *device)
{
if (!device)
return NULL;
return ((const Device *)device)->Configuration();
}
status_t
set_configuration(const usb_device *device,
const usb_configuration_info *configuration)
{
if (!device)
return B_BAD_VALUE;
return ((Device *)device)->SetConfiguration(configuration);
}
status_t
set_alt_interface(const usb_device *device,
const usb_interface_info *interface)
{
return B_ERROR;
}
status_t
set_feature(const void *object, uint16 selector)
{
if (!object)
return B_BAD_VALUE;
return ((ControlPipe *)object)->SetFeature(selector);
}
status_t
clear_feature(const void *object, uint16 selector)
{
if (!object)
return B_BAD_VALUE;
return ((ControlPipe *)object)->ClearFeature(selector);
}
status_t
get_status(const void *object, uint16 *status)
{
if (!object || !status)
return B_BAD_VALUE;
return ((ControlPipe *)object)->GetStatus(status);
}
status_t
get_descriptor(const usb_device *device, uint8 type, uint8 index,
uint16 languageID, void *data, size_t dataLength, size_t *actualLength)
{
if (!device || !data)
return B_BAD_VALUE;
return ((Device *)device)->GetDescriptor(type, index, languageID,
data, dataLength, actualLength);
}
status_t
send_request(const usb_device *device, uint8 requestType, uint8 request,
uint16 value, uint16 index, uint16 length, void *data, size_t dataLength,
size_t *actualLength)
{
if (!device)
return B_BAD_VALUE;
return ((Device *)device)->SendRequest(requestType, request, value, index,
length, data, dataLength, actualLength);
}
status_t
queue_request(const usb_device *device, uint8 requestType, uint8 request,
uint16 value, uint16 index, uint16 length, void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie)
{
if (!device)
return B_BAD_VALUE;
return ((Device *)device)->QueueRequest(requestType, request, value, index,
length, data, dataLength, callback, callbackCookie);
}
status_t
queue_interrupt(const usb_pipe *pipe, void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie)
{
if (((Pipe *)pipe)->Type() != Pipe::Interrupt)
return B_BAD_VALUE;
return ((InterruptPipe *)pipe)->QueueInterrupt(data, dataLength, callback,
callbackCookie);
}
status_t
queue_bulk(const usb_pipe *pipe, void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie)
{
if (((Pipe *)pipe)->Type() != Pipe::Bulk)
return B_BAD_VALUE;
return ((BulkPipe *)pipe)->QueueBulk(data, dataLength, callback,
callbackCookie);
}
status_t
queue_isochronous(const usb_pipe *pipe, void *data, size_t dataLength,
rlea *rleArray, uint16 bufferDurationMS, usb_callback_func callback,
void *callbackCookie)
{
if (((Pipe *)pipe)->Type() != Pipe::Isochronous)
return B_BAD_VALUE;
return ((IsochronousPipe *)pipe)->QueueIsochronous(data, dataLength,
rleArray, bufferDurationMS, callback, callbackCookie);
}
status_t
set_pipe_policy(const usb_pipe *pipe, uint8 maxQueuedPackets,
uint16 maxBufferDurationMS, uint16 sampleSize)
{
return B_ERROR;
}
status_t
cancel_queued_transfers(const usb_pipe *pipe)
{
return ((Pipe *)pipe)->CancelQueuedTransfers();
}
status_t
usb_ioctl(uint32 opcode, void *buffer, size_t bufferSize)
{
return B_ERROR;
}
/*
This module exports the USB API
*/
@ -59,33 +268,33 @@ struct usb_module_info gModuleInfo = {
// First the bus_manager_info:
{
{
"bus_managers/usb/nielx",
B_USB_MODULE_NAME,
B_KEEP_LOADED, // Keep loaded, even if no driver requires it
bus_std_ops
},
NULL // the rescan function
NULL // the rescan function
},
NULL, // register_driver
NULL, // install_notify
NULL, // uninstall_notify
NULL, // get_device_descriptor
NULL, // get_nth_configuration_info
NULL, // get_configuration
NULL, // set_configuration
NULL, // set_alt_interface
NULL, // set_feature
NULL, // clear_feature
NULL, // get_status
NULL, // get_descriptor
NULL, // send_request
NULL, // queue_interrupt
NULL, // queue_bulk
NULL, // queue_isochronous
NULL, // queue_request
NULL, // set_pipe_policy
NULL, // cancel_queued_transfers
NULL // usb_ioctl
register_driver, // register_driver
install_notify, // install_notify
uninstall_notify, // uninstall_notify
get_device_descriptor, // get_device_descriptor
get_nth_configuration, // get_nth_configuration
get_configuration, // get_configuration
set_configuration, // set_configuration
set_alt_interface, // set_alt_interface
set_feature, // set_feature
clear_feature, // clear_feature
get_status, // get_status
get_descriptor, // get_descriptor
send_request, // send_request
queue_interrupt, // queue_interrupt
queue_bulk, // queue_bulk
queue_isochronous, // queue_isochronous
queue_request, // queue_request
set_pipe_policy, // set_pipe_policy
cancel_queued_transfers, // cancel_queued_transfers
usb_ioctl // usb_ioctl
};

View File

@ -13,6 +13,8 @@
#include "usbspec_p.h"
class Hub;
class Device;
class Stack;
class Device;
class Transfer;
@ -27,6 +29,16 @@ struct host_controller_info {
};
struct usb_driver_info {
const char *driver_name;
usb_support_descriptor *support_descriptors;
uint32 support_descriptor_count;
const char *republish_driver_name;
usb_notify_hooks notify_hooks;
usb_driver_info *link;
};
class Stack {
public:
Stack();
@ -34,7 +46,7 @@ public:
status_t InitCheck();
void Lock();
bool Lock();
void Unlock();
void AddBusManager(BusManager *bus);
@ -48,6 +60,19 @@ public:
void **physicalAddress,
size_t size, const char *name);
void NotifyDeviceChange(Device *device,
bool added);
// USB API
status_t RegisterDriver(const char *driverName,
const usb_support_descriptor *descriptors,
size_t descriptorCount,
const char *republishDriverName);
status_t InstallNotify(const char *driverName,
const usb_notify_hooks *hooks);
status_t UninstallNotify(const char *driverName);
private:
Vector<BusManager *> fBusManagers;
@ -62,61 +87,9 @@ private:
addr_t fListhead8;
addr_t fListhead16;
addr_t fListhead32;
};
addr_t fListhead64;
extern "C" Stack *usb_stack;
class Device {
public:
Device(BusManager *bus, Device *parent,
usb_device_descriptor &desc,
int8 deviceAddress, bool lowSpeed);
status_t InitCheck();
virtual bool IsHub() { return false; };
int8 Address() { return fDeviceAddress; };
BusManager *Manager() { return fBus; };
size_t GetDescriptor(uint8 descriptorType,
uint16 index, void *buffer,
size_t bufferSize);
status_t SetConfiguration(uint8 value);
protected:
usb_device_descriptor fDeviceDescriptor;
usb_configuration_descriptor *fConfigurations;
usb_configuration_descriptor *fCurrentConfiguration;
ControlPipe *fDefaultPipe;
bool fInitOK;
bool fLowSpeed;
BusManager *fBus;
Device *fParent;
int8 fDeviceAddress;
uint32 fMaxPacketIn[16];
uint32 fMaxPacketOut[16];
sem_id fLock;
};
class Hub : public Device {
public:
Hub(BusManager *bus, Device *parent,
usb_device_descriptor &desc,
int8 deviceAddress, bool lowSpeed);
virtual bool IsHub() { return true; };
void Explore();
private:
usb_interface_descriptor fInterruptInterface;
usb_endpoint_descriptor fInterruptEndpoint;
usb_hub_descriptor fHubDescriptor;
usb_port_status fPortStatus[8];
Device *fChildren[8];
usb_driver_info *fDriverList;
};
@ -143,10 +116,13 @@ virtual status_t Stop();
virtual status_t SubmitTransfer(Transfer *transfer);
virtual status_t SubmitRequest(Transfer *transfer);
protected:
void SetRootHub(Hub *hub) { fRootHub = hub; };
Device *GetRootHub() { return fRootHub; };
Stack *GetStack() { return fStack; };
void SetStack(Stack *stack) { fStack = stack; };
Hub *GetRootHub() { return fRootHub; };
void SetRootHub(Hub *hub) { fRootHub = hub; };
protected:
bool fInitOK;
private:
@ -156,13 +132,14 @@ static int32 ExploreThread(void *data);
bool fDeviceMap[128];
ControlPipe *fDefaultPipe;
ControlPipe *fDefaultPipeLowSpeed;
Device *fRootHub;
Hub *fRootHub;
Stack *fStack;
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
* the stack. It creates packets, manages these and performs callbacks.
*/
class Pipe {
@ -173,60 +150,230 @@ enum pipeType { Control, Bulk, Isochronous, Interrupt, Invalid };
Pipe(Device *device,
pipeDirection direction,
pipeSpeed speed,
uint8 endpointAddress,
uint32 maxPacketSize);
virtual ~Pipe();
virtual int8 DeviceAddress();
virtual pipeType Type() { return Invalid; };
virtual pipeSpeed Speed() { return LowSpeed; };
//Provide a default: should never be called
virtual pipeSpeed Speed() { return fSpeed; };
virtual pipeDirection Direction() { return fDirection; };
virtual int8 EndpointAddress() { return fEndpoint; };
virtual uint32 MaxPacketSize() { return fMaxPacketSize; };
virtual bool DataToggle() { return fDataToggle; };
virtual void SetDataToggle(bool toggle) { fDataToggle = toggle; };
status_t SubmitTransfer(Transfer *transfer);
status_t CancelQueuedTransfers();
protected:
Device *fDevice;
BusManager *fBus;
pipeDirection fDirection;
pipeSpeed fSpeed;
uint8 fEndpoint;
uint32 fMaxPacketSize;
bool fDataToggle;
};
class InterruptPipe : public Pipe {
public:
InterruptPipe(Device *device,
pipeDirection direction,
pipeSpeed speed,
uint8 endpointAddress,
uint32 maxPacketSize);
virtual pipeType Type() { return Interrupt; };
status_t QueueInterrupt(void *data,
size_t dataLength,
usb_callback_func callback,
void *callbackCookie);
};
class BulkPipe : public Pipe {
public:
BulkPipe(Device *device,
pipeDirection direction,
pipeSpeed speed,
uint8 endpointAddress,
uint32 maxPacketSize);
virtual pipeType Type() { return Bulk; };
status_t QueueBulk(void *data,
size_t dataLength,
usb_callback_func callback,
void *callbackCookie);
};
class IsochronousPipe : public Pipe {
public:
IsochronousPipe(Device *device,
pipeDirection direction,
pipeSpeed speed,
uint8 endpointAddress,
uint32 maxPacketSize);
virtual pipeType Type() { return Isochronous; };
status_t QueueIsochronous(void *data,
size_t dataLength,
rlea *rleArray,
uint16 bufferDurationMS,
usb_callback_func callback,
void *callbackCookie);
};
class ControlPipe : public Pipe {
public:
ControlPipe(Device *device,
pipeDirection direction,
pipeSpeed speed,
uint8 endpointAddress,
uint32 maxPacketSize);
ControlPipe(Device *device,
pipeSpeed speed,
uint8 endpointAddress,
uint32 maxPacketSize);
// Constructor for default control pipe
ControlPipe(BusManager *bus,
int8 deviceAddress,
pipeDirection direction,
pipeSpeed speed,
uint8 endpointAddress,
uint32 maxPacketSize);
// Constructor for default control pipe
ControlPipe(BusManager *bus,
int8 deviceAddress,
pipeSpeed speed,
uint8 endpointAddress,
uint32 maxPacketSize);
virtual int8 DeviceAddress();
virtual pipeType Type() { return Control; };
virtual pipeSpeed Speed() { return fSpeed; };
virtual int8 DeviceAddress();
virtual pipeType Type() { return Control; };
status_t SendRequest(uint8 requestType,
uint8 request, uint16 value,
uint16 index, uint16 length,
void *data, size_t dataLength,
size_t *actualLength);
// The data toggle is not relevant
// for control transfers, as they are
// always enclosed by a setup and
// status packet. The toggle always
// starts at 1.
virtual bool DataToggle() { return true; };
virtual void SetDataToggle(bool toggle) {};
status_t SendControlMessage(usb_request_data *command,
void *data, size_t dataLength,
size_t *actualLength,
bigtime_t timeout);
status_t SendRequest(uint8 requestType,
uint8 request, uint16 value,
uint16 index, uint16 length,
void *data, size_t dataLength,
size_t *actualLength);
status_t QueueRequest(uint8 requestType,
uint8 request, uint16 value,
uint16 index, uint16 length,
void *data, size_t dataLength,
usb_callback_func callback,
void *callbackCookie);
// Convenience functions for standard requests
virtual status_t SetFeature(uint16 selector);
virtual status_t ClearFeature(uint16 selector);
virtual status_t GetStatus(uint16 *status);
private:
int8 fDeviceAddress;
pipeSpeed fSpeed;
int8 fDeviceAddress;
};
class Interface : public ControlPipe {
public:
Interface(Device *device);
// Convenience functions for standard requests
virtual status_t SetFeature(uint16 selector);
virtual status_t ClearFeature(uint16 selector);
virtual status_t GetStatus(uint16 *status);
private:
Device *fDevice;
};
class Device : public ControlPipe {
public:
Device(BusManager *bus, Device *parent,
usb_device_descriptor &desc,
int8 deviceAddress, bool lowSpeed);
status_t InitCheck();
virtual bool IsHub() { return false; };
int8 Address() { return fDeviceAddress; };
BusManager *Manager() { return fBus; };
bool LowSpeed() { return fLowSpeed; };
virtual status_t GetDescriptor(uint8 descriptorType,
uint8 index, uint16 languageID,
void *data, size_t dataLength,
size_t *actualLength);
const usb_device_descriptor *DeviceDescriptor() const;
const usb_configuration_info *Configuration() const;
const usb_configuration_info *ConfigurationAt(uint8 index) const;
status_t SetConfiguration(const usb_configuration_info *configuration);
status_t SetConfigurationAt(uint8 index);
virtual void ReportDevice(
usb_support_descriptor *supportDescriptors,
uint32 supportDescriptorCount,
const usb_notify_hooks *hooks,
bool added);
// Convenience functions for standard requests
virtual status_t SetFeature(uint16 selector);
virtual status_t ClearFeature(uint16 selector);
virtual status_t GetStatus(uint16 *status);
protected:
usb_device_descriptor fDeviceDescriptor;
usb_configuration_info *fConfigurations;
usb_configuration_info *fCurrentConfiguration;
bool fInitOK;
bool fLowSpeed;
BusManager *fBus;
Device *fParent;
int8 fDeviceAddress;
uint32 fMaxPacketIn[16];
uint32 fMaxPacketOut[16];
sem_id fLock;
void *fNotifyCookie;
};
class Hub : public Device {
public:
Hub(BusManager *bus, Device *parent,
usb_device_descriptor &desc,
int8 deviceAddress, bool lowSpeed);
virtual bool IsHub() { return true; };
virtual status_t GetDescriptor(uint8 descriptorType,
uint8 index, uint16 languageID,
void *data, size_t dataLength,
size_t *actualLength);
void Explore();
virtual void ReportDevice(
usb_support_descriptor *supportDescriptors,
uint32 supportDescriptorCount,
const usb_notify_hooks *hooks,
bool added);
private:
usb_interface_descriptor *fInterruptInterface;
usb_endpoint_descriptor *fInterruptEndpoint;
usb_hub_descriptor fHubDescriptor;
usb_port_status fPortStatus[8];
Device *fChildren[8];
};
@ -250,13 +397,11 @@ public:
Pipe *TransferPipe() { return fPipe; };
void SetRequestData(usb_request_data *data);
usb_request_data *RequestData() { return fRequest; };
usb_request_data *RequestData() { return fRequestData; };
void SetBuffer(uint8 *buffer);
uint8 *Buffer() { return fBuffer; };
void SetBufferLength(size_t length);
size_t BufferLength() { return fBufferLength; };
void SetData(uint8 *buffer, size_t length);
uint8 *Data() { return fData; };
size_t DataLength() { return fDataLength; };
void SetActualLength(size_t *actualLength);
size_t *ActualLength() { return fActualLength; };
@ -264,19 +409,19 @@ public:
void SetHostPrivate(hostcontroller_priv *priv);
hostcontroller_priv *HostPrivate() { return fHostPrivate; };
void SetCallbackFunction(
usb_callback_func callback,
void SetCallback(usb_callback_func callback,
void *cookie);
status_t WaitForFinish();
void Finished(status_t result);
private:
// Data that is related to the transfer
Pipe *fPipe;
uint8 *fBuffer;
size_t fBufferLength;
uint8 *fData;
size_t fDataLength;
size_t *fActualLength;
size_t fOwnActualLength;
status_t fStatus;
usb_callback_func fCallback;
@ -286,7 +431,7 @@ private:
hostcontroller_priv *fHostPrivate;
// For control transfers
usb_request_data *fRequest;
usb_request_data *fRequestData;
};
#endif

View File

@ -21,8 +21,10 @@
#define TRACE_UHCI
#ifdef TRACE_UHCI
#define TRACE(x) dprintf x
#define TRACE_ERROR(x) dprintf x
#else
#define TRACE(x) /* nothing */
#define TRACE_ERROR(x) dprintf x
#endif
@ -101,15 +103,11 @@ Queue::Queue(Stack *stack)
{
fStack = stack;
fLockAtom = 0;
fLockSem = create_sem(1, "uhci queue lock");
if (fLockSem < B_OK) {
if (benaphore_init(&fLock, "uhci queue lock") < B_OK) {
TRACE(("usb_uhci: failed to create queue lock\n"));
return;
}
set_sem_owner(fLockSem, B_SYSTEM_TEAM);
void *physicalAddress;
fStatus = fStack->AllocateChunk((void **)&fQueueHead, &physicalAddress, 32);
if (fStatus < B_OK)
@ -117,7 +115,6 @@ Queue::Queue(Stack *stack)
fQueueHead->this_phy = (addr_t)physicalAddress;
fQueueHead->element_phy = QH_TERMINATE;
fQueueHead->element_log = 0;
fStrayDescriptor = NULL;
fQueueTop = NULL;
@ -127,7 +124,7 @@ Queue::Queue(Stack *stack)
Queue::~Queue()
{
Lock();
delete_sem(fLockSem);
benaphore_destroy(&fLock);
fStack->FreeChunk(fQueueHead, (void *)fQueueHead->this_phy, 32);
@ -146,18 +143,14 @@ Queue::InitCheck()
bool
Queue::Lock()
{
if (atomic_add(&fLockAtom, 1) > 0)
return acquire_sem(fLockSem) == B_OK;
return true;
return (benaphore_lock(&fLock) == B_OK);
}
void
Queue::Unlock()
{
if (atomic_add(&fLockAtom, -1) > 1)
release_sem(fLockSem);
benaphore_unlock(&fLock);
}
@ -210,7 +203,6 @@ Queue::TerminateByStrayDescriptor()
fQueueHead->link_phy = fStrayDescriptor->this_phy;
fQueueHead->link_log = fStrayDescriptor;
fQueueHead->element_phy = QH_TERMINATE;
fQueueHead->element_log = 0;
Unlock();
return B_OK;
@ -231,18 +223,17 @@ Queue::AppendDescriptor(uhci_td *descriptor)
if (fQueueHead->element_phy & QH_TERMINATE) {
// the queue is empty, make this the first element
fQueueHead->element_phy = descriptor->this_phy;
fQueueHead->element_log = descriptor;
fQueueTop = descriptor;
fQueueHead->element_phy = descriptor->this_phy;
TRACE(("usb_uhci: first transfer in queue\n"));
} else {
// there are transfers linked, append to the queue
uhci_td *element = (uhci_td *)fQueueHead->element_log;
uhci_td *element = fQueueTop;
while ((element->link_phy & TD_TERMINATE) == 0)
element = (uhci_td *)element->link_log;
element->link_phy = descriptor->this_phy | TD_DEPTH_FIRST;
element->link_log = descriptor;
element->link_phy = descriptor->this_phy | TD_DEPTH_FIRST;
TRACE(("usb_uhci: appended transfer to queue\n"));
}
@ -254,27 +245,57 @@ Queue::AppendDescriptor(uhci_td *descriptor)
status_t
Queue::RemoveDescriptors(uhci_td *firstDescriptor, uhci_td *lastDescriptor)
{
TRACE(("usb_uhci: removing descriptors\n"));
if (!Lock())
return B_ERROR;
if (fQueueTop == firstDescriptor) {
// it was the first chain in this queue
fQueueTop = (uhci_td *)lastDescriptor->link_log;
Unlock();
return B_OK;
}
if ((lastDescriptor->link_phy & TD_TERMINATE) > 0) {
// it was the only transfer
fQueueTop = NULL;
fQueueHead->element_phy = QH_TERMINATE;
} else {
// there are still linked transfers
fQueueTop = (uhci_td *)lastDescriptor->link_log;
fQueueHead->element_phy = fQueueTop->this_phy & TD_LINK_MASK;
}
} else {
uhci_td *descriptor = fQueueTop;
while (descriptor) {
if (descriptor->link_log == firstDescriptor) {
descriptor->link_log = lastDescriptor->link_log;
descriptor->link_phy = lastDescriptor->link_phy;
break;
}
uhci_td *descriptor = fQueueTop;
while (descriptor) {
if (descriptor->link_log == firstDescriptor) {
descriptor->link_log = lastDescriptor->link_log;
descriptor->link_phy = lastDescriptor->link_phy;
break;
descriptor = (uhci_td *)descriptor->link_log;
}
descriptor = (uhci_td *)descriptor->link_log;
descriptor = firstDescriptor;
while (descriptor) {
if ((fQueueHead->element_phy & TD_LINK_MASK)
== (descriptor->this_phy & TD_LINK_MASK)) {
if ((lastDescriptor->link_phy) & TD_TERMINATE > 0)
fQueueHead->element_phy = QH_TERMINATE;
else
fQueueHead->element_phy = lastDescriptor->link_phy & TD_LINK_MASK;
break;
}
descriptor = (uhci_td *)descriptor->link_log;
}
}
lastDescriptor->link_log = NULL;
lastDescriptor->link_phy = TD_TERMINATE;
#ifdef TRACE_UHCI
print_descriptor_chain(firstDescriptor);
#endif
Unlock();
return B_OK;
}
@ -324,15 +345,11 @@ UHCI::UHCI(pci_info *info, Stack *stack)
TRACE(("usb_uhci: constructing new UHCI Host Controller Driver\n"));
fInitOK = false;
fLockAtom = 0;
fLockSem = create_sem(1, "usb uhci lock");
if (fLockSem < B_OK) {
if (benaphore_init(&fUHCILock, "usb uhci lock") < B_OK) {
TRACE(("usb_uhci: failed to create busmanager lock\n"));
return;
}
set_sem_owner(fLockSem, B_SYSTEM_TEAM);
fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus,
fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4);
fRegisterBase &= PCI_address_io_mask;
@ -378,10 +395,15 @@ UHCI::UHCI(pci_info *info, Stack *stack)
WriteReg16(UHCI_FRNUM, 0);
fQueueCount = 4;
fQueues = new Queue *[fQueueCount];
fQueues = new(std::nothrow) Queue *[fQueueCount];
if (!fQueues) {
delete_area(fFrameArea);
return;
}
for (int32 i = 0; i < fQueueCount; i++) {
fQueues[i] = new Queue(fStack);
if (fQueues[i]->InitCheck() < B_OK) {
fQueues[i] = new(std::nothrow) Queue(fStack);
if (!fQueues[i] || fQueues[i]->InitCheck() < B_OK) {
TRACE(("usb_uhci: cannot create queues\n"));
delete_area(fFrameArea);
return;
@ -436,7 +458,7 @@ UHCI::~UHCI()
delete [] fQueues;
delete fRootHub;
delete_area(fFrameArea);
delete_sem(fLockSem);
benaphore_destroy(&fUHCILock);
put_module(B_PCI_MODULE_NAME);
}
@ -445,18 +467,14 @@ UHCI::~UHCI()
bool
UHCI::Lock()
{
if (atomic_add(&fLockAtom, 1) > 0)
return acquire_sem(fLockSem) == B_OK;
return true;
return (benaphore_lock(&fUHCILock) == B_OK);
}
void
UHCI::Unlock()
{
if (atomic_add(&fLockAtom, -1) > 1)
release_sem(fLockSem);
benaphore_unlock(&fUHCILock);
}
@ -490,8 +508,20 @@ UHCI::Start()
}
fRootHubAddress = AllocateAddress();
fRootHub = new UHCIRootHub(this, fRootHubAddress);
fRootHub = new(std::nothrow) UHCIRootHub(this, fRootHubAddress);
if (!fRootHub) {
TRACE(("usb_uhci: no memory to allocate root hub\n"));
return B_NO_MEMORY;
}
if (fRootHub->InitCheck() < B_OK) {
TRACE(("usb_uhci: root hub could not be created\n"));
delete fRootHub;
return B_ERROR;
}
SetRootHub(fRootHub);
SetStack(fStack);
TRACE(("usb_uhci: controller is started. status: %u curframe: %u\n",
ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM)));
@ -511,7 +541,52 @@ UHCI::SubmitTransfer(Transfer *transfer)
if (transfer->TransferPipe()->Type() == Pipe::Control)
return SubmitRequest(transfer);
return B_ERROR;
if (!transfer->Data() || transfer->DataLength() == 0)
return B_BAD_VALUE;
Pipe *pipe = transfer->TransferPipe();
bool directionIn = (pipe->Direction() == Pipe::In);
uhci_td *firstDescriptor = NULL;
uhci_td *lastDescriptor = NULL;
status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
&lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
transfer->DataLength());
if (result < B_OK)
return result;
if (!firstDescriptor || !lastDescriptor)
return B_NO_MEMORY;
lastDescriptor->status |= TD_STATUS_IOC;
lastDescriptor->link_phy = TD_TERMINATE;
lastDescriptor->link_log = 0;
if (!directionIn) {
WriteDescriptorChain(firstDescriptor, transfer->Data(),
transfer->DataLength());
}
Queue *queue = fQueues[3];
if (pipe->Type() == Pipe::Interrupt)
queue = fQueues[2];
result = AddPendingTransfer(transfer, queue, firstDescriptor,
firstDescriptor, lastDescriptor, directionIn);
if (result < B_OK) {
TRACE(("usb_uhci: failed to add pending transfer\n"));
FreeDescriptorChain(firstDescriptor);
return result;
}
result = queue->AppendDescriptor(firstDescriptor);
if (result < B_OK) {
TRACE(("usb_uhci: failed to append descriptors\n"));
FreeDescriptorChain(firstDescriptor);
return result;
}
return EINPROGRESS;
}
@ -544,11 +619,11 @@ UHCI::SubmitRequest(Transfer *transfer)
statusDescriptor->link_log = 0;
uhci_td *dataDescriptor = NULL;
if (transfer->Buffer() && transfer->BufferLength() > 0) {
if (transfer->Data() && transfer->DataLength() > 0) {
uhci_td *lastDescriptor = NULL;
status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
&lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
transfer->BufferLength());
transfer->DataLength());
if (result < B_OK) {
FreeDescriptor(setupDescriptor);
@ -557,8 +632,8 @@ UHCI::SubmitRequest(Transfer *transfer)
}
if (!directionIn) {
WriteDescriptorChain(dataDescriptor, transfer->Buffer(),
transfer->BufferLength());
WriteDescriptorChain(dataDescriptor, transfer->Data(),
transfer->DataLength());
}
LinkDescriptors(setupDescriptor, dataDescriptor);
@ -568,17 +643,22 @@ UHCI::SubmitRequest(Transfer *transfer)
LinkDescriptors(setupDescriptor, statusDescriptor);
}
AddPendingTransfer(transfer, fQueues[1], setupDescriptor, dataDescriptor,
statusDescriptor, directionIn);
status_t result = AddPendingTransfer(transfer, fQueues[1], setupDescriptor,
dataDescriptor, statusDescriptor, directionIn);
if (result < B_OK) {
TRACE(("usb_uhci: failed to add pending transfer\n"));
FreeDescriptorChain(setupDescriptor);
return result;
}
status_t result = fQueues[1]->AppendDescriptor(setupDescriptor);
result = fQueues[1]->AppendDescriptor(setupDescriptor);
if (result < B_OK) {
TRACE(("usb_uhci: failed to append descriptors\n"));
FreeDescriptorChain(setupDescriptor);
return result;
}
return EINPROGRESS;
return EINPROGRESS;
}
@ -588,7 +668,10 @@ UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue,
bool directionIn)
{
TRACE(("usb_uhci: add pending transfer\n"));
transfer_data *data = new transfer_data();
transfer_data *data = new(std::nothrow) transfer_data();
if (!data)
return B_NO_MEMORY;
data->transfer = transfer;
data->queue = queue;
data->first_descriptor = firstDescriptor;
@ -640,6 +723,8 @@ UHCI::FinishTransfers()
TRACE(("usb_uhci: finishing transfers (first transfer: 0x%08x; last transfer: 0x%08x)\n", fFirstTransfer, fLastTransfer));
transfer_data *lastTransfer = NULL;
transfer_data *transfer = fFirstTransfer;
Unlock();
while (transfer) {
bool transferDone = false;
uhci_td *descriptor = transfer->first_descriptor;
@ -653,7 +738,7 @@ UHCI::FinishTransfers()
}
if (status & TD_ERROR_MASK) {
TRACE(("usb_uhci: td (0x%08x) error: 0x%08x\n", descriptor->this_phy, status));
TRACE_ERROR(("usb_uhci: td (0x%08x) error: 0x%08x\n", descriptor->this_phy, status));
// an error occured. we have to remove the
// transfer from the queue and clean up
transfer->queue->RemoveDescriptors(transfer->first_descriptor,
@ -675,12 +760,10 @@ UHCI::FinishTransfers()
// data to read out
TRACE(("usb_uhci: reading incoming data buffer to transfer 0x%08x\n", transfer));
size_t length = ReadDescriptorChain(transfer->data_descriptor,
transfer->transfer->Buffer(),
transfer->transfer->BufferLength());
transfer->transfer->Data(),
transfer->transfer->DataLength());
size_t *actualLength = transfer->transfer->ActualLength();
if (actualLength)
*actualLength = length;
*(transfer->transfer->ActualLength()) = length;
}
FreeDescriptorChain(transfer->first_descriptor);
@ -695,17 +778,21 @@ UHCI::FinishTransfers()
if (transferDone) {
TRACE(("usb_uhci: transfer (0x%08x) done\n", transfer));
if (lastTransfer)
lastTransfer->link = transfer->link;
if (Lock()) {
if (lastTransfer)
lastTransfer->link = transfer->link;
if (transfer == fFirstTransfer)
fFirstTransfer = transfer->link;
if (transfer == fLastTransfer)
fLastTransfer = lastTransfer;
if (transfer == fFirstTransfer)
fFirstTransfer = transfer->link;
if (transfer == fLastTransfer)
fLastTransfer = lastTransfer;
transfer_data *next = transfer->link;
delete transfer;
transfer = next;
transfer_data *next = transfer->link;
delete transfer;
transfer = next;
Unlock();
}
} else {
TRACE(("usb_uhci: transfer (0x%08x) not done\n", transfer));
lastTransfer = transfer;
@ -906,7 +993,13 @@ UHCI::AddTo(Stack &stack)
TRACE(("usb_uhci: AddTo(): setting up hardware\n"));
bool found = false;
pci_info *item = new pci_info;
pci_info *item = new(std::nothrow) pci_info;
if (!item) {
sPCIModule = NULL;
put_module(B_PCI_MODULE_NAME);
return B_NO_MEMORY;
}
for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) {
//class_base = 0C (serial bus) class_sub = 03 (usb) prog_int: 00 (UHCI)
if (item->class_base == 0x0C && item->class_sub == 0x03
@ -918,7 +1011,14 @@ UHCI::AddTo(Stack &stack)
}
TRACE(("usb_uhci: AddTo(): found at IRQ %u\n", item->u.h0.interrupt_line));
UHCI *bus = new UHCI(item, &stack);
UHCI *bus = new(std::nothrow) UHCI(item, &stack);
if (!bus) {
delete item;
sPCIModule = NULL;
put_module(B_PCI_MODULE_NAME);
return B_NO_MEMORY;
}
if (bus->InitCheck() < B_OK) {
TRACE(("usb_uhci: AddTo(): InitCheck() failed 0x%08x\n", bus->InitCheck()));
delete bus;
@ -970,8 +1070,11 @@ UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, int32 bufferSize)
result->link_phy = 0;
result->link_log = NULL;
if (bufferSize <= 0)
if (bufferSize <= 0) {
result->buffer_log = NULL;
result->buffer_phy = NULL;
return result;
}
if (fStack->AllocateChunk(&result->buffer_log, &result->buffer_phy,
bufferSize) < B_OK) {
@ -991,7 +1094,7 @@ UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
int32 packetSize = pipe->MaxPacketSize();
int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
bool dataToggle = true;
bool dataToggle = pipe->DataToggle();
uhci_td *firstDescriptor = NULL;
uhci_td *lastDescriptor = *_firstDescriptor;
for (int32 i = 0; i < descriptorCount; i++) {
@ -1017,6 +1120,7 @@ UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
firstDescriptor = descriptor;
}
pipe->SetDataToggle(dataToggle);
*_firstDescriptor = firstDescriptor;
*_lastDescriptor = lastDescriptor;
return B_OK;
@ -1029,7 +1133,6 @@ UHCI::FreeDescriptor(uhci_td *descriptor)
if (!descriptor)
return;
return;
if (descriptor->buffer_log) {
fStack->FreeChunk(descriptor->buffer_log,
(void *)descriptor->buffer_phy, descriptor->buffer_size);

View File

@ -12,6 +12,7 @@
#include "usb_p.h"
#include "uhci_hardware.h"
#include <lock.h>
struct pci_info;
struct pci_module_info;
@ -45,10 +46,7 @@ private:
uhci_qh *fQueueHead;
uhci_td *fStrayDescriptor;
uhci_td *fQueueTop;
// Benaphore locking
sem_id fLockSem;
int32 fLockAtom;
benaphore fLock;
};
@ -133,10 +131,7 @@ static pci_module_info *sPCIModule;
uint32 fRegisterBase;
pci_info *fPCIInfo;
Stack *fStack;
// Benaphore locking
sem_id fLockSem;
int32 fLockAtom;
benaphore fUHCILock;
// Frame list memory
area_id fFrameArea;

View File

@ -115,6 +115,7 @@ typedef struct
#define TD_DEPTH_FIRST 0x4
#define TD_TERMINATE 0x1
#define TD_ERROR_MASK 0x7e0000
#define TD_LINK_MASK 0xfffffff0
//Represents a Queue Head (QH)
@ -126,7 +127,6 @@ typedef struct
// Software part
addr_t this_phy; //The physical pointer to this address
void * link_log; //Link to the next TD/QH logical
void * element_log; //
} uhci_qh;
#define QH_TERMINATE 0x1
@ -143,11 +143,10 @@ typedef struct
#define RH_SET_CONFIG 9
//Descriptors (in usb_request_data->Value)
#define RH_DEVICE_DESCRIPTOR ( 1 << 8 )
#define RH_CONFIG_DESCRIPTOR ( 2 << 8 )
#define RH_INTERFACE_DESCRIPTOR ( 4 << 8 )
#define RH_ENDPOINT_DESCRIPTOR ( 5 << 8 )
#define RH_HUB_DESCRIPTOR ( 0x29 << 8 )
#define RH_DEVICE_DESCRIPTOR (0x01 << 8)
#define RH_CONFIG_DESCRIPTOR (0x02 << 8)
#define RH_STRING_DESCRIPTOR (0x03 << 8)
#define RH_HUB_DESCRIPTOR (0x29 << 8)
//Hub/Portstatus buffer
typedef struct

View File

@ -19,75 +19,114 @@
#endif
usb_device_descriptor uhci_devd =
static usb_device_descriptor sUHCIRootHubDevice =
{
0x12, //Descriptor size
USB_DESCRIPTOR_DEVICE, //Type of descriptor
0x110, //USB 1.1
0x09, //Hub type
0, //Subclass
0, //Protocol
64, //Max packet size
0, //Vendor
0, //Product
0x110, //Version
1, 2, 0, //Other data
1 //Number of configurations
18, // Descriptor length
USB_DESCRIPTOR_DEVICE, // Descriptor type
0x110, // USB 1.1
0x09, // Class (9 = Hub)
0, // Subclass
0, // Protocol
64, // Max packet size on endpoint 0
0, // Vendor ID
0, // Product ID
0x110, // Version
1, // Index of manufacturer string
2, // Index of product string
0, // Index of serial number string
1 // Number of configurations
};
usb_configuration_descriptor uhci_confd =
struct uhci_root_hub_configuration_s {
usb_configuration_descriptor configuration;
usb_interface_descriptor interface;
usb_endpoint_descriptor endpoint;
usb_hub_descriptor hub;
} _PACKED;
static uhci_root_hub_configuration_s sUHCIRootHubConfig =
{
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)
{ // configuration descriptor
9, // Descriptor length
USB_DESCRIPTOR_CONFIGURATION, // Descriptor type
34, // Total length of configuration (including
// interface, endpoint and hub descriptors)
1, // Number of interfaces
1, // Value of this configuration
0, // Index of configuration string
0x40, // Attributes (0x40 = self powered)
0 // Max power (0, since self powered)
},
{ // interface descriptor
9, // Descriptor length
USB_DESCRIPTOR_INTERFACE, // Descriptor type
0, // Interface number
0, // Alternate setting
1, // Number of endpoints
0x09, // Interface class (9 = Hub)
0, // Interface subclass
0, // Interface protocol
0, // Index of interface string
},
{ // endpoint descriptor
7, // Descriptor length
USB_DESCRIPTOR_ENDPOINT, // Descriptor type
USB_REQTYPE_DEVICE_IN | 1, // Endpoint address (first in IN endpoint)
0x03, // Attributes (0x03 = interrupt endpoint)
8, // Max packet size
0xFF // Interval
},
{ // hub descriptor
9, // Descriptor length (including
// deprecated power control mask)
USB_DESCRIPTOR_HUB, // Descriptor type
2, // Number of ports
0x0000, // Hub characteristics
50, // Power on to power good (in 2ms units)
0, // Maximum current (in mA)
0x00, // Both ports are removable
0xff // Depricated power control mask
}
};
usb_interface_descriptor uhci_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 uhci_root_hub_string_s {
uint8 length;
uint8 descriptor_type;
uint16 unicode_string[12];
};
usb_endpoint_descriptor uhci_endd =
{
0x07, //Size
USB_DESCRIPTOR_ENDPOINT,
USB_REQTYPE_DEVICE_IN | 1, //1 from freebsd driver
0x3, // Interrupt
8, // Max packet size
0xFF // Interval 256
};
static uhci_root_hub_string_s sUHCIRootHubStrings[3] = {
{
4, // Descriptor length
USB_DESCRIPTOR_STRING, // Descriptor type
0x0409 // Supported language IDs (English US)
},
{
12, // Descriptor length
USB_DESCRIPTOR_STRING, // Descriptor type
'H', 'A', 'I', 'K', 'U', ' ', // Characters
'I', 'n', 'c', '.'
},
usb_hub_descriptor uhci_hubd =
{
0x09, //Including deprecated powerctrlmask
USB_DESCRIPTOR_HUB,
2, //Number of ports
0x02 | 0x01, //Hub characteristics FIXME
50, //Power on to power good
0, // Current
0x00 //Both ports are removable
{
26, // Descriptor length
USB_DESCRIPTOR_STRING, // Descriptor type
'U', 'H', 'C', 'I', ' ', 'R', // Characters
'o', 'o', 't', 'H', 'u', 'b'
}
};
UHCIRootHub::UHCIRootHub(UHCI *uhci, int8 devicenum)
: Hub(uhci, NULL, uhci_devd, devicenum, false)
: Hub(uhci, NULL, sUHCIRootHubDevice, devicenum, false)
{
fUHCI = uhci;
}
@ -100,14 +139,14 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
TRACE(("usb_uhci_roothub: rh_submit_packet called. request: %u\n", request->Request));
status_t result = B_ERROR;
switch(request->Request) {
switch (request->Request) {
case RH_GET_STATUS:
if (request->Index == 0) {
// Get the hub status -- everything as 0 means all-right
memset(transfer->Buffer(), 0, sizeof(get_status_buffer));
memset(transfer->Data(), 0, sizeof(get_status_buffer));
result = B_OK;
break;
} else if (request->Index > uhci_hubd.bNbrPorts) {
} else if (request->Index > sUHCIRootHubConfig.hub.bNbrPorts) {
// This port doesn't exist
result = EINVAL;
break;
@ -115,11 +154,11 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
// Get port status
UpdatePortStatus();
memcpy(transfer->Buffer(),
memcpy(transfer->Data(),
(void *)&fPortStatus[request->Index - 1],
transfer->BufferLength());
transfer->DataLength());
*(transfer->ActualLength()) = transfer->BufferLength();
*(transfer->ActualLength()) = transfer->DataLength();
result = B_OK;
break;
@ -136,37 +175,54 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
case RH_GET_DESCRIPTOR:
TRACE(("usb_uhci_roothub: rh_submit_packet GET_DESC: %d\n", request->Value));
switch (request->Value) {
case RH_DEVICE_DESCRIPTOR:
memcpy(transfer->Buffer(), (void *)&uhci_devd,
transfer->BufferLength());
*(transfer->ActualLength()) = transfer->BufferLength();
switch (request->Value & 0xff00) {
case RH_DEVICE_DESCRIPTOR: {
size_t length = MIN(sizeof(usb_device_descriptor),
transfer->DataLength());
memcpy(transfer->Data(), (void *)&sUHCIRootHubDevice,
length);
*(transfer->ActualLength()) = length;
result = B_OK;
break;
case RH_CONFIG_DESCRIPTOR:
memcpy(transfer->Buffer(), (void *)&uhci_confd,
transfer->BufferLength());
*(transfer->ActualLength()) = transfer->BufferLength();
}
case RH_CONFIG_DESCRIPTOR: {
size_t length = MIN(sizeof(uhci_root_hub_configuration_s),
transfer->DataLength());
memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig,
length);
*(transfer->ActualLength()) = length;
result = B_OK;
break;
case RH_INTERFACE_DESCRIPTOR:
memcpy(transfer->Buffer(), (void *)&uhci_intd,
transfer->BufferLength());
*(transfer->ActualLength()) = transfer->BufferLength();
result = B_OK ;
break;
case RH_ENDPOINT_DESCRIPTOR:
memcpy(transfer->Buffer(), (void *)&uhci_endd,
transfer->BufferLength());
*(transfer->ActualLength()) = transfer->BufferLength();
result = B_OK ;
break;
case RH_HUB_DESCRIPTOR:
memcpy(transfer->Buffer(), (void *)&uhci_hubd,
transfer->BufferLength());
*(transfer->ActualLength()) = transfer->BufferLength();
}
case RH_STRING_DESCRIPTOR: {
uint8 index = request->Value & 0x00ff;
if (index > 2) {
*(transfer->ActualLength()) = 0;
result = EINVAL;
break;
}
size_t length = MIN(sUHCIRootHubStrings[index].length,
transfer->DataLength());
memcpy(transfer->Data(), (void *)&sUHCIRootHubStrings[index],
length);
*(transfer->ActualLength()) = length;
result = B_OK;
break;
}
case RH_HUB_DESCRIPTOR: {
size_t length = MIN(sizeof(usb_hub_descriptor),
transfer->DataLength());
memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig.hub,
length);
*(transfer->ActualLength()) = length;
result = B_OK;
break;
}
default:
result = EINVAL;
break;
@ -183,7 +239,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE no hub changes!\n"));
result = EINVAL;
break;
} else if (request->Index > uhci_hubd.bNbrPorts) {
} else if (request->Index > sUHCIRootHubConfig.hub.bNbrPorts) {
// Invalid port number
TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE invalid port!\n"));
result = EINVAL;
@ -217,7 +273,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
TRACE(("usb_uhci_roothub: RH_SET_FEATURE no hub changes!\n"));
result = EINVAL;
break;
} else if (request->Index > uhci_hubd.bNbrPorts) {
} else if (request->Index > sUHCIRootHubConfig.hub.bNbrPorts) {
// Invalid port number
TRACE(("usb_uhci_roothub: RH_SET_FEATURE invalid port!\n"));
result = EINVAL;
@ -256,7 +312,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
void
UHCIRootHub::UpdatePortStatus()
{
for (int32 i = 0; i < uhci_hubd.bNbrPorts; i++) {
for (int32 i = 0; i < sUHCIRootHubConfig.hub.bNbrPorts; i++) {
uint16 newStatus = 0;
uint16 newChange = 0;