* 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:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<BusManager *>::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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#ifndef _USB_P_
|
||||
#define _USB_P_
|
||||
|
||||
#include <lock.h>
|
||||
#include "usbspec_p.h"
|
||||
|
||||
|
||||
@@ -76,9 +77,7 @@ public:
|
||||
private:
|
||||
Vector<BusManager *> 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;
|
||||
|
||||
@@ -14,9 +14,16 @@
|
||||
#include <USB.h>
|
||||
#include <util/kernel_cpp.h>
|
||||
|
||||
#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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user