* Redisigned some of the USB Stack. Unified constructors, removed redundant functions and moved some other functions around

* Implemented the EHCIRootHub
* Reworked UHCIRootHub to be more of a utility class and moved the actual work into the UHCI BusManager
* Implemented port reset in EHCI. Ports with low and fullspeed devices are now correctly handed over to the companion host controller.

Attachs and detachs as well as port resetting / enabling works now in EHCI. Only the actual data transfers are missing thereafter ;-)

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18656 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2006-08-28 00:43:10 +00:00
parent f50c1ececf
commit ffe3f107c4
18 changed files with 559 additions and 391 deletions

View File

@ -28,11 +28,11 @@ BusManager::BusManager(Stack *stack)
fDeviceMap[i] = false;
// Set up the default pipes
fDefaultPipe = new(std::nothrow) ControlPipe(this, 0, Pipe::NormalSpeed, 8);
fDefaultPipe = new(std::nothrow) ControlPipe(this, 0, Pipe::FullSpeed, 0, 8);
if (!fDefaultPipe)
return;
fDefaultPipeLowSpeed = new(std::nothrow) ControlPipe(this, 0, Pipe::LowSpeed, 8);
fDefaultPipeLowSpeed = new(std::nothrow) ControlPipe(this, 0, Pipe::LowSpeed, 0, 8);
if (!fDefaultPipeLowSpeed)
return;
@ -135,7 +135,7 @@ BusManager::AllocateNewDevice(Device *parent, bool lowSpeed)
// Create a temporary pipe with the new address
ControlPipe pipe(this, deviceAddress,
lowSpeed ? Pipe::LowSpeed : Pipe::NormalSpeed, 8);
lowSpeed ? Pipe::LowSpeed : Pipe::FullSpeed, 0, 8);
// Get the device descriptor
// Just retrieve the first 8 bytes of the descriptor -> minimum supported
@ -261,11 +261,3 @@ BusManager::SubmitTransfer(Transfer *transfer)
// virtual function to be overridden
return B_ERROR;
}
status_t
BusManager::SubmitRequest(Transfer *transfer)
{
// virtual function to be overridden
return B_ERROR;
}

View File

@ -13,14 +13,13 @@
Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
int8 deviceAddress, bool lowSpeed)
: ControlPipe(bus, deviceAddress,
lowSpeed ? Pipe::LowSpeed : Pipe::NormalSpeed,
lowSpeed ? Pipe::LowSpeed : Pipe::FullSpeed, 0,
desc.max_packet_size_0),
fDeviceDescriptor(desc),
fConfigurations(NULL),
fCurrentConfiguration(NULL),
fInitOK(false),
fLowSpeed(lowSpeed),
fBus(bus),
fParent(parent),
fDeviceAddress(deviceAddress),
fLock(-1),
@ -60,7 +59,7 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
TRACE(("\tvendor_id:...........0x%04x\n", fDeviceDescriptor.vendor_id));
TRACE(("\tproduct_id:..........0x%04x\n", fDeviceDescriptor.product_id));
TRACE(("\tdevice_version:......0x%04x\n", fDeviceDescriptor.device_version));
TRACE(("\tmanufacturer:........0x%04x\n", fDeviceDescriptor.manufacturer));
TRACE(("\tmanufacturer:........0x%02x\n", fDeviceDescriptor.manufacturer));
TRACE(("\tproduct:.............0x%02x\n", fDeviceDescriptor.product));
TRACE(("\tserial_number:.......0x%02x\n", fDeviceDescriptor.serial_number));
TRACE(("\tnum_configurations:..%d\n", fDeviceDescriptor.num_configurations));
@ -147,7 +146,8 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
interfaceInfo->generic_count = 0;
interfaceInfo->generic = NULL;
Interface *interface = new(std::nothrow) Interface(this);
Interface *interface = new(std::nothrow) Interface(GetBusManager(),
fDeviceAddress, Speed());
interfaceInfo->handle = interface->USBID();
currentInterface = interfaceInfo;
@ -182,14 +182,15 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
Pipe *endpoint = NULL;
switch (endpointDescriptor->attributes & 0x03) {
case 0x00: /* Control Endpoint */
endpoint = new(std::nothrow) ControlPipe(this,
Speed(),
endpoint = new(std::nothrow) ControlPipe(GetBusManager(),
fDeviceAddress, Speed(),
endpointDescriptor->endpoint_address & 0x0f,
endpointDescriptor->max_packet_size);
break;
case 0x01: /* Isochronous Endpoint */
endpoint = new(std::nothrow) IsochronousPipe(this,
endpoint = new(std::nothrow) IsochronousPipe(GetBusManager(),
fDeviceAddress,
endpointDescriptor->endpoint_address & 0x80 > 0 ? Pipe::In : Pipe::Out,
Speed(),
endpointDescriptor->endpoint_address & 0x0f,
@ -197,7 +198,8 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
break;
case 0x02: /* Bulk Endpoint */
endpoint = new(std::nothrow) BulkPipe(this,
endpoint = new(std::nothrow) BulkPipe(GetBusManager(),
fDeviceAddress,
endpointDescriptor->endpoint_address & 0x80 > 0 ? Pipe::In : Pipe::Out,
Speed(),
endpointDescriptor->endpoint_address & 0x0f,
@ -205,7 +207,8 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
break;
case 0x03: /* Interrupt Endpoint */
endpoint = new(std::nothrow) InterruptPipe(this,
endpoint = new(std::nothrow) InterruptPipe(GetBusManager(),
fDeviceAddress,
endpointDescriptor->endpoint_address & 0x80 > 0 ? Pipe::In : Pipe::Out,
Speed(),
endpointDescriptor->endpoint_address & 0x0f,

View File

@ -180,7 +180,7 @@ Hub::Explore()
continue;
}
Device *newDevice = fBus->AllocateNewDevice(this,
Device *newDevice = GetBusManager()->AllocateNewDevice(this,
(fPortStatus[i].status & PORT_STATUS_LOW_SPEED) > 0);
if (newDevice) {
@ -273,7 +273,7 @@ Hub::BuildDeviceName(char *string, uint32 *index, size_t bufferSize,
status_t result = Device::BuildDeviceName(string, index, bufferSize, device);
if (result < B_OK) {
// recursion to parent failed, we're at the root(hub)
int32 managerIndex = GetStack()->IndexOfBusManager(Manager());
int32 managerIndex = GetStack()->IndexOfBusManager(GetBusManager());
*index += snprintf(string + *index, bufferSize - *index, "%ld", managerIndex);
}

View File

@ -9,8 +9,8 @@
#include "usb_p.h"
Interface::Interface(Device *device)
: ControlPipe(device, device->Speed(), 0, 8)
Interface::Interface(BusManager *bus, int8 deviceAddress, pipeSpeed speed)
: ControlPipe(bus, deviceAddress, speed, 0, 8)
{
}

View File

@ -10,7 +10,8 @@
Object::Object(BusManager *bus)
: fBusManager(bus),
fStack(bus->GetStack()),
fUSBID(fStack->GetUSBID(this))
{
fStack = bus->GetStack();
fUSBID = fStack->GetUSBID(this);
}

View File

@ -10,30 +10,13 @@
#include "usb_p.h"
Pipe::Pipe(Device *device, pipeDirection direction, pipeSpeed speed,
uint8 endpointAddress, size_t maxPacketSize)
: Object(device->Manager()),
fDevice(device),
fDeviceAddress(device->Address()),
fBus(device->Manager()),
Pipe::Pipe(BusManager *bus, int8 deviceAddress, pipeDirection direction,
pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize)
: Object(bus),
fDeviceAddress(deviceAddress),
fEndpointAddress(endpointAddress),
fDirection(direction),
fSpeed(speed),
fEndpoint(endpointAddress),
fMaxPacketSize(maxPacketSize),
fDataToggle(false)
{
}
Pipe::Pipe(BusManager *bus, int8 deviceAddress, pipeSpeed speed,
size_t maxPacketSize)
: Object(bus),
fDevice(NULL),
fDeviceAddress(deviceAddress),
fBus(bus),
fDirection(Default),
fSpeed(speed),
fEndpoint(0),
fMaxPacketSize(maxPacketSize),
fDataToggle(true)
{
@ -45,21 +28,11 @@ Pipe::~Pipe()
}
int8
Pipe::DeviceAddress()
{
if (!fDevice)
return fDeviceAddress;
return fDevice->Address();
}
status_t
Pipe::SubmitTransfer(Transfer *transfer)
{
// ToDo: keep track of all submited transfers to be able to cancel them
return fBus->SubmitTransfer(transfer);
return GetBusManager()->SubmitTransfer(transfer);
}
@ -70,68 +43,16 @@ Pipe::CancelQueuedTransfers()
}
status_t
Pipe::SetFeature(uint16 selector)
{
if (!fDevice)
return B_ERROR;
return fDevice->SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT,
USB_REQUEST_SET_FEATURE,
selector,
0,
0,
NULL,
0,
NULL);
}
status_t
Pipe::ClearFeature(uint16 selector)
{
if (!fDevice)
return B_ERROR;
return fDevice->SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT,
USB_REQUEST_CLEAR_FEATURE,
selector,
0,
0,
NULL,
0,
NULL);
}
status_t
Pipe::GetStatus(uint16 *status)
{
if (!fDevice)
return B_ERROR;
return fDevice->SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_IN,
USB_REQUEST_GET_STATUS,
0,
0,
2,
(void *)status,
2,
NULL);
}
//
// #pragma mark -
//
InterruptPipe::InterruptPipe(Device *device, pipeDirection direction,
pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize)
: Pipe(device, direction, speed, endpointAddress, maxPacketSize)
InterruptPipe::InterruptPipe(BusManager *bus, int8 deviceAddress,
pipeDirection direction, pipeSpeed speed, uint8 endpointAddress,
size_t maxPacketSize)
: Pipe(bus, deviceAddress, direction, speed, endpointAddress,
maxPacketSize)
{
}
@ -159,9 +80,11 @@ InterruptPipe::QueueInterrupt(void *data, size_t dataLength,
//
BulkPipe::BulkPipe(Device *device, pipeDirection direction,
pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize)
: Pipe(device, direction, speed, endpointAddress, maxPacketSize)
BulkPipe::BulkPipe(BusManager *bus, int8 deviceAddress,
pipeDirection direction, pipeSpeed speed, uint8 endpointAddress,
size_t maxPacketSize)
: Pipe(bus, deviceAddress, direction, speed, endpointAddress,
maxPacketSize)
{
}
@ -207,9 +130,11 @@ BulkPipe::QueueBulkV(iovec *vector, size_t vectorCount,
//
IsochronousPipe::IsochronousPipe(Device *device, pipeDirection direction,
pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize)
: Pipe(device, direction, speed, endpointAddress, maxPacketSize)
IsochronousPipe::IsochronousPipe(BusManager *bus, int8 deviceAddress,
pipeDirection direction, pipeSpeed speed, uint8 endpointAddress,
size_t maxPacketSize)
: Pipe(bus, deviceAddress, direction, speed, endpointAddress,
maxPacketSize)
{
}
@ -235,16 +160,9 @@ struct transfer_result_data {
};
ControlPipe::ControlPipe(Device *device, pipeSpeed speed,
uint8 endpointAddress, size_t maxPacketSize)
: Pipe(device, Pipe::Default, speed, endpointAddress, maxPacketSize)
{
}
ControlPipe::ControlPipe(BusManager *bus, int8 deviceAddress, pipeSpeed speed,
size_t maxPacketSize)
: Pipe(bus, deviceAddress, speed, maxPacketSize)
uint8 endpointAddress, size_t maxPacketSize)
: Pipe(bus, deviceAddress, Default, speed, endpointAddress, maxPacketSize)
{
}
@ -322,3 +240,48 @@ ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value,
delete transfer;
return result;
}
status_t
ControlPipe::SetFeature(uint16 selector)
{
return SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT,
USB_REQUEST_SET_FEATURE,
selector,
0,
0,
NULL,
0,
NULL);
}
status_t
ControlPipe::ClearFeature(uint16 selector)
{
return SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT,
USB_REQUEST_CLEAR_FEATURE,
selector,
0,
0,
NULL,
0,
NULL);
}
status_t
ControlPipe::GetStatus(uint16 *status)
{
return SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_IN,
USB_REQUEST_GET_STATUS,
0,
0,
2,
(void *)status,
2,
NULL);
}

View File

@ -26,6 +26,9 @@ Transfer::~Transfer()
// we take ownership of the request data
if (fRequestData)
delete fRequestData;
if (fVector && fVector != &fData)
delete[] fVector;
}
@ -50,7 +53,8 @@ Transfer::SetData(uint8 *data, size_t dataLength)
void
Transfer::SetVector(iovec *vector, size_t vectorCount)
{
fVector = vector;
fVector = new(std::nothrow) iovec[vectorCount];
memcpy(fVector, vector, vectorCount * sizeof(iovec));
fVectorCount = vectorCount;
}

View File

@ -145,10 +145,10 @@ set_feature(usb_id handle, uint16 selector)
{
TRACE(("usb_module: set_feature(0x%08x, %d)\n", handle, selector));
Object *object = gUSBStack->GetObject(handle);
if (!object || (object->Type() & USB_OBJECT_PIPE) == 0)
if (!object || (object->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
return B_BAD_VALUE;
return ((Pipe *)object)->SetFeature(selector);
return ((ControlPipe *)object)->SetFeature(selector);
}
@ -157,10 +157,10 @@ clear_feature(usb_id handle, uint16 selector)
{
TRACE(("usb_module: clear_feature(0x%08x, %d)\n", handle, selector));
Object *object = gUSBStack->GetObject(handle);
if (!object || (object->Type() & USB_OBJECT_PIPE) == 0)
if (!object || (object->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
return B_BAD_VALUE;
return ((Pipe *)object)->ClearFeature(selector);
return ((ControlPipe *)object)->ClearFeature(selector);
}
@ -172,10 +172,10 @@ get_status(usb_id handle, uint16 *status)
return B_BAD_VALUE;
Object *object = gUSBStack->GetObject(handle);
if (!object || (object->Type() & USB_OBJECT_PIPE) == 0)
if (!object || (object->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
return B_BAD_VALUE;
return ((Pipe *)object)->GetStatus(status);
return ((ControlPipe *)object)->GetStatus(status);
}

View File

@ -147,7 +147,6 @@ virtual status_t Start();
virtual status_t Stop();
virtual status_t SubmitTransfer(Transfer *transfer);
virtual status_t SubmitRequest(Transfer *transfer);
Stack *GetStack() { return fStack; };
void SetStack(Stack *stack) { fStack = stack; };
@ -175,12 +174,14 @@ class Object {
public:
Object(BusManager *bus);
BusManager *GetBusManager() { return fBusManager; };
Stack *GetStack() { return fStack; };
usb_id USBID() { return fUSBID; };
virtual uint32 Type() { return USB_OBJECT_NONE; };
private:
BusManager *fBusManager;
Stack *fStack;
usb_id fUSBID;
};
@ -193,25 +194,22 @@ private:
class Pipe : public Object {
public:
enum pipeDirection { In, Out, Default };
enum pipeSpeed { LowSpeed, NormalSpeed };
enum pipeSpeed { LowSpeed, FullSpeed, HighSpeed };
Pipe(Device *device,
Pipe(BusManager *bus,
int8 deviceAddress,
pipeDirection direction,
pipeSpeed speed,
uint8 endpointAddress,
size_t maxPacketSize);
Pipe(BusManager *bus,
int8 deviceAddress,
pipeSpeed speed,
size_t maxPacketSize);
virtual ~Pipe();
virtual uint32 Type() { return USB_OBJECT_PIPE; };
int8 DeviceAddress();
int8 DeviceAddress() { return fDeviceAddress; };
pipeSpeed Speed() { return fSpeed; };
pipeDirection Direction() { return fDirection; };
int8 EndpointAddress() { return fEndpoint; };
int8 EndpointAddress() { return fEndpointAddress; };
size_t MaxPacketSize() { return fMaxPacketSize; };
virtual bool DataToggle() { return fDataToggle; };
@ -220,19 +218,11 @@ virtual void SetDataToggle(bool toggle) { fDataToggle = toggle; };
status_t SubmitTransfer(Transfer *transfer);
status_t CancelQueuedTransfers();
// Convenience functions for standard requests
virtual status_t SetFeature(uint16 selector);
virtual status_t ClearFeature(uint16 selector);
virtual status_t GetStatus(uint16 *status);
protected:
Device *fDevice;
int8 fDeviceAddress;
BusManager *fBus;
usb_id fUSBID;
uint8 fEndpointAddress;
pipeDirection fDirection;
pipeSpeed fSpeed;
uint8 fEndpoint;
size_t fMaxPacketSize;
bool fDataToggle;
};
@ -240,15 +230,10 @@ protected:
class ControlPipe : public Pipe {
public:
ControlPipe(Device *device,
pipeSpeed speed,
uint8 endpointAddress,
size_t maxPacketSize);
// Constructor for default control pipe
ControlPipe(BusManager *bus,
int8 deviceAddress,
pipeSpeed speed,
uint8 endpointAddress,
size_t maxPacketSize);
virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_CONTROL_PIPE; };
@ -276,12 +261,18 @@ static void SendRequestCallback(void *cookie,
void *data, size_t dataLength,
usb_callback_func callback,
void *callbackCookie);
// Convenience functions for standard requests
virtual status_t SetFeature(uint16 selector);
virtual status_t ClearFeature(uint16 selector);
virtual status_t GetStatus(uint16 *status);
};
class InterruptPipe : public Pipe {
public:
InterruptPipe(Device *device,
InterruptPipe(BusManager *bus,
int8 deviceAddress,
pipeDirection direction,
pipeSpeed speed,
uint8 endpointAddress,
@ -298,7 +289,8 @@ virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_INTERRUPT_PIPE
class BulkPipe : public Pipe {
public:
BulkPipe(Device *device,
BulkPipe(BusManager *bus,
int8 deviceAddress,
pipeDirection direction,
pipeSpeed speed,
uint8 endpointAddress,
@ -319,7 +311,8 @@ virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_BULK_PIPE; };
class IsochronousPipe : public Pipe {
public:
IsochronousPipe(Device *device,
IsochronousPipe(BusManager *bus,
int8 deviceAddress,
pipeDirection direction,
pipeSpeed speed,
uint8 endpointAddress,
@ -338,7 +331,9 @@ virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_ISO_PIPE; };
class Interface : public ControlPipe {
public:
Interface(Device *device);
Interface(BusManager *bus,
int8 deviceAddress,
pipeSpeed speed);
virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_CONTROL_PIPE | USB_OBJECT_INTERFACE; };
@ -359,9 +354,6 @@ public:
virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_CONTROL_PIPE | USB_OBJECT_DEVICE; };
int8 Address() { return fDeviceAddress; };
BusManager *Manager() { return fBus; };
virtual status_t GetDescriptor(uint8 descriptorType,
uint8 index, uint16 languageID,
void *data, size_t dataLength,
@ -394,7 +386,6 @@ protected:
usb_configuration_info *fCurrentConfiguration;
bool fInitOK;
bool fLowSpeed;
BusManager *fBus;
Device *fParent;
int8 fDeviceAddress;
size_t fMaxPacketIn[16];

View File

@ -80,6 +80,7 @@ struct usb_port_status
#define PORT_STATUS_RESET 0x0010
#define PORT_STATUS_POWER 0x0100
#define PORT_STATUS_LOW_SPEED 0x0200
#define PORT_STATUS_HIGH_SPEED 0x0400
//The feature requests with ports

View File

@ -11,7 +11,6 @@
#include <USB3.h>
#include <KernelExport.h>
#define TRACE_USB
#include "ehci.h"
pci_module_info *EHCI::sPCIModule = NULL;
@ -67,7 +66,10 @@ EHCI::EHCI(pci_info *info, Stack *stack)
fFinishThread(-1),
fStopFinishThread(false),
fRootHub(NULL),
fRootHubAddress(0)
fRootHubAddress(0),
fPortCount(0),
fPortResetChange(0),
fPortSuspendChange(0)
{
if (BusManager::InitCheck() < B_OK) {
TRACE_ERROR(("usb_ehci: bus manager failed to init\n"));
@ -111,6 +113,9 @@ EHCI::EHCI(pci_info *info, Stack *stack)
TRACE(("usb_ehci: mapped capability registers: 0x%08x\n", fCapabilityRegisters));
TRACE(("usb_ehci: mapped operational registers: 0x%08x\n", fOperationalRegisters));
// read port count from capability register
fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f;
// disable interrupts
WriteOpReg(EHCI_USBINTR, 0);
@ -217,14 +222,11 @@ EHCI::Start()
status_t
EHCI::SubmitTransfer(Transfer *transfer)
{
return B_ERROR;
}
// short circuit the root hub
if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
return fRootHub->ProcessTransfer(this, transfer);
status_t
EHCI::SubmitRequest(Transfer *transfer)
{
return B_ERROR;
return B_ERROR;
}
@ -301,9 +303,169 @@ EHCI::AddTo(Stack *stack)
status_t
EHCI::ResetPort(int32 index)
EHCI::GetPortStatus(uint8 index, usb_port_status *status)
{
return B_ERROR;
if (index >= fPortCount)
return B_BAD_INDEX;
status->status = status->change = 0;
uint32 portStatus = ReadOpReg(EHCI_PORTSC + index * sizeof(uint32));
// build the status
if (portStatus & EHCI_PORTSC_CONNSTATUS)
status->status |= PORT_STATUS_CONNECTION;
if (portStatus & EHCI_PORTSC_ENABLE)
status->status |= PORT_STATUS_ENABLE;
if (portStatus & EHCI_PORTSC_ENABLE)
status->status |= PORT_STATUS_HIGH_SPEED;
if (portStatus & EHCI_PORTSC_OCACTIVE)
status->status |= PORT_STATUS_OVER_CURRENT;
if (portStatus & EHCI_PORTSC_PORTRESET)
status->status |= PORT_STATUS_RESET;
if (portStatus & EHCI_PORTSC_PORTPOWER)
status->status |= PORT_STATUS_POWER;
if (portStatus & EHCI_PORTSC_SUSPEND)
status->status |= PORT_STATUS_SUSPEND;
if (portStatus & EHCI_PORTSC_DMINUS)
status->status |= PORT_STATUS_LOW_SPEED;
// build the change
if (portStatus & EHCI_PORTSC_CONNCHANGE)
status->change |= PORT_STATUS_CONNECTION;
if (portStatus & EHCI_PORTSC_ENABLECHANGE)
status->change |= PORT_STATUS_ENABLE;
if (portStatus & EHCI_PORTSC_OCCHANGE)
status->change |= PORT_STATUS_OVER_CURRENT;
// there are no bits to indicate suspend and reset change
if (fPortResetChange & (1 << index))
status->change |= PORT_STATUS_RESET;
if (fPortSuspendChange & (1 << index))
status->change |= PORT_STATUS_SUSPEND;
return B_OK;
}
status_t
EHCI::SetPortFeature(uint8 index, uint16 feature)
{
if (index >= fPortCount)
return B_BAD_INDEX;
uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
switch (feature) {
case PORT_SUSPEND:
return SuspendPort(index);
case PORT_RESET:
return ResetPort(index);
case PORT_POWER:
WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTPOWER);
return B_OK;
}
return B_BAD_VALUE;
}
status_t
EHCI::ClearPortFeature(uint8 index, uint16 feature)
{
if (index >= fPortCount)
return B_BAD_INDEX;
uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
switch (feature) {
case PORT_ENABLE:
WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_ENABLE);
return B_OK;
case PORT_POWER:
WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTPOWER);
return B_OK;
case C_PORT_CONNECTION:
WriteOpReg(portRegister, portStatus | EHCI_PORTSC_CONNCHANGE);
return B_OK;
case C_PORT_ENABLE:
WriteOpReg(portRegister, portStatus | EHCI_PORTSC_ENABLECHANGE);
return B_OK;
case C_PORT_OVER_CURRENT:
WriteOpReg(portRegister, portStatus | EHCI_PORTSC_OCCHANGE);
return B_OK;
case C_PORT_RESET:
fPortResetChange &= ~(1 << index);
return B_OK;
case C_PORT_SUSPEND:
fPortSuspendChange &= ~(1 << index);
return B_OK;
}
return B_BAD_VALUE;
}
status_t
EHCI::ResetPort(uint8 index)
{
TRACE(("usb_ehci: reset port %d\n", index));
uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
if (portStatus & EHCI_PORTSC_DMINUS) {
TRACE(("usb_ehci: lowspeed device connected, giving up port ownership\n"));
// there is a lowspeed device connected.
// we give the ownership to a companion controller.
WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER);
fPortResetChange |= (1 << index);
return B_OK;
}
// enable reset signaling
WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTRESET);
snooze(250000);
// disable reset signaling
portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTRESET);
snooze(2000);
portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
if (portStatus & EHCI_PORTSC_PORTRESET) {
TRACE(("usb_ehci: port reset won't complete\n"));
return B_ERROR;
}
if ((portStatus & EHCI_PORTSC_ENABLE) == 0) {
TRACE(("usb_ehci: fullspeed device connected, giving up port ownership\n"));
// the port was not enabled, this means that no high speed device is
// attached to this port. we give up ownership to a companion controler
WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER);
}
fPortResetChange |= (1 << index);
return B_OK;
}
status_t
EHCI::SuspendPort(uint8 index)
{
uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
WriteOpReg(portRegister, portStatus | EHCI_PORTSC_SUSPEND);
fPortSuspendChange |= (1 << index);
return B_OK;
}

View File

@ -9,6 +9,7 @@
#ifndef EHCI_H
#define EHCI_H
#define TRACE_USB
#include "usb_p.h"
#include "ehci_hardware.h"
@ -36,12 +37,17 @@ public:
status_t Start();
virtual status_t SubmitTransfer(Transfer *transfer);
virtual status_t SubmitRequest(Transfer *transfer);
static status_t AddTo(Stack *stack);
// Port operations for root hub
status_t ResetPort(int32 index);
uint8 PortCount() { return fPortCount; };
status_t GetPortStatus(uint8 index, usb_port_status *status);
status_t SetPortFeature(uint8 index, uint16 feature);
status_t ClearPortFeature(uint8 index, uint16 feature);
status_t ResetPort(uint8 index);
status_t SuspendPort(uint8 index);
private:
// Controller resets
@ -118,6 +124,11 @@ static pci_module_info *sPCIModule;
// Root Hub
EHCIRootHub *fRootHub;
uint8 fRootHubAddress;
// Port management
uint8 fPortCount;
uint16 fPortResetChange;
uint16 fPortSuspendChange;
};
@ -125,12 +136,8 @@ class EHCIRootHub : public Hub {
public:
EHCIRootHub(EHCI *ehci, int8 deviceAddress);
status_t SubmitTransfer(Transfer *transfer);
void UpdatePortStatus();
private:
usb_port_status fPortStatus[2];
EHCI *fEHCI;
static status_t ProcessTransfer(EHCI *ehci,
Transfer *transfer);
};

View File

@ -88,11 +88,13 @@
#define EHCI_PORTSC_FORCERESUME (1 << 6) // Force Port Resume
#define EHCI_PORTSC_OCCHANGE (1 << 5) // Over-Current Change
#define EHCI_PORTSC_OCACTIVE (1 << 4) // Over-Current Active
#define EHCI_PORTSC_ENDISCHANGE (1 << 3) // Port Enable/Disable Change
#define EHCI_PORTSC_ENDIS (1 << 2) // Port Enabled/Disabled
#define EHCI_PORTSC_ENABLECHANGE (1 << 3) // Port Enable/Disable Change
#define EHCI_PORTSC_ENABLE (1 << 2) // Port Enabled/Disabled
#define EHCI_PORTSC_CONNCHANGE (1 << 1) // Connect Status Change
#define EHCI_PORTSC_CONNSTATUS (1 << 0) // Current Connect Status
#define EHCI_PORTSC_DATAMASK 0xffffffd5
// PCI Registers
#define PCI_LEGSUP 0xc0 // PCI Legacy Support

View File

@ -8,7 +8,6 @@
#include "ehci.h"
static usb_device_descriptor sEHCIRootHubDevice =
{
18, // Descriptor length
@ -75,11 +74,11 @@ static ehci_root_hub_configuration_s sEHCIRootHubConfig =
9, // Descriptor length (including
// deprecated power control mask)
USB_DESCRIPTOR_HUB, // Descriptor type
2, // Number of ports
0x0f, // Number of ports
0x0000, // Hub characteristics
50, // Power on to power good (in 2ms units)
0, // Maximum current (in mA)
0x00, // Both ports are removable
0x00, // All ports are removable
0xff // Depricated power control mask
}
};
@ -118,22 +117,135 @@ static ehci_root_hub_string_s sEHCIRootHubStrings[3] = {
EHCIRootHub::EHCIRootHub(EHCI *ehci, int8 deviceAddress)
: Hub(ehci, NULL, sEHCIRootHubDevice, deviceAddress, false)
{
fEHCI = ehci;
}
status_t
EHCIRootHub::SubmitTransfer(Transfer *transfer)
EHCIRootHub::ProcessTransfer(EHCI *ehci, Transfer *transfer)
{
return B_ERROR;
}
if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
return B_ERROR;
usb_request_data *request = transfer->RequestData();
TRACE(("usb_ehci_roothub: request: %d\n", request->Request));
void
EHCIRootHub::UpdatePortStatus()
{
for (int32 i = 0; i < sEHCIRootHubConfig.hub.num_ports; i++) {
fPortStatus[i].status = 0;
fPortStatus[i].change = 0;
// ToDo: define better status codes. We should return a request error.
uint32 status = B_USB_STATUS_DEVICE_TIMEOUT;
size_t actualLength = 0;
switch (request->Request) {
case USB_REQUEST_GET_STATUS: {
if (request->Index == 0) {
// get hub status
actualLength = MIN(sizeof(usb_port_status),
transfer->DataLength());
// the hub reports whether the local power failed (bit 0)
// and if there is a over-current condition (bit 1).
// everything as 0 means all is ok.
memset(transfer->Data(), 0, actualLength);
status = B_USB_STATUS_SUCCESS;
break;
}
usb_port_status portStatus;
if (ehci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) {
actualLength = MIN(sizeof(usb_port_status), transfer->DataLength());
memcpy(transfer->Data(), (void *)&portStatus, actualLength);
status = B_USB_STATUS_SUCCESS;
}
break;
}
case USB_REQUEST_SET_ADDRESS:
if (request->Value >= 128) {
status = B_USB_STATUS_DEVICE_TIMEOUT;
break;
}
TRACE(("usb_ehci_roothub: set address: %d\n", request->Value));
status = B_USB_STATUS_SUCCESS;
break;
case USB_REQUEST_GET_DESCRIPTOR:
TRACE(("usb_ehci_roothub: get descriptor: %d\n", request->Value >> 8));
switch (request->Value >> 8) {
case USB_DESCRIPTOR_DEVICE: {
actualLength = MIN(sizeof(usb_device_descriptor),
transfer->DataLength());
memcpy(transfer->Data(), (void *)&sEHCIRootHubDevice,
actualLength);
status = B_USB_STATUS_SUCCESS;
break;
}
case USB_DESCRIPTOR_CONFIGURATION: {
actualLength = MIN(sizeof(ehci_root_hub_configuration_s),
transfer->DataLength());
sEHCIRootHubConfig.hub.num_ports = ehci->PortCount();
memcpy(transfer->Data(), (void *)&sEHCIRootHubConfig,
actualLength);
status = B_USB_STATUS_SUCCESS;
break;
}
case USB_DESCRIPTOR_STRING: {
uint8 index = request->Value & 0x00ff;
if (index > 2)
break;
actualLength = MIN(sEHCIRootHubStrings[index].length,
transfer->DataLength());
memcpy(transfer->Data(), (void *)&sEHCIRootHubStrings[index],
actualLength);
status = B_USB_STATUS_SUCCESS;
break;
}
case USB_DESCRIPTOR_HUB: {
actualLength = MIN(sizeof(usb_hub_descriptor),
transfer->DataLength());
sEHCIRootHubConfig.hub.num_ports = ehci->PortCount();
memcpy(transfer->Data(), (void *)&sEHCIRootHubConfig.hub,
actualLength);
status = B_USB_STATUS_SUCCESS;
break;
}
}
break;
case USB_REQUEST_SET_CONFIGURATION:
status = B_USB_STATUS_SUCCESS;
break;
case USB_REQUEST_CLEAR_FEATURE: {
if (request->Index == 0) {
// we don't support any hub changes
TRACE_ERROR(("usb_ehci_roothub: clear feature: no hub changes\n"));
break;
}
TRACE(("usb_ehci_roothub: clear feature: %d\n", request->Value));
if (ehci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK)
status = B_USB_STATUS_SUCCESS;
break;
}
case USB_REQUEST_SET_FEATURE: {
if (request->Index == 0) {
// we don't support any hub changes
TRACE_ERROR(("usb_ehci_roothub: set feature: no hub changes\n"));
break;
}
TRACE(("usb_ehci_roothub: set feature: %d\n", request->Value));
if (ehci->SetPortFeature(request->Index - 1, request->Value) >= B_OK)
status = B_USB_STATUS_SUCCESS;
break;
}
}
transfer->Finished(status, actualLength);
delete transfer;
return B_OK;
}

View File

@ -326,7 +326,8 @@ UHCI::UHCI(pci_info *info, Stack *stack)
fFinishThread(-1),
fStopFinishThread(false),
fRootHub(NULL),
fRootHubAddress(0)
fRootHubAddress(0),
fPortResetChange(0)
{
if (!fInitOK) {
TRACE_ERROR(("usb_uhci: bus manager failed to init\n"));
@ -481,7 +482,6 @@ UHCI::Start()
return B_ERROR;
}
fPortResetChange[0] = fPortResetChange[1] = false;
fRootHubAddress = AllocateAddress();
fRootHub = new(std::nothrow) UHCIRootHub(this, fRootHubAddress);
if (!fRootHub) {
@ -510,7 +510,7 @@ UHCI::SubmitTransfer(Transfer *transfer)
// Short circuit the root hub
if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
return fRootHub->SubmitTransfer(transfer);
return fRootHub->ProcessTransfer(this, transfer);
if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE)
return SubmitRequest(transfer);
@ -828,34 +828,90 @@ UHCI::ControllerReset()
}
uint16
UHCI::PortStatus(int32 index)
{
if (index > 1)
return B_BAD_VALUE;
return ReadReg16(UHCI_PORTSC1 + index * 2);
}
status_t
UHCI::SetPortStatus(int32 index, uint16 status)
UHCI::GetPortStatus(uint8 index, usb_port_status *status)
{
if (index > 1)
return B_BAD_VALUE;
return B_BAD_INDEX;
TRACE(("usb_uhci: set port status of port %d: 0x%04x\n", index, status));
WriteReg16(UHCI_PORTSC1 + index * 2, status);
snooze(1000);
status->status = status->change = 0;
uint16 portStatus = ReadReg16(UHCI_PORTSC1 + index * 2);
// build the status
if (portStatus & UHCI_PORTSC_CURSTAT)
status->status |= PORT_STATUS_CONNECTION;
if (portStatus & UHCI_PORTSC_ENABLED)
status->status |= PORT_STATUS_ENABLE;
if (portStatus & UHCI_PORTSC_RESET)
status->status |= PORT_STATUS_RESET;
if (portStatus & UHCI_PORTSC_LOWSPEED)
status->status |= PORT_STATUS_LOW_SPEED;
// build the change
if (portStatus & UHCI_PORTSC_STATCHA)
status->change |= PORT_STATUS_CONNECTION;
if (portStatus & UHCI_PORTSC_ENABCHA)
status->change |= PORT_STATUS_ENABLE;
// ToDo: work out suspended/resume
// there are no bits to indicate reset change
if (fPortResetChange & (1 << index))
status->change |= PORT_STATUS_RESET;
// the port is automagically powered on
status->status |= PORT_STATUS_POWER;
return B_OK;
}
status_t
UHCI::ResetPort(int32 index)
UHCI::SetPortFeature(uint8 index, uint16 feature)
{
if (index > 1)
return B_BAD_VALUE;
return B_BAD_INDEX;
switch (feature) {
case PORT_RESET:
return ResetPort(index);
case PORT_POWER:
// the ports are automatically powered
return B_OK;
}
return B_BAD_VALUE;
}
status_t
UHCI::ClearPortFeature(uint8 index, uint16 feature)
{
if (index > 1)
return B_BAD_INDEX;
uint32 portRegister = UHCI_PORTSC1 + index * 2;
uint16 portStatus = ReadReg16(portRegister) & UHCI_PORTSC_DATAMASK;
switch (feature) {
case C_PORT_RESET:
fPortResetChange &= ~(1 << index);
return B_OK;
case C_PORT_CONNECTION:
WriteReg16(portRegister, portStatus | UHCI_PORTSC_STATCHA);
return B_OK;
}
return B_BAD_VALUE;
}
status_t
UHCI::ResetPort(uint8 index)
{
if (index > 1)
return B_BAD_INDEX;
TRACE(("usb_uhci: reset port %d\n", index));
@ -899,32 +955,12 @@ UHCI::ResetPort(int32 index)
}
}
SetPortResetChange(index, true);
fPortResetChange |= (1 << index);
TRACE(("usb_uhci: port was reset: 0x%04x\n", ReadReg16(port)));
return B_OK;
}
bool
UHCI::PortResetChange(int32 index)
{
if (index > 1)
return false;
return fPortResetChange[index];
}
void
UHCI::SetPortResetChange(int32 index, bool value)
{
if (index > 1)
return;
fPortResetChange[index] = value;
}
int32
UHCI::InterruptHandler(void *data)
{

View File

@ -69,16 +69,16 @@ public:
status_t Start();
virtual status_t SubmitTransfer(Transfer *transfer);
virtual status_t SubmitRequest(Transfer *transfer);
status_t SubmitRequest(Transfer *transfer);
static status_t AddTo(Stack *stack);
// Port operations
uint16 PortStatus(int32 index);
status_t SetPortStatus(int32 index, uint16 status);
status_t ResetPort(int32 index);
bool PortResetChange(int32 index);
void SetPortResetChange(int32 index, bool value);
status_t GetPortStatus(uint8 index, usb_port_status *status);
status_t SetPortFeature(uint8 index, uint16 feature);
status_t ClearPortFeature(uint8 index, uint16 feature);
status_t ResetPort(uint8 index);
private:
// Controller resets
@ -155,7 +155,7 @@ static pci_module_info *sPCIModule;
// Root hub
UHCIRootHub *fRootHub;
uint8 fRootHubAddress;
bool fPortResetChange[2];
uint8 fPortResetChange;
};
@ -163,12 +163,8 @@ class UHCIRootHub : public Hub {
public:
UHCIRootHub(UHCI *uhci, int8 deviceAddress);
status_t SubmitTransfer(Transfer *transfer);
void UpdatePortStatus();
private:
usb_port_status fPortStatus[2];
UHCI *fUHCI;
static status_t ProcessTransfer(UHCI *uhci,
Transfer *transfer);
};

View File

@ -147,28 +147,4 @@ typedef struct
#define QH_NEXT_IS_QH 0x02
#define QH_LINK_MASK 0xfffffff0
/************************************************************
* Roothub Emulation *
************************************************************/
#define RH_GET_STATUS 0
#define RH_CLEAR_FEATURE 1
#define RH_SET_FEATURE 3
#define RH_SET_ADDRESS 5
#define RH_GET_DESCRIPTOR 6
#define RH_SET_CONFIG 9
// Descriptors (in usb_request_data->Value)
#define RH_DEVICE_DESCRIPTOR (0x01 << 8)
#define RH_CONFIG_DESCRIPTOR (0x02 << 8)
#define RH_STRING_DESCRIPTOR (0x03 << 8)
#define RH_HUB_DESCRIPTOR (0x29 << 8)
// Hub/Portstatus buffer
typedef struct
{
uint16 status;
uint16 change;
} get_status_buffer;
#endif

View File

@ -120,61 +120,56 @@ static uhci_root_hub_string_s sUHCIRootHubStrings[3] = {
UHCIRootHub::UHCIRootHub(UHCI *uhci, int8 deviceAddress)
: Hub(uhci, NULL, sUHCIRootHubDevice, deviceAddress, false)
{
fUHCI = uhci;
}
status_t
UHCIRootHub::SubmitTransfer(Transfer *transfer)
UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer)
{
if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
return B_ERROR;
usb_request_data *request = transfer->RequestData();
TRACE(("usb_uhci_roothub: rh_submit_packet called. request: %u\n", request->Request));
TRACE(("usb_uhci_roothub: request: %d\n", request->Request));
// ToDo: define better status codes. We should return a request error.
uint32 status = B_USB_STATUS_DEVICE_TIMEOUT;
size_t actualLength = 0;
switch (request->Request) {
case RH_GET_STATUS: {
case USB_REQUEST_GET_STATUS: {
if (request->Index == 0) {
// Get the hub status -- everything as 0 means all-right
actualLength = MIN(sizeof(get_status_buffer),
actualLength = MIN(sizeof(usb_port_status),
transfer->DataLength());
memset(transfer->Data(), 0, actualLength);
status = B_USB_STATUS_SUCCESS;
break;
} else if (request->Index > sUHCIRootHubConfig.hub.num_ports) {
// This port doesn't exist
break;
}
// Get port status
UpdatePortStatus();
actualLength = MIN(4, transfer->DataLength());
memcpy(transfer->Data(),
(void *)&fPortStatus[request->Index - 1], actualLength);
status = B_USB_STATUS_SUCCESS;
usb_port_status portStatus;
if (uhci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) {
actualLength = MIN(sizeof(usb_port_status), transfer->DataLength());
memcpy(transfer->Data(), (void *)&portStatus, actualLength);
status = B_USB_STATUS_SUCCESS;
}
break;
}
case RH_SET_ADDRESS:
case USB_REQUEST_SET_ADDRESS:
if (request->Value >= 128) {
status = B_USB_STATUS_DEVICE_TIMEOUT;
break;
}
TRACE(("usb_uhci_roothub: rh_submit_packet RH_ADDRESS: %d\n", request->Value));
TRACE(("usb_uhci_roothub: set address: %d\n", request->Value));
status = B_USB_STATUS_SUCCESS;
break;
case RH_GET_DESCRIPTOR:
TRACE(("usb_uhci_roothub: rh_submit_packet GET_DESC: %d\n", request->Value));
case USB_REQUEST_GET_DESCRIPTOR:
TRACE(("usb_uhci_roothub: get descriptor: %d\n", request->Value >> 8));
switch (request->Value & 0xff00) {
case RH_DEVICE_DESCRIPTOR: {
switch (request->Value >> 8) {
case USB_DESCRIPTOR_DEVICE: {
actualLength = MIN(sizeof(usb_device_descriptor),
transfer->DataLength());
memcpy(transfer->Data(), (void *)&sUHCIRootHubDevice,
@ -183,7 +178,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
break;
}
case RH_CONFIG_DESCRIPTOR: {
case USB_DESCRIPTOR_CONFIGURATION: {
actualLength = MIN(sizeof(uhci_root_hub_configuration_s),
transfer->DataLength());
memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig,
@ -192,7 +187,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
break;
}
case RH_STRING_DESCRIPTOR: {
case USB_DESCRIPTOR_STRING: {
uint8 index = request->Value & 0x00ff;
if (index > 2)
break;
@ -205,7 +200,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
break;
}
case RH_HUB_DESCRIPTOR: {
case USB_DESCRIPTOR_HUB: {
actualLength = MIN(sizeof(usb_hub_descriptor),
transfer->DataLength());
memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig.hub,
@ -216,63 +211,33 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
}
break;
case RH_SET_CONFIG:
case USB_REQUEST_SET_CONFIGURATION:
status = B_USB_STATUS_SUCCESS;
break;
case RH_CLEAR_FEATURE: {
case USB_REQUEST_CLEAR_FEATURE: {
if (request->Index == 0) {
// We don't support any hub changes
TRACE_ERROR(("usb_uhci_roothub: RH_CLEAR_FEATURE no hub changes!\n"));
break;
} else if (request->Index > sUHCIRootHubConfig.hub.num_ports) {
// Invalid port number
TRACE_ERROR(("usb_uhci_roothub: RH_CLEAR_FEATURE invalid port!\n"));
TRACE_ERROR(("usb_uhci_roothub: clear feature: no hub changes\n"));
break;
}
TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE called. Feature: %u!\n", request->Value));
uint16 portStatus;
switch(request->Value) {
case C_PORT_RESET:
fUHCI->SetPortResetChange(request->Index - 1, false);
status = B_USB_STATUS_SUCCESS;
break;
case C_PORT_CONNECTION:
portStatus = fUHCI->PortStatus(request->Index - 1);
if (fUHCI->SetPortStatus(request->Index - 1,
(portStatus & UHCI_PORTSC_DATAMASK)
| UHCI_PORTSC_STATCHA) >= B_OK)
status = B_USB_STATUS_SUCCESS;
break;
}
TRACE(("usb_uhci_roothub: clear feature: %d\n", request->Value));
if (uhci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK)
status = B_USB_STATUS_SUCCESS;
break;
}
case RH_SET_FEATURE: {
case USB_REQUEST_SET_FEATURE: {
if (request->Index == 0) {
// We don't support any hub changes
TRACE_ERROR(("usb_uhci_roothub: RH_SET_FEATURE no hub changes!\n"));
break;
} else if (request->Index > sUHCIRootHubConfig.hub.num_ports) {
// Invalid port number
TRACE_ERROR(("usb_uhci_roothub: RH_SET_FEATURE invalid port!\n"));
// we don't support any hub changes
TRACE_ERROR(("usb_uhci_roothub: set feature: no hub changes\n"));
break;
}
TRACE(("usb_uhci_roothub: RH_SET_FEATURE called. Feature: %u!\n", request->Value));
switch(request->Value) {
case PORT_RESET:
if (fUHCI->ResetPort(request->Index - 1) >= B_OK)
status = B_USB_STATUS_SUCCESS;
break;
case PORT_POWER:
// the ports are automatically powered
status = B_USB_STATUS_SUCCESS;
break;
}
TRACE(("usb_uhci_roothub: set feature: %d!\n", request->Value));
if (uhci->SetPortFeature(request->Index - 1, request->Value) >= B_OK)
status = B_USB_STATUS_SUCCESS;
break;
}
}
@ -281,46 +246,3 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
delete transfer;
return B_OK;
}
void
UHCIRootHub::UpdatePortStatus()
{
for (int32 i = 0; i < sUHCIRootHubConfig.hub.num_ports; i++) {
uint16 newStatus = 0;
uint16 newChange = 0;
uint16 portStatus = fUHCI->PortStatus(i);
TRACE(("usb_uhci_roothub: port: %d status: 0x%04x\n", i, portStatus));
// Set all individual bits
if (portStatus & UHCI_PORTSC_CURSTAT)
newStatus |= PORT_STATUS_CONNECTION;
if (portStatus & UHCI_PORTSC_STATCHA)
newChange |= PORT_STATUS_CONNECTION;
if (portStatus & UHCI_PORTSC_ENABLED)
newStatus |= PORT_STATUS_ENABLE;
if (portStatus & UHCI_PORTSC_ENABCHA)
newChange |= PORT_STATUS_ENABLE;
// TODO: work out suspended/resume
if (portStatus & UHCI_PORTSC_RESET)
newStatus |= PORT_STATUS_RESET;
if (fUHCI->PortResetChange(i))
newChange |= PORT_STATUS_RESET;
//The port is automagically powered on
newStatus |= PORT_STATUS_POWER;
if (portStatus & UHCI_PORTSC_LOWSPEED)
newStatus |= PORT_STATUS_LOW_SPEED;
//Update the stored port status
fPortStatus[i].status = newStatus;
fPortStatus[i].change = newChange;
}
}