* 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
This commit is contained in:
Michael Lotz
2006-08-12 21:07:34 +00:00
parent 8be9a75c4e
commit f1020a6c49
12 changed files with 380 additions and 249 deletions
@@ -74,10 +74,10 @@ BusManager::ExploreThread(void *data)
if (!rootHub) if (!rootHub)
return B_ERROR; return B_ERROR;
snooze(3000000); snooze(USB_DELAY_FIRST_EXPLORE);
while (true) { while (true) {
rootHub->Explore(); rootHub->Explore();
snooze(1000000); snooze(USB_DELAY_HUB_EXPLORE);
} }
return B_OK; return B_OK;
@@ -98,16 +98,24 @@ BusManager::AllocateNewDevice(Device *parent, bool lowSpeed)
ControlPipe *defaultPipe = (lowSpeed ? fDefaultPipeLowSpeed : fDefaultPipe); ControlPipe *defaultPipe = (lowSpeed ? fDefaultPipeLowSpeed : fDefaultPipe);
// Set the address of the device USB 1.1 spec p202 status_t result = B_ERROR;
status_t result = defaultPipe->SendRequest( for (int32 i = 0; i < 15; i++) {
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT, // type // Set the address of the device USB 1.1 spec p202
USB_REQUEST_SET_ADDRESS, // request result = defaultPipe->SendRequest(
deviceAddress, // value USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT, // type
0, // index USB_REQUEST_SET_ADDRESS, // request
0, // length deviceAddress, // value
NULL, // buffer 0, // index
0, // buffer length 0, // length
NULL); // actual length NULL, // buffer
0, // buffer length
NULL); // actual length
if (result >= B_OK)
break;
snooze(USB_DELAY_SET_ADDRESS_RETRY);
}
if (result < B_OK) { if (result < B_OK) {
TRACE(("usb BusManager::AllocateNewDevice(): error while setting device address\n")); 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 // Wait a bit for the device to complete addressing
snooze(10000); snooze(USB_DELAY_SET_ADDRESS);
// Create a temporary pipe with the new address // Create a temporary pipe with the new address
ControlPipe pipe(this, deviceAddress, ControlPipe pipe(this, deviceAddress,
@@ -339,7 +339,7 @@ Device::SetConfigurationAt(uint8 index)
fCurrentConfiguration = &fConfigurations[index]; fCurrentConfiguration = &fConfigurations[index];
// Wait some for the configuration being finished // Wait some for the configuration being finished
snooze(10000); snooze(USB_DELAY_SET_CONFIGURATION);
return B_OK; return B_OK;
} }
+124 -66
View File
@@ -62,91 +62,146 @@ Hub::Hub(BusManager *bus, Device *parent, usb_device_descriptor &desc,
size_t actualLength; size_t actualLength;
status_t status = GetDescriptor(USB_DESCRIPTOR_HUB, 0, 0, status_t status = GetDescriptor(USB_DESCRIPTOR_HUB, 0, 0,
(void *)&fHubDescriptor, sizeof(usb_hub_descriptor), &actualLength); (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")); TRACE(("USB Hub: Error getting hub descriptor\n"));
return; 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 // Enable port power on all ports
for (int32 i = 0; i < fHubDescriptor.bNbrPorts; i++) { for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, status = SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
USB_REQUEST_SET_FEATURE, USB_REQUEST_SET_FEATURE, PORT_POWER, i + 1, 0, NULL, 0, NULL);
PORT_POWER,
i + 1, if (status < B_OK)
0, TRACE(("USB Hub: power up failed on port %d\n", i));
NULL,
0,
&actualLength);
} }
// Wait for power to stabilize // Wait for power to stabilize
snooze(fHubDescriptor.bPwrOn2PwrGood * 2000); snooze(fHubDescriptor.power_on_to_power_good * 2000);
fInitOK = true; fInitOK = true;
TRACE(("USB Hub: initialised ok\n")); 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 void
Hub::Explore() Hub::Explore()
{ {
for (int32 i = 0; i < fHubDescriptor.bNbrPorts; i++) { for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
size_t actualLength; status_t result = UpdatePortStatus(i);
if (result < B_OK)
// Get the current port status continue;
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);
}
if (fPortStatus[i].change & PORT_STATUS_CONNECTION) { if (fPortStatus[i].change & PORT_STATUS_CONNECTION) {
if (fPortStatus[i].status & PORT_STATUS_CONNECTION) { if (fPortStatus[i].status & PORT_STATUS_CONNECTION) {
// New device attached! // 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);
}
TRACE(("USB Hub: Explore(): New device connected\n")); 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, Device *newDevice = fBus->AllocateNewDevice(this,
(fPortStatus[i].status & PORT_STATUS_LOW_SPEED) > 0); (fPortStatus[i].status & PORT_STATUS_LOW_SPEED) > 0);
if (newDevice) { if (newDevice) {
fChildren[i] = newDevice; fChildren[i] = newDevice;
Manager()->GetStack()->NotifyDeviceChange(fChildren[i], true); 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 { } else {
// Device removed... // Device removed...
@@ -158,17 +213,20 @@ Hub::Explore()
} }
} }
// Clear status change // clear status change
SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT,
USB_REQUEST_CLEAR_FEATURE, USB_REQUEST_CLEAR_FEATURE, C_PORT_CONNECTION, i + 1,
C_PORT_CONNECTION, 0, NULL, 0, NULL);
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); Device::ReportDevice(supportDescriptors, supportDescriptorCount, hooks, added);
// Then report all of our children // 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]) if (!fChildren[i])
continue; continue;
@@ -24,13 +24,10 @@ Stack::Stack()
{ {
TRACE(("usb stack: stack init\n")); TRACE(("usb stack: stack init\n"));
// Create the master lock if (benaphore_init(&fLock, "USB Stack Master Lock") < B_OK) {
fMasterLock = create_sem(1, "usb master lock"); TRACE(("usb stack: failed to create benaphore lock\n"));
set_sem_owner(fMasterLock, B_SYSTEM_TEAM); return;
}
// Create the data lock
fDataLock = create_sem(1, "usb data lock");
set_sem_owner(fDataLock, B_SYSTEM_TEAM);
// Initialise the memory chunks: create 8, 16 and 32 byte-heaps // Initialise the memory chunks: create 8, 16 and 32 byte-heaps
// NOTE: This is probably the most ugly code you will see in the // NOTE: This is probably the most ugly code you will see in the
@@ -149,6 +146,9 @@ Stack::Stack()
Stack::~Stack() Stack::~Stack()
{ {
Lock();
benaphore_destroy(&fLock);
//Release the bus modules //Release the bus modules
for (Vector<BusManager *>::Iterator i = fBusManagers.Begin(); for (Vector<BusManager *>::Iterator i = fBusManagers.Begin();
i != fBusManagers.End(); i++) { i != fBusManagers.End(); i++) {
@@ -174,14 +174,14 @@ Stack::InitCheck()
bool bool
Stack::Lock() Stack::Lock()
{ {
return (acquire_sem(fMasterLock) == B_OK); return (benaphore_lock(&fLock) == B_OK);
} }
void void
Stack::Unlock() Stack::Unlock()
{ {
release_sem(fMasterLock); benaphore_unlock(&fLock);
} }
@@ -15,7 +15,7 @@ Transfer::Transfer(Pipe *pipe, bool synchronous)
fDataLength(0), fDataLength(0),
fActualLength(NULL), fActualLength(NULL),
fOwnActualLength(0), fOwnActualLength(0),
fStatus(B_NO_INIT), fStatus(B_USB_STATUS_DRIVER_INTERNAL_ERROR),
fCallback(NULL), fCallback(NULL),
fCallbackCookie(NULL), fCallbackCookie(NULL),
fSem(-1), fSem(-1),
@@ -78,22 +78,23 @@ status_t
Transfer::WaitForFinish() Transfer::WaitForFinish()
{ {
if (fSem < B_OK) if (fSem < B_OK)
return fStatus; return fSem;
status_t result = B_OK;
result = acquire_sem(fSem);
status_t result = acquire_sem(fSem);
if (result < B_OK) if (result < B_OK)
return result; return result;
return fStatus; if (fStatus == B_USB_STATUS_SUCCESS)
return B_OK;
return B_ERROR;
} }
void void
Transfer::Finished(status_t result) Transfer::Finished(uint32 status)
{ {
fStatus = result; fStatus = status;
// Call the callback function ... // Call the callback function ...
if (fCallback) { if (fCallback) {
@@ -87,6 +87,7 @@ uninstall_notify(const char *driverName)
const usb_device_descriptor * const usb_device_descriptor *
get_device_descriptor(const usb_device *device) get_device_descriptor(const usb_device *device)
{ {
TRACE(("usb_module: get_device_descriptor(0x%08x)\n", device));
if (!device) if (!device)
return NULL; return NULL;
@@ -97,6 +98,7 @@ get_device_descriptor(const usb_device *device)
const usb_configuration_info * const usb_configuration_info *
get_nth_configuration(const usb_device *device, uint index) get_nth_configuration(const usb_device *device, uint index)
{ {
TRACE(("usb_module: get_nth_configuration(0x%08x, %d)\n", device, index));
if (!device) if (!device)
return NULL; return NULL;
@@ -108,6 +110,7 @@ get_nth_configuration(const usb_device *device, uint index)
const usb_configuration_info * const usb_configuration_info *
get_configuration(const usb_device *device) get_configuration(const usb_device *device)
{ {
TRACE(("usb_module: get_configuration(0x%08x)\n", device));
if (!device) if (!device)
return NULL; return NULL;
@@ -119,6 +122,7 @@ status_t
set_configuration(const usb_device *device, set_configuration(const usb_device *device,
const usb_configuration_info *configuration) const usb_configuration_info *configuration)
{ {
TRACE(("usb_module: set_configuration(0x%08x, 0x%08x)\n", device, configuration));
if (!device) if (!device)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -130,6 +134,7 @@ status_t
set_alt_interface(const usb_device *device, set_alt_interface(const usb_device *device,
const usb_interface_info *interface) const usb_interface_info *interface)
{ {
TRACE(("usb_module: set_alt_interface(0x%08x, 0x%08x)\n", device, interface));
return B_ERROR; return B_ERROR;
} }
@@ -137,6 +142,7 @@ set_alt_interface(const usb_device *device,
status_t status_t
set_feature(const void *object, uint16 selector) set_feature(const void *object, uint16 selector)
{ {
TRACE(("usb_module: set_feature(0x%08x, %d)\n", object, selector));
if (!object) if (!object)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -147,6 +153,7 @@ set_feature(const void *object, uint16 selector)
status_t status_t
clear_feature(const void *object, uint16 selector) clear_feature(const void *object, uint16 selector)
{ {
TRACE(("usb_module: clear_feature(0x%08x, %d)\n", object, selector));
if (!object) if (!object)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -157,6 +164,7 @@ clear_feature(const void *object, uint16 selector)
status_t status_t
get_status(const void *object, uint16 *status) get_status(const void *object, uint16 *status)
{ {
TRACE(("usb_module: get_status(0x%08x, 0x%08x)\n", object, status));
if (!object || !status) if (!object || !status)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -168,6 +176,7 @@ status_t
get_descriptor(const usb_device *device, uint8 type, uint8 index, get_descriptor(const usb_device *device, uint8 type, uint8 index,
uint16 languageID, void *data, size_t dataLength, size_t *actualLength) 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) if (!device || !data)
return B_BAD_VALUE; 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, uint16 value, uint16 index, uint16 length, void *data, size_t dataLength,
size_t *actualLength) 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) if (!device)
return B_BAD_VALUE; 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, uint16 value, uint16 index, uint16 length, void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie) 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) if (!device)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -206,6 +217,7 @@ status_t
queue_interrupt(const usb_pipe *pipe, void *data, size_t dataLength, queue_interrupt(const usb_pipe *pipe, void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie) 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) if (((Pipe *)pipe)->Type() != Pipe::Interrupt)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -218,6 +230,7 @@ status_t
queue_bulk(const usb_pipe *pipe, void *data, size_t dataLength, queue_bulk(const usb_pipe *pipe, void *data, size_t dataLength,
usb_callback_func callback, void *callbackCookie) 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) if (((Pipe *)pipe)->Type() != Pipe::Bulk)
return B_BAD_VALUE; 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, rlea *rleArray, uint16 bufferDurationMS, usb_callback_func callback,
void *callbackCookie) 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) if (((Pipe *)pipe)->Type() != Pipe::Isochronous)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -243,6 +257,7 @@ status_t
set_pipe_policy(const usb_pipe *pipe, uint8 maxQueuedPackets, set_pipe_policy(const usb_pipe *pipe, uint8 maxQueuedPackets,
uint16 maxBufferDurationMS, uint16 sampleSize) uint16 maxBufferDurationMS, uint16 sampleSize)
{ {
TRACE(("usb_module: set_pipe_policy(0x%08x, %d, %d, %d)\n", pipe, maxQueuedPackets, maxBufferDurationMS, sampleSize));
return B_ERROR; return B_ERROR;
} }
@@ -250,6 +265,7 @@ set_pipe_policy(const usb_pipe *pipe, uint8 maxQueuedPackets,
status_t status_t
cancel_queued_transfers(const usb_pipe *pipe) cancel_queued_transfers(const usb_pipe *pipe)
{ {
TRACE(("usb_module: cancel_queued_transfers(0x%08x)\n", pipe));
return ((Pipe *)pipe)->CancelQueuedTransfers(); return ((Pipe *)pipe)->CancelQueuedTransfers();
} }
@@ -257,6 +273,7 @@ cancel_queued_transfers(const usb_pipe *pipe)
status_t status_t
usb_ioctl(uint32 opcode, void *buffer, size_t bufferSize) 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; return B_ERROR;
} }
+6 -5
View File
@@ -10,6 +10,7 @@
#ifndef _USB_P_ #ifndef _USB_P_
#define _USB_P_ #define _USB_P_
#include <lock.h>
#include "usbspec_p.h" #include "usbspec_p.h"
@@ -76,9 +77,7 @@ public:
private: private:
Vector<BusManager *> fBusManagers; Vector<BusManager *> fBusManagers;
sem_id fMasterLock; benaphore fLock;
sem_id fDataLock;
area_id fAreas[USB_MAX_AREAS]; area_id fAreas[USB_MAX_AREAS];
void *fLogical[USB_MAX_AREAS]; void *fLogical[USB_MAX_AREAS];
void *fPhysical[USB_MAX_AREAS]; void *fPhysical[USB_MAX_AREAS];
@@ -359,6 +358,8 @@ virtual status_t GetDescriptor(uint8 descriptorType,
void *data, size_t dataLength, void *data, size_t dataLength,
size_t *actualLength); size_t *actualLength);
status_t UpdatePortStatus(uint8 index);
status_t ResetPort(uint8 index);
void Explore(); void Explore();
virtual void ReportDevice( virtual void ReportDevice(
@@ -413,7 +414,7 @@ public:
void *cookie); void *cookie);
status_t WaitForFinish(); status_t WaitForFinish();
void Finished(status_t result); void Finished(uint32 status);
private: private:
// Data that is related to the transfer // Data that is related to the transfer
@@ -422,7 +423,7 @@ private:
size_t fDataLength; size_t fDataLength;
size_t *fActualLength; size_t *fActualLength;
size_t fOwnActualLength; size_t fOwnActualLength;
status_t fStatus; uint32 fStatus;
usb_callback_func fCallback; usb_callback_func fCallback;
void *fCallbackCookie; void *fCallbackCookie;
+18 -11
View File
@@ -14,9 +14,16 @@
#include <USB.h> #include <USB.h>
#include <util/kernel_cpp.h> #include <util/kernel_cpp.h>
#define USB_MAX_AREAS 8 #define USB_MAX_AREAS 8
#define POWER_DELAY
#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) Important data from the USB spec (not interesting for drivers)
@@ -41,15 +48,15 @@ struct usb_request_data
struct usb_hub_descriptor struct usb_hub_descriptor
{ {
uint8 bDescLength; uint8 length;
uint8 bDescriptorType; uint8 descriptor_type;
uint8 bNbrPorts; uint8 num_ports;
uint16 wHubCharacteristics; uint16 characteristics;
uint8 bPwrOn2PwrGood; uint8 power_on_to_power_good;
uint8 bHucContrCurrent; uint8 max_power;
uint8 DeviceRemovable; //Should be variable!!! uint8 device_removeable; //Should be variable!!!
uint8 PortPwrCtrlMask; //Deprecated uint8 power_control_mask; //Deprecated
}; } _PACKED;
#define USB_DESCRIPTOR_HUB 0x29 #define USB_DESCRIPTOR_HUB 0x29
+90 -70
View File
@@ -104,7 +104,7 @@ Queue::Queue(Stack *stack)
fStack = stack; fStack = stack;
if (benaphore_init(&fLock, "uhci queue lock") < B_OK) { 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; return;
} }
@@ -180,7 +180,7 @@ Queue::TerminateByStrayDescriptor()
status_t result = fStack->AllocateChunk((void **)&fStrayDescriptor, status_t result = fStack->AllocateChunk((void **)&fStrayDescriptor,
&physicalAddress, 32); &physicalAddress, 32);
if (result < B_OK) { 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; return result;
} }
@@ -191,8 +191,8 @@ Queue::TerminateByStrayDescriptor()
fStrayDescriptor->buffer_phy = 0; fStrayDescriptor->buffer_phy = 0;
fStrayDescriptor->buffer_log = 0; fStrayDescriptor->buffer_log = 0;
fStrayDescriptor->buffer_size = 0; fStrayDescriptor->buffer_size = 0;
fStrayDescriptor->token = TD_TOKEN_NULL | (0x7f << TD_TOKEN_DEVADDR_SHIFT) fStrayDescriptor->token = TD_TOKEN_NULL_DATA
| TD_TOKEN_IN; | (0x7f << TD_TOKEN_DEVADDR_SHIFT) | TD_TOKEN_IN;
if (!Lock()) { if (!Lock()) {
fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy, fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy,
@@ -210,9 +210,9 @@ Queue::TerminateByStrayDescriptor()
status_t 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()) if (!Lock())
return B_ERROR; return B_ERROR;
@@ -221,7 +221,7 @@ Queue::AppendDescriptor(uhci_td *descriptor)
print_descriptor_chain(descriptor); print_descriptor_chain(descriptor);
#endif #endif
if (fQueueHead->element_phy & QH_TERMINATE) { if (fQueueTop == NULL) {
// the queue is empty, make this the first element // the queue is empty, make this the first element
fQueueTop = descriptor; fQueueTop = descriptor;
fQueueHead->element_phy = descriptor->this_phy; fQueueHead->element_phy = descriptor->this_phy;
@@ -243,17 +243,17 @@ Queue::AppendDescriptor(uhci_td *descriptor)
status_t 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()) if (!Lock())
return B_ERROR; return B_ERROR;
if (fQueueTop == firstDescriptor) { 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) { if ((lastDescriptor->link_phy & TD_TERMINATE) > 0) {
// it was the only transfer // it is the only chain in this queue
fQueueTop = NULL; fQueueTop = NULL;
fQueueHead->element_phy = QH_TERMINATE; fQueueHead->element_phy = QH_TERMINATE;
} else { } else {
@@ -262,30 +262,26 @@ Queue::RemoveDescriptors(uhci_td *firstDescriptor, uhci_td *lastDescriptor)
fQueueHead->element_phy = fQueueTop->this_phy & TD_LINK_MASK; fQueueHead->element_phy = fQueueTop->this_phy & TD_LINK_MASK;
} }
} else { } else {
uhci_td *descriptor = fQueueTop; // unlink the chain
while (descriptor) { uhci_td *element = fQueueTop;
if (descriptor->link_log == firstDescriptor) { while (element) {
descriptor->link_log = lastDescriptor->link_log; if (element->link_log == firstDescriptor) {
descriptor->link_phy = lastDescriptor->link_phy; element->link_log = lastDescriptor->link_log;
element->link_phy = lastDescriptor->link_phy;
break; break;
} }
descriptor = (uhci_td *)descriptor->link_log; element = (uhci_td *)element->link_log;
} }
descriptor = firstDescriptor; element = firstDescriptor;
while (descriptor) { while (element && element != lastDescriptor) {
if ((fQueueHead->element_phy & TD_LINK_MASK) if ((fQueueHead->element_phy & TD_LINK_MASK) == element->this_phy) {
== (descriptor->this_phy & TD_LINK_MASK)) { fQueueHead->element_phy = lastDescriptor->link_phy;
if ((lastDescriptor->link_phy) & TD_TERMINATE > 0)
fQueueHead->element_phy = QH_TERMINATE;
else
fQueueHead->element_phy = lastDescriptor->link_phy & TD_LINK_MASK;
break; 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; fInitOK = false;
if (benaphore_init(&fUHCILock, "usb uhci lock") < B_OK) { 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; return;
} }
@@ -376,7 +372,7 @@ UHCI::UHCI(pci_info *info, Stack *stack)
// do a global and host reset // do a global and host reset
GlobalReset(); GlobalReset();
if (ControllerReset() < B_OK) { if (ControllerReset() < B_OK) {
TRACE(("usb_uhci: host failed to reset\n")); TRACE_ERROR(("usb_uhci: host failed to reset\n"));
return; return;
} }
@@ -386,7 +382,7 @@ UHCI::UHCI(pci_info *info, Stack *stack)
(void **)&physicalAddress, 4096, "USB UHCI framelist"); (void **)&physicalAddress, 4096, "USB UHCI framelist");
if (fFrameArea < B_OK) { 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; return;
} }
@@ -404,7 +400,7 @@ UHCI::UHCI(pci_info *info, Stack *stack)
for (int32 i = 0; i < fQueueCount; i++) { for (int32 i = 0; i < fQueueCount; i++) {
fQueues[i] = new(std::nothrow) Queue(fStack); fQueues[i] = new(std::nothrow) Queue(fStack);
if (!fQueues[i] || fQueues[i]->InitCheck() < B_OK) { 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); delete_area(fFrameArea);
return; return;
} }
@@ -503,19 +499,20 @@ UHCI::Start()
} }
if (!running) { if (!running) {
TRACE(("usb_uhci: controller won't start running\n")); TRACE_ERROR(("usb_uhci: controller won't start running\n"));
return B_ERROR; return B_ERROR;
} }
fPortResetChange[0] = fPortResetChange[1] = false;
fRootHubAddress = AllocateAddress(); fRootHubAddress = AllocateAddress();
fRootHub = new(std::nothrow) UHCIRootHub(this, fRootHubAddress); fRootHub = new(std::nothrow) UHCIRootHub(this, fRootHubAddress);
if (!fRootHub) { 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; return B_NO_MEMORY;
} }
if (fRootHub->InitCheck() < B_OK) { 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; delete fRootHub;
return B_ERROR; return B_ERROR;
} }
@@ -558,7 +555,7 @@ UHCI::SubmitTransfer(Transfer *transfer)
if (!firstDescriptor || !lastDescriptor) if (!firstDescriptor || !lastDescriptor)
return B_NO_MEMORY; return B_NO_MEMORY;
lastDescriptor->status |= TD_STATUS_IOC; lastDescriptor->status |= TD_CONTROL_IOC;
lastDescriptor->link_phy = TD_TERMINATE; lastDescriptor->link_phy = TD_TERMINATE;
lastDescriptor->link_log = 0; lastDescriptor->link_log = 0;
@@ -574,14 +571,14 @@ UHCI::SubmitTransfer(Transfer *transfer)
result = AddPendingTransfer(transfer, queue, firstDescriptor, result = AddPendingTransfer(transfer, queue, firstDescriptor,
firstDescriptor, lastDescriptor, directionIn); firstDescriptor, lastDescriptor, directionIn);
if (result < B_OK) { 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); FreeDescriptorChain(firstDescriptor);
return result; return result;
} }
result = queue->AppendDescriptor(firstDescriptor); result = queue->AppendDescriptorChain(firstDescriptor);
if (result < B_OK) { if (result < B_OK) {
TRACE(("usb_uhci: failed to append descriptors\n")); TRACE_ERROR(("usb_uhci: failed to append descriptor chain\n"));
FreeDescriptorChain(firstDescriptor); FreeDescriptorChain(firstDescriptor);
return result; return result;
} }
@@ -604,7 +601,7 @@ UHCI::SubmitRequest(Transfer *transfer)
directionIn ? TD_TOKEN_OUT : TD_TOKEN_IN, 0); directionIn ? TD_TOKEN_OUT : TD_TOKEN_IN, 0);
if (!setupDescriptor || !statusDescriptor) { if (!setupDescriptor || !statusDescriptor) {
TRACE(("usb_uhci: failed to allocate descriptors\n")); TRACE_ERROR(("usb_uhci: failed to allocate descriptors\n"));
FreeDescriptor(setupDescriptor); FreeDescriptor(setupDescriptor);
FreeDescriptor(statusDescriptor); FreeDescriptor(statusDescriptor);
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -613,10 +610,10 @@ UHCI::SubmitRequest(Transfer *transfer)
WriteDescriptorChain(setupDescriptor, (const uint8 *)requestData, WriteDescriptorChain(setupDescriptor, (const uint8 *)requestData,
sizeof(usb_request_data)); sizeof(usb_request_data));
statusDescriptor->status |= TD_STATUS_IOC; statusDescriptor->status |= TD_CONTROL_IOC;
statusDescriptor->token |= TD_TOKEN_DATA1; statusDescriptor->token |= TD_TOKEN_DATA1;
statusDescriptor->link_phy = TD_TERMINATE; statusDescriptor->link_phy = TD_TERMINATE;
statusDescriptor->link_log = 0; statusDescriptor->link_log = NULL;
uhci_td *dataDescriptor = NULL; uhci_td *dataDescriptor = NULL;
if (transfer->Data() && transfer->DataLength() > 0) { if (transfer->Data() && transfer->DataLength() > 0) {
@@ -646,14 +643,14 @@ UHCI::SubmitRequest(Transfer *transfer)
status_t result = AddPendingTransfer(transfer, fQueues[1], setupDescriptor, status_t result = AddPendingTransfer(transfer, fQueues[1], setupDescriptor,
dataDescriptor, statusDescriptor, directionIn); dataDescriptor, statusDescriptor, directionIn);
if (result < B_OK) { 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); FreeDescriptorChain(setupDescriptor);
return result; return result;
} }
result = fQueues[1]->AppendDescriptor(setupDescriptor); result = fQueues[1]->AppendDescriptorChain(setupDescriptor);
if (result < B_OK) { if (result < B_OK) {
TRACE(("usb_uhci: failed to append descriptors\n")); TRACE_ERROR(("usb_uhci: failed to append descriptor chain\n"));
FreeDescriptorChain(setupDescriptor); FreeDescriptorChain(setupDescriptor);
return result; return result;
} }
@@ -667,7 +664,6 @@ UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue,
uhci_td *firstDescriptor, uhci_td *dataDescriptor, uhci_td *lastDescriptor, uhci_td *firstDescriptor, uhci_td *dataDescriptor, uhci_td *lastDescriptor,
bool directionIn) bool directionIn)
{ {
TRACE(("usb_uhci: add pending transfer\n"));
transfer_data *data = new(std::nothrow) transfer_data(); transfer_data *data = new(std::nothrow) transfer_data();
if (!data) if (!data)
return B_NO_MEMORY; 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)); TRACE_ERROR(("usb_uhci: td (0x%08x) error: 0x%08x\n", descriptor->this_phy, status));
// an error occured. we have to remove the // an error occured. we have to remove the
// transfer from the queue and clean up // transfer from the queue and clean up
transfer->queue->RemoveDescriptors(transfer->first_descriptor,
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); transfer->last_descriptor);
FreeDescriptorChain(transfer->first_descriptor); FreeDescriptorChain(transfer->first_descriptor);
TRACE(("usb_uhci: notify transfer 0x%08x\n", transfer)); transfer->transfer->Finished(callbackStatus);
transfer->transfer->Finished(B_ERROR);
transferDone = true; transferDone = true;
break; break;
} }
@@ -753,13 +760,14 @@ UHCI::FinishTransfers()
if (descriptor == transfer->last_descriptor) { if (descriptor == transfer->last_descriptor) {
TRACE(("usb_uhci: td (0x%08x) ok\n", descriptor->this_phy)); TRACE(("usb_uhci: td (0x%08x) ok\n", descriptor->this_phy));
// we got through without errors so we are finished // we got through without errors so we are finished
transfer->queue->RemoveDescriptors(transfer->first_descriptor, transfer->queue->RemoveDescriptorChain(
transfer->first_descriptor,
transfer->last_descriptor); transfer->last_descriptor);
if (transfer->data_descriptor && transfer->incoming) { if (transfer->data_descriptor && transfer->incoming) {
// data to read out // data to read out
TRACE(("usb_uhci: reading incoming data buffer to transfer 0x%08x\n", transfer)); size_t length = ReadDescriptorChain(
size_t length = ReadDescriptorChain(transfer->data_descriptor, transfer->data_descriptor,
transfer->transfer->Data(), transfer->transfer->Data(),
transfer->transfer->DataLength()); transfer->transfer->DataLength());
@@ -767,7 +775,6 @@ UHCI::FinishTransfers()
} }
FreeDescriptorChain(transfer->first_descriptor); FreeDescriptorChain(transfer->first_descriptor);
TRACE(("usb_uhci: notify transfer 0x%08x\n", transfer));
transfer->transfer->Finished(B_OK); transfer->transfer->Finished(B_OK);
transferDone = true; transferDone = true;
break; break;
@@ -777,7 +784,6 @@ UHCI::FinishTransfers()
} }
if (transferDone) { if (transferDone) {
TRACE(("usb_uhci: transfer (0x%08x) done\n", transfer));
if (Lock()) { if (Lock()) {
if (lastTransfer) if (lastTransfer)
lastTransfer->link = transfer->link; lastTransfer->link = transfer->link;
@@ -794,7 +800,6 @@ UHCI::FinishTransfers()
Unlock(); Unlock();
} }
} else { } else {
TRACE(("usb_uhci: transfer (0x%08x) not done\n", transfer));
lastTransfer = transfer; lastTransfer = transfer;
transfer = transfer->link; transfer = transfer->link;
} }
@@ -837,7 +842,6 @@ UHCI::PortStatus(int32 index)
if (index > 1) if (index > 1)
return B_BAD_VALUE; return B_BAD_VALUE;
//TRACE(("usb_uhci: read port status of port: %d\n", index));
return ReadReg16(UHCI_PORTSC1 + index * 2); 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))); TRACE(("usb_uhci: port was reset: 0x%04x\n", ReadReg16(port)));
return B_OK; 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 int32
UHCI::InterruptHandler(void *data) UHCI::InterruptHandler(void *data)
{ {
@@ -931,9 +956,6 @@ UHCI::Interrupt()
if ((status & UHCI_INTERRUPT_MASK) == 0) if ((status & UHCI_INTERRUPT_MASK) == 0)
return B_UNHANDLED_INTERRUPT; return B_UNHANDLED_INTERRUPT;
TRACE(("usb_uhci: Interrupt()\n"));
TRACE(("usb_uhci: status: 0x%04x\n", status));
uint16 acknowledge = 0; uint16 acknowledge = 0;
if (status & UHCI_USBSTS_USBINT) { if (status & UHCI_USBSTS_USBINT) {
TRACE(("usb_uhci: transfer finished\n")); TRACE(("usb_uhci: transfer finished\n"));
@@ -984,7 +1006,7 @@ UHCI::AddTo(Stack &stack)
if (!sPCIModule) { if (!sPCIModule) {
status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule); status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule);
if (status < B_OK) { 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)); status));
return status; return status;
} }
@@ -1006,7 +1028,7 @@ UHCI::AddTo(Stack &stack)
&& item->class_api == 0x00) { && item->class_api == 0x00) {
if (item->u.h0.interrupt_line == 0 if (item->u.h0.interrupt_line == 0
|| item->u.h0.interrupt_line == 0xFF) { || 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; continue;
} }
@@ -1020,7 +1042,7 @@ UHCI::AddTo(Stack &stack)
} }
if (bus->InitCheck() < B_OK) { 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; delete bus;
continue; continue;
} }
@@ -1050,22 +1072,22 @@ UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, int32 bufferSize)
void *physicalAddress; void *physicalAddress;
if (fStack->AllocateChunk((void **)&result, &physicalAddress, 32) < B_OK) { 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; return NULL;
} }
result->this_phy = (addr_t)physicalAddress; 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) if (pipe->Speed() == Pipe::LowSpeed)
result->status |= TD_STATUS_LOWSPEED; result->status |= TD_CONTROL_LOWSPEED;
result->buffer_size = bufferSize; result->buffer_size = bufferSize;
if (bufferSize == 0) if (bufferSize == 0)
result->token = TD_TOKEN_NULL; result->token = TD_TOKEN_NULL_DATA;
else 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; | (pipe->DeviceAddress() << 8) | direction;
result->link_phy = 0; 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, if (fStack->AllocateChunk(&result->buffer_log, &result->buffer_phy,
bufferSize) < B_OK) { 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); fStack->FreeChunk(result, (void *)result->this_phy, 32);
return NULL; return NULL;
} }
@@ -1168,7 +1190,6 @@ size_t
UHCI::WriteDescriptorChain(uhci_td *topDescriptor, const uint8 *buffer, UHCI::WriteDescriptorChain(uhci_td *topDescriptor, const uint8 *buffer,
int32 bufferSize) int32 bufferSize)
{ {
TRACE(("usb_uhci: writing descriptor chain from buffer 0x%08x\n", buffer));
size_t actualSize = 0; size_t actualSize = 0;
uhci_td *current = topDescriptor; uhci_td *current = topDescriptor;
@@ -1198,7 +1219,6 @@ size_t
UHCI::ReadDescriptorChain(uhci_td *topDescriptor, uint8 *buffer, UHCI::ReadDescriptorChain(uhci_td *topDescriptor, uint8 *buffer,
int32 bufferSize) int32 bufferSize)
{ {
TRACE(("usb_uhci: reading descriptor chain to buffer 0x%08x\n", buffer));
size_t actualSize = 0; size_t actualSize = 0;
uhci_td *current = topDescriptor; uhci_td *current = topDescriptor;
+6 -2
View File
@@ -32,8 +32,9 @@ public:
status_t LinkTo(Queue *other); status_t LinkTo(Queue *other);
status_t TerminateByStrayDescriptor(); status_t TerminateByStrayDescriptor();
status_t AppendDescriptor(uhci_td *descriptor); status_t AppendDescriptorChain(uhci_td *descriptor);
status_t RemoveDescriptors(uhci_td *firstDescriptor, status_t RemoveDescriptorChain(
uhci_td *firstDescriptor,
uhci_td *lastDescriptor); uhci_td *lastDescriptor);
addr_t PhysicalAddress(); addr_t PhysicalAddress();
@@ -79,6 +80,8 @@ static bool AddTo(Stack &stack);
uint16 PortStatus(int32 index); uint16 PortStatus(int32 index);
status_t SetPortStatus(int32 index, uint16 status); status_t SetPortStatus(int32 index, uint16 status);
status_t ResetPort(int32 index); status_t ResetPort(int32 index);
bool PortResetChange(int32 index);
void SetPortResetChange(int32 index, bool value);
private: private:
// Controller resets // Controller resets
@@ -151,6 +154,7 @@ static pci_module_info *sPCIModule;
// Root hub // Root hub
UHCIRootHub *fRootHub; UHCIRootHub *fRootHub;
uint8 fRootHubAddress; uint8 fRootHubAddress;
bool fPortResetChange[2];
}; };
+59 -44
View File
@@ -14,7 +14,6 @@
* The Registers * * The Registers *
************************************************************/ ************************************************************/
// R/W -- Read/Write // R/W -- Read/Write
// R/WC -- Read/Write Clear // R/WC -- Read/Write Clear
// ** -- Only writable with words! // ** -- Only writable with words!
@@ -80,75 +79,91 @@
#define FRAMELIST_NEXT_IS_QH 0x2 #define FRAMELIST_NEXT_IS_QH 0x2
//Represents a Transfer Descriptor (TD) // Represents a Transfer Descriptor (TD)
typedef struct typedef struct
{ {
//Hardware part //Hardware part
addr_t link_phy; // Link to the next TD/QH addr_t link_phy; // Link to the next TD/QH
uint32 status; // Status field uint32 status; // Status field
uint32 token; // Contains the packet header (where it needs to be sent) uint32 token; // Contains the packet header (where it needs to be sent)
void * buffer_phy; // A pointer to the buffer with the actual packet void *buffer_phy; // A pointer to the buffer with the actual packet
// Software part // Software part
addr_t this_phy; // A physical pointer to this address addr_t this_phy; // A physical pointer to this address
void * link_log; // Link to the next logical TD/QT void *link_log; // Pointer to the next logical TD/QT
void * buffer_log; // Link to the buffer void *buffer_log; // Pointer to the logical buffer
int32 buffer_size; // Size of the buffer int32 buffer_size; // Size of the buffer
} uhci_td; } uhci_td;
#define TD_STATUS_3_ERRORS (3 << 27) // Control and Status
#define TD_STATUS_LOWSPEED (1 << 26) #define TD_CONTROL_SHORT_PACKET (1 << 29)
#define TD_STATUS_IOS (1 << 25) #define TD_CONTROL_3_ERRORS (3 << 27)
#define TD_STATUS_IOC (1 << 24) #define TD_CONTROL_LOWSPEED (1 << 26)
#define TD_STATUS_ACTIVE (1 << 23) #define TD_CONTROL_ISOCHRONOUS (1 << 25)
#define TD_STATUS_ACTLEN_MASK 0x3ff #define TD_CONTROL_IOC (1 << 24)
#define TD_STATUS_ACTLEN_NULL 0x7ff
#define TD_TOKEN_DATA1 (1 << 19) #define TD_STATUS_ACTIVE (1 << 23)
#define TD_TOKEN_NULL (0x7ff << 21) #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_STATUS_ACTLEN_MASK 0x03ff
#define TD_TOKEN_IN 0x69 #define TD_STATUS_ACTLEN_NULL 0x07ff
#define TD_TOKEN_OUT 0xe1
#define TD_TOKEN_DEVADDR_SHIFT 8 // Token
#define TD_DEPTH_FIRST 0x4 #define TD_TOKEN_MAXLEN_SHIFT 21
#define TD_TERMINATE 0x1 #define TD_TOKEN_NULL_DATA (0x07ff << TD_TOKEN_MAXLEN_SHIFT)
#define TD_ERROR_MASK 0x7e0000 #define TD_TOKEN_DATA1 (1 << 19)
#define TD_LINK_MASK 0xfffffff0
//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 typedef struct
{ {
// Hardware part // Hardware part
addr_t link_phy; //Link to the next TD/QH 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 element_phy; // Pointer to the first element in the queue
// Software part // Software part
addr_t this_phy; //The physical pointer to this address addr_t this_phy; // The physical pointer to this address
void * link_log; //Link to the next TD/QH logical void *link_log; // Pointer to the next logical TD/QH
} uhci_qh; } uhci_qh;
#define QH_TERMINATE 0x1 #define QH_TERMINATE 0x01
#define QH_NEXT_IS_QH 0x2 #define QH_NEXT_IS_QH 0x02
#define QH_LINK_MASK 0xfffffff0
/************************************************************ /************************************************************
* Roothub Emulation * * Roothub Emulation *
************************************************************/ ************************************************************/
#define RH_GET_STATUS 0 #define RH_GET_STATUS 0
#define RH_CLEAR_FEATURE 1 #define RH_CLEAR_FEATURE 1
#define RH_SET_FEATURE 3 #define RH_SET_FEATURE 3
#define RH_SET_ADDRESS 5 #define RH_SET_ADDRESS 5
#define RH_GET_DESCRIPTOR 6 #define RH_GET_DESCRIPTOR 6
#define RH_SET_CONFIG 9 #define RH_SET_CONFIG 9
//Descriptors (in usb_request_data->Value) // Descriptors (in usb_request_data->Value)
#define RH_DEVICE_DESCRIPTOR (0x01 << 8) #define RH_DEVICE_DESCRIPTOR (0x01 << 8)
#define RH_CONFIG_DESCRIPTOR (0x02 << 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) #define RH_HUB_DESCRIPTOR (0x29 << 8)
//Hub/Portstatus buffer // Hub/Portstatus buffer
typedef struct typedef struct
{ {
uint16 status; uint16 status;
+20 -20
View File
@@ -140,13 +140,13 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
status_t result = B_ERROR; status_t result = B_ERROR;
switch (request->Request) { switch (request->Request) {
case RH_GET_STATUS: case RH_GET_STATUS: {
if (request->Index == 0) { if (request->Index == 0) {
// Get the hub status -- everything as 0 means all-right // Get the hub status -- everything as 0 means all-right
memset(transfer->Data(), 0, sizeof(get_status_buffer)); memset(transfer->Data(), 0, sizeof(get_status_buffer));
result = B_OK; result = B_OK;
break; break;
} else if (request->Index > sUHCIRootHubConfig.hub.bNbrPorts) { } else if (request->Index > sUHCIRootHubConfig.hub.num_ports) {
// This port doesn't exist // This port doesn't exist
result = EINVAL; result = EINVAL;
break; break;
@@ -154,13 +154,15 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
// Get port status // Get port status
UpdatePortStatus(); 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; result = B_OK;
break; break;
}
case RH_SET_ADDRESS: case RH_SET_ADDRESS:
if (request->Value >= 128) { if (request->Value >= 128) {
@@ -239,7 +241,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE no hub changes!\n")); TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE no hub changes!\n"));
result = EINVAL; result = EINVAL;
break; break;
} else if (request->Index > sUHCIRootHubConfig.hub.bNbrPorts) { } else if (request->Index > sUHCIRootHubConfig.hub.num_ports) {
// Invalid port number // Invalid port number
TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE invalid port!\n")); TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE invalid port!\n"));
result = EINVAL; result = EINVAL;
@@ -249,10 +251,9 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE called. Feature: %u!\n", request->Value)); TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE called. Feature: %u!\n", request->Value));
uint16 status; uint16 status;
switch(request->Value) { switch(request->Value) {
case PORT_RESET: case C_PORT_RESET:
status = fUHCI->PortStatus(request->Index - 1); fUHCI->SetPortResetChange(request->Index - 1, false);
result = fUHCI->SetPortStatus(request->Index - 1, result = B_OK;
status & UHCI_PORTSC_DATAMASK & ~UHCI_PORTSC_RESET);
break; break;
case C_PORT_CONNECTION: case C_PORT_CONNECTION:
@@ -273,7 +274,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
TRACE(("usb_uhci_roothub: RH_SET_FEATURE no hub changes!\n")); TRACE(("usb_uhci_roothub: RH_SET_FEATURE no hub changes!\n"));
result = EINVAL; result = EINVAL;
break; break;
} else if (request->Index > sUHCIRootHubConfig.hub.bNbrPorts) { } else if (request->Index > sUHCIRootHubConfig.hub.num_ports) {
// Invalid port number // Invalid port number
TRACE(("usb_uhci_roothub: RH_SET_FEATURE invalid port!\n")); TRACE(("usb_uhci_roothub: RH_SET_FEATURE invalid port!\n"));
result = EINVAL; result = EINVAL;
@@ -281,17 +282,16 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
} }
TRACE(("usb_uhci_roothub: RH_SET_FEATURE called. Feature: %u!\n", request->Value)); TRACE(("usb_uhci_roothub: RH_SET_FEATURE called. Feature: %u!\n", request->Value));
uint16 status;
switch(request->Value) { switch(request->Value) {
case PORT_RESET: case PORT_RESET:
result = fUHCI->ResetPort(request->Index - 1); result = fUHCI->ResetPort(request->Index - 1);
break; break;
case PORT_ENABLE: case PORT_POWER:
status = fUHCI->PortStatus(request->Index - 1); // the ports are automatically powered
result = fUHCI->SetPortStatus(request->Index - 1, result = B_OK;
(status & UHCI_PORTSC_DATAMASK) | UHCI_PORTSC_ENABLED);
break; break;
default: default:
result = EINVAL; result = EINVAL;
break; break;
@@ -312,7 +312,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
void void
UHCIRootHub::UpdatePortStatus() 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 newStatus = 0;
uint16 newChange = 0; uint16 newChange = 0;
@@ -336,8 +336,8 @@ UHCIRootHub::UpdatePortStatus()
if (portStatus & UHCI_PORTSC_RESET) if (portStatus & UHCI_PORTSC_RESET)
newStatus |= PORT_STATUS_RESET; newStatus |= PORT_STATUS_RESET;
if (fUHCI->PortResetChange(i))
//TODO: work out reset change... newChange |= PORT_STATUS_RESET;
//The port is automagically powered on //The port is automagically powered on
newStatus |= PORT_POWER; newStatus |= PORT_POWER;