diff --git a/src/add-ons/kernel/bus_managers/usb/BusManager.cpp b/src/add-ons/kernel/bus_managers/usb/BusManager.cpp index 1aa4f4b8ae..d0a6538fea 100644 --- a/src/add-ons/kernel/bus_managers/usb/BusManager.cpp +++ b/src/add-ons/kernel/bus_managers/usb/BusManager.cpp @@ -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; } diff --git a/src/add-ons/kernel/bus_managers/usb/Device.cpp b/src/add-ons/kernel/bus_managers/usb/Device.cpp index b32c82f29a..70dc06ec13 100644 --- a/src/add-ons/kernel/bus_managers/usb/Device.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Device.cpp @@ -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 = + ¤tInterface->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); +} diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index 57a4aeeaa1..ffb246b3c9 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -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); + } +} diff --git a/src/add-ons/kernel/bus_managers/usb/Jamfile b/src/add-ons/kernel/bus_managers/usb/Jamfile index c4631ee269..328418608b 100644 --- a/src/add-ons/kernel/bus_managers/usb/Jamfile +++ b/src/add-ons/kernel/bus_managers/usb/Jamfile @@ -12,6 +12,7 @@ KernelStaticLibrary libusb.a : BusManager.cpp Transfer.cpp Pipe.cpp + Interface.cpp : -fno-pic ; diff --git a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp index f4c214209b..f60c868bf0 100644 --- a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp @@ -3,21 +3,23 @@ * Distributed under the terms of the MIT License. * * Authors: + * Michael Lotz * 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); } diff --git a/src/add-ons/kernel/bus_managers/usb/Stack.cpp b/src/add-ons/kernel/bus_managers/usb/Stack.cpp index 1c67987661..1df9fce4cc 100644 --- a/src/add-ons/kernel/bus_managers/usb/Stack.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Stack.cpp @@ -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; +} diff --git a/src/add-ons/kernel/bus_managers/usb/Transfer.cpp b/src/add-ons/kernel/bus_managers/usb/Transfer.cpp index 04f5e29db4..25713829bf 100644 --- a/src/add-ons/kernel/bus_managers/usb/Transfer.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Transfer.cpp @@ -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; + } } diff --git a/src/add-ons/kernel/bus_managers/usb/usb.cpp b/src/add-ons/kernel/bus_managers/usb/usb.cpp index f9a992ed84..c4e18a34f7 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb.cpp +++ b/src/add-ons/kernel/bus_managers/usb/usb.cpp @@ -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 }; diff --git a/src/add-ons/kernel/bus_managers/usb/usb_p.h b/src/add-ons/kernel/bus_managers/usb/usb_p.h index bc1495af2e..be26b863fc 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb_p.h +++ b/src/add-ons/kernel/bus_managers/usb/usb_p.h @@ -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 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 diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index 242acc5456..046ea1abd7 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -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); diff --git a/src/add-ons/kernel/busses/usb/uhci.h b/src/add-ons/kernel/busses/usb/uhci.h index 7268797b08..bfee60d4e3 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -12,6 +12,7 @@ #include "usb_p.h" #include "uhci_hardware.h" +#include 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; diff --git a/src/add-ons/kernel/busses/usb/uhci_hardware.h b/src/add-ons/kernel/busses/usb/uhci_hardware.h index 4b21c27ed8..f0c1776765 100644 --- a/src/add-ons/kernel/busses/usb/uhci_hardware.h +++ b/src/add-ons/kernel/busses/usb/uhci_hardware.h @@ -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 diff --git a/src/add-ons/kernel/busses/usb/uhci_rh.cpp b/src/add-ons/kernel/busses/usb/uhci_rh.cpp index 398180a877..bfdef5faad 100644 --- a/src/add-ons/kernel/busses/usb/uhci_rh.cpp +++ b/src/add-ons/kernel/busses/usb/uhci_rh.cpp @@ -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;