From f1020a6c4914d769f910ae85158a8fb9c9c060f7 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sat, 12 Aug 2006 21:07:34 +0000 Subject: [PATCH] * Changed the Stack lock to a benaphore * Removed some debug output from UHCI * Added some debug output to the usb module instead ;) * Rewrote the way new devices are attached and ports are handled (now more similar to FreeBSD) * Corrected handling of port resets so that they should work on hubs too * Cleaned up some headers git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18499 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/bus_managers/usb/BusManager.cpp | 34 ++-- .../kernel/bus_managers/usb/Device.cpp | 2 +- src/add-ons/kernel/bus_managers/usb/Hub.cpp | 190 ++++++++++++------ src/add-ons/kernel/bus_managers/usb/Stack.cpp | 18 +- .../kernel/bus_managers/usb/Transfer.cpp | 17 +- src/add-ons/kernel/bus_managers/usb/usb.cpp | 17 ++ src/add-ons/kernel/bus_managers/usb/usb_p.h | 11 +- .../kernel/bus_managers/usb/usbspec_p.h | 29 ++- src/add-ons/kernel/busses/usb/uhci.cpp | 160 ++++++++------- src/add-ons/kernel/busses/usb/uhci.h | 8 +- src/add-ons/kernel/busses/usb/uhci_hardware.h | 103 ++++++---- src/add-ons/kernel/busses/usb/uhci_rh.cpp | 40 ++-- 12 files changed, 380 insertions(+), 249 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/usb/BusManager.cpp b/src/add-ons/kernel/bus_managers/usb/BusManager.cpp index d0a6538fea..159afb7b18 100644 --- a/src/add-ons/kernel/bus_managers/usb/BusManager.cpp +++ b/src/add-ons/kernel/bus_managers/usb/BusManager.cpp @@ -74,10 +74,10 @@ BusManager::ExploreThread(void *data) if (!rootHub) return B_ERROR; - snooze(3000000); + snooze(USB_DELAY_FIRST_EXPLORE); while (true) { rootHub->Explore(); - snooze(1000000); + snooze(USB_DELAY_HUB_EXPLORE); } return B_OK; @@ -98,16 +98,24 @@ BusManager::AllocateNewDevice(Device *parent, bool lowSpeed) ControlPipe *defaultPipe = (lowSpeed ? fDefaultPipeLowSpeed : fDefaultPipe); - // Set the address of the device USB 1.1 spec p202 - status_t result = defaultPipe->SendRequest( - USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT, // type - USB_REQUEST_SET_ADDRESS, // request - deviceAddress, // value - 0, // index - 0, // length - NULL, // buffer - 0, // buffer length - NULL); // actual length + status_t result = B_ERROR; + for (int32 i = 0; i < 15; i++) { + // Set the address of the device USB 1.1 spec p202 + result = defaultPipe->SendRequest( + USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT, // type + USB_REQUEST_SET_ADDRESS, // request + deviceAddress, // value + 0, // index + 0, // length + NULL, // buffer + 0, // buffer length + NULL); // actual length + + if (result >= B_OK) + break; + + snooze(USB_DELAY_SET_ADDRESS_RETRY); + } if (result < B_OK) { TRACE(("usb BusManager::AllocateNewDevice(): error while setting device address\n")); @@ -115,7 +123,7 @@ BusManager::AllocateNewDevice(Device *parent, bool lowSpeed) } // Wait a bit for the device to complete addressing - snooze(10000); + snooze(USB_DELAY_SET_ADDRESS); // Create a temporary pipe with the new address ControlPipe pipe(this, deviceAddress, diff --git a/src/add-ons/kernel/bus_managers/usb/Device.cpp b/src/add-ons/kernel/bus_managers/usb/Device.cpp index 70dc06ec13..d9be001e65 100644 --- a/src/add-ons/kernel/bus_managers/usb/Device.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Device.cpp @@ -339,7 +339,7 @@ Device::SetConfigurationAt(uint8 index) fCurrentConfiguration = &fConfigurations[index]; // Wait some for the configuration being finished - snooze(10000); + snooze(USB_DELAY_SET_CONFIGURATION); return B_OK; } diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index ffb246b3c9..43781eb46b 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -62,91 +62,146 @@ Hub::Hub(BusManager *bus, Device *parent, usb_device_descriptor &desc, 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)) { + + // we need at least 8 bytes + if (status < B_OK || actualLength < 8) { TRACE(("USB Hub: Error getting hub descriptor\n")); return; } + TRACE(("USB Hub: Hub descriptor (%d bytes):\n", actualLength)); + TRACE(("\tlength:..............%d\n", fHubDescriptor.length)); + TRACE(("\tdescriptor_type:.....0x%02x\n", fHubDescriptor.descriptor_type)); + TRACE(("\tnum_ports:...........%d\n", fHubDescriptor.num_ports)); + TRACE(("\tcharacteristics:.....0x%04x\n", fHubDescriptor.characteristics)); + TRACE(("\tpower_on_to_power_g:.%d\n", fHubDescriptor.power_on_to_power_good)); + TRACE(("\tdevice_removeable:...0x%02x\n", fHubDescriptor.device_removeable)); + TRACE(("\tpower_control_mask:..0x%02x\n", fHubDescriptor.power_control_mask)); + // Enable port power on all ports - for (int32 i = 0; i < fHubDescriptor.bNbrPorts; i++) { - SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, - USB_REQUEST_SET_FEATURE, - PORT_POWER, - i + 1, - 0, - NULL, - 0, - &actualLength); + for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { + status = SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, + USB_REQUEST_SET_FEATURE, PORT_POWER, i + 1, 0, NULL, 0, NULL); + + if (status < B_OK) + TRACE(("USB Hub: power up failed on port %d\n", i)); } // Wait for power to stabilize - snooze(fHubDescriptor.bPwrOn2PwrGood * 2000); + snooze(fHubDescriptor.power_on_to_power_good * 2000); fInitOK = true; TRACE(("USB Hub: initialised ok\n")); } +status_t +Hub::UpdatePortStatus(uint8 index) +{ + // get the current port status + size_t actualLength = 0; + status_t result = SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_IN, + USB_REQUEST_GET_STATUS, 0, index + 1, 4, (void *)&fPortStatus[index], + 4, &actualLength); + + if (result < B_OK || actualLength < 4) { + TRACE(("USB Hub: error updating port status\n")); + return B_ERROR; + } + + return B_OK; +} + + +status_t +Hub::ResetPort(uint8 index) +{ + status_t result = SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, + USB_REQUEST_SET_FEATURE, PORT_RESET, index + 1, 0, NULL, 0, NULL); + + if (result < B_OK) + return result; + + for (int32 i = 0; i < 10; i++) { + snooze(USB_DELAY_PORT_RESET); + + result = UpdatePortStatus(index); + if (result < B_OK) + return result; + + if ((fPortStatus[index].status & PORT_STATUS_CONNECTION) == 0) { + // device disappeared, this is no error + TRACE(("USB Hub: device disappeared on reset\n")); + return B_OK; + } + + if (fPortStatus[index].change & C_PORT_RESET) { + // reset is done + break; + } + } + + if ((fPortStatus[index].change & C_PORT_RESET) == 0) { + TRACE(("USB Hub: port %d won't reset\n", index)); + return B_ERROR; + } + + // clear the reset change + result = SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, + USB_REQUEST_CLEAR_FEATURE, C_PORT_RESET, index + 1, 0, NULL, 0, NULL); + if (result < B_OK) + return result; + + // wait for reset recovery + snooze(USB_DELAY_PORT_RESET_RECOVERY); + TRACE(("USB Hub: port %d was reset successfully\n", index)); + return B_OK; +} + + void Hub::Explore() { - for (int32 i = 0; i < fHubDescriptor.bNbrPorts; i++) { - size_t actualLength; - - // Get the current port status - SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_IN, - USB_REQUEST_GET_STATUS, - 0, - i + 1, - 4, - (void *)&fPortStatus[i], - 4, - &actualLength); - - if (actualLength < 4) { - TRACE(("USB Hub: error getting port status\n")); - return; - } - - //TRACE(("status: 0x%04x; change: 0x%04x\n", fPortStatus[i].status, fPortStatus[i].change)); - - // We need to test the port change against a number of things - if (fPortStatus[i].status & PORT_RESET) { - SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, - USB_REQUEST_CLEAR_FEATURE, - PORT_RESET, - i + 1, - 0, - NULL, - 0, - &actualLength); - } + for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { + status_t result = UpdatePortStatus(i); + if (result < B_OK) + continue; if (fPortStatus[i].change & PORT_STATUS_CONNECTION) { if (fPortStatus[i].status & PORT_STATUS_CONNECTION) { - // New device attached! - - if ((fPortStatus[i].status & PORT_STATUS_ENABLE) == 0) { - // enable the port if it isn't - SendRequest( - USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, - USB_REQUEST_SET_FEATURE, - PORT_ENABLE, - i + 1, - 0, - NULL, - 0, - NULL); - } - + // new device attached! TRACE(("USB Hub: Explore(): New device connected\n")); + // wait some time for the device to power up + snooze(USB_DELAY_DEVICE_POWER_UP); + + // reset the port, this will also enable it + result = ResetPort(i); + if (result < B_OK) + continue; + + result = UpdatePortStatus(i); + if (result < B_OK) + continue; + + if ((fPortStatus[i].status & PORT_STATUS_CONNECTION) == 0) { + // device has vanished after reset, ignore + continue; + } + Device *newDevice = fBus->AllocateNewDevice(this, (fPortStatus[i].status & PORT_STATUS_LOW_SPEED) > 0); if (newDevice) { fChildren[i] = newDevice; Manager()->GetStack()->NotifyDeviceChange(fChildren[i], true); + } else { + // the device failed to setup correctly, disable the port + // so that the device doesn't get in the way of future + // addressing. + SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, + USB_REQUEST_CLEAR_FEATURE, PORT_ENABLE, i + 1, + 0, NULL, 0, NULL); } } else { // Device removed... @@ -158,17 +213,20 @@ Hub::Explore() } } - // Clear status change + // clear status change SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, - USB_REQUEST_CLEAR_FEATURE, - C_PORT_CONNECTION, - i + 1, - 0, - NULL, - 0, - NULL); + USB_REQUEST_CLEAR_FEATURE, C_PORT_CONNECTION, i + 1, + 0, NULL, 0, NULL); } } + + // explore down the tree if we have hubs connected + for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { + if (!fChildren[i] || !fChildren[i]->IsHub()) + continue; + + ((Hub *)fChildren[i])->Explore(); + } } @@ -198,7 +256,7 @@ Hub::ReportDevice(usb_support_descriptor *supportDescriptors, Device::ReportDevice(supportDescriptors, supportDescriptorCount, hooks, added); // Then report all of our children - for (int32 i = 0; i < fHubDescriptor.bNbrPorts; i++) { + for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { if (!fChildren[i]) continue; diff --git a/src/add-ons/kernel/bus_managers/usb/Stack.cpp b/src/add-ons/kernel/bus_managers/usb/Stack.cpp index 1df9fce4cc..a7d25fa0d1 100644 --- a/src/add-ons/kernel/bus_managers/usb/Stack.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Stack.cpp @@ -24,13 +24,10 @@ Stack::Stack() { TRACE(("usb stack: stack init\n")); - // Create the master lock - fMasterLock = create_sem(1, "usb master lock"); - set_sem_owner(fMasterLock, B_SYSTEM_TEAM); - - // Create the data lock - fDataLock = create_sem(1, "usb data lock"); - set_sem_owner(fDataLock, B_SYSTEM_TEAM); + if (benaphore_init(&fLock, "USB Stack Master Lock") < B_OK) { + TRACE(("usb stack: failed to create benaphore lock\n")); + return; + } // Initialise the memory chunks: create 8, 16 and 32 byte-heaps // NOTE: This is probably the most ugly code you will see in the @@ -149,6 +146,9 @@ Stack::Stack() Stack::~Stack() { + Lock(); + benaphore_destroy(&fLock); + //Release the bus modules for (Vector::Iterator i = fBusManagers.Begin(); i != fBusManagers.End(); i++) { @@ -174,14 +174,14 @@ Stack::InitCheck() bool Stack::Lock() { - return (acquire_sem(fMasterLock) == B_OK); + return (benaphore_lock(&fLock) == B_OK); } void Stack::Unlock() { - release_sem(fMasterLock); + benaphore_unlock(&fLock); } diff --git a/src/add-ons/kernel/bus_managers/usb/Transfer.cpp b/src/add-ons/kernel/bus_managers/usb/Transfer.cpp index 25713829bf..a13f5cc7b8 100644 --- a/src/add-ons/kernel/bus_managers/usb/Transfer.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Transfer.cpp @@ -15,7 +15,7 @@ Transfer::Transfer(Pipe *pipe, bool synchronous) fDataLength(0), fActualLength(NULL), fOwnActualLength(0), - fStatus(B_NO_INIT), + fStatus(B_USB_STATUS_DRIVER_INTERNAL_ERROR), fCallback(NULL), fCallbackCookie(NULL), fSem(-1), @@ -78,22 +78,23 @@ status_t Transfer::WaitForFinish() { if (fSem < B_OK) - return fStatus; - - status_t result = B_OK; - result = acquire_sem(fSem); + return fSem; + status_t result = acquire_sem(fSem); if (result < B_OK) return result; - return fStatus; + if (fStatus == B_USB_STATUS_SUCCESS) + return B_OK; + + return B_ERROR; } void -Transfer::Finished(status_t result) +Transfer::Finished(uint32 status) { - fStatus = result; + fStatus = status; // Call the callback function ... if (fCallback) { diff --git a/src/add-ons/kernel/bus_managers/usb/usb.cpp b/src/add-ons/kernel/bus_managers/usb/usb.cpp index c4e18a34f7..6b1e31ccc7 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb.cpp +++ b/src/add-ons/kernel/bus_managers/usb/usb.cpp @@ -87,6 +87,7 @@ uninstall_notify(const char *driverName) const usb_device_descriptor * get_device_descriptor(const usb_device *device) { + TRACE(("usb_module: get_device_descriptor(0x%08x)\n", device)); if (!device) return NULL; @@ -97,6 +98,7 @@ get_device_descriptor(const usb_device *device) const usb_configuration_info * get_nth_configuration(const usb_device *device, uint index) { + TRACE(("usb_module: get_nth_configuration(0x%08x, %d)\n", device, index)); if (!device) return NULL; @@ -108,6 +110,7 @@ get_nth_configuration(const usb_device *device, uint index) const usb_configuration_info * get_configuration(const usb_device *device) { + TRACE(("usb_module: get_configuration(0x%08x)\n", device)); if (!device) return NULL; @@ -119,6 +122,7 @@ status_t set_configuration(const usb_device *device, const usb_configuration_info *configuration) { + TRACE(("usb_module: set_configuration(0x%08x, 0x%08x)\n", device, configuration)); if (!device) return B_BAD_VALUE; @@ -130,6 +134,7 @@ status_t set_alt_interface(const usb_device *device, const usb_interface_info *interface) { + TRACE(("usb_module: set_alt_interface(0x%08x, 0x%08x)\n", device, interface)); return B_ERROR; } @@ -137,6 +142,7 @@ set_alt_interface(const usb_device *device, status_t set_feature(const void *object, uint16 selector) { + TRACE(("usb_module: set_feature(0x%08x, %d)\n", object, selector)); if (!object) return B_BAD_VALUE; @@ -147,6 +153,7 @@ set_feature(const void *object, uint16 selector) status_t clear_feature(const void *object, uint16 selector) { + TRACE(("usb_module: clear_feature(0x%08x, %d)\n", object, selector)); if (!object) return B_BAD_VALUE; @@ -157,6 +164,7 @@ clear_feature(const void *object, uint16 selector) status_t get_status(const void *object, uint16 *status) { + TRACE(("usb_module: get_status(0x%08x, 0x%08x)\n", object, status)); if (!object || !status) return B_BAD_VALUE; @@ -168,6 +176,7 @@ status_t get_descriptor(const usb_device *device, uint8 type, uint8 index, uint16 languageID, void *data, size_t dataLength, size_t *actualLength) { + TRACE(("usb_module: get_descriptor(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%08x, %d, 0x%08x)\n", device, type, index, languageID, data, dataLength, actualLength)); if (!device || !data) return B_BAD_VALUE; @@ -181,6 +190,7 @@ send_request(const usb_device *device, uint8 requestType, uint8 request, uint16 value, uint16 index, uint16 length, void *data, size_t dataLength, size_t *actualLength) { + TRACE(("usb_module: send_request(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%04x, %d, 0x%08x, %d, 0x%08x)\n", device, requestType, request, value, index, length, data, dataLength, actualLength)); if (!device) return B_BAD_VALUE; @@ -194,6 +204,7 @@ 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) { + TRACE(("usb_module: queue_request(0x%08x, 0x%02x, 0x%02x, 0x%04x, 0x%04x, %d, 0x%08x, %d, 0x%08x, 0x%08x)\n", device, requestType, request, value, index, length, data, dataLength, callback, callbackCookie)); if (!device) return B_BAD_VALUE; @@ -206,6 +217,7 @@ status_t queue_interrupt(const usb_pipe *pipe, void *data, size_t dataLength, usb_callback_func callback, void *callbackCookie) { + TRACE(("usb_module: queue_interrupt(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, data, dataLength, callback, callbackCookie)); if (((Pipe *)pipe)->Type() != Pipe::Interrupt) return B_BAD_VALUE; @@ -218,6 +230,7 @@ status_t queue_bulk(const usb_pipe *pipe, void *data, size_t dataLength, usb_callback_func callback, void *callbackCookie) { + TRACE(("usb_module: queue_bulk(0x%08x, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, data, dataLength, callback, callbackCookie)); if (((Pipe *)pipe)->Type() != Pipe::Bulk) return B_BAD_VALUE; @@ -231,6 +244,7 @@ queue_isochronous(const usb_pipe *pipe, void *data, size_t dataLength, rlea *rleArray, uint16 bufferDurationMS, usb_callback_func callback, void *callbackCookie) { + TRACE(("usb_module: queue_isochronous(0x%08x, 0x%08x, %d, 0x%08x, %d, 0x%08x, 0x%08x)\n", pipe, data, dataLength, rleArray, bufferDurationMS, callback, callbackCookie)); if (((Pipe *)pipe)->Type() != Pipe::Isochronous) return B_BAD_VALUE; @@ -243,6 +257,7 @@ status_t set_pipe_policy(const usb_pipe *pipe, uint8 maxQueuedPackets, uint16 maxBufferDurationMS, uint16 sampleSize) { + TRACE(("usb_module: set_pipe_policy(0x%08x, %d, %d, %d)\n", pipe, maxQueuedPackets, maxBufferDurationMS, sampleSize)); return B_ERROR; } @@ -250,6 +265,7 @@ set_pipe_policy(const usb_pipe *pipe, uint8 maxQueuedPackets, status_t cancel_queued_transfers(const usb_pipe *pipe) { + TRACE(("usb_module: cancel_queued_transfers(0x%08x)\n", pipe)); return ((Pipe *)pipe)->CancelQueuedTransfers(); } @@ -257,6 +273,7 @@ cancel_queued_transfers(const usb_pipe *pipe) status_t usb_ioctl(uint32 opcode, void *buffer, size_t bufferSize) { + TRACE(("usb_module: usb_ioctl(0x%08x, 0x%08x, %d)\n", opcode, buffer, bufferSize)); return B_ERROR; } 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 be26b863fc..57eb39a98e 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb_p.h +++ b/src/add-ons/kernel/bus_managers/usb/usb_p.h @@ -10,6 +10,7 @@ #ifndef _USB_P_ #define _USB_P_ +#include #include "usbspec_p.h" @@ -76,9 +77,7 @@ public: private: Vector fBusManagers; - sem_id fMasterLock; - sem_id fDataLock; - + benaphore fLock; area_id fAreas[USB_MAX_AREAS]; void *fLogical[USB_MAX_AREAS]; void *fPhysical[USB_MAX_AREAS]; @@ -359,6 +358,8 @@ virtual status_t GetDescriptor(uint8 descriptorType, void *data, size_t dataLength, size_t *actualLength); + status_t UpdatePortStatus(uint8 index); + status_t ResetPort(uint8 index); void Explore(); virtual void ReportDevice( @@ -413,7 +414,7 @@ public: void *cookie); status_t WaitForFinish(); - void Finished(status_t result); + void Finished(uint32 status); private: // Data that is related to the transfer @@ -422,7 +423,7 @@ private: size_t fDataLength; size_t *fActualLength; size_t fOwnActualLength; - status_t fStatus; + uint32 fStatus; usb_callback_func fCallback; void *fCallbackCookie; 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 3eac90052b..fdfbe469bc 100644 --- a/src/add-ons/kernel/bus_managers/usb/usbspec_p.h +++ b/src/add-ons/kernel/bus_managers/usb/usbspec_p.h @@ -14,9 +14,16 @@ #include #include -#define USB_MAX_AREAS 8 -#define POWER_DELAY +#define USB_MAX_AREAS 8 +#define USB_DELAY_DEVICE_POWER_UP 300000 +#define USB_DELAY_PORT_RESET 50000 +#define USB_DELAY_PORT_RESET_RECOVERY 250000 +#define USB_DELAY_SET_ADDRESS_RETRY 200000 +#define USB_DELAY_SET_ADDRESS 10000 +#define USB_DELAY_SET_CONFIGURATION 50000 +#define USB_DELAY_FIRST_EXPLORE 5000000 +#define USB_DELAY_HUB_EXPLORE 1000000 /* Important data from the USB spec (not interesting for drivers) @@ -41,15 +48,15 @@ struct usb_request_data struct usb_hub_descriptor { - uint8 bDescLength; - uint8 bDescriptorType; - uint8 bNbrPorts; - uint16 wHubCharacteristics; - uint8 bPwrOn2PwrGood; - uint8 bHucContrCurrent; - uint8 DeviceRemovable; //Should be variable!!! - uint8 PortPwrCtrlMask; //Deprecated -}; + uint8 length; + uint8 descriptor_type; + uint8 num_ports; + uint16 characteristics; + uint8 power_on_to_power_good; + uint8 max_power; + uint8 device_removeable; //Should be variable!!! + uint8 power_control_mask; //Deprecated +} _PACKED; #define USB_DESCRIPTOR_HUB 0x29 diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index 046ea1abd7..051c18dc9b 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -104,7 +104,7 @@ Queue::Queue(Stack *stack) fStack = stack; if (benaphore_init(&fLock, "uhci queue lock") < B_OK) { - TRACE(("usb_uhci: failed to create queue lock\n")); + TRACE_ERROR(("usb_uhci: failed to create queue lock\n")); return; } @@ -180,7 +180,7 @@ Queue::TerminateByStrayDescriptor() status_t result = fStack->AllocateChunk((void **)&fStrayDescriptor, &physicalAddress, 32); if (result < B_OK) { - TRACE(("usb_uhci: failed to allocate a stray transfer descriptor\n")); + TRACE_ERROR(("usb_uhci: failed to allocate a stray transfer descriptor\n")); return result; } @@ -191,8 +191,8 @@ Queue::TerminateByStrayDescriptor() fStrayDescriptor->buffer_phy = 0; fStrayDescriptor->buffer_log = 0; fStrayDescriptor->buffer_size = 0; - fStrayDescriptor->token = TD_TOKEN_NULL | (0x7f << TD_TOKEN_DEVADDR_SHIFT) - | TD_TOKEN_IN; + fStrayDescriptor->token = TD_TOKEN_NULL_DATA + | (0x7f << TD_TOKEN_DEVADDR_SHIFT) | TD_TOKEN_IN; if (!Lock()) { fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy, @@ -210,9 +210,9 @@ Queue::TerminateByStrayDescriptor() status_t -Queue::AppendDescriptor(uhci_td *descriptor) +Queue::AppendDescriptorChain(uhci_td *descriptor) { - TRACE(("usb_uhci: appending descriptors\n")); + TRACE(("usb_uhci: appending descriptor chain\n")); if (!Lock()) return B_ERROR; @@ -221,7 +221,7 @@ Queue::AppendDescriptor(uhci_td *descriptor) print_descriptor_chain(descriptor); #endif - if (fQueueHead->element_phy & QH_TERMINATE) { + if (fQueueTop == NULL) { // the queue is empty, make this the first element fQueueTop = descriptor; fQueueHead->element_phy = descriptor->this_phy; @@ -243,17 +243,17 @@ Queue::AppendDescriptor(uhci_td *descriptor) status_t -Queue::RemoveDescriptors(uhci_td *firstDescriptor, uhci_td *lastDescriptor) +Queue::RemoveDescriptorChain(uhci_td *firstDescriptor, uhci_td *lastDescriptor) { - TRACE(("usb_uhci: removing descriptors\n")); + TRACE(("usb_uhci: removing descriptor chain\n")); if (!Lock()) return B_ERROR; if (fQueueTop == firstDescriptor) { - // it was the first chain in this queue + // it is the first chain in this queue if ((lastDescriptor->link_phy & TD_TERMINATE) > 0) { - // it was the only transfer + // it is the only chain in this queue fQueueTop = NULL; fQueueHead->element_phy = QH_TERMINATE; } else { @@ -262,30 +262,26 @@ Queue::RemoveDescriptors(uhci_td *firstDescriptor, uhci_td *lastDescriptor) 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; + // unlink the chain + uhci_td *element = fQueueTop; + while (element) { + if (element->link_log == firstDescriptor) { + element->link_log = lastDescriptor->link_log; + element->link_phy = lastDescriptor->link_phy; break; } - descriptor = (uhci_td *)descriptor->link_log; + element = (uhci_td *)element->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; - + element = firstDescriptor; + while (element && element != lastDescriptor) { + if ((fQueueHead->element_phy & TD_LINK_MASK) == element->this_phy) { + fQueueHead->element_phy = lastDescriptor->link_phy; break; } - descriptor = (uhci_td *)descriptor->link_log; + element = (uhci_td *)element->link_log; } } @@ -346,7 +342,7 @@ UHCI::UHCI(pci_info *info, Stack *stack) fInitOK = false; if (benaphore_init(&fUHCILock, "usb uhci lock") < B_OK) { - TRACE(("usb_uhci: failed to create busmanager lock\n")); + TRACE_ERROR(("usb_uhci: failed to create busmanager lock\n")); return; } @@ -376,7 +372,7 @@ UHCI::UHCI(pci_info *info, Stack *stack) // do a global and host reset GlobalReset(); if (ControllerReset() < B_OK) { - TRACE(("usb_uhci: host failed to reset\n")); + TRACE_ERROR(("usb_uhci: host failed to reset\n")); return; } @@ -386,7 +382,7 @@ UHCI::UHCI(pci_info *info, Stack *stack) (void **)&physicalAddress, 4096, "USB UHCI framelist"); if (fFrameArea < B_OK) { - TRACE(("usb_uhci: unable to create an area for the frame pointer list\n")); + TRACE_ERROR(("usb_uhci: unable to create an area for the frame pointer list\n")); return; } @@ -404,7 +400,7 @@ UHCI::UHCI(pci_info *info, Stack *stack) for (int32 i = 0; i < fQueueCount; i++) { fQueues[i] = new(std::nothrow) Queue(fStack); if (!fQueues[i] || fQueues[i]->InitCheck() < B_OK) { - TRACE(("usb_uhci: cannot create queues\n")); + TRACE_ERROR(("usb_uhci: cannot create queues\n")); delete_area(fFrameArea); return; } @@ -503,19 +499,20 @@ UHCI::Start() } if (!running) { - TRACE(("usb_uhci: controller won't start running\n")); + TRACE_ERROR(("usb_uhci: controller won't start running\n")); return B_ERROR; } + fPortResetChange[0] = fPortResetChange[1] = false; fRootHubAddress = AllocateAddress(); fRootHub = new(std::nothrow) UHCIRootHub(this, fRootHubAddress); if (!fRootHub) { - TRACE(("usb_uhci: no memory to allocate root hub\n")); + TRACE_ERROR(("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")); + TRACE_ERROR(("usb_uhci: root hub failed init check\n")); delete fRootHub; return B_ERROR; } @@ -558,7 +555,7 @@ UHCI::SubmitTransfer(Transfer *transfer) if (!firstDescriptor || !lastDescriptor) return B_NO_MEMORY; - lastDescriptor->status |= TD_STATUS_IOC; + lastDescriptor->status |= TD_CONTROL_IOC; lastDescriptor->link_phy = TD_TERMINATE; lastDescriptor->link_log = 0; @@ -574,14 +571,14 @@ UHCI::SubmitTransfer(Transfer *transfer) result = AddPendingTransfer(transfer, queue, firstDescriptor, firstDescriptor, lastDescriptor, directionIn); if (result < B_OK) { - TRACE(("usb_uhci: failed to add pending transfer\n")); + TRACE_ERROR(("usb_uhci: failed to add pending transfer\n")); FreeDescriptorChain(firstDescriptor); return result; } - result = queue->AppendDescriptor(firstDescriptor); + result = queue->AppendDescriptorChain(firstDescriptor); if (result < B_OK) { - TRACE(("usb_uhci: failed to append descriptors\n")); + TRACE_ERROR(("usb_uhci: failed to append descriptor chain\n")); FreeDescriptorChain(firstDescriptor); return result; } @@ -604,7 +601,7 @@ UHCI::SubmitRequest(Transfer *transfer) directionIn ? TD_TOKEN_OUT : TD_TOKEN_IN, 0); if (!setupDescriptor || !statusDescriptor) { - TRACE(("usb_uhci: failed to allocate descriptors\n")); + TRACE_ERROR(("usb_uhci: failed to allocate descriptors\n")); FreeDescriptor(setupDescriptor); FreeDescriptor(statusDescriptor); return B_NO_MEMORY; @@ -613,10 +610,10 @@ UHCI::SubmitRequest(Transfer *transfer) WriteDescriptorChain(setupDescriptor, (const uint8 *)requestData, sizeof(usb_request_data)); - statusDescriptor->status |= TD_STATUS_IOC; + statusDescriptor->status |= TD_CONTROL_IOC; statusDescriptor->token |= TD_TOKEN_DATA1; statusDescriptor->link_phy = TD_TERMINATE; - statusDescriptor->link_log = 0; + statusDescriptor->link_log = NULL; uhci_td *dataDescriptor = NULL; if (transfer->Data() && transfer->DataLength() > 0) { @@ -646,14 +643,14 @@ UHCI::SubmitRequest(Transfer *transfer) status_t result = AddPendingTransfer(transfer, fQueues[1], setupDescriptor, dataDescriptor, statusDescriptor, directionIn); if (result < B_OK) { - TRACE(("usb_uhci: failed to add pending transfer\n")); + TRACE_ERROR(("usb_uhci: failed to add pending transfer\n")); FreeDescriptorChain(setupDescriptor); return result; } - result = fQueues[1]->AppendDescriptor(setupDescriptor); + result = fQueues[1]->AppendDescriptorChain(setupDescriptor); if (result < B_OK) { - TRACE(("usb_uhci: failed to append descriptors\n")); + TRACE_ERROR(("usb_uhci: failed to append descriptor chain\n")); FreeDescriptorChain(setupDescriptor); return result; } @@ -667,7 +664,6 @@ UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue, uhci_td *firstDescriptor, uhci_td *dataDescriptor, uhci_td *lastDescriptor, bool directionIn) { - TRACE(("usb_uhci: add pending transfer\n")); transfer_data *data = new(std::nothrow) transfer_data(); if (!data) return B_NO_MEMORY; @@ -741,11 +737,22 @@ UHCI::FinishTransfers() 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, + + uint32 callbackStatus = 0; + if (status & TD_STATUS_ERROR_STALLED) + callbackStatus |= B_USB_STATUS_DEVICE_STALLED; + if (status & TD_STATUS_ERROR_TIMEOUT) { + if (transfer->incoming) + callbackStatus |= B_USB_STATUS_DEVICE_CRC_ERROR; + else + callbackStatus |= B_USB_STATUS_DEVICE_TIMEOUT; + } + + transfer->queue->RemoveDescriptorChain( + transfer->first_descriptor, transfer->last_descriptor); FreeDescriptorChain(transfer->first_descriptor); - TRACE(("usb_uhci: notify transfer 0x%08x\n", transfer)); - transfer->transfer->Finished(B_ERROR); + transfer->transfer->Finished(callbackStatus); transferDone = true; break; } @@ -753,13 +760,14 @@ UHCI::FinishTransfers() if (descriptor == transfer->last_descriptor) { TRACE(("usb_uhci: td (0x%08x) ok\n", descriptor->this_phy)); // we got through without errors so we are finished - transfer->queue->RemoveDescriptors(transfer->first_descriptor, + transfer->queue->RemoveDescriptorChain( + transfer->first_descriptor, transfer->last_descriptor); if (transfer->data_descriptor && transfer->incoming) { // data to read out - TRACE(("usb_uhci: reading incoming data buffer to transfer 0x%08x\n", transfer)); - size_t length = ReadDescriptorChain(transfer->data_descriptor, + size_t length = ReadDescriptorChain( + transfer->data_descriptor, transfer->transfer->Data(), transfer->transfer->DataLength()); @@ -767,7 +775,6 @@ UHCI::FinishTransfers() } FreeDescriptorChain(transfer->first_descriptor); - TRACE(("usb_uhci: notify transfer 0x%08x\n", transfer)); transfer->transfer->Finished(B_OK); transferDone = true; break; @@ -777,7 +784,6 @@ UHCI::FinishTransfers() } if (transferDone) { - TRACE(("usb_uhci: transfer (0x%08x) done\n", transfer)); if (Lock()) { if (lastTransfer) lastTransfer->link = transfer->link; @@ -794,7 +800,6 @@ UHCI::FinishTransfers() Unlock(); } } else { - TRACE(("usb_uhci: transfer (0x%08x) not done\n", transfer)); lastTransfer = transfer; transfer = transfer->link; } @@ -837,7 +842,6 @@ UHCI::PortStatus(int32 index) if (index > 1) return B_BAD_VALUE; - //TRACE(("usb_uhci: read port status of port: %d\n", index)); return ReadReg16(UHCI_PORTSC1 + index * 2); } @@ -903,11 +907,32 @@ UHCI::ResetPort(int32 index) } } + SetPortResetChange(index, true); 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) { @@ -931,9 +956,6 @@ UHCI::Interrupt() if ((status & UHCI_INTERRUPT_MASK) == 0) return B_UNHANDLED_INTERRUPT; - TRACE(("usb_uhci: Interrupt()\n")); - TRACE(("usb_uhci: status: 0x%04x\n", status)); - uint16 acknowledge = 0; if (status & UHCI_USBSTS_USBINT) { TRACE(("usb_uhci: transfer finished\n")); @@ -984,7 +1006,7 @@ UHCI::AddTo(Stack &stack) if (!sPCIModule) { status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule); if (status < B_OK) { - TRACE(("usb_uhci: AddTo(): getting pci module failed! 0x%08x\n", + TRACE_ERROR(("usb_uhci: AddTo(): getting pci module failed! 0x%08x\n", status)); return status; } @@ -1006,7 +1028,7 @@ UHCI::AddTo(Stack &stack) && item->class_api == 0x00) { if (item->u.h0.interrupt_line == 0 || item->u.h0.interrupt_line == 0xFF) { - TRACE(("usb_uhci: AddTo(): found with invalid IRQ - check IRQ assignement\n")); + TRACE_ERROR(("usb_uhci: AddTo(): found with invalid IRQ - check IRQ assignement\n")); continue; } @@ -1020,7 +1042,7 @@ UHCI::AddTo(Stack &stack) } if (bus->InitCheck() < B_OK) { - TRACE(("usb_uhci: AddTo(): InitCheck() failed 0x%08x\n", bus->InitCheck())); + TRACE_ERROR(("usb_uhci: AddTo(): InitCheck() failed 0x%08x\n", bus->InitCheck())); delete bus; continue; } @@ -1050,22 +1072,22 @@ UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, int32 bufferSize) void *physicalAddress; if (fStack->AllocateChunk((void **)&result, &physicalAddress, 32) < B_OK) { - TRACE(("usb_uhci: failed to allocate a transfer descriptor\n")); + TRACE_ERROR(("usb_uhci: failed to allocate a transfer descriptor\n")); return NULL; } result->this_phy = (addr_t)physicalAddress; - result->status = TD_STATUS_ACTIVE | TD_STATUS_3_ERRORS; + result->status = TD_STATUS_ACTIVE | TD_CONTROL_3_ERRORS; if (pipe->Speed() == Pipe::LowSpeed) - result->status |= TD_STATUS_LOWSPEED; + result->status |= TD_CONTROL_LOWSPEED; result->buffer_size = bufferSize; if (bufferSize == 0) - result->token = TD_TOKEN_NULL; + result->token = TD_TOKEN_NULL_DATA; else - result->token = (bufferSize - 1) << 21; + result->token = (bufferSize - 1) << TD_TOKEN_MAXLEN_SHIFT; - result->token |= (pipe->EndpointAddress() << 15) + result->token |= (pipe->EndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT) | (pipe->DeviceAddress() << 8) | direction; result->link_phy = 0; @@ -1078,7 +1100,7 @@ UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, int32 bufferSize) if (fStack->AllocateChunk(&result->buffer_log, &result->buffer_phy, bufferSize) < B_OK) { - TRACE(("usb_uhci: unable to allocate space for the buffer\n")); + TRACE_ERROR(("usb_uhci: unable to allocate space for the buffer\n")); fStack->FreeChunk(result, (void *)result->this_phy, 32); return NULL; } @@ -1168,7 +1190,6 @@ size_t UHCI::WriteDescriptorChain(uhci_td *topDescriptor, const uint8 *buffer, int32 bufferSize) { - TRACE(("usb_uhci: writing descriptor chain from buffer 0x%08x\n", buffer)); size_t actualSize = 0; uhci_td *current = topDescriptor; @@ -1198,7 +1219,6 @@ size_t UHCI::ReadDescriptorChain(uhci_td *topDescriptor, uint8 *buffer, int32 bufferSize) { - TRACE(("usb_uhci: reading descriptor chain to buffer 0x%08x\n", buffer)); size_t actualSize = 0; uhci_td *current = topDescriptor; diff --git a/src/add-ons/kernel/busses/usb/uhci.h b/src/add-ons/kernel/busses/usb/uhci.h index bfee60d4e3..6ce08b9795 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -32,8 +32,9 @@ public: status_t LinkTo(Queue *other); status_t TerminateByStrayDescriptor(); - status_t AppendDescriptor(uhci_td *descriptor); - status_t RemoveDescriptors(uhci_td *firstDescriptor, + status_t AppendDescriptorChain(uhci_td *descriptor); + status_t RemoveDescriptorChain( + uhci_td *firstDescriptor, uhci_td *lastDescriptor); addr_t PhysicalAddress(); @@ -79,6 +80,8 @@ static bool AddTo(Stack &stack); 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); private: // Controller resets @@ -151,6 +154,7 @@ static pci_module_info *sPCIModule; // Root hub UHCIRootHub *fRootHub; uint8 fRootHubAddress; + bool fPortResetChange[2]; }; diff --git a/src/add-ons/kernel/busses/usb/uhci_hardware.h b/src/add-ons/kernel/busses/usb/uhci_hardware.h index f0c1776765..5eed58cf40 100644 --- a/src/add-ons/kernel/busses/usb/uhci_hardware.h +++ b/src/add-ons/kernel/busses/usb/uhci_hardware.h @@ -14,7 +14,6 @@ * The Registers * ************************************************************/ - // R/W -- Read/Write // R/WC -- Read/Write Clear // ** -- Only writable with words! @@ -80,75 +79,91 @@ #define FRAMELIST_NEXT_IS_QH 0x2 -//Represents a Transfer Descriptor (TD) - +// Represents a Transfer Descriptor (TD) typedef struct { //Hardware part - addr_t link_phy; // Link to the next TD/QH - uint32 status; // Status field - uint32 token; // Contains the packet header (where it needs to be sent) - void * buffer_phy; // A pointer to the buffer with the actual packet + addr_t link_phy; // Link to the next TD/QH + uint32 status; // Status field + uint32 token; // Contains the packet header (where it needs to be sent) + void *buffer_phy; // A pointer to the buffer with the actual packet // Software part - addr_t this_phy; // A physical pointer to this address - void * link_log; // Link to the next logical TD/QT - void * buffer_log; // Link to the buffer - int32 buffer_size; // Size of the buffer + addr_t this_phy; // A physical pointer to this address + void *link_log; // Pointer to the next logical TD/QT + void *buffer_log; // Pointer to the logical buffer + int32 buffer_size; // Size of the buffer } uhci_td; -#define TD_STATUS_3_ERRORS (3 << 27) -#define TD_STATUS_LOWSPEED (1 << 26) -#define TD_STATUS_IOS (1 << 25) -#define TD_STATUS_IOC (1 << 24) -#define TD_STATUS_ACTIVE (1 << 23) -#define TD_STATUS_ACTLEN_MASK 0x3ff -#define TD_STATUS_ACTLEN_NULL 0x7ff +// Control and Status +#define TD_CONTROL_SHORT_PACKET (1 << 29) +#define TD_CONTROL_3_ERRORS (3 << 27) +#define TD_CONTROL_LOWSPEED (1 << 26) +#define TD_CONTROL_ISOCHRONOUS (1 << 25) +#define TD_CONTROL_IOC (1 << 24) -#define TD_TOKEN_DATA1 (1 << 19) -#define TD_TOKEN_NULL (0x7ff << 21) +#define TD_STATUS_ACTIVE (1 << 23) +#define TD_STATUS_ERROR_STALLED (1 << 22) +#define TD_STATUS_ERROR_BUFFER (1 << 21) +#define TD_STATUS_ERROR_BABBLE (1 << 20) +#define TD_STATUS_ERROR_NAK (1 << 19) +#define TD_STATUS_ERROR_CRC (1 << 18) +#define TD_STATUS_ERROR_TIMEOUT (1 << 18) +#define TD_STATUS_ERROR_BITSTUFF (1 << 17) -#define TD_TOKEN_SETUP 0x2d -#define TD_TOKEN_IN 0x69 -#define TD_TOKEN_OUT 0xe1 +#define TD_STATUS_ACTLEN_MASK 0x03ff +#define TD_STATUS_ACTLEN_NULL 0x07ff -#define TD_TOKEN_DEVADDR_SHIFT 8 -#define TD_DEPTH_FIRST 0x4 -#define TD_TERMINATE 0x1 -#define TD_ERROR_MASK 0x7e0000 -#define TD_LINK_MASK 0xfffffff0 +// Token +#define TD_TOKEN_MAXLEN_SHIFT 21 +#define TD_TOKEN_NULL_DATA (0x07ff << TD_TOKEN_MAXLEN_SHIFT) +#define TD_TOKEN_DATA1 (1 << 19) -//Represents a Queue Head (QH) +#define TD_TOKEN_SETUP 0x2d +#define TD_TOKEN_IN 0x69 +#define TD_TOKEN_OUT 0xe1 +#define TD_TOKEN_ENDPTADDR_SHIFT 15 +#define TD_TOKEN_DEVADDR_SHIFT 8 + +#define TD_DEPTH_FIRST 0x04 +#define TD_TERMINATE 0x01 +#define TD_ERROR_MASK 0x7e0000 +#define TD_LINK_MASK 0xfffffff0 + + +// Represents a Queue Head (QH) typedef struct { // Hardware part - addr_t link_phy; //Link to the next TD/QH - addr_t element_phy; //Link to the first element pointer in the queue + addr_t link_phy; // Link to the next TD/QH + addr_t element_phy; // Pointer to the first element in the queue // Software part - addr_t this_phy; //The physical pointer to this address - void * link_log; //Link to the next TD/QH logical + addr_t this_phy; // The physical pointer to this address + void *link_log; // Pointer to the next logical TD/QH } uhci_qh; -#define QH_TERMINATE 0x1 -#define QH_NEXT_IS_QH 0x2 +#define QH_TERMINATE 0x01 +#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 +#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) +// 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_STRING_DESCRIPTOR (0x03 << 8) #define RH_HUB_DESCRIPTOR (0x29 << 8) -//Hub/Portstatus buffer +// Hub/Portstatus buffer typedef struct { uint16 status; diff --git a/src/add-ons/kernel/busses/usb/uhci_rh.cpp b/src/add-ons/kernel/busses/usb/uhci_rh.cpp index bfdef5faad..00e9664389 100644 --- a/src/add-ons/kernel/busses/usb/uhci_rh.cpp +++ b/src/add-ons/kernel/busses/usb/uhci_rh.cpp @@ -140,13 +140,13 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer) status_t result = B_ERROR; switch (request->Request) { - case RH_GET_STATUS: + case RH_GET_STATUS: { if (request->Index == 0) { // Get the hub status -- everything as 0 means all-right memset(transfer->Data(), 0, sizeof(get_status_buffer)); result = B_OK; break; - } else if (request->Index > sUHCIRootHubConfig.hub.bNbrPorts) { + } else if (request->Index > sUHCIRootHubConfig.hub.num_ports) { // This port doesn't exist result = EINVAL; break; @@ -154,13 +154,15 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer) // Get port status UpdatePortStatus(); - memcpy(transfer->Data(), - (void *)&fPortStatus[request->Index - 1], - transfer->DataLength()); - *(transfer->ActualLength()) = transfer->DataLength(); + size_t length = MIN(4, transfer->DataLength()); + memcpy(transfer->Data(), + (void *)&fPortStatus[request->Index - 1], length); + + *(transfer->ActualLength()) = length; result = B_OK; break; + } case RH_SET_ADDRESS: if (request->Value >= 128) { @@ -239,7 +241,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer) TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE no hub changes!\n")); result = EINVAL; break; - } else if (request->Index > sUHCIRootHubConfig.hub.bNbrPorts) { + } else if (request->Index > sUHCIRootHubConfig.hub.num_ports) { // Invalid port number TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE invalid port!\n")); result = EINVAL; @@ -249,10 +251,9 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer) TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE called. Feature: %u!\n", request->Value)); uint16 status; switch(request->Value) { - case PORT_RESET: - status = fUHCI->PortStatus(request->Index - 1); - result = fUHCI->SetPortStatus(request->Index - 1, - status & UHCI_PORTSC_DATAMASK & ~UHCI_PORTSC_RESET); + case C_PORT_RESET: + fUHCI->SetPortResetChange(request->Index - 1, false); + result = B_OK; break; case C_PORT_CONNECTION: @@ -273,7 +274,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer) TRACE(("usb_uhci_roothub: RH_SET_FEATURE no hub changes!\n")); result = EINVAL; break; - } else if (request->Index > sUHCIRootHubConfig.hub.bNbrPorts) { + } else if (request->Index > sUHCIRootHubConfig.hub.num_ports) { // Invalid port number TRACE(("usb_uhci_roothub: RH_SET_FEATURE invalid port!\n")); result = EINVAL; @@ -281,17 +282,16 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer) } TRACE(("usb_uhci_roothub: RH_SET_FEATURE called. Feature: %u!\n", request->Value)); - uint16 status; switch(request->Value) { case PORT_RESET: result = fUHCI->ResetPort(request->Index - 1); break; - case PORT_ENABLE: - status = fUHCI->PortStatus(request->Index - 1); - result = fUHCI->SetPortStatus(request->Index - 1, - (status & UHCI_PORTSC_DATAMASK) | UHCI_PORTSC_ENABLED); + case PORT_POWER: + // the ports are automatically powered + result = B_OK; break; + default: result = EINVAL; break; @@ -312,7 +312,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer) void UHCIRootHub::UpdatePortStatus() { - for (int32 i = 0; i < sUHCIRootHubConfig.hub.bNbrPorts; i++) { + for (int32 i = 0; i < sUHCIRootHubConfig.hub.num_ports; i++) { uint16 newStatus = 0; uint16 newChange = 0; @@ -336,8 +336,8 @@ UHCIRootHub::UpdatePortStatus() if (portStatus & UHCI_PORTSC_RESET) newStatus |= PORT_STATUS_RESET; - - //TODO: work out reset change... + if (fUHCI->PortResetChange(i)) + newChange |= PORT_STATUS_RESET; //The port is automagically powered on newStatus |= PORT_POWER;