* 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:
parent
f50c1ececf
commit
ffe3f107c4
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,8 @@
|
||||
|
||||
|
||||
Object::Object(BusManager *bus)
|
||||
: fBusManager(bus),
|
||||
fStack(bus->GetStack()),
|
||||
fUSBID(fStack->GetUSBID(this))
|
||||
{
|
||||
fStack = bus->GetStack();
|
||||
fUSBID = fStack->GetUSBID(this);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user