* 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
@@ -35,10 +35,13 @@ BusManager::BusManager()
fDeviceMap[i] = false; fDeviceMap[i] = false;
// Set up the default pipes // Set up the default pipes
fDefaultPipe = new ControlPipe(this, 0, Pipe::Default, Pipe::NormalSpeed, fDefaultPipe = new(std::nothrow) ControlPipe(this, 0, Pipe::NormalSpeed, 0, 8);
0, 8); if (!fDefaultPipe)
fDefaultPipeLowSpeed = new ControlPipe(this, 0, Pipe::Default, return;
Pipe::LowSpeed, 0, 8);
fDefaultPipeLowSpeed = new(std::nothrow) ControlPipe(this, 0, Pipe::LowSpeed, 0, 8);
if (!fDefaultPipeLowSpeed)
return;
fExploreThread = -1; fExploreThread = -1;
fInitOK = true; fInitOK = true;
@@ -97,7 +100,7 @@ BusManager::AllocateNewDevice(Device *parent, bool lowSpeed)
// Set the address of the device USB 1.1 spec p202 // Set the address of the device USB 1.1 spec p202
status_t result = defaultPipe->SendRequest( 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 USB_REQUEST_SET_ADDRESS, // request
deviceAddress, // value deviceAddress, // value
0, // index 0, // index
@@ -115,7 +118,7 @@ BusManager::AllocateNewDevice(Device *parent, bool lowSpeed)
snooze(10000); snooze(10000);
// Create a temporary pipe with the new address // 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); lowSpeed ? Pipe::LowSpeed : Pipe::NormalSpeed, 0, 8);
// Get the device descriptor // 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) // Create a new instance based on the type (Hub or Device)
if (deviceDescriptor.device_class == 0x09) { if (deviceDescriptor.device_class == 0x09) {
TRACE(("usb BusManager::AllocateNewDevice(): creating new hub\n")); TRACE(("usb BusManager::AllocateNewDevice(): creating new hub\n"));
Device *ret = new Hub(this, parent, deviceDescriptor, deviceAddress, Hub *hub = new(std::nothrow) Hub(this, parent, deviceDescriptor,
lowSpeed); 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) { if (parent == NULL) {
// root hub // root hub
fRootHub = ret; fRootHub = hub;
} }
return ret; return (Device *)hub;
} }
TRACE(("usb BusManager::AllocateNewDevice(): creating new device\n")); 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;
} }
+345 -40
View File
@@ -19,13 +19,20 @@
Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc, Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
int8 deviceAddress, bool lowSpeed) 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")); TRACE(("USB Device: new device\n"));
fLock = create_sem(1, "USB Device Lock"); 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); set_sem_owner(fLock, B_SYSTEM_TEAM);
fLowSpeed = lowSpeed;
fDeviceDescriptor = desc;
fMaxPacketIn[0] = fMaxPacketOut[0] = fDeviceDescriptor.max_packet_size_0; 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 // Get the device descriptor
// We already have a part of it, but we want it all // We already have a part of it, but we want it all
status_t status = GetDescriptor(USB_DESCRIPTOR_DEVICE, 0, size_t actualLength;
(void *)&fDeviceDescriptor, sizeof(fDeviceDescriptor)); 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")); TRACE(("USB Device: error while getting the device descriptor\n"));
return; return;
} }
@@ -69,28 +73,190 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
TRACE(("\tnum_configurations:..%d\n", fDeviceDescriptor.num_configurations)); TRACE(("\tnum_configurations:..%d\n", fDeviceDescriptor.num_configurations));
// Get the configurations // Get the configurations
fConfigurations = (usb_configuration_descriptor *)malloc(fDeviceDescriptor.num_configurations fConfigurations = (usb_configuration_info *)malloc(
* sizeof(usb_configuration_descriptor)); fDeviceDescriptor.num_configurations * sizeof(usb_configuration_info));
if (fConfigurations == NULL) { if (fConfigurations == NULL) {
TRACE(("USB Device: out of memory during config creations!\n")); TRACE(("USB Device: out of memory during config creations!\n"));
return; return;
} }
for (int32 i = 0; i < fDeviceDescriptor.num_configurations; i++) { for (int32 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
size_t size = GetDescriptor(USB_DESCRIPTOR_CONFIGURATION, i, usb_configuration_descriptor configDescriptor;
(void *)&fConfigurations[i], sizeof(usb_configuration_descriptor)); 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)); TRACE(("USB Device %d: error fetching configuration %d\n", fDeviceAddress, i));
return; 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 // Set default configuration
TRACE(("USB Device %d: setting default configuration\n", fDeviceAddress)); 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; fInitOK = true;
} }
@@ -105,36 +271,61 @@ Device::InitCheck()
} }
// Returns the length that was copied (index gives the number of the config) status_t
size_t Device::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID,
Device::GetDescriptor(uint8 descriptorType, uint16 index, void *buffer, void *data, size_t dataLength, size_t *actualLength)
size_t bufferSize)
{ {
size_t actualLength = 0; return SendRequest(
fDefaultPipe->SendRequest(
USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD, // type USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD, // type
USB_REQUEST_GET_DESCRIPTOR, // request USB_REQUEST_GET_DESCRIPTOR, // request
(descriptorType << 8) | index, // value (descriptorType << 8) | index, // value
0, // index languageID, // index
bufferSize, // length dataLength, // length
buffer, // buffer data, // buffer
bufferSize, // buffer length dataLength, // buffer length
&actualLength); // actual length actualLength); // actual length
return actualLength;
} }
status_t const usb_configuration_info *
Device::SetConfiguration(uint8 value) Device::Configuration() const
{ {
if (value >= fDeviceDescriptor.num_configurations) return fCurrentConfiguration;
return EINVAL; }
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_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD, // type
USB_REQUEST_SET_CONFIGURATION, // request USB_REQUEST_SET_CONFIGURATION, // request
value, // value index, // value
0, // index 0, // index
0, // length 0, // length
NULL, // buffer NULL, // buffer
@@ -145,6 +336,120 @@ Device::SetConfiguration(uint8 value)
return result; return result;
// Set current configuration // Set current configuration
fCurrentConfiguration = &fConfigurations[value]; fCurrentConfiguration = &fConfigurations[index];
// Wait some for the configuration being finished
snooze(10000);
return B_OK; 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);
}
+66 -32
View File
@@ -31,50 +31,45 @@ Hub::Hub(BusManager *bus, Device *parent, usb_device_descriptor &desc,
// Set to false again for the hub init. // Set to false again for the hub init.
fInitOK = false; 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) { || fDeviceDescriptor.device_protocol != 0) {
TRACE(("USB Hub: wrong class/subclass/protocol! Bailing out\n")); TRACE(("USB Hub: wrong class/subclass/protocol! Bailing out\n"));
return; return;
} }
if (fCurrentConfiguration->number_interfaces > 1) { if (Configuration()->descr->number_interfaces > 1) {
TRACE(("USB Hub: too many interfaces\n")); TRACE(("USB Hub: too many interfaces\n"));
return; return;
} }
size_t actualLength; fInterruptInterface = Configuration()->interface->active->descr;
if (GetDescriptor(USB_DESCRIPTOR_INTERFACE, 0, (void *)&fInterruptInterface, if (fInterruptInterface->num_endpoints > 1) {
sizeof(usb_interface_descriptor)) != sizeof(usb_interface_descriptor)) {
TRACE(("USB Hub: error getting the interrupt interface\n"));
return;
}
if (fInterruptInterface.num_endpoints > 1) {
TRACE(("USB Hub: too many endpoints\n")); TRACE(("USB Hub: too many endpoints\n"));
return; return;
} }
if (GetDescriptor(USB_DESCRIPTOR_ENDPOINT, 0, (void *)&fInterruptEndpoint, fInterruptEndpoint = Configuration()->interface->active->endpoint[0].descr;
sizeof(usb_endpoint_descriptor)) != sizeof(usb_endpoint_descriptor)) { if (fInterruptEndpoint->attributes != 0x03) { // interrupt endpoint
TRACE(("USB Hub: Error getting the endpoint\n"));
return;
}
if (fInterruptEndpoint.attributes != 0x03) { // interrupt transfer
TRACE(("USB Hub: Not an interrupt endpoint\n")); TRACE(("USB Hub: Not an interrupt endpoint\n"));
return; return;
} }
TRACE(("USB Hub: Getting hub descriptor...\n")); TRACE(("USB Hub: Getting hub descriptor...\n"));
if (GetDescriptor(USB_DESCRIPTOR_HUB, 0, (void *)&fHubDescriptor, size_t actualLength;
sizeof(usb_hub_descriptor)) != sizeof(usb_hub_descriptor)) { 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")); TRACE(("USB Hub: Error getting hub descriptor\n"));
return; return;
} }
// Enable port power on all ports // Enable port power on all ports
for (int32 i = 0; i < fHubDescriptor.bNbrPorts; i++) { 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, USB_REQUEST_SET_FEATURE,
PORT_POWER, PORT_POWER,
i + 1, i + 1,
@@ -85,7 +80,7 @@ Hub::Hub(BusManager *bus, Device *parent, usb_device_descriptor &desc,
} }
// Wait for power to stabilize // Wait for power to stabilize
snooze(fHubDescriptor.bPwrOn2PwrGood * 2); snooze(fHubDescriptor.bPwrOn2PwrGood * 2000);
fInitOK = true; fInitOK = true;
TRACE(("USB Hub: initialised ok\n")); TRACE(("USB Hub: initialised ok\n"));
@@ -99,7 +94,7 @@ Hub::Explore()
size_t actualLength; size_t actualLength;
// Get the current port status // 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, USB_REQUEST_GET_STATUS,
0, 0,
i + 1, i + 1,
@@ -117,7 +112,7 @@ Hub::Explore()
// We need to test the port change against a number of things // We need to test the port change against a number of things
if (fPortStatus[i].status & PORT_RESET) { 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, USB_REQUEST_CLEAR_FEATURE,
PORT_RESET, PORT_RESET,
i + 1, i + 1,
@@ -133,7 +128,7 @@ Hub::Explore()
if ((fPortStatus[i].status & PORT_STATUS_ENABLE) == 0) { if ((fPortStatus[i].status & PORT_STATUS_ENABLE) == 0) {
// enable the port if it isn't // enable the port if it isn't
fDefaultPipe->SendRequest( SendRequest(
USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
USB_REQUEST_SET_FEATURE, USB_REQUEST_SET_FEATURE,
PORT_ENABLE, PORT_ENABLE,
@@ -146,22 +141,25 @@ Hub::Explore()
TRACE(("USB Hub: Explore(): New device connected\n")); TRACE(("USB Hub: Explore(): New device connected\n"));
Device *newDevice; Device *newDevice = fBus->AllocateNewDevice(this,
if (fPortStatus[i].status & PORT_STATUS_LOW_SPEED) (fPortStatus[i].status & PORT_STATUS_LOW_SPEED) > 0);
newDevice = fBus->AllocateNewDevice(this, true);
else
newDevice = fBus->AllocateNewDevice(this, false);
if (newDevice) if (newDevice) {
fChildren[i] = newDevice; fChildren[i] = newDevice;
Manager()->GetStack()->NotifyDeviceChange(fChildren[i], true);
}
} else { } else {
// Device removed... // Device removed...
// ToDo: do something
TRACE(("USB Hub Explore(): Device removed\n")); 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 // Clear status change
fDefaultPipe->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
USB_REQUEST_CLEAR_FEATURE, USB_REQUEST_CLEAR_FEATURE,
C_PORT_CONNECTION, C_PORT_CONNECTION,
i + 1, 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);
}
}
@@ -12,6 +12,7 @@ KernelStaticLibrary libusb.a :
BusManager.cpp BusManager.cpp
Transfer.cpp Transfer.cpp
Pipe.cpp Pipe.cpp
Interface.cpp
: -fno-pic : -fno-pic
; ;
+203 -30
View File
@@ -3,21 +3,23 @@
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Michael Lotz <[email protected]>
* Niels S. Reedijk * Niels S. Reedijk
*/ */
#include "usb_p.h" #include "usb_p.h"
Pipe::Pipe(Device *device, pipeDirection direction, uint8 endpointAddress, Pipe::Pipe(Device *device, pipeDirection direction, pipeSpeed speed,
uint32 maxPacketSize) 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) if (fDevice)
fBus = fDevice->Manager(); 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 - // #pragma mark -
// //
ControlPipe::ControlPipe(Device *device, pipeDirection direction, InterruptPipe::InterruptPipe(Device *device, pipeDirection direction,
pipeSpeed speed, uint8 endpointAddress, uint32 maxPacketSize) 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, status_t
pipeDirection direction, pipeSpeed speed, uint8 endpointAddress, InterruptPipe::QueueInterrupt(void *data, size_t dataLength,
uint32 maxPacketSize) usb_callback_func callback, void *callbackCookie)
: Pipe(NULL, direction, endpointAddress, maxPacketSize) {
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; fBus = bus;
fDeviceAddress = deviceAddress;
fSpeed = speed;
} }
@@ -78,30 +177,104 @@ ControlPipe::SendRequest(uint8 requestType, uint8 request, uint16 value,
size_t *actualLength) size_t *actualLength)
{ {
usb_request_data requestData; usb_request_data requestData;
requestData.RequestType = requestType; requestData.RequestType = requestType;
requestData.Request = request; requestData.Request = request;
requestData.Value = value; requestData.Value = value;
requestData.Index = index; requestData.Index = index;
requestData.Length = length; requestData.Length = length;
return SendControlMessage(&requestData, data, dataLength, actualLength, Transfer *transfer = new(std::nothrow) Transfer(this, true);
3 * 1000 * 1000); 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 status_t
ControlPipe::SendControlMessage(usb_request_data *command, void *data, ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value,
size_t dataLength, size_t *actualLength, bigtime_t timeout) uint16 index, uint16 length, void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie)
{ {
// builds an usb packet with the needed data usb_request_data *requestData = new(std::nothrow) usb_request_data;
Transfer transfer(this, true); if (!requestData)
return B_NO_MEMORY;
transfer.SetRequestData(command); requestData->RequestType = requestType;
transfer.SetBuffer((uint8 *)data); requestData->Request = request;
transfer.SetBufferLength(dataLength); requestData->Value = value;
transfer.SetActualLength(actualLength); requestData->Index = index;
requestData->Length = length;
fBus->SubmitTransfer(&transfer); Transfer *transfer = new(std::nothrow) Transfer(this, false);
return transfer.WaitForFinish(); 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);
} }
+141 -6
View File
@@ -20,6 +20,7 @@
Stack::Stack() Stack::Stack()
: fDriverList(NULL)
{ {
TRACE(("usb stack: stack init\n")); TRACE(("usb stack: stack init\n"));
@@ -31,9 +32,6 @@ Stack::Stack()
fDataLock = create_sem(1, "usb data lock"); fDataLock = create_sem(1, "usb data lock");
set_sem_owner(fDataLock, B_SYSTEM_TEAM); 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 // Initialise the memory chunks: create 8, 16 and 32 byte-heaps
// NOTE: This is probably the most ugly code you will see in the // NOTE: This is probably the most ugly code you will see in the
// whole stack. Unfortunately this is needed because of the fact // whole stack. Unfortunately this is needed because of the fact
@@ -103,6 +101,27 @@ Stack::Stack()
chunk->next_item = NULL; 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 // Check for host controller modules
void *moduleList = open_module_list("busses/usb"); void *moduleList = open_module_list("busses/usb");
char moduleName[B_PATH_NAME_LENGTH]; char moduleName[B_PATH_NAME_LENGTH];
@@ -152,10 +171,10 @@ Stack::InitCheck()
} }
void bool
Stack::Lock() 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; listhead = fListhead16;
else if (size <= 32) else if (size <= 32)
listhead = fListhead32; listhead = fListhead32;
else if (size <= 64)
listhead = fListhead64;
else { else {
TRACE(("usb stack: Chunk size %d to big\n", size)); TRACE(("usb stack: Chunk size %d to big\n", size));
Unlock(); Unlock();
@@ -215,6 +236,8 @@ Stack::AllocateChunk(void **logicalAddress, void **physicalAddress, uint8 size)
fListhead16 = listhead; fListhead16 = listhead;
else if (size <= 32) else if (size <= 32)
fListhead32 = listhead; fListhead32 = listhead;
else if (size <= 64)
fListhead64 = listhead;
Unlock(); Unlock();
//TRACE(("usb stack: allocated a new chunk with size %u\n", size)); //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; listhead = fListhead16;
else if (size <= 32) else if (size <= 32)
listhead = fListhead32; listhead = fListhead32;
else if (size <= 64)
listhead = fListhead64;
else { else {
TRACE(("usb stack: Chunk size %d invalid\n", size)); TRACE(("usb stack: Chunk size %d invalid\n", size));
Unlock(); Unlock();
@@ -250,6 +275,8 @@ Stack::FreeChunk(void *logicalAddress, void *physicalAddress, uint8 size)
fListhead16 = (addr_t)logicalAddress; fListhead16 = (addr_t)logicalAddress;
else if (size <= 32) else if (size <= 32)
fListhead32 = (addr_t)logicalAddress; fListhead32 = (addr_t)logicalAddress;
else if (size <= 64)
fListhead64 = (addr_t)logicalAddress;
Unlock(); Unlock();
return B_OK; 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;
}
@@ -10,16 +10,19 @@
Transfer::Transfer(Pipe *pipe, bool synchronous) 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; fActualLength = &fOwnActualLength;
fBuffer = NULL;
fBufferLength = 0;
fActualLength = NULL;
fStatus = B_NO_INIT;
fSem = -1;
fHostPrivate = NULL;
fCallback = NULL;
if (synchronous) { if (synchronous) {
fSem = create_sem(0, "USB Transfer"); fSem = create_sem(0, "USB Transfer");
set_sem_owner(fSem, B_SYSTEM_TEAM); set_sem_owner(fSem, B_SYSTEM_TEAM);
@@ -37,21 +40,15 @@ Transfer::~Transfer()
void void
Transfer::SetRequestData(usb_request_data *data) Transfer::SetRequestData(usb_request_data *data)
{ {
fRequest = data; fRequestData = data;
} }
void void
Transfer::SetBuffer(uint8 *buffer) Transfer::SetData(uint8 *data, size_t dataLength)
{ {
fBuffer = buffer; fData = data;
} fDataLength = dataLength;
void
Transfer::SetBufferLength(size_t length)
{
fBufferLength = length;
} }
@@ -63,7 +60,7 @@ Transfer::SetActualLength(size_t *actualLength)
void void
Transfer::SetCallbackFunction(usb_callback_func callback, void *cookie) Transfer::SetCallback(usb_callback_func callback, void *cookie)
{ {
fCallback = callback; fCallback = callback;
fCallbackCookie = cookie; fCallbackCookie = cookie;
@@ -98,11 +95,15 @@ Transfer::Finished(status_t result)
{ {
fStatus = result; fStatus = result;
// If we are synchronous, release the sem // Call the callback function ...
if (fSem > B_OK) if (fCallback) {
release_sem(fSem); fCallback(fCallbackCookie, fStatus, fData, *fActualLength);
return;
}
// ToDo: implement callback correctly // ... or release the sem
if (fCallback) if (fSem > B_OK) {
fCallback(fCallbackCookie, fStatus, fBuffer, 0); release_sem(fSem);
return;
}
} }
+235 -26
View File
@@ -19,6 +19,9 @@
#endif #endif
Stack *gUSBStack = NULL;
static int32 static int32
bus_std_ops(int32 op, ...) bus_std_ops(int32 op, ...)
{ {
@@ -28,20 +31,25 @@ bus_std_ops(int32 op, ...)
set_dprintf_enabled(true); set_dprintf_enabled(true);
load_driver_symbols("usb"); load_driver_symbols("usb");
#endif #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) { if (stack->InitCheck() != B_OK) {
delete stack; delete stack;
return ENODEV; return ENODEV;
} }
gUSBStack = stack;
break; break;
} }
case B_MODULE_UNINIT: case B_MODULE_UNINIT:
TRACE(("usb_nielx: bus module: uninit\n")); TRACE(("usb_module: bus module: uninit\n"));
delete usb_stack; delete gUSBStack;
gUSBStack = NULL;
break; break;
default: 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 This module exports the USB API
*/ */
@@ -59,33 +268,33 @@ struct usb_module_info gModuleInfo = {
// First the bus_manager_info: // First the bus_manager_info:
{ {
{ {
"bus_managers/usb/nielx", B_USB_MODULE_NAME,
B_KEEP_LOADED, // Keep loaded, even if no driver requires it B_KEEP_LOADED, // Keep loaded, even if no driver requires it
bus_std_ops bus_std_ops
}, },
NULL // the rescan function NULL // the rescan function
}, },
NULL, // register_driver register_driver, // register_driver
NULL, // install_notify install_notify, // install_notify
NULL, // uninstall_notify uninstall_notify, // uninstall_notify
NULL, // get_device_descriptor get_device_descriptor, // get_device_descriptor
NULL, // get_nth_configuration_info get_nth_configuration, // get_nth_configuration
NULL, // get_configuration get_configuration, // get_configuration
NULL, // set_configuration set_configuration, // set_configuration
NULL, // set_alt_interface set_alt_interface, // set_alt_interface
NULL, // set_feature set_feature, // set_feature
NULL, // clear_feature clear_feature, // clear_feature
NULL, // get_status get_status, // get_status
NULL, // get_descriptor get_descriptor, // get_descriptor
NULL, // send_request send_request, // send_request
NULL, // queue_interrupt queue_interrupt, // queue_interrupt
NULL, // queue_bulk queue_bulk, // queue_bulk
NULL, // queue_isochronous queue_isochronous, // queue_isochronous
NULL, // queue_request queue_request, // queue_request
NULL, // set_pipe_policy set_pipe_policy, // set_pipe_policy
NULL, // cancel_queued_transfers cancel_queued_transfers, // cancel_queued_transfers
NULL // usb_ioctl usb_ioctl // usb_ioctl
}; };
+245 -100
View File
@@ -13,6 +13,8 @@
#include "usbspec_p.h" #include "usbspec_p.h"
class Hub;
class Device;
class Stack; class Stack;
class Device; class Device;
class Transfer; 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 { class Stack {
public: public:
Stack(); Stack();
@@ -34,7 +46,7 @@ public:
status_t InitCheck(); status_t InitCheck();
void Lock(); bool Lock();
void Unlock(); void Unlock();
void AddBusManager(BusManager *bus); void AddBusManager(BusManager *bus);
@@ -48,6 +60,19 @@ public:
void **physicalAddress, void **physicalAddress,
size_t size, const char *name); 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: private:
Vector<BusManager *> fBusManagers; Vector<BusManager *> fBusManagers;
@@ -62,61 +87,9 @@ private:
addr_t fListhead8; addr_t fListhead8;
addr_t fListhead16; addr_t fListhead16;
addr_t fListhead32; addr_t fListhead32;
}; addr_t fListhead64;
extern "C" Stack *usb_stack; usb_driver_info *fDriverList;
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];
}; };
@@ -143,10 +116,13 @@ virtual status_t Stop();
virtual status_t SubmitTransfer(Transfer *transfer); virtual status_t SubmitTransfer(Transfer *transfer);
virtual status_t SubmitRequest(Transfer *transfer); virtual status_t SubmitRequest(Transfer *transfer);
protected: Stack *GetStack() { return fStack; };
void SetRootHub(Hub *hub) { fRootHub = hub; }; void SetStack(Stack *stack) { fStack = stack; };
Device *GetRootHub() { return fRootHub; };
Hub *GetRootHub() { return fRootHub; };
void SetRootHub(Hub *hub) { fRootHub = hub; };
protected:
bool fInitOK; bool fInitOK;
private: private:
@@ -156,13 +132,14 @@ static int32 ExploreThread(void *data);
bool fDeviceMap[128]; bool fDeviceMap[128];
ControlPipe *fDefaultPipe; ControlPipe *fDefaultPipe;
ControlPipe *fDefaultPipeLowSpeed; ControlPipe *fDefaultPipeLowSpeed;
Device *fRootHub; Hub *fRootHub;
Stack *fStack;
thread_id fExploreThread; 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. * the stack. It creates packets, manages these and performs callbacks.
*/ */
class Pipe { class Pipe {
@@ -173,60 +150,230 @@ enum pipeType { Control, Bulk, Isochronous, Interrupt, Invalid };
Pipe(Device *device, Pipe(Device *device,
pipeDirection direction, pipeDirection direction,
pipeSpeed speed,
uint8 endpointAddress, uint8 endpointAddress,
uint32 maxPacketSize); uint32 maxPacketSize);
virtual ~Pipe(); virtual ~Pipe();
virtual int8 DeviceAddress(); virtual int8 DeviceAddress();
virtual pipeType Type() { return Invalid; }; virtual pipeType Type() { return Invalid; };
virtual pipeSpeed Speed() { return LowSpeed; }; virtual pipeSpeed Speed() { return fSpeed; };
//Provide a default: should never be called virtual pipeDirection Direction() { return fDirection; };
virtual int8 EndpointAddress() { return fEndpoint; }; virtual int8 EndpointAddress() { return fEndpoint; };
virtual uint32 MaxPacketSize() { return fMaxPacketSize; }; 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: protected:
Device *fDevice; Device *fDevice;
BusManager *fBus; BusManager *fBus;
pipeDirection fDirection; pipeDirection fDirection;
pipeSpeed fSpeed;
uint8 fEndpoint; uint8 fEndpoint;
uint32 fMaxPacketSize; 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 { class ControlPipe : public Pipe {
public: public:
ControlPipe(Device *device, ControlPipe(Device *device,
pipeDirection direction, pipeSpeed speed,
pipeSpeed speed, uint8 endpointAddress,
uint8 endpointAddress, uint32 maxPacketSize);
uint32 maxPacketSize);
// Constructor for default control pipe // Constructor for default control pipe
ControlPipe(BusManager *bus, ControlPipe(BusManager *bus,
int8 deviceAddress, int8 deviceAddress,
pipeDirection direction, pipeSpeed speed,
pipeSpeed speed, uint8 endpointAddress,
uint8 endpointAddress, uint32 maxPacketSize);
uint32 maxPacketSize);
virtual int8 DeviceAddress(); virtual int8 DeviceAddress();
virtual pipeType Type() { return Control; }; virtual pipeType Type() { return Control; };
virtual pipeSpeed Speed() { return fSpeed; };
status_t SendRequest(uint8 requestType, // The data toggle is not relevant
uint8 request, uint16 value, // for control transfers, as they are
uint16 index, uint16 length, // always enclosed by a setup and
void *data, size_t dataLength, // status packet. The toggle always
size_t *actualLength); // starts at 1.
virtual bool DataToggle() { return true; };
virtual void SetDataToggle(bool toggle) {};
status_t SendControlMessage(usb_request_data *command, status_t SendRequest(uint8 requestType,
void *data, size_t dataLength, uint8 request, uint16 value,
size_t *actualLength, uint16 index, uint16 length,
bigtime_t timeout); 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: private:
int8 fDeviceAddress; int8 fDeviceAddress;
pipeSpeed fSpeed; };
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; }; Pipe *TransferPipe() { return fPipe; };
void SetRequestData(usb_request_data *data); void SetRequestData(usb_request_data *data);
usb_request_data *RequestData() { return fRequest; }; usb_request_data *RequestData() { return fRequestData; };
void SetBuffer(uint8 *buffer); void SetData(uint8 *buffer, size_t length);
uint8 *Buffer() { return fBuffer; }; uint8 *Data() { return fData; };
size_t DataLength() { return fDataLength; };
void SetBufferLength(size_t length);
size_t BufferLength() { return fBufferLength; };
void SetActualLength(size_t *actualLength); void SetActualLength(size_t *actualLength);
size_t *ActualLength() { return fActualLength; }; size_t *ActualLength() { return fActualLength; };
@@ -264,19 +409,19 @@ public:
void SetHostPrivate(hostcontroller_priv *priv); void SetHostPrivate(hostcontroller_priv *priv);
hostcontroller_priv *HostPrivate() { return fHostPrivate; }; hostcontroller_priv *HostPrivate() { return fHostPrivate; };
void SetCallbackFunction( void SetCallback(usb_callback_func callback,
usb_callback_func callback,
void *cookie); void *cookie);
status_t WaitForFinish(); status_t WaitForFinish();
void Finished(status_t result); void Finished(status_t result);
private: private:
// Data that is related to the transfer // Data that is related to the transfer
Pipe *fPipe; Pipe *fPipe;
uint8 *fBuffer; uint8 *fData;
size_t fBufferLength; size_t fDataLength;
size_t *fActualLength; size_t *fActualLength;
size_t fOwnActualLength;
status_t fStatus; status_t fStatus;
usb_callback_func fCallback; usb_callback_func fCallback;
@@ -286,7 +431,7 @@ private:
hostcontroller_priv *fHostPrivate; hostcontroller_priv *fHostPrivate;
// For control transfers // For control transfers
usb_request_data *fRequest; usb_request_data *fRequestData;
}; };
#endif #endif
+178 -75
View File
@@ -21,8 +21,10 @@
#define TRACE_UHCI #define TRACE_UHCI
#ifdef TRACE_UHCI #ifdef TRACE_UHCI
#define TRACE(x) dprintf x #define TRACE(x) dprintf x
#define TRACE_ERROR(x) dprintf x
#else #else
#define TRACE(x) /* nothing */ #define TRACE(x) /* nothing */
#define TRACE_ERROR(x) dprintf x
#endif #endif
@@ -101,15 +103,11 @@ Queue::Queue(Stack *stack)
{ {
fStack = stack; fStack = stack;
fLockAtom = 0; if (benaphore_init(&fLock, "uhci queue lock") < B_OK) {
fLockSem = create_sem(1, "uhci queue lock");
if (fLockSem < B_OK) {
TRACE(("usb_uhci: failed to create queue lock\n")); TRACE(("usb_uhci: failed to create queue lock\n"));
return; return;
} }
set_sem_owner(fLockSem, B_SYSTEM_TEAM);
void *physicalAddress; void *physicalAddress;
fStatus = fStack->AllocateChunk((void **)&fQueueHead, &physicalAddress, 32); fStatus = fStack->AllocateChunk((void **)&fQueueHead, &physicalAddress, 32);
if (fStatus < B_OK) if (fStatus < B_OK)
@@ -117,7 +115,6 @@ Queue::Queue(Stack *stack)
fQueueHead->this_phy = (addr_t)physicalAddress; fQueueHead->this_phy = (addr_t)physicalAddress;
fQueueHead->element_phy = QH_TERMINATE; fQueueHead->element_phy = QH_TERMINATE;
fQueueHead->element_log = 0;
fStrayDescriptor = NULL; fStrayDescriptor = NULL;
fQueueTop = NULL; fQueueTop = NULL;
@@ -127,7 +124,7 @@ Queue::Queue(Stack *stack)
Queue::~Queue() Queue::~Queue()
{ {
Lock(); Lock();
delete_sem(fLockSem); benaphore_destroy(&fLock);
fStack->FreeChunk(fQueueHead, (void *)fQueueHead->this_phy, 32); fStack->FreeChunk(fQueueHead, (void *)fQueueHead->this_phy, 32);
@@ -146,18 +143,14 @@ Queue::InitCheck()
bool bool
Queue::Lock() Queue::Lock()
{ {
if (atomic_add(&fLockAtom, 1) > 0) return (benaphore_lock(&fLock) == B_OK);
return acquire_sem(fLockSem) == B_OK;
return true;
} }
void void
Queue::Unlock() Queue::Unlock()
{ {
if (atomic_add(&fLockAtom, -1) > 1) benaphore_unlock(&fLock);
release_sem(fLockSem);
} }
@@ -210,7 +203,6 @@ Queue::TerminateByStrayDescriptor()
fQueueHead->link_phy = fStrayDescriptor->this_phy; fQueueHead->link_phy = fStrayDescriptor->this_phy;
fQueueHead->link_log = fStrayDescriptor; fQueueHead->link_log = fStrayDescriptor;
fQueueHead->element_phy = QH_TERMINATE; fQueueHead->element_phy = QH_TERMINATE;
fQueueHead->element_log = 0;
Unlock(); Unlock();
return B_OK; return B_OK;
@@ -231,18 +223,17 @@ Queue::AppendDescriptor(uhci_td *descriptor)
if (fQueueHead->element_phy & QH_TERMINATE) { if (fQueueHead->element_phy & QH_TERMINATE) {
// the queue is empty, make this the first element // the queue is empty, make this the first element
fQueueHead->element_phy = descriptor->this_phy;
fQueueHead->element_log = descriptor;
fQueueTop = descriptor; fQueueTop = descriptor;
fQueueHead->element_phy = descriptor->this_phy;
TRACE(("usb_uhci: first transfer in queue\n")); TRACE(("usb_uhci: first transfer in queue\n"));
} else { } else {
// there are transfers linked, append to the queue // 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) while ((element->link_phy & TD_TERMINATE) == 0)
element = (uhci_td *)element->link_log; element = (uhci_td *)element->link_log;
element->link_phy = descriptor->this_phy | TD_DEPTH_FIRST;
element->link_log = descriptor; element->link_log = descriptor;
element->link_phy = descriptor->this_phy | TD_DEPTH_FIRST;
TRACE(("usb_uhci: appended transfer to queue\n")); TRACE(("usb_uhci: appended transfer to queue\n"));
} }
@@ -254,27 +245,57 @@ Queue::AppendDescriptor(uhci_td *descriptor)
status_t status_t
Queue::RemoveDescriptors(uhci_td *firstDescriptor, uhci_td *lastDescriptor) Queue::RemoveDescriptors(uhci_td *firstDescriptor, uhci_td *lastDescriptor)
{ {
TRACE(("usb_uhci: removing descriptors\n"));
if (!Lock()) if (!Lock())
return B_ERROR; return B_ERROR;
if (fQueueTop == firstDescriptor) { if (fQueueTop == firstDescriptor) {
// it was the first chain in this queue // it was the first chain in this queue
fQueueTop = (uhci_td *)lastDescriptor->link_log; if ((lastDescriptor->link_phy & TD_TERMINATE) > 0) {
Unlock(); // it was the only transfer
return B_OK; 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; descriptor = (uhci_td *)descriptor->link_log;
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 = 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(); Unlock();
return B_OK; return B_OK;
} }
@@ -324,15 +345,11 @@ UHCI::UHCI(pci_info *info, Stack *stack)
TRACE(("usb_uhci: constructing new UHCI Host Controller Driver\n")); TRACE(("usb_uhci: constructing new UHCI Host Controller Driver\n"));
fInitOK = false; fInitOK = false;
fLockAtom = 0; if (benaphore_init(&fUHCILock, "usb uhci lock") < B_OK) {
fLockSem = create_sem(1, "usb uhci lock");
if (fLockSem < B_OK) {
TRACE(("usb_uhci: failed to create busmanager lock\n")); TRACE(("usb_uhci: failed to create busmanager lock\n"));
return; return;
} }
set_sem_owner(fLockSem, B_SYSTEM_TEAM);
fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus, fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus,
fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4); fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4);
fRegisterBase &= PCI_address_io_mask; fRegisterBase &= PCI_address_io_mask;
@@ -378,10 +395,15 @@ UHCI::UHCI(pci_info *info, Stack *stack)
WriteReg16(UHCI_FRNUM, 0); WriteReg16(UHCI_FRNUM, 0);
fQueueCount = 4; 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++) { for (int32 i = 0; i < fQueueCount; i++) {
fQueues[i] = new Queue(fStack); fQueues[i] = new(std::nothrow) Queue(fStack);
if (fQueues[i]->InitCheck() < B_OK) { if (!fQueues[i] || fQueues[i]->InitCheck() < B_OK) {
TRACE(("usb_uhci: cannot create queues\n")); TRACE(("usb_uhci: cannot create queues\n"));
delete_area(fFrameArea); delete_area(fFrameArea);
return; return;
@@ -436,7 +458,7 @@ UHCI::~UHCI()
delete [] fQueues; delete [] fQueues;
delete fRootHub; delete fRootHub;
delete_area(fFrameArea); delete_area(fFrameArea);
delete_sem(fLockSem); benaphore_destroy(&fUHCILock);
put_module(B_PCI_MODULE_NAME); put_module(B_PCI_MODULE_NAME);
} }
@@ -445,18 +467,14 @@ UHCI::~UHCI()
bool bool
UHCI::Lock() UHCI::Lock()
{ {
if (atomic_add(&fLockAtom, 1) > 0) return (benaphore_lock(&fUHCILock) == B_OK);
return acquire_sem(fLockSem) == B_OK;
return true;
} }
void void
UHCI::Unlock() UHCI::Unlock()
{ {
if (atomic_add(&fLockAtom, -1) > 1) benaphore_unlock(&fUHCILock);
release_sem(fLockSem);
} }
@@ -490,8 +508,20 @@ UHCI::Start()
} }
fRootHubAddress = AllocateAddress(); 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); SetRootHub(fRootHub);
SetStack(fStack);
TRACE(("usb_uhci: controller is started. status: %u curframe: %u\n", TRACE(("usb_uhci: controller is started. status: %u curframe: %u\n",
ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM))); ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM)));
@@ -511,7 +541,52 @@ UHCI::SubmitTransfer(Transfer *transfer)
if (transfer->TransferPipe()->Type() == Pipe::Control) if (transfer->TransferPipe()->Type() == Pipe::Control)
return SubmitRequest(transfer); 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; statusDescriptor->link_log = 0;
uhci_td *dataDescriptor = NULL; uhci_td *dataDescriptor = NULL;
if (transfer->Buffer() && transfer->BufferLength() > 0) { if (transfer->Data() && transfer->DataLength() > 0) {
uhci_td *lastDescriptor = NULL; uhci_td *lastDescriptor = NULL;
status_t result = CreateDescriptorChain(pipe, &dataDescriptor, status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
&lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, &lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
transfer->BufferLength()); transfer->DataLength());
if (result < B_OK) { if (result < B_OK) {
FreeDescriptor(setupDescriptor); FreeDescriptor(setupDescriptor);
@@ -557,8 +632,8 @@ UHCI::SubmitRequest(Transfer *transfer)
} }
if (!directionIn) { if (!directionIn) {
WriteDescriptorChain(dataDescriptor, transfer->Buffer(), WriteDescriptorChain(dataDescriptor, transfer->Data(),
transfer->BufferLength()); transfer->DataLength());
} }
LinkDescriptors(setupDescriptor, dataDescriptor); LinkDescriptors(setupDescriptor, dataDescriptor);
@@ -568,17 +643,22 @@ UHCI::SubmitRequest(Transfer *transfer)
LinkDescriptors(setupDescriptor, statusDescriptor); LinkDescriptors(setupDescriptor, statusDescriptor);
} }
AddPendingTransfer(transfer, fQueues[1], setupDescriptor, dataDescriptor, status_t result = AddPendingTransfer(transfer, fQueues[1], setupDescriptor,
statusDescriptor, directionIn); 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) { if (result < B_OK) {
TRACE(("usb_uhci: failed to append descriptors\n")); TRACE(("usb_uhci: failed to append descriptors\n"));
FreeDescriptorChain(setupDescriptor); FreeDescriptorChain(setupDescriptor);
return result; return result;
} }
return EINPROGRESS; return EINPROGRESS;
} }
@@ -588,7 +668,10 @@ UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue,
bool directionIn) bool directionIn)
{ {
TRACE(("usb_uhci: add pending transfer\n")); 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->transfer = transfer;
data->queue = queue; data->queue = queue;
data->first_descriptor = firstDescriptor; 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)); TRACE(("usb_uhci: finishing transfers (first transfer: 0x%08x; last transfer: 0x%08x)\n", fFirstTransfer, fLastTransfer));
transfer_data *lastTransfer = NULL; transfer_data *lastTransfer = NULL;
transfer_data *transfer = fFirstTransfer; transfer_data *transfer = fFirstTransfer;
Unlock();
while (transfer) { while (transfer) {
bool transferDone = false; bool transferDone = false;
uhci_td *descriptor = transfer->first_descriptor; uhci_td *descriptor = transfer->first_descriptor;
@@ -653,7 +738,7 @@ UHCI::FinishTransfers()
} }
if (status & TD_ERROR_MASK) { 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 // an error occured. we have to remove the
// transfer from the queue and clean up // transfer from the queue and clean up
transfer->queue->RemoveDescriptors(transfer->first_descriptor, transfer->queue->RemoveDescriptors(transfer->first_descriptor,
@@ -675,12 +760,10 @@ UHCI::FinishTransfers()
// data to read out // data to read out
TRACE(("usb_uhci: reading incoming data buffer to transfer 0x%08x\n", transfer)); TRACE(("usb_uhci: reading incoming data buffer to transfer 0x%08x\n", transfer));
size_t length = ReadDescriptorChain(transfer->data_descriptor, size_t length = ReadDescriptorChain(transfer->data_descriptor,
transfer->transfer->Buffer(), transfer->transfer->Data(),
transfer->transfer->BufferLength()); transfer->transfer->DataLength());
size_t *actualLength = transfer->transfer->ActualLength(); *(transfer->transfer->ActualLength()) = length;
if (actualLength)
*actualLength = length;
} }
FreeDescriptorChain(transfer->first_descriptor); FreeDescriptorChain(transfer->first_descriptor);
@@ -695,17 +778,21 @@ UHCI::FinishTransfers()
if (transferDone) { if (transferDone) {
TRACE(("usb_uhci: transfer (0x%08x) done\n", transfer)); TRACE(("usb_uhci: transfer (0x%08x) done\n", transfer));
if (lastTransfer) if (Lock()) {
lastTransfer->link = transfer->link; if (lastTransfer)
lastTransfer->link = transfer->link;
if (transfer == fFirstTransfer) if (transfer == fFirstTransfer)
fFirstTransfer = transfer->link; fFirstTransfer = transfer->link;
if (transfer == fLastTransfer) if (transfer == fLastTransfer)
fLastTransfer = lastTransfer; fLastTransfer = lastTransfer;
transfer_data *next = transfer->link; transfer_data *next = transfer->link;
delete transfer; delete transfer;
transfer = next; transfer = next;
Unlock();
}
} else { } else {
TRACE(("usb_uhci: transfer (0x%08x) not done\n", transfer)); TRACE(("usb_uhci: transfer (0x%08x) not done\n", transfer));
lastTransfer = transfer; lastTransfer = transfer;
@@ -906,7 +993,13 @@ UHCI::AddTo(Stack &stack)
TRACE(("usb_uhci: AddTo(): setting up hardware\n")); TRACE(("usb_uhci: AddTo(): setting up hardware\n"));
bool found = false; 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++) { 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) //class_base = 0C (serial bus) class_sub = 03 (usb) prog_int: 00 (UHCI)
if (item->class_base == 0x0C && item->class_sub == 0x03 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)); 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) { if (bus->InitCheck() < B_OK) {
TRACE(("usb_uhci: AddTo(): InitCheck() failed 0x%08x\n", bus->InitCheck())); TRACE(("usb_uhci: AddTo(): InitCheck() failed 0x%08x\n", bus->InitCheck()));
delete bus; delete bus;
@@ -970,8 +1070,11 @@ UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, int32 bufferSize)
result->link_phy = 0; result->link_phy = 0;
result->link_log = NULL; result->link_log = NULL;
if (bufferSize <= 0) if (bufferSize <= 0) {
result->buffer_log = NULL;
result->buffer_phy = NULL;
return result; return result;
}
if (fStack->AllocateChunk(&result->buffer_log, &result->buffer_phy, if (fStack->AllocateChunk(&result->buffer_log, &result->buffer_phy,
bufferSize) < B_OK) { bufferSize) < B_OK) {
@@ -991,7 +1094,7 @@ UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
int32 packetSize = pipe->MaxPacketSize(); int32 packetSize = pipe->MaxPacketSize();
int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize; int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
bool dataToggle = true; bool dataToggle = pipe->DataToggle();
uhci_td *firstDescriptor = NULL; uhci_td *firstDescriptor = NULL;
uhci_td *lastDescriptor = *_firstDescriptor; uhci_td *lastDescriptor = *_firstDescriptor;
for (int32 i = 0; i < descriptorCount; i++) { for (int32 i = 0; i < descriptorCount; i++) {
@@ -1017,6 +1120,7 @@ UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
firstDescriptor = descriptor; firstDescriptor = descriptor;
} }
pipe->SetDataToggle(dataToggle);
*_firstDescriptor = firstDescriptor; *_firstDescriptor = firstDescriptor;
*_lastDescriptor = lastDescriptor; *_lastDescriptor = lastDescriptor;
return B_OK; return B_OK;
@@ -1029,7 +1133,6 @@ UHCI::FreeDescriptor(uhci_td *descriptor)
if (!descriptor) if (!descriptor)
return; return;
return;
if (descriptor->buffer_log) { if (descriptor->buffer_log) {
fStack->FreeChunk(descriptor->buffer_log, fStack->FreeChunk(descriptor->buffer_log,
(void *)descriptor->buffer_phy, descriptor->buffer_size); (void *)descriptor->buffer_phy, descriptor->buffer_size);
+3 -8
View File
@@ -12,6 +12,7 @@
#include "usb_p.h" #include "usb_p.h"
#include "uhci_hardware.h" #include "uhci_hardware.h"
#include <lock.h>
struct pci_info; struct pci_info;
struct pci_module_info; struct pci_module_info;
@@ -45,10 +46,7 @@ private:
uhci_qh *fQueueHead; uhci_qh *fQueueHead;
uhci_td *fStrayDescriptor; uhci_td *fStrayDescriptor;
uhci_td *fQueueTop; uhci_td *fQueueTop;
benaphore fLock;
// Benaphore locking
sem_id fLockSem;
int32 fLockAtom;
}; };
@@ -133,10 +131,7 @@ static pci_module_info *sPCIModule;
uint32 fRegisterBase; uint32 fRegisterBase;
pci_info *fPCIInfo; pci_info *fPCIInfo;
Stack *fStack; Stack *fStack;
benaphore fUHCILock;
// Benaphore locking
sem_id fLockSem;
int32 fLockAtom;
// Frame list memory // Frame list memory
area_id fFrameArea; area_id fFrameArea;
@@ -115,6 +115,7 @@ typedef struct
#define TD_DEPTH_FIRST 0x4 #define TD_DEPTH_FIRST 0x4
#define TD_TERMINATE 0x1 #define TD_TERMINATE 0x1
#define TD_ERROR_MASK 0x7e0000 #define TD_ERROR_MASK 0x7e0000
#define TD_LINK_MASK 0xfffffff0
//Represents a Queue Head (QH) //Represents a Queue Head (QH)
@@ -126,7 +127,6 @@ typedef struct
// Software part // Software part
addr_t this_phy; //The physical pointer to this address addr_t this_phy; //The physical pointer to this address
void * link_log; //Link to the next TD/QH logical void * link_log; //Link to the next TD/QH logical
void * element_log; //
} uhci_qh; } uhci_qh;
#define QH_TERMINATE 0x1 #define QH_TERMINATE 0x1
@@ -143,11 +143,10 @@ typedef struct
#define RH_SET_CONFIG 9 #define RH_SET_CONFIG 9
//Descriptors (in usb_request_data->Value) //Descriptors (in usb_request_data->Value)
#define RH_DEVICE_DESCRIPTOR ( 1 << 8 ) #define RH_DEVICE_DESCRIPTOR (0x01 << 8)
#define RH_CONFIG_DESCRIPTOR ( 2 << 8 ) #define RH_CONFIG_DESCRIPTOR (0x02 << 8)
#define RH_INTERFACE_DESCRIPTOR ( 4 << 8 ) #define RH_STRING_DESCRIPTOR (0x03 << 8)
#define RH_ENDPOINT_DESCRIPTOR ( 5 << 8 ) #define RH_HUB_DESCRIPTOR (0x29 << 8)
#define RH_HUB_DESCRIPTOR ( 0x29 << 8 )
//Hub/Portstatus buffer //Hub/Portstatus buffer
typedef struct typedef struct
+142 -86
View File
@@ -19,75 +19,114 @@
#endif #endif
usb_device_descriptor uhci_devd = static usb_device_descriptor sUHCIRootHubDevice =
{ {
0x12, //Descriptor size 18, // Descriptor length
USB_DESCRIPTOR_DEVICE, //Type of descriptor USB_DESCRIPTOR_DEVICE, // Descriptor type
0x110, //USB 1.1 0x110, // USB 1.1
0x09, //Hub type 0x09, // Class (9 = Hub)
0, //Subclass 0, // Subclass
0, //Protocol 0, // Protocol
64, //Max packet size 64, // Max packet size on endpoint 0
0, //Vendor 0, // Vendor ID
0, //Product 0, // Product ID
0x110, //Version 0x110, // Version
1, 2, 0, //Other data 1, // Index of manufacturer string
1 //Number of configurations 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 { // configuration descriptor
USB_DESCRIPTOR_CONFIGURATION, 9, // Descriptor length
25, //Total size (taken from BSD source) USB_DESCRIPTOR_CONFIGURATION, // Descriptor type
1, //Number interfaces 34, // Total length of configuration (including
1, //Value of configuration // interface, endpoint and hub descriptors)
0, //Number of configuration 1, // Number of interfaces
0x40, //Self powered 1, // Value of this configuration
0 //Max power (0, because of self power) 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 = struct uhci_root_hub_string_s {
{ uint8 length;
0x09, //Size uint8 descriptor_type;
USB_DESCRIPTOR_INTERFACE, uint16 unicode_string[12];
0, //Interface number
0, //Alternate setting
1, //Num endpoints
0x09, //Interface class
0, //Interface subclass
0, //Interface protocol
0, //Interface
}; };
usb_endpoint_descriptor uhci_endd = static uhci_root_hub_string_s sUHCIRootHubStrings[3] = {
{ {
0x07, //Size 4, // Descriptor length
USB_DESCRIPTOR_ENDPOINT, USB_DESCRIPTOR_STRING, // Descriptor type
USB_REQTYPE_DEVICE_IN | 1, //1 from freebsd driver 0x0409 // Supported language IDs (English US)
0x3, // Interrupt },
8, // Max packet size
0xFF // Interval 256
};
{
12, // Descriptor length
USB_DESCRIPTOR_STRING, // Descriptor type
'H', 'A', 'I', 'K', 'U', ' ', // Characters
'I', 'n', 'c', '.'
},
usb_hub_descriptor uhci_hubd = {
{ 26, // Descriptor length
0x09, //Including deprecated powerctrlmask USB_DESCRIPTOR_STRING, // Descriptor type
USB_DESCRIPTOR_HUB, 'U', 'H', 'C', 'I', ' ', 'R', // Characters
2, //Number of ports 'o', 'o', 't', 'H', 'u', 'b'
0x02 | 0x01, //Hub characteristics FIXME }
50, //Power on to power good
0, // Current
0x00 //Both ports are removable
}; };
UHCIRootHub::UHCIRootHub(UHCI *uhci, int8 devicenum) UHCIRootHub::UHCIRootHub(UHCI *uhci, int8 devicenum)
: Hub(uhci, NULL, uhci_devd, devicenum, false) : Hub(uhci, NULL, sUHCIRootHubDevice, devicenum, false)
{ {
fUHCI = uhci; fUHCI = uhci;
} }
@@ -100,14 +139,14 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
TRACE(("usb_uhci_roothub: rh_submit_packet called. request: %u\n", request->Request)); TRACE(("usb_uhci_roothub: rh_submit_packet called. request: %u\n", request->Request));
status_t result = B_ERROR; status_t result = B_ERROR;
switch(request->Request) { switch (request->Request) {
case RH_GET_STATUS: case RH_GET_STATUS:
if (request->Index == 0) { if (request->Index == 0) {
// Get the hub status -- everything as 0 means all-right // 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; result = B_OK;
break; break;
} else if (request->Index > uhci_hubd.bNbrPorts) { } else if (request->Index > sUHCIRootHubConfig.hub.bNbrPorts) {
// This port doesn't exist // This port doesn't exist
result = EINVAL; result = EINVAL;
break; break;
@@ -115,11 +154,11 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
// Get port status // Get port status
UpdatePortStatus(); UpdatePortStatus();
memcpy(transfer->Buffer(), memcpy(transfer->Data(),
(void *)&fPortStatus[request->Index - 1], (void *)&fPortStatus[request->Index - 1],
transfer->BufferLength()); transfer->DataLength());
*(transfer->ActualLength()) = transfer->BufferLength(); *(transfer->ActualLength()) = transfer->DataLength();
result = B_OK; result = B_OK;
break; break;
@@ -136,37 +175,54 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
case RH_GET_DESCRIPTOR: case RH_GET_DESCRIPTOR:
TRACE(("usb_uhci_roothub: rh_submit_packet GET_DESC: %d\n", request->Value)); TRACE(("usb_uhci_roothub: rh_submit_packet GET_DESC: %d\n", request->Value));
switch (request->Value) { switch (request->Value & 0xff00) {
case RH_DEVICE_DESCRIPTOR: case RH_DEVICE_DESCRIPTOR: {
memcpy(transfer->Buffer(), (void *)&uhci_devd, size_t length = MIN(sizeof(usb_device_descriptor),
transfer->BufferLength()); transfer->DataLength());
*(transfer->ActualLength()) = transfer->BufferLength(); memcpy(transfer->Data(), (void *)&sUHCIRootHubDevice,
length);
*(transfer->ActualLength()) = length;
result = B_OK; result = B_OK;
break; break;
case RH_CONFIG_DESCRIPTOR: }
memcpy(transfer->Buffer(), (void *)&uhci_confd,
transfer->BufferLength()); case RH_CONFIG_DESCRIPTOR: {
*(transfer->ActualLength()) = transfer->BufferLength(); size_t length = MIN(sizeof(uhci_root_hub_configuration_s),
transfer->DataLength());
memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig,
length);
*(transfer->ActualLength()) = length;
result = B_OK; result = B_OK;
break; break;
case RH_INTERFACE_DESCRIPTOR: }
memcpy(transfer->Buffer(), (void *)&uhci_intd,
transfer->BufferLength()); case RH_STRING_DESCRIPTOR: {
*(transfer->ActualLength()) = transfer->BufferLength(); uint8 index = request->Value & 0x00ff;
result = B_OK ; if (index > 2) {
break; *(transfer->ActualLength()) = 0;
case RH_ENDPOINT_DESCRIPTOR: result = EINVAL;
memcpy(transfer->Buffer(), (void *)&uhci_endd, break;
transfer->BufferLength()); }
*(transfer->ActualLength()) = transfer->BufferLength();
result = B_OK ; size_t length = MIN(sUHCIRootHubStrings[index].length,
break; transfer->DataLength());
case RH_HUB_DESCRIPTOR: memcpy(transfer->Data(), (void *)&sUHCIRootHubStrings[index],
memcpy(transfer->Buffer(), (void *)&uhci_hubd, length);
transfer->BufferLength()); *(transfer->ActualLength()) = length;
*(transfer->ActualLength()) = transfer->BufferLength();
result = B_OK; result = B_OK;
break; 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: default:
result = EINVAL; result = EINVAL;
break; break;
@@ -183,7 +239,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE no hub changes!\n")); TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE no hub changes!\n"));
result = EINVAL; result = EINVAL;
break; break;
} else if (request->Index > uhci_hubd.bNbrPorts) { } else if (request->Index > sUHCIRootHubConfig.hub.bNbrPorts) {
// Invalid port number // Invalid port number
TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE invalid port!\n")); TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE invalid port!\n"));
result = EINVAL; result = EINVAL;
@@ -217,7 +273,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
TRACE(("usb_uhci_roothub: RH_SET_FEATURE no hub changes!\n")); TRACE(("usb_uhci_roothub: RH_SET_FEATURE no hub changes!\n"));
result = EINVAL; result = EINVAL;
break; break;
} else if (request->Index > uhci_hubd.bNbrPorts) { } else if (request->Index > sUHCIRootHubConfig.hub.bNbrPorts) {
// Invalid port number // Invalid port number
TRACE(("usb_uhci_roothub: RH_SET_FEATURE invalid port!\n")); TRACE(("usb_uhci_roothub: RH_SET_FEATURE invalid port!\n"));
result = EINVAL; result = EINVAL;
@@ -256,7 +312,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
void void
UHCIRootHub::UpdatePortStatus() UHCIRootHub::UpdatePortStatus()
{ {
for (int32 i = 0; i < uhci_hubd.bNbrPorts; i++) { for (int32 i = 0; i < sUHCIRootHubConfig.hub.bNbrPorts; i++) {
uint16 newStatus = 0; uint16 newStatus = 0;
uint16 newChange = 0; uint16 newChange = 0;