From ffe3f107c4ae65ec52128bb36115779fe07a01c0 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Mon, 28 Aug 2006 00:43:10 +0000 Subject: [PATCH] * Redisigned some of the USB Stack. Unified constructors, removed redundant functions and moved some other functions around * Implemented the EHCIRootHub * Reworked UHCIRootHub to be more of a utility class and moved the actual work into the UHCI BusManager * Implemented port reset in EHCI. Ports with low and fullspeed devices are now correctly handed over to the companion host controller. Attachs and detachs as well as port resetting / enabling works now in EHCI. Only the actual data transfers are missing thereafter ;-) git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18656 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/bus_managers/usb/BusManager.cpp | 14 +- .../kernel/bus_managers/usb/Device.cpp | 21 +- src/add-ons/kernel/bus_managers/usb/Hub.cpp | 4 +- .../kernel/bus_managers/usb/Interface.cpp | 4 +- .../kernel/bus_managers/usb/Object.cpp | 5 +- src/add-ons/kernel/bus_managers/usb/Pipe.cpp | 173 +++++++--------- .../kernel/bus_managers/usb/Transfer.cpp | 6 +- src/add-ons/kernel/bus_managers/usb/usb.cpp | 12 +- src/add-ons/kernel/bus_managers/usb/usb_p.h | 55 +++--- .../kernel/bus_managers/usb/usbspec_p.h | 1 + src/add-ons/kernel/busses/usb/ehci.cpp | 184 ++++++++++++++++-- src/add-ons/kernel/busses/usb/ehci.h | 23 ++- src/add-ons/kernel/busses/usb/ehci_hardware.h | 6 +- src/add-ons/kernel/busses/usb/ehci_rh.cpp | 138 +++++++++++-- src/add-ons/kernel/busses/usb/uhci.cpp | 118 +++++++---- src/add-ons/kernel/busses/usb/uhci.h | 22 +-- src/add-ons/kernel/busses/usb/uhci_hardware.h | 24 --- src/add-ons/kernel/busses/usb/uhci_rh.cpp | 140 +++---------- 18 files changed, 559 insertions(+), 391 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/usb/BusManager.cpp b/src/add-ons/kernel/bus_managers/usb/BusManager.cpp index 25b08e085b..5e4cf364b1 100644 --- a/src/add-ons/kernel/bus_managers/usb/BusManager.cpp +++ b/src/add-ons/kernel/bus_managers/usb/BusManager.cpp @@ -28,11 +28,11 @@ BusManager::BusManager(Stack *stack) fDeviceMap[i] = false; // Set up the default pipes - fDefaultPipe = new(std::nothrow) ControlPipe(this, 0, Pipe::NormalSpeed, 8); + fDefaultPipe = new(std::nothrow) ControlPipe(this, 0, Pipe::FullSpeed, 0, 8); if (!fDefaultPipe) return; - fDefaultPipeLowSpeed = new(std::nothrow) ControlPipe(this, 0, Pipe::LowSpeed, 8); + fDefaultPipeLowSpeed = new(std::nothrow) ControlPipe(this, 0, Pipe::LowSpeed, 0, 8); if (!fDefaultPipeLowSpeed) return; @@ -135,7 +135,7 @@ BusManager::AllocateNewDevice(Device *parent, bool lowSpeed) // Create a temporary pipe with the new address ControlPipe pipe(this, deviceAddress, - lowSpeed ? Pipe::LowSpeed : Pipe::NormalSpeed, 8); + lowSpeed ? Pipe::LowSpeed : Pipe::FullSpeed, 0, 8); // Get the device descriptor // Just retrieve the first 8 bytes of the descriptor -> minimum supported @@ -261,11 +261,3 @@ BusManager::SubmitTransfer(Transfer *transfer) // virtual function to be overridden return B_ERROR; } - - -status_t -BusManager::SubmitRequest(Transfer *transfer) -{ - // virtual function to be overridden - return B_ERROR; -} diff --git a/src/add-ons/kernel/bus_managers/usb/Device.cpp b/src/add-ons/kernel/bus_managers/usb/Device.cpp index 765fdae564..3c489443ec 100644 --- a/src/add-ons/kernel/bus_managers/usb/Device.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Device.cpp @@ -13,14 +13,13 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc, int8 deviceAddress, bool lowSpeed) : ControlPipe(bus, deviceAddress, - lowSpeed ? Pipe::LowSpeed : Pipe::NormalSpeed, + lowSpeed ? Pipe::LowSpeed : Pipe::FullSpeed, 0, desc.max_packet_size_0), fDeviceDescriptor(desc), fConfigurations(NULL), fCurrentConfiguration(NULL), fInitOK(false), fLowSpeed(lowSpeed), - fBus(bus), fParent(parent), fDeviceAddress(deviceAddress), fLock(-1), @@ -60,7 +59,7 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc, TRACE(("\tvendor_id:...........0x%04x\n", fDeviceDescriptor.vendor_id)); TRACE(("\tproduct_id:..........0x%04x\n", fDeviceDescriptor.product_id)); TRACE(("\tdevice_version:......0x%04x\n", fDeviceDescriptor.device_version)); - TRACE(("\tmanufacturer:........0x%04x\n", fDeviceDescriptor.manufacturer)); + TRACE(("\tmanufacturer:........0x%02x\n", fDeviceDescriptor.manufacturer)); TRACE(("\tproduct:.............0x%02x\n", fDeviceDescriptor.product)); TRACE(("\tserial_number:.......0x%02x\n", fDeviceDescriptor.serial_number)); TRACE(("\tnum_configurations:..%d\n", fDeviceDescriptor.num_configurations)); @@ -147,7 +146,8 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc, interfaceInfo->generic_count = 0; interfaceInfo->generic = NULL; - Interface *interface = new(std::nothrow) Interface(this); + Interface *interface = new(std::nothrow) Interface(GetBusManager(), + fDeviceAddress, Speed()); interfaceInfo->handle = interface->USBID(); currentInterface = interfaceInfo; @@ -182,14 +182,15 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc, Pipe *endpoint = NULL; switch (endpointDescriptor->attributes & 0x03) { case 0x00: /* Control Endpoint */ - endpoint = new(std::nothrow) ControlPipe(this, - Speed(), + endpoint = new(std::nothrow) ControlPipe(GetBusManager(), + fDeviceAddress, Speed(), endpointDescriptor->endpoint_address & 0x0f, endpointDescriptor->max_packet_size); break; case 0x01: /* Isochronous Endpoint */ - endpoint = new(std::nothrow) IsochronousPipe(this, + endpoint = new(std::nothrow) IsochronousPipe(GetBusManager(), + fDeviceAddress, endpointDescriptor->endpoint_address & 0x80 > 0 ? Pipe::In : Pipe::Out, Speed(), endpointDescriptor->endpoint_address & 0x0f, @@ -197,7 +198,8 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc, break; case 0x02: /* Bulk Endpoint */ - endpoint = new(std::nothrow) BulkPipe(this, + endpoint = new(std::nothrow) BulkPipe(GetBusManager(), + fDeviceAddress, endpointDescriptor->endpoint_address & 0x80 > 0 ? Pipe::In : Pipe::Out, Speed(), endpointDescriptor->endpoint_address & 0x0f, @@ -205,7 +207,8 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc, break; case 0x03: /* Interrupt Endpoint */ - endpoint = new(std::nothrow) InterruptPipe(this, + endpoint = new(std::nothrow) InterruptPipe(GetBusManager(), + fDeviceAddress, endpointDescriptor->endpoint_address & 0x80 > 0 ? Pipe::In : Pipe::Out, Speed(), endpointDescriptor->endpoint_address & 0x0f, diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index 337aaba36c..7383c5e3b7 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -180,7 +180,7 @@ Hub::Explore() continue; } - Device *newDevice = fBus->AllocateNewDevice(this, + Device *newDevice = GetBusManager()->AllocateNewDevice(this, (fPortStatus[i].status & PORT_STATUS_LOW_SPEED) > 0); if (newDevice) { @@ -273,7 +273,7 @@ Hub::BuildDeviceName(char *string, uint32 *index, size_t bufferSize, status_t result = Device::BuildDeviceName(string, index, bufferSize, device); if (result < B_OK) { // recursion to parent failed, we're at the root(hub) - int32 managerIndex = GetStack()->IndexOfBusManager(Manager()); + int32 managerIndex = GetStack()->IndexOfBusManager(GetBusManager()); *index += snprintf(string + *index, bufferSize - *index, "%ld", managerIndex); } diff --git a/src/add-ons/kernel/bus_managers/usb/Interface.cpp b/src/add-ons/kernel/bus_managers/usb/Interface.cpp index 1783cdeaa1..f10304a749 100644 --- a/src/add-ons/kernel/bus_managers/usb/Interface.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Interface.cpp @@ -9,8 +9,8 @@ #include "usb_p.h" -Interface::Interface(Device *device) - : ControlPipe(device, device->Speed(), 0, 8) +Interface::Interface(BusManager *bus, int8 deviceAddress, pipeSpeed speed) + : ControlPipe(bus, deviceAddress, speed, 0, 8) { } diff --git a/src/add-ons/kernel/bus_managers/usb/Object.cpp b/src/add-ons/kernel/bus_managers/usb/Object.cpp index ab64ee6c00..578f30c8b8 100644 --- a/src/add-ons/kernel/bus_managers/usb/Object.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Object.cpp @@ -10,7 +10,8 @@ Object::Object(BusManager *bus) + : fBusManager(bus), + fStack(bus->GetStack()), + fUSBID(fStack->GetUSBID(this)) { - fStack = bus->GetStack(); - fUSBID = fStack->GetUSBID(this); } diff --git a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp index b5b7a536f8..a17ab797a8 100644 --- a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp @@ -10,30 +10,13 @@ #include "usb_p.h" -Pipe::Pipe(Device *device, pipeDirection direction, pipeSpeed speed, - uint8 endpointAddress, size_t maxPacketSize) - : Object(device->Manager()), - fDevice(device), - fDeviceAddress(device->Address()), - fBus(device->Manager()), +Pipe::Pipe(BusManager *bus, int8 deviceAddress, pipeDirection direction, + pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize) + : Object(bus), + fDeviceAddress(deviceAddress), + fEndpointAddress(endpointAddress), fDirection(direction), fSpeed(speed), - fEndpoint(endpointAddress), - fMaxPacketSize(maxPacketSize), - fDataToggle(false) -{ -} - - -Pipe::Pipe(BusManager *bus, int8 deviceAddress, pipeSpeed speed, - size_t maxPacketSize) - : Object(bus), - fDevice(NULL), - fDeviceAddress(deviceAddress), - fBus(bus), - fDirection(Default), - fSpeed(speed), - fEndpoint(0), fMaxPacketSize(maxPacketSize), fDataToggle(true) { @@ -45,21 +28,11 @@ Pipe::~Pipe() } -int8 -Pipe::DeviceAddress() -{ - if (!fDevice) - return fDeviceAddress; - - return fDevice->Address(); -} - - status_t Pipe::SubmitTransfer(Transfer *transfer) { // ToDo: keep track of all submited transfers to be able to cancel them - return fBus->SubmitTransfer(transfer); + return GetBusManager()->SubmitTransfer(transfer); } @@ -70,68 +43,16 @@ Pipe::CancelQueuedTransfers() } -status_t -Pipe::SetFeature(uint16 selector) -{ - if (!fDevice) - return B_ERROR; - - return fDevice->SendRequest( - USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, - USB_REQUEST_SET_FEATURE, - selector, - 0, - 0, - NULL, - 0, - NULL); -} - - -status_t -Pipe::ClearFeature(uint16 selector) -{ - if (!fDevice) - return B_ERROR; - - return fDevice->SendRequest( - USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, - USB_REQUEST_CLEAR_FEATURE, - selector, - 0, - 0, - NULL, - 0, - NULL); -} - - -status_t -Pipe::GetStatus(uint16 *status) -{ - if (!fDevice) - return B_ERROR; - - return fDevice->SendRequest( - USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_IN, - USB_REQUEST_GET_STATUS, - 0, - 0, - 2, - (void *)status, - 2, - NULL); -} - - // // #pragma mark - // -InterruptPipe::InterruptPipe(Device *device, pipeDirection direction, - pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize) - : Pipe(device, direction, speed, endpointAddress, maxPacketSize) +InterruptPipe::InterruptPipe(BusManager *bus, int8 deviceAddress, + pipeDirection direction, pipeSpeed speed, uint8 endpointAddress, + size_t maxPacketSize) + : Pipe(bus, deviceAddress, direction, speed, endpointAddress, + maxPacketSize) { } @@ -159,9 +80,11 @@ InterruptPipe::QueueInterrupt(void *data, size_t dataLength, // -BulkPipe::BulkPipe(Device *device, pipeDirection direction, - pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize) - : Pipe(device, direction, speed, endpointAddress, maxPacketSize) +BulkPipe::BulkPipe(BusManager *bus, int8 deviceAddress, + pipeDirection direction, pipeSpeed speed, uint8 endpointAddress, + size_t maxPacketSize) + : Pipe(bus, deviceAddress, direction, speed, endpointAddress, + maxPacketSize) { } @@ -207,9 +130,11 @@ BulkPipe::QueueBulkV(iovec *vector, size_t vectorCount, // -IsochronousPipe::IsochronousPipe(Device *device, pipeDirection direction, - pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize) - : Pipe(device, direction, speed, endpointAddress, maxPacketSize) +IsochronousPipe::IsochronousPipe(BusManager *bus, int8 deviceAddress, + pipeDirection direction, pipeSpeed speed, uint8 endpointAddress, + size_t maxPacketSize) + : Pipe(bus, deviceAddress, direction, speed, endpointAddress, + maxPacketSize) { } @@ -235,16 +160,9 @@ struct transfer_result_data { }; -ControlPipe::ControlPipe(Device *device, pipeSpeed speed, - uint8 endpointAddress, size_t maxPacketSize) - : Pipe(device, Pipe::Default, speed, endpointAddress, maxPacketSize) -{ -} - - ControlPipe::ControlPipe(BusManager *bus, int8 deviceAddress, pipeSpeed speed, - size_t maxPacketSize) - : Pipe(bus, deviceAddress, speed, maxPacketSize) + uint8 endpointAddress, size_t maxPacketSize) + : Pipe(bus, deviceAddress, Default, speed, endpointAddress, maxPacketSize) { } @@ -322,3 +240,48 @@ ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value, 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/Transfer.cpp b/src/add-ons/kernel/bus_managers/usb/Transfer.cpp index 4f432e235e..85312a75f1 100644 --- a/src/add-ons/kernel/bus_managers/usb/Transfer.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Transfer.cpp @@ -26,6 +26,9 @@ Transfer::~Transfer() // we take ownership of the request data if (fRequestData) delete fRequestData; + + if (fVector && fVector != &fData) + delete[] fVector; } @@ -50,7 +53,8 @@ Transfer::SetData(uint8 *data, size_t dataLength) void Transfer::SetVector(iovec *vector, size_t vectorCount) { - fVector = vector; + fVector = new(std::nothrow) iovec[vectorCount]; + memcpy(fVector, vector, vectorCount * sizeof(iovec)); fVectorCount = vectorCount; } diff --git a/src/add-ons/kernel/bus_managers/usb/usb.cpp b/src/add-ons/kernel/bus_managers/usb/usb.cpp index 6188ec40f4..7f24549ee9 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb.cpp +++ b/src/add-ons/kernel/bus_managers/usb/usb.cpp @@ -145,10 +145,10 @@ set_feature(usb_id handle, uint16 selector) { TRACE(("usb_module: set_feature(0x%08x, %d)\n", handle, selector)); Object *object = gUSBStack->GetObject(handle); - if (!object || (object->Type() & USB_OBJECT_PIPE) == 0) + if (!object || (object->Type() & USB_OBJECT_CONTROL_PIPE) == 0) return B_BAD_VALUE; - return ((Pipe *)object)->SetFeature(selector); + return ((ControlPipe *)object)->SetFeature(selector); } @@ -157,10 +157,10 @@ clear_feature(usb_id handle, uint16 selector) { TRACE(("usb_module: clear_feature(0x%08x, %d)\n", handle, selector)); Object *object = gUSBStack->GetObject(handle); - if (!object || (object->Type() & USB_OBJECT_PIPE) == 0) + if (!object || (object->Type() & USB_OBJECT_CONTROL_PIPE) == 0) return B_BAD_VALUE; - return ((Pipe *)object)->ClearFeature(selector); + return ((ControlPipe *)object)->ClearFeature(selector); } @@ -172,10 +172,10 @@ get_status(usb_id handle, uint16 *status) return B_BAD_VALUE; Object *object = gUSBStack->GetObject(handle); - if (!object || (object->Type() & USB_OBJECT_PIPE) == 0) + if (!object || (object->Type() & USB_OBJECT_CONTROL_PIPE) == 0) return B_BAD_VALUE; - return ((Pipe *)object)->GetStatus(status); + return ((ControlPipe *)object)->GetStatus(status); } 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 f968378517..6e532192ff 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb_p.h +++ b/src/add-ons/kernel/bus_managers/usb/usb_p.h @@ -147,7 +147,6 @@ virtual status_t Start(); virtual status_t Stop(); virtual status_t SubmitTransfer(Transfer *transfer); -virtual status_t SubmitRequest(Transfer *transfer); Stack *GetStack() { return fStack; }; void SetStack(Stack *stack) { fStack = stack; }; @@ -175,12 +174,14 @@ class Object { public: Object(BusManager *bus); + BusManager *GetBusManager() { return fBusManager; }; Stack *GetStack() { return fStack; }; usb_id USBID() { return fUSBID; }; virtual uint32 Type() { return USB_OBJECT_NONE; }; private: + BusManager *fBusManager; Stack *fStack; usb_id fUSBID; }; @@ -193,25 +194,22 @@ private: class Pipe : public Object { public: enum pipeDirection { In, Out, Default }; -enum pipeSpeed { LowSpeed, NormalSpeed }; +enum pipeSpeed { LowSpeed, FullSpeed, HighSpeed }; - Pipe(Device *device, + Pipe(BusManager *bus, + int8 deviceAddress, pipeDirection direction, pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize); - Pipe(BusManager *bus, - int8 deviceAddress, - pipeSpeed speed, - size_t maxPacketSize); virtual ~Pipe(); virtual uint32 Type() { return USB_OBJECT_PIPE; }; - int8 DeviceAddress(); + int8 DeviceAddress() { return fDeviceAddress; }; pipeSpeed Speed() { return fSpeed; }; pipeDirection Direction() { return fDirection; }; - int8 EndpointAddress() { return fEndpoint; }; + int8 EndpointAddress() { return fEndpointAddress; }; size_t MaxPacketSize() { return fMaxPacketSize; }; virtual bool DataToggle() { return fDataToggle; }; @@ -220,19 +218,11 @@ virtual void SetDataToggle(bool toggle) { fDataToggle = toggle; }; status_t SubmitTransfer(Transfer *transfer); status_t CancelQueuedTransfers(); - // Convenience functions for standard requests -virtual status_t SetFeature(uint16 selector); -virtual status_t ClearFeature(uint16 selector); -virtual status_t GetStatus(uint16 *status); - protected: - Device *fDevice; int8 fDeviceAddress; - BusManager *fBus; - usb_id fUSBID; + uint8 fEndpointAddress; pipeDirection fDirection; pipeSpeed fSpeed; - uint8 fEndpoint; size_t fMaxPacketSize; bool fDataToggle; }; @@ -240,15 +230,10 @@ protected: class ControlPipe : public Pipe { public: - ControlPipe(Device *device, - pipeSpeed speed, - uint8 endpointAddress, - size_t maxPacketSize); - - // Constructor for default control pipe ControlPipe(BusManager *bus, int8 deviceAddress, pipeSpeed speed, + uint8 endpointAddress, size_t maxPacketSize); virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_CONTROL_PIPE; }; @@ -276,12 +261,18 @@ static void SendRequestCallback(void *cookie, 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); }; class InterruptPipe : public Pipe { public: - InterruptPipe(Device *device, + InterruptPipe(BusManager *bus, + int8 deviceAddress, pipeDirection direction, pipeSpeed speed, uint8 endpointAddress, @@ -298,7 +289,8 @@ virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_INTERRUPT_PIPE class BulkPipe : public Pipe { public: - BulkPipe(Device *device, + BulkPipe(BusManager *bus, + int8 deviceAddress, pipeDirection direction, pipeSpeed speed, uint8 endpointAddress, @@ -319,7 +311,8 @@ virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_BULK_PIPE; }; class IsochronousPipe : public Pipe { public: - IsochronousPipe(Device *device, + IsochronousPipe(BusManager *bus, + int8 deviceAddress, pipeDirection direction, pipeSpeed speed, uint8 endpointAddress, @@ -338,7 +331,9 @@ virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_ISO_PIPE; }; class Interface : public ControlPipe { public: - Interface(Device *device); + Interface(BusManager *bus, + int8 deviceAddress, + pipeSpeed speed); virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_CONTROL_PIPE | USB_OBJECT_INTERFACE; }; @@ -359,9 +354,6 @@ public: virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_CONTROL_PIPE | USB_OBJECT_DEVICE; }; - int8 Address() { return fDeviceAddress; }; - BusManager *Manager() { return fBus; }; - virtual status_t GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID, void *data, size_t dataLength, @@ -394,7 +386,6 @@ protected: usb_configuration_info *fCurrentConfiguration; bool fInitOK; bool fLowSpeed; - BusManager *fBus; Device *fParent; int8 fDeviceAddress; size_t fMaxPacketIn[16]; diff --git a/src/add-ons/kernel/bus_managers/usb/usbspec_p.h b/src/add-ons/kernel/bus_managers/usb/usbspec_p.h index d90e43da97..59703a66fb 100644 --- a/src/add-ons/kernel/bus_managers/usb/usbspec_p.h +++ b/src/add-ons/kernel/bus_managers/usb/usbspec_p.h @@ -80,6 +80,7 @@ struct usb_port_status #define PORT_STATUS_RESET 0x0010 #define PORT_STATUS_POWER 0x0100 #define PORT_STATUS_LOW_SPEED 0x0200 +#define PORT_STATUS_HIGH_SPEED 0x0400 //The feature requests with ports diff --git a/src/add-ons/kernel/busses/usb/ehci.cpp b/src/add-ons/kernel/busses/usb/ehci.cpp index f5d8ec3537..8e5b7fb9d2 100644 --- a/src/add-ons/kernel/busses/usb/ehci.cpp +++ b/src/add-ons/kernel/busses/usb/ehci.cpp @@ -11,7 +11,6 @@ #include #include -#define TRACE_USB #include "ehci.h" pci_module_info *EHCI::sPCIModule = NULL; @@ -67,7 +66,10 @@ EHCI::EHCI(pci_info *info, Stack *stack) fFinishThread(-1), fStopFinishThread(false), fRootHub(NULL), - fRootHubAddress(0) + fRootHubAddress(0), + fPortCount(0), + fPortResetChange(0), + fPortSuspendChange(0) { if (BusManager::InitCheck() < B_OK) { TRACE_ERROR(("usb_ehci: bus manager failed to init\n")); @@ -111,6 +113,9 @@ EHCI::EHCI(pci_info *info, Stack *stack) TRACE(("usb_ehci: mapped capability registers: 0x%08x\n", fCapabilityRegisters)); TRACE(("usb_ehci: mapped operational registers: 0x%08x\n", fOperationalRegisters)); + // read port count from capability register + fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f; + // disable interrupts WriteOpReg(EHCI_USBINTR, 0); @@ -217,14 +222,11 @@ EHCI::Start() status_t EHCI::SubmitTransfer(Transfer *transfer) { - return B_ERROR; -} + // short circuit the root hub + if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress) + return fRootHub->ProcessTransfer(this, transfer); - -status_t -EHCI::SubmitRequest(Transfer *transfer) -{ - return B_ERROR; + return B_ERROR; } @@ -301,9 +303,169 @@ EHCI::AddTo(Stack *stack) status_t -EHCI::ResetPort(int32 index) +EHCI::GetPortStatus(uint8 index, usb_port_status *status) { - return B_ERROR; + if (index >= fPortCount) + return B_BAD_INDEX; + + status->status = status->change = 0; + uint32 portStatus = ReadOpReg(EHCI_PORTSC + index * sizeof(uint32)); + + // build the status + if (portStatus & EHCI_PORTSC_CONNSTATUS) + status->status |= PORT_STATUS_CONNECTION; + if (portStatus & EHCI_PORTSC_ENABLE) + status->status |= PORT_STATUS_ENABLE; + if (portStatus & EHCI_PORTSC_ENABLE) + status->status |= PORT_STATUS_HIGH_SPEED; + if (portStatus & EHCI_PORTSC_OCACTIVE) + status->status |= PORT_STATUS_OVER_CURRENT; + if (portStatus & EHCI_PORTSC_PORTRESET) + status->status |= PORT_STATUS_RESET; + if (portStatus & EHCI_PORTSC_PORTPOWER) + status->status |= PORT_STATUS_POWER; + if (portStatus & EHCI_PORTSC_SUSPEND) + status->status |= PORT_STATUS_SUSPEND; + if (portStatus & EHCI_PORTSC_DMINUS) + status->status |= PORT_STATUS_LOW_SPEED; + + // build the change + if (portStatus & EHCI_PORTSC_CONNCHANGE) + status->change |= PORT_STATUS_CONNECTION; + if (portStatus & EHCI_PORTSC_ENABLECHANGE) + status->change |= PORT_STATUS_ENABLE; + if (portStatus & EHCI_PORTSC_OCCHANGE) + status->change |= PORT_STATUS_OVER_CURRENT; + + // there are no bits to indicate suspend and reset change + if (fPortResetChange & (1 << index)) + status->change |= PORT_STATUS_RESET; + if (fPortSuspendChange & (1 << index)) + status->change |= PORT_STATUS_SUSPEND; + + return B_OK; +} + + +status_t +EHCI::SetPortFeature(uint8 index, uint16 feature) +{ + if (index >= fPortCount) + return B_BAD_INDEX; + + uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32); + uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; + + switch (feature) { + case PORT_SUSPEND: + return SuspendPort(index); + + case PORT_RESET: + return ResetPort(index); + + case PORT_POWER: + WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTPOWER); + return B_OK; + } + + return B_BAD_VALUE; +} + + +status_t +EHCI::ClearPortFeature(uint8 index, uint16 feature) +{ + if (index >= fPortCount) + return B_BAD_INDEX; + + uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32); + uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; + + switch (feature) { + case PORT_ENABLE: + WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_ENABLE); + return B_OK; + + case PORT_POWER: + WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTPOWER); + return B_OK; + + case C_PORT_CONNECTION: + WriteOpReg(portRegister, portStatus | EHCI_PORTSC_CONNCHANGE); + return B_OK; + + case C_PORT_ENABLE: + WriteOpReg(portRegister, portStatus | EHCI_PORTSC_ENABLECHANGE); + return B_OK; + + case C_PORT_OVER_CURRENT: + WriteOpReg(portRegister, portStatus | EHCI_PORTSC_OCCHANGE); + return B_OK; + + case C_PORT_RESET: + fPortResetChange &= ~(1 << index); + return B_OK; + + case C_PORT_SUSPEND: + fPortSuspendChange &= ~(1 << index); + return B_OK; + } + + return B_BAD_VALUE; +} + + +status_t +EHCI::ResetPort(uint8 index) +{ + TRACE(("usb_ehci: reset port %d\n", index)); + uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32); + uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; + + if (portStatus & EHCI_PORTSC_DMINUS) { + TRACE(("usb_ehci: lowspeed device connected, giving up port ownership\n")); + // there is a lowspeed device connected. + // we give the ownership to a companion controller. + WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER); + fPortResetChange |= (1 << index); + return B_OK; + } + + // enable reset signaling + WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTRESET); + snooze(250000); + + // disable reset signaling + portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; + WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTRESET); + snooze(2000); + + portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; + if (portStatus & EHCI_PORTSC_PORTRESET) { + TRACE(("usb_ehci: port reset won't complete\n")); + return B_ERROR; + } + + if ((portStatus & EHCI_PORTSC_ENABLE) == 0) { + TRACE(("usb_ehci: fullspeed device connected, giving up port ownership\n")); + // the port was not enabled, this means that no high speed device is + // attached to this port. we give up ownership to a companion controler + WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER); + } + + fPortResetChange |= (1 << index); + return B_OK; +} + + +status_t +EHCI::SuspendPort(uint8 index) +{ + uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32); + uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; + WriteOpReg(portRegister, portStatus | EHCI_PORTSC_SUSPEND); + fPortSuspendChange |= (1 << index); + return B_OK; } diff --git a/src/add-ons/kernel/busses/usb/ehci.h b/src/add-ons/kernel/busses/usb/ehci.h index 0ca47aa026..39d1349860 100644 --- a/src/add-ons/kernel/busses/usb/ehci.h +++ b/src/add-ons/kernel/busses/usb/ehci.h @@ -9,6 +9,7 @@ #ifndef EHCI_H #define EHCI_H +#define TRACE_USB #include "usb_p.h" #include "ehci_hardware.h" @@ -36,12 +37,17 @@ public: status_t Start(); virtual status_t SubmitTransfer(Transfer *transfer); -virtual status_t SubmitRequest(Transfer *transfer); static status_t AddTo(Stack *stack); // Port operations for root hub - status_t ResetPort(int32 index); + uint8 PortCount() { return fPortCount; }; + status_t GetPortStatus(uint8 index, usb_port_status *status); + status_t SetPortFeature(uint8 index, uint16 feature); + status_t ClearPortFeature(uint8 index, uint16 feature); + + status_t ResetPort(uint8 index); + status_t SuspendPort(uint8 index); private: // Controller resets @@ -118,6 +124,11 @@ static pci_module_info *sPCIModule; // Root Hub EHCIRootHub *fRootHub; uint8 fRootHubAddress; + + // Port management + uint8 fPortCount; + uint16 fPortResetChange; + uint16 fPortSuspendChange; }; @@ -125,12 +136,8 @@ class EHCIRootHub : public Hub { public: EHCIRootHub(EHCI *ehci, int8 deviceAddress); - status_t SubmitTransfer(Transfer *transfer); - void UpdatePortStatus(); - -private: - usb_port_status fPortStatus[2]; - EHCI *fEHCI; +static status_t ProcessTransfer(EHCI *ehci, + Transfer *transfer); }; diff --git a/src/add-ons/kernel/busses/usb/ehci_hardware.h b/src/add-ons/kernel/busses/usb/ehci_hardware.h index 44c53456d9..786330e14e 100644 --- a/src/add-ons/kernel/busses/usb/ehci_hardware.h +++ b/src/add-ons/kernel/busses/usb/ehci_hardware.h @@ -88,11 +88,13 @@ #define EHCI_PORTSC_FORCERESUME (1 << 6) // Force Port Resume #define EHCI_PORTSC_OCCHANGE (1 << 5) // Over-Current Change #define EHCI_PORTSC_OCACTIVE (1 << 4) // Over-Current Active -#define EHCI_PORTSC_ENDISCHANGE (1 << 3) // Port Enable/Disable Change -#define EHCI_PORTSC_ENDIS (1 << 2) // Port Enabled/Disabled +#define EHCI_PORTSC_ENABLECHANGE (1 << 3) // Port Enable/Disable Change +#define EHCI_PORTSC_ENABLE (1 << 2) // Port Enabled/Disabled #define EHCI_PORTSC_CONNCHANGE (1 << 1) // Connect Status Change #define EHCI_PORTSC_CONNSTATUS (1 << 0) // Current Connect Status +#define EHCI_PORTSC_DATAMASK 0xffffffd5 + // PCI Registers #define PCI_LEGSUP 0xc0 // PCI Legacy Support diff --git a/src/add-ons/kernel/busses/usb/ehci_rh.cpp b/src/add-ons/kernel/busses/usb/ehci_rh.cpp index b438b351ac..09ef1b9402 100644 --- a/src/add-ons/kernel/busses/usb/ehci_rh.cpp +++ b/src/add-ons/kernel/busses/usb/ehci_rh.cpp @@ -8,7 +8,6 @@ #include "ehci.h" - static usb_device_descriptor sEHCIRootHubDevice = { 18, // Descriptor length @@ -75,11 +74,11 @@ static ehci_root_hub_configuration_s sEHCIRootHubConfig = 9, // Descriptor length (including // deprecated power control mask) USB_DESCRIPTOR_HUB, // Descriptor type - 2, // Number of ports + 0x0f, // 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 + 0x00, // All ports are removable 0xff // Depricated power control mask } }; @@ -118,22 +117,135 @@ static ehci_root_hub_string_s sEHCIRootHubStrings[3] = { EHCIRootHub::EHCIRootHub(EHCI *ehci, int8 deviceAddress) : Hub(ehci, NULL, sEHCIRootHubDevice, deviceAddress, false) { - fEHCI = ehci; } status_t -EHCIRootHub::SubmitTransfer(Transfer *transfer) +EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer) { - return B_ERROR; -} + if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0) + return B_ERROR; + usb_request_data *request = transfer->RequestData(); + TRACE(("usb_ehci_roothub: request: %d\n", request->Request)); -void -EHCIRootHub::UpdatePortStatus() -{ - for (int32 i = 0; i < sEHCIRootHubConfig.hub.num_ports; i++) { - fPortStatus[i].status = 0; - fPortStatus[i].change = 0; + // ToDo: define better status codes. We should return a request error. + uint32 status = B_USB_STATUS_DEVICE_TIMEOUT; + size_t actualLength = 0; + switch (request->Request) { + case USB_REQUEST_GET_STATUS: { + if (request->Index == 0) { + // get hub status + actualLength = MIN(sizeof(usb_port_status), + transfer->DataLength()); + // the hub reports whether the local power failed (bit 0) + // and if there is a over-current condition (bit 1). + // everything as 0 means all is ok. + memset(transfer->Data(), 0, actualLength); + status = B_USB_STATUS_SUCCESS; + break; + } + + usb_port_status portStatus; + if (ehci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) { + actualLength = MIN(sizeof(usb_port_status), transfer->DataLength()); + memcpy(transfer->Data(), (void *)&portStatus, actualLength); + status = B_USB_STATUS_SUCCESS; + } + + break; + } + + case USB_REQUEST_SET_ADDRESS: + if (request->Value >= 128) { + status = B_USB_STATUS_DEVICE_TIMEOUT; + break; + } + + TRACE(("usb_ehci_roothub: set address: %d\n", request->Value)); + status = B_USB_STATUS_SUCCESS; + break; + + case USB_REQUEST_GET_DESCRIPTOR: + TRACE(("usb_ehci_roothub: get descriptor: %d\n", request->Value >> 8)); + + switch (request->Value >> 8) { + case USB_DESCRIPTOR_DEVICE: { + actualLength = MIN(sizeof(usb_device_descriptor), + transfer->DataLength()); + memcpy(transfer->Data(), (void *)&sEHCIRootHubDevice, + actualLength); + status = B_USB_STATUS_SUCCESS; + break; + } + + case USB_DESCRIPTOR_CONFIGURATION: { + actualLength = MIN(sizeof(ehci_root_hub_configuration_s), + transfer->DataLength()); + sEHCIRootHubConfig.hub.num_ports = ehci->PortCount(); + memcpy(transfer->Data(), (void *)&sEHCIRootHubConfig, + actualLength); + status = B_USB_STATUS_SUCCESS; + break; + } + + case USB_DESCRIPTOR_STRING: { + uint8 index = request->Value & 0x00ff; + if (index > 2) + break; + + actualLength = MIN(sEHCIRootHubStrings[index].length, + transfer->DataLength()); + memcpy(transfer->Data(), (void *)&sEHCIRootHubStrings[index], + actualLength); + status = B_USB_STATUS_SUCCESS; + break; + } + + case USB_DESCRIPTOR_HUB: { + actualLength = MIN(sizeof(usb_hub_descriptor), + transfer->DataLength()); + sEHCIRootHubConfig.hub.num_ports = ehci->PortCount(); + memcpy(transfer->Data(), (void *)&sEHCIRootHubConfig.hub, + actualLength); + status = B_USB_STATUS_SUCCESS; + break; + } + } + break; + + case USB_REQUEST_SET_CONFIGURATION: + status = B_USB_STATUS_SUCCESS; + break; + + case USB_REQUEST_CLEAR_FEATURE: { + if (request->Index == 0) { + // we don't support any hub changes + TRACE_ERROR(("usb_ehci_roothub: clear feature: no hub changes\n")); + break; + } + + TRACE(("usb_ehci_roothub: clear feature: %d\n", request->Value)); + if (ehci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK) + status = B_USB_STATUS_SUCCESS; + break; + } + + case USB_REQUEST_SET_FEATURE: { + if (request->Index == 0) { + // we don't support any hub changes + TRACE_ERROR(("usb_ehci_roothub: set feature: no hub changes\n")); + break; + } + + TRACE(("usb_ehci_roothub: set feature: %d\n", request->Value)); + if (ehci->SetPortFeature(request->Index - 1, request->Value) >= B_OK) + status = B_USB_STATUS_SUCCESS; + break; + } } + + transfer->Finished(status, actualLength); + delete transfer; + return B_OK; } diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index e17806ef43..1ddfdeda8a 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -326,7 +326,8 @@ UHCI::UHCI(pci_info *info, Stack *stack) fFinishThread(-1), fStopFinishThread(false), fRootHub(NULL), - fRootHubAddress(0) + fRootHubAddress(0), + fPortResetChange(0) { if (!fInitOK) { TRACE_ERROR(("usb_uhci: bus manager failed to init\n")); @@ -481,7 +482,6 @@ UHCI::Start() return B_ERROR; } - fPortResetChange[0] = fPortResetChange[1] = false; fRootHubAddress = AllocateAddress(); fRootHub = new(std::nothrow) UHCIRootHub(this, fRootHubAddress); if (!fRootHub) { @@ -510,7 +510,7 @@ UHCI::SubmitTransfer(Transfer *transfer) // Short circuit the root hub if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress) - return fRootHub->SubmitTransfer(transfer); + return fRootHub->ProcessTransfer(this, transfer); if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) return SubmitRequest(transfer); @@ -828,34 +828,90 @@ UHCI::ControllerReset() } -uint16 -UHCI::PortStatus(int32 index) -{ - if (index > 1) - return B_BAD_VALUE; - - return ReadReg16(UHCI_PORTSC1 + index * 2); -} - - status_t -UHCI::SetPortStatus(int32 index, uint16 status) +UHCI::GetPortStatus(uint8 index, usb_port_status *status) { if (index > 1) - return B_BAD_VALUE; + return B_BAD_INDEX; - TRACE(("usb_uhci: set port status of port %d: 0x%04x\n", index, status)); - WriteReg16(UHCI_PORTSC1 + index * 2, status); - snooze(1000); + status->status = status->change = 0; + uint16 portStatus = ReadReg16(UHCI_PORTSC1 + index * 2); + + // build the status + if (portStatus & UHCI_PORTSC_CURSTAT) + status->status |= PORT_STATUS_CONNECTION; + if (portStatus & UHCI_PORTSC_ENABLED) + status->status |= PORT_STATUS_ENABLE; + if (portStatus & UHCI_PORTSC_RESET) + status->status |= PORT_STATUS_RESET; + if (portStatus & UHCI_PORTSC_LOWSPEED) + status->status |= PORT_STATUS_LOW_SPEED; + + // build the change + if (portStatus & UHCI_PORTSC_STATCHA) + status->change |= PORT_STATUS_CONNECTION; + if (portStatus & UHCI_PORTSC_ENABCHA) + status->change |= PORT_STATUS_ENABLE; + + // ToDo: work out suspended/resume + + // there are no bits to indicate reset change + if (fPortResetChange & (1 << index)) + status->change |= PORT_STATUS_RESET; + + // the port is automagically powered on + status->status |= PORT_STATUS_POWER; return B_OK; } status_t -UHCI::ResetPort(int32 index) +UHCI::SetPortFeature(uint8 index, uint16 feature) { if (index > 1) - return B_BAD_VALUE; + return B_BAD_INDEX; + + switch (feature) { + case PORT_RESET: + return ResetPort(index); + + case PORT_POWER: + // the ports are automatically powered + return B_OK; + } + + return B_BAD_VALUE; +} + + +status_t +UHCI::ClearPortFeature(uint8 index, uint16 feature) +{ + if (index > 1) + return B_BAD_INDEX; + + uint32 portRegister = UHCI_PORTSC1 + index * 2; + uint16 portStatus = ReadReg16(portRegister) & UHCI_PORTSC_DATAMASK; + + switch (feature) { + case C_PORT_RESET: + fPortResetChange &= ~(1 << index); + return B_OK; + + case C_PORT_CONNECTION: + WriteReg16(portRegister, portStatus | UHCI_PORTSC_STATCHA); + return B_OK; + } + + return B_BAD_VALUE; +} + + +status_t +UHCI::ResetPort(uint8 index) +{ + if (index > 1) + return B_BAD_INDEX; TRACE(("usb_uhci: reset port %d\n", index)); @@ -899,32 +955,12 @@ UHCI::ResetPort(int32 index) } } - SetPortResetChange(index, true); + fPortResetChange |= (1 << index); TRACE(("usb_uhci: port was reset: 0x%04x\n", ReadReg16(port))); return B_OK; } -bool -UHCI::PortResetChange(int32 index) -{ - if (index > 1) - return false; - - return fPortResetChange[index]; -} - - -void -UHCI::SetPortResetChange(int32 index, bool value) -{ - if (index > 1) - return; - - fPortResetChange[index] = value; -} - - int32 UHCI::InterruptHandler(void *data) { diff --git a/src/add-ons/kernel/busses/usb/uhci.h b/src/add-ons/kernel/busses/usb/uhci.h index 1123a6641f..f9174a7f3d 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -69,16 +69,16 @@ public: status_t Start(); virtual status_t SubmitTransfer(Transfer *transfer); -virtual status_t SubmitRequest(Transfer *transfer); + status_t SubmitRequest(Transfer *transfer); static status_t AddTo(Stack *stack); // Port operations - uint16 PortStatus(int32 index); - status_t SetPortStatus(int32 index, uint16 status); - status_t ResetPort(int32 index); - bool PortResetChange(int32 index); - void SetPortResetChange(int32 index, bool value); + status_t GetPortStatus(uint8 index, usb_port_status *status); + status_t SetPortFeature(uint8 index, uint16 feature); + status_t ClearPortFeature(uint8 index, uint16 feature); + + status_t ResetPort(uint8 index); private: // Controller resets @@ -155,7 +155,7 @@ static pci_module_info *sPCIModule; // Root hub UHCIRootHub *fRootHub; uint8 fRootHubAddress; - bool fPortResetChange[2]; + uint8 fPortResetChange; }; @@ -163,12 +163,8 @@ class UHCIRootHub : public Hub { public: UHCIRootHub(UHCI *uhci, int8 deviceAddress); - status_t SubmitTransfer(Transfer *transfer); - void UpdatePortStatus(); - -private: - usb_port_status fPortStatus[2]; - UHCI *fUHCI; +static status_t ProcessTransfer(UHCI *uhci, + Transfer *transfer); }; diff --git a/src/add-ons/kernel/busses/usb/uhci_hardware.h b/src/add-ons/kernel/busses/usb/uhci_hardware.h index ebc9942bc2..2174bb5ade 100644 --- a/src/add-ons/kernel/busses/usb/uhci_hardware.h +++ b/src/add-ons/kernel/busses/usb/uhci_hardware.h @@ -147,28 +147,4 @@ typedef struct #define QH_NEXT_IS_QH 0x02 #define QH_LINK_MASK 0xfffffff0 - -/************************************************************ - * Roothub Emulation * - ************************************************************/ -#define RH_GET_STATUS 0 -#define RH_CLEAR_FEATURE 1 -#define RH_SET_FEATURE 3 -#define RH_SET_ADDRESS 5 -#define RH_GET_DESCRIPTOR 6 -#define RH_SET_CONFIG 9 - -// Descriptors (in usb_request_data->Value) -#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 -{ - uint16 status; - uint16 change; -} get_status_buffer; - #endif diff --git a/src/add-ons/kernel/busses/usb/uhci_rh.cpp b/src/add-ons/kernel/busses/usb/uhci_rh.cpp index 60f5ea4a1e..64193d65bc 100644 --- a/src/add-ons/kernel/busses/usb/uhci_rh.cpp +++ b/src/add-ons/kernel/busses/usb/uhci_rh.cpp @@ -120,61 +120,56 @@ static uhci_root_hub_string_s sUHCIRootHubStrings[3] = { UHCIRootHub::UHCIRootHub(UHCI *uhci, int8 deviceAddress) : Hub(uhci, NULL, sUHCIRootHubDevice, deviceAddress, false) { - fUHCI = uhci; } status_t -UHCIRootHub::SubmitTransfer(Transfer *transfer) +UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer) { if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0) return B_ERROR; usb_request_data *request = transfer->RequestData(); - TRACE(("usb_uhci_roothub: rh_submit_packet called. request: %u\n", request->Request)); + TRACE(("usb_uhci_roothub: request: %d\n", request->Request)); // ToDo: define better status codes. We should return a request error. uint32 status = B_USB_STATUS_DEVICE_TIMEOUT; size_t actualLength = 0; switch (request->Request) { - case RH_GET_STATUS: { + case USB_REQUEST_GET_STATUS: { if (request->Index == 0) { // Get the hub status -- everything as 0 means all-right - actualLength = MIN(sizeof(get_status_buffer), + actualLength = MIN(sizeof(usb_port_status), transfer->DataLength()); memset(transfer->Data(), 0, actualLength); status = B_USB_STATUS_SUCCESS; break; - } else if (request->Index > sUHCIRootHubConfig.hub.num_ports) { - // This port doesn't exist - break; } - // Get port status - UpdatePortStatus(); - - actualLength = MIN(4, transfer->DataLength()); - memcpy(transfer->Data(), - (void *)&fPortStatus[request->Index - 1], actualLength); - status = B_USB_STATUS_SUCCESS; + usb_port_status portStatus; + if (uhci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) { + actualLength = MIN(sizeof(usb_port_status), transfer->DataLength()); + memcpy(transfer->Data(), (void *)&portStatus, actualLength); + status = B_USB_STATUS_SUCCESS; + } break; } - case RH_SET_ADDRESS: + case USB_REQUEST_SET_ADDRESS: if (request->Value >= 128) { status = B_USB_STATUS_DEVICE_TIMEOUT; break; } - TRACE(("usb_uhci_roothub: rh_submit_packet RH_ADDRESS: %d\n", request->Value)); + TRACE(("usb_uhci_roothub: set address: %d\n", request->Value)); status = B_USB_STATUS_SUCCESS; break; - case RH_GET_DESCRIPTOR: - TRACE(("usb_uhci_roothub: rh_submit_packet GET_DESC: %d\n", request->Value)); + case USB_REQUEST_GET_DESCRIPTOR: + TRACE(("usb_uhci_roothub: get descriptor: %d\n", request->Value >> 8)); - switch (request->Value & 0xff00) { - case RH_DEVICE_DESCRIPTOR: { + switch (request->Value >> 8) { + case USB_DESCRIPTOR_DEVICE: { actualLength = MIN(sizeof(usb_device_descriptor), transfer->DataLength()); memcpy(transfer->Data(), (void *)&sUHCIRootHubDevice, @@ -183,7 +178,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer) break; } - case RH_CONFIG_DESCRIPTOR: { + case USB_DESCRIPTOR_CONFIGURATION: { actualLength = MIN(sizeof(uhci_root_hub_configuration_s), transfer->DataLength()); memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig, @@ -192,7 +187,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer) break; } - case RH_STRING_DESCRIPTOR: { + case USB_DESCRIPTOR_STRING: { uint8 index = request->Value & 0x00ff; if (index > 2) break; @@ -205,7 +200,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer) break; } - case RH_HUB_DESCRIPTOR: { + case USB_DESCRIPTOR_HUB: { actualLength = MIN(sizeof(usb_hub_descriptor), transfer->DataLength()); memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig.hub, @@ -216,63 +211,33 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer) } break; - case RH_SET_CONFIG: + case USB_REQUEST_SET_CONFIGURATION: status = B_USB_STATUS_SUCCESS; break; - case RH_CLEAR_FEATURE: { + case USB_REQUEST_CLEAR_FEATURE: { if (request->Index == 0) { // We don't support any hub changes - TRACE_ERROR(("usb_uhci_roothub: RH_CLEAR_FEATURE no hub changes!\n")); - break; - } else if (request->Index > sUHCIRootHubConfig.hub.num_ports) { - // Invalid port number - TRACE_ERROR(("usb_uhci_roothub: RH_CLEAR_FEATURE invalid port!\n")); + TRACE_ERROR(("usb_uhci_roothub: clear feature: no hub changes\n")); break; } - TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE called. Feature: %u!\n", request->Value)); - uint16 portStatus; - switch(request->Value) { - case C_PORT_RESET: - fUHCI->SetPortResetChange(request->Index - 1, false); - status = B_USB_STATUS_SUCCESS; - break; - - case C_PORT_CONNECTION: - portStatus = fUHCI->PortStatus(request->Index - 1); - if (fUHCI->SetPortStatus(request->Index - 1, - (portStatus & UHCI_PORTSC_DATAMASK) - | UHCI_PORTSC_STATCHA) >= B_OK) - status = B_USB_STATUS_SUCCESS; - break; - } + TRACE(("usb_uhci_roothub: clear feature: %d\n", request->Value)); + if (uhci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK) + status = B_USB_STATUS_SUCCESS; break; } - case RH_SET_FEATURE: { + case USB_REQUEST_SET_FEATURE: { if (request->Index == 0) { - // We don't support any hub changes - TRACE_ERROR(("usb_uhci_roothub: RH_SET_FEATURE no hub changes!\n")); - break; - } else if (request->Index > sUHCIRootHubConfig.hub.num_ports) { - // Invalid port number - TRACE_ERROR(("usb_uhci_roothub: RH_SET_FEATURE invalid port!\n")); + // we don't support any hub changes + TRACE_ERROR(("usb_uhci_roothub: set feature: no hub changes\n")); break; } - TRACE(("usb_uhci_roothub: RH_SET_FEATURE called. Feature: %u!\n", request->Value)); - switch(request->Value) { - case PORT_RESET: - if (fUHCI->ResetPort(request->Index - 1) >= B_OK) - status = B_USB_STATUS_SUCCESS; - break; - - case PORT_POWER: - // the ports are automatically powered - status = B_USB_STATUS_SUCCESS; - break; - } + TRACE(("usb_uhci_roothub: set feature: %d!\n", request->Value)); + if (uhci->SetPortFeature(request->Index - 1, request->Value) >= B_OK) + status = B_USB_STATUS_SUCCESS; break; } } @@ -281,46 +246,3 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer) delete transfer; return B_OK; } - - -void -UHCIRootHub::UpdatePortStatus() -{ - for (int32 i = 0; i < sUHCIRootHubConfig.hub.num_ports; i++) { - uint16 newStatus = 0; - uint16 newChange = 0; - - uint16 portStatus = fUHCI->PortStatus(i); - TRACE(("usb_uhci_roothub: port: %d status: 0x%04x\n", i, portStatus)); - - // Set all individual bits - if (portStatus & UHCI_PORTSC_CURSTAT) - newStatus |= PORT_STATUS_CONNECTION; - - if (portStatus & UHCI_PORTSC_STATCHA) - newChange |= PORT_STATUS_CONNECTION; - - if (portStatus & UHCI_PORTSC_ENABLED) - newStatus |= PORT_STATUS_ENABLE; - - if (portStatus & UHCI_PORTSC_ENABCHA) - newChange |= PORT_STATUS_ENABLE; - - // TODO: work out suspended/resume - - if (portStatus & UHCI_PORTSC_RESET) - newStatus |= PORT_STATUS_RESET; - if (fUHCI->PortResetChange(i)) - newChange |= PORT_STATUS_RESET; - - //The port is automagically powered on - newStatus |= PORT_STATUS_POWER; - - if (portStatus & UHCI_PORTSC_LOWSPEED) - newStatus |= PORT_STATUS_LOW_SPEED; - - //Update the stored port status - fPortStatus[i].status = newStatus; - fPortStatus[i].change = newChange; - } -}