* 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:
@@ -28,11 +28,11 @@ BusManager::BusManager(Stack *stack)
|
|||||||
fDeviceMap[i] = false;
|
fDeviceMap[i] = false;
|
||||||
|
|
||||||
// Set up the default pipes
|
// 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)
|
if (!fDefaultPipe)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fDefaultPipeLowSpeed = new(std::nothrow) ControlPipe(this, 0, Pipe::LowSpeed, 8);
|
fDefaultPipeLowSpeed = new(std::nothrow) ControlPipe(this, 0, Pipe::LowSpeed, 0, 8);
|
||||||
if (!fDefaultPipeLowSpeed)
|
if (!fDefaultPipeLowSpeed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ BusManager::AllocateNewDevice(Device *parent, bool lowSpeed)
|
|||||||
|
|
||||||
// Create a temporary pipe with the new address
|
// Create a temporary pipe with the new address
|
||||||
ControlPipe pipe(this, deviceAddress,
|
ControlPipe pipe(this, deviceAddress,
|
||||||
lowSpeed ? Pipe::LowSpeed : Pipe::NormalSpeed, 8);
|
lowSpeed ? Pipe::LowSpeed : Pipe::FullSpeed, 0, 8);
|
||||||
|
|
||||||
// Get the device descriptor
|
// Get the device descriptor
|
||||||
// Just retrieve the first 8 bytes of the descriptor -> minimum supported
|
// Just retrieve the first 8 bytes of the descriptor -> minimum supported
|
||||||
@@ -261,11 +261,3 @@ BusManager::SubmitTransfer(Transfer *transfer)
|
|||||||
// virtual function to be overridden
|
// virtual function to be overridden
|
||||||
return B_ERROR;
|
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,
|
Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
|
||||||
int8 deviceAddress, bool lowSpeed)
|
int8 deviceAddress, bool lowSpeed)
|
||||||
: ControlPipe(bus, deviceAddress,
|
: ControlPipe(bus, deviceAddress,
|
||||||
lowSpeed ? Pipe::LowSpeed : Pipe::NormalSpeed,
|
lowSpeed ? Pipe::LowSpeed : Pipe::FullSpeed, 0,
|
||||||
desc.max_packet_size_0),
|
desc.max_packet_size_0),
|
||||||
fDeviceDescriptor(desc),
|
fDeviceDescriptor(desc),
|
||||||
fConfigurations(NULL),
|
fConfigurations(NULL),
|
||||||
fCurrentConfiguration(NULL),
|
fCurrentConfiguration(NULL),
|
||||||
fInitOK(false),
|
fInitOK(false),
|
||||||
fLowSpeed(lowSpeed),
|
fLowSpeed(lowSpeed),
|
||||||
fBus(bus),
|
|
||||||
fParent(parent),
|
fParent(parent),
|
||||||
fDeviceAddress(deviceAddress),
|
fDeviceAddress(deviceAddress),
|
||||||
fLock(-1),
|
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(("\tvendor_id:...........0x%04x\n", fDeviceDescriptor.vendor_id));
|
||||||
TRACE(("\tproduct_id:..........0x%04x\n", fDeviceDescriptor.product_id));
|
TRACE(("\tproduct_id:..........0x%04x\n", fDeviceDescriptor.product_id));
|
||||||
TRACE(("\tdevice_version:......0x%04x\n", fDeviceDescriptor.device_version));
|
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(("\tproduct:.............0x%02x\n", fDeviceDescriptor.product));
|
||||||
TRACE(("\tserial_number:.......0x%02x\n", fDeviceDescriptor.serial_number));
|
TRACE(("\tserial_number:.......0x%02x\n", fDeviceDescriptor.serial_number));
|
||||||
TRACE(("\tnum_configurations:..%d\n", fDeviceDescriptor.num_configurations));
|
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_count = 0;
|
||||||
interfaceInfo->generic = NULL;
|
interfaceInfo->generic = NULL;
|
||||||
|
|
||||||
Interface *interface = new(std::nothrow) Interface(this);
|
Interface *interface = new(std::nothrow) Interface(GetBusManager(),
|
||||||
|
fDeviceAddress, Speed());
|
||||||
interfaceInfo->handle = interface->USBID();
|
interfaceInfo->handle = interface->USBID();
|
||||||
|
|
||||||
currentInterface = interfaceInfo;
|
currentInterface = interfaceInfo;
|
||||||
@@ -182,14 +182,15 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
|
|||||||
Pipe *endpoint = NULL;
|
Pipe *endpoint = NULL;
|
||||||
switch (endpointDescriptor->attributes & 0x03) {
|
switch (endpointDescriptor->attributes & 0x03) {
|
||||||
case 0x00: /* Control Endpoint */
|
case 0x00: /* Control Endpoint */
|
||||||
endpoint = new(std::nothrow) ControlPipe(this,
|
endpoint = new(std::nothrow) ControlPipe(GetBusManager(),
|
||||||
Speed(),
|
fDeviceAddress, Speed(),
|
||||||
endpointDescriptor->endpoint_address & 0x0f,
|
endpointDescriptor->endpoint_address & 0x0f,
|
||||||
endpointDescriptor->max_packet_size);
|
endpointDescriptor->max_packet_size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x01: /* Isochronous Endpoint */
|
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,
|
endpointDescriptor->endpoint_address & 0x80 > 0 ? Pipe::In : Pipe::Out,
|
||||||
Speed(),
|
Speed(),
|
||||||
endpointDescriptor->endpoint_address & 0x0f,
|
endpointDescriptor->endpoint_address & 0x0f,
|
||||||
@@ -197,7 +198,8 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x02: /* Bulk Endpoint */
|
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,
|
endpointDescriptor->endpoint_address & 0x80 > 0 ? Pipe::In : Pipe::Out,
|
||||||
Speed(),
|
Speed(),
|
||||||
endpointDescriptor->endpoint_address & 0x0f,
|
endpointDescriptor->endpoint_address & 0x0f,
|
||||||
@@ -205,7 +207,8 @@ Device::Device(BusManager *bus, Device *parent, usb_device_descriptor &desc,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x03: /* Interrupt Endpoint */
|
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,
|
endpointDescriptor->endpoint_address & 0x80 > 0 ? Pipe::In : Pipe::Out,
|
||||||
Speed(),
|
Speed(),
|
||||||
endpointDescriptor->endpoint_address & 0x0f,
|
endpointDescriptor->endpoint_address & 0x0f,
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ Hub::Explore()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Device *newDevice = fBus->AllocateNewDevice(this,
|
Device *newDevice = GetBusManager()->AllocateNewDevice(this,
|
||||||
(fPortStatus[i].status & PORT_STATUS_LOW_SPEED) > 0);
|
(fPortStatus[i].status & PORT_STATUS_LOW_SPEED) > 0);
|
||||||
|
|
||||||
if (newDevice) {
|
if (newDevice) {
|
||||||
@@ -273,7 +273,7 @@ Hub::BuildDeviceName(char *string, uint32 *index, size_t bufferSize,
|
|||||||
status_t result = Device::BuildDeviceName(string, index, bufferSize, device);
|
status_t result = Device::BuildDeviceName(string, index, bufferSize, device);
|
||||||
if (result < B_OK) {
|
if (result < B_OK) {
|
||||||
// recursion to parent failed, we're at the root(hub)
|
// 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);
|
*index += snprintf(string + *index, bufferSize - *index, "%ld", managerIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
#include "usb_p.h"
|
#include "usb_p.h"
|
||||||
|
|
||||||
|
|
||||||
Interface::Interface(Device *device)
|
Interface::Interface(BusManager *bus, int8 deviceAddress, pipeSpeed speed)
|
||||||
: ControlPipe(device, device->Speed(), 0, 8)
|
: ControlPipe(bus, deviceAddress, speed, 0, 8)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
|
|
||||||
|
|
||||||
Object::Object(BusManager *bus)
|
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"
|
#include "usb_p.h"
|
||||||
|
|
||||||
|
|
||||||
Pipe::Pipe(Device *device, pipeDirection direction, pipeSpeed speed,
|
Pipe::Pipe(BusManager *bus, int8 deviceAddress, pipeDirection direction,
|
||||||
uint8 endpointAddress, size_t maxPacketSize)
|
pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize)
|
||||||
: Object(device->Manager()),
|
: Object(bus),
|
||||||
fDevice(device),
|
fDeviceAddress(deviceAddress),
|
||||||
fDeviceAddress(device->Address()),
|
fEndpointAddress(endpointAddress),
|
||||||
fBus(device->Manager()),
|
|
||||||
fDirection(direction),
|
fDirection(direction),
|
||||||
fSpeed(speed),
|
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),
|
fMaxPacketSize(maxPacketSize),
|
||||||
fDataToggle(true)
|
fDataToggle(true)
|
||||||
{
|
{
|
||||||
@@ -45,21 +28,11 @@ Pipe::~Pipe()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int8
|
|
||||||
Pipe::DeviceAddress()
|
|
||||||
{
|
|
||||||
if (!fDevice)
|
|
||||||
return fDeviceAddress;
|
|
||||||
|
|
||||||
return fDevice->Address();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Pipe::SubmitTransfer(Transfer *transfer)
|
Pipe::SubmitTransfer(Transfer *transfer)
|
||||||
{
|
{
|
||||||
// ToDo: keep track of all submited transfers to be able to cancel them
|
// 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 -
|
// #pragma mark -
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
InterruptPipe::InterruptPipe(Device *device, pipeDirection direction,
|
InterruptPipe::InterruptPipe(BusManager *bus, int8 deviceAddress,
|
||||||
pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize)
|
pipeDirection direction, pipeSpeed speed, uint8 endpointAddress,
|
||||||
: Pipe(device, direction, speed, endpointAddress, maxPacketSize)
|
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,
|
BulkPipe::BulkPipe(BusManager *bus, int8 deviceAddress,
|
||||||
pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize)
|
pipeDirection direction, pipeSpeed speed, uint8 endpointAddress,
|
||||||
: Pipe(device, direction, speed, endpointAddress, maxPacketSize)
|
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,
|
IsochronousPipe::IsochronousPipe(BusManager *bus, int8 deviceAddress,
|
||||||
pipeSpeed speed, uint8 endpointAddress, size_t maxPacketSize)
|
pipeDirection direction, pipeSpeed speed, uint8 endpointAddress,
|
||||||
: Pipe(device, direction, speed, endpointAddress, maxPacketSize)
|
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,
|
ControlPipe::ControlPipe(BusManager *bus, int8 deviceAddress, pipeSpeed speed,
|
||||||
size_t maxPacketSize)
|
uint8 endpointAddress, size_t maxPacketSize)
|
||||||
: Pipe(bus, deviceAddress, speed, maxPacketSize)
|
: Pipe(bus, deviceAddress, Default, speed, endpointAddress, maxPacketSize)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,3 +240,48 @@ ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value,
|
|||||||
delete transfer;
|
delete transfer;
|
||||||
return result;
|
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
|
// we take ownership of the request data
|
||||||
if (fRequestData)
|
if (fRequestData)
|
||||||
delete fRequestData;
|
delete fRequestData;
|
||||||
|
|
||||||
|
if (fVector && fVector != &fData)
|
||||||
|
delete[] fVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -50,7 +53,8 @@ Transfer::SetData(uint8 *data, size_t dataLength)
|
|||||||
void
|
void
|
||||||
Transfer::SetVector(iovec *vector, size_t vectorCount)
|
Transfer::SetVector(iovec *vector, size_t vectorCount)
|
||||||
{
|
{
|
||||||
fVector = vector;
|
fVector = new(std::nothrow) iovec[vectorCount];
|
||||||
|
memcpy(fVector, vector, vectorCount * sizeof(iovec));
|
||||||
fVectorCount = vectorCount;
|
fVectorCount = vectorCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -145,10 +145,10 @@ set_feature(usb_id handle, uint16 selector)
|
|||||||
{
|
{
|
||||||
TRACE(("usb_module: set_feature(0x%08x, %d)\n", handle, selector));
|
TRACE(("usb_module: set_feature(0x%08x, %d)\n", handle, selector));
|
||||||
Object *object = gUSBStack->GetObject(handle);
|
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 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));
|
TRACE(("usb_module: clear_feature(0x%08x, %d)\n", handle, selector));
|
||||||
Object *object = gUSBStack->GetObject(handle);
|
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 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;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
Object *object = gUSBStack->GetObject(handle);
|
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 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 Stop();
|
||||||
|
|
||||||
virtual status_t SubmitTransfer(Transfer *transfer);
|
virtual status_t SubmitTransfer(Transfer *transfer);
|
||||||
virtual status_t SubmitRequest(Transfer *transfer);
|
|
||||||
|
|
||||||
Stack *GetStack() { return fStack; };
|
Stack *GetStack() { return fStack; };
|
||||||
void SetStack(Stack *stack) { fStack = stack; };
|
void SetStack(Stack *stack) { fStack = stack; };
|
||||||
@@ -175,12 +174,14 @@ class Object {
|
|||||||
public:
|
public:
|
||||||
Object(BusManager *bus);
|
Object(BusManager *bus);
|
||||||
|
|
||||||
|
BusManager *GetBusManager() { return fBusManager; };
|
||||||
Stack *GetStack() { return fStack; };
|
Stack *GetStack() { return fStack; };
|
||||||
|
|
||||||
usb_id USBID() { return fUSBID; };
|
usb_id USBID() { return fUSBID; };
|
||||||
virtual uint32 Type() { return USB_OBJECT_NONE; };
|
virtual uint32 Type() { return USB_OBJECT_NONE; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
BusManager *fBusManager;
|
||||||
Stack *fStack;
|
Stack *fStack;
|
||||||
usb_id fUSBID;
|
usb_id fUSBID;
|
||||||
};
|
};
|
||||||
@@ -193,25 +194,22 @@ private:
|
|||||||
class Pipe : public Object {
|
class Pipe : public Object {
|
||||||
public:
|
public:
|
||||||
enum pipeDirection { In, Out, Default };
|
enum pipeDirection { In, Out, Default };
|
||||||
enum pipeSpeed { LowSpeed, NormalSpeed };
|
enum pipeSpeed { LowSpeed, FullSpeed, HighSpeed };
|
||||||
|
|
||||||
Pipe(Device *device,
|
Pipe(BusManager *bus,
|
||||||
|
int8 deviceAddress,
|
||||||
pipeDirection direction,
|
pipeDirection direction,
|
||||||
pipeSpeed speed,
|
pipeSpeed speed,
|
||||||
uint8 endpointAddress,
|
uint8 endpointAddress,
|
||||||
size_t maxPacketSize);
|
size_t maxPacketSize);
|
||||||
Pipe(BusManager *bus,
|
|
||||||
int8 deviceAddress,
|
|
||||||
pipeSpeed speed,
|
|
||||||
size_t maxPacketSize);
|
|
||||||
virtual ~Pipe();
|
virtual ~Pipe();
|
||||||
|
|
||||||
virtual uint32 Type() { return USB_OBJECT_PIPE; };
|
virtual uint32 Type() { return USB_OBJECT_PIPE; };
|
||||||
|
|
||||||
int8 DeviceAddress();
|
int8 DeviceAddress() { return fDeviceAddress; };
|
||||||
pipeSpeed Speed() { return fSpeed; };
|
pipeSpeed Speed() { return fSpeed; };
|
||||||
pipeDirection Direction() { return fDirection; };
|
pipeDirection Direction() { return fDirection; };
|
||||||
int8 EndpointAddress() { return fEndpoint; };
|
int8 EndpointAddress() { return fEndpointAddress; };
|
||||||
size_t MaxPacketSize() { return fMaxPacketSize; };
|
size_t MaxPacketSize() { return fMaxPacketSize; };
|
||||||
|
|
||||||
virtual bool DataToggle() { return fDataToggle; };
|
virtual bool DataToggle() { return fDataToggle; };
|
||||||
@@ -220,19 +218,11 @@ virtual void SetDataToggle(bool toggle) { fDataToggle = toggle; };
|
|||||||
status_t SubmitTransfer(Transfer *transfer);
|
status_t SubmitTransfer(Transfer *transfer);
|
||||||
status_t CancelQueuedTransfers();
|
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:
|
protected:
|
||||||
Device *fDevice;
|
|
||||||
int8 fDeviceAddress;
|
int8 fDeviceAddress;
|
||||||
BusManager *fBus;
|
uint8 fEndpointAddress;
|
||||||
usb_id fUSBID;
|
|
||||||
pipeDirection fDirection;
|
pipeDirection fDirection;
|
||||||
pipeSpeed fSpeed;
|
pipeSpeed fSpeed;
|
||||||
uint8 fEndpoint;
|
|
||||||
size_t fMaxPacketSize;
|
size_t fMaxPacketSize;
|
||||||
bool fDataToggle;
|
bool fDataToggle;
|
||||||
};
|
};
|
||||||
@@ -240,15 +230,10 @@ protected:
|
|||||||
|
|
||||||
class ControlPipe : public Pipe {
|
class ControlPipe : public Pipe {
|
||||||
public:
|
public:
|
||||||
ControlPipe(Device *device,
|
|
||||||
pipeSpeed speed,
|
|
||||||
uint8 endpointAddress,
|
|
||||||
size_t maxPacketSize);
|
|
||||||
|
|
||||||
// Constructor for default control pipe
|
|
||||||
ControlPipe(BusManager *bus,
|
ControlPipe(BusManager *bus,
|
||||||
int8 deviceAddress,
|
int8 deviceAddress,
|
||||||
pipeSpeed speed,
|
pipeSpeed speed,
|
||||||
|
uint8 endpointAddress,
|
||||||
size_t maxPacketSize);
|
size_t maxPacketSize);
|
||||||
|
|
||||||
virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_CONTROL_PIPE; };
|
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,
|
void *data, size_t dataLength,
|
||||||
usb_callback_func callback,
|
usb_callback_func callback,
|
||||||
void *callbackCookie);
|
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 {
|
class InterruptPipe : public Pipe {
|
||||||
public:
|
public:
|
||||||
InterruptPipe(Device *device,
|
InterruptPipe(BusManager *bus,
|
||||||
|
int8 deviceAddress,
|
||||||
pipeDirection direction,
|
pipeDirection direction,
|
||||||
pipeSpeed speed,
|
pipeSpeed speed,
|
||||||
uint8 endpointAddress,
|
uint8 endpointAddress,
|
||||||
@@ -298,7 +289,8 @@ virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_INTERRUPT_PIPE
|
|||||||
|
|
||||||
class BulkPipe : public Pipe {
|
class BulkPipe : public Pipe {
|
||||||
public:
|
public:
|
||||||
BulkPipe(Device *device,
|
BulkPipe(BusManager *bus,
|
||||||
|
int8 deviceAddress,
|
||||||
pipeDirection direction,
|
pipeDirection direction,
|
||||||
pipeSpeed speed,
|
pipeSpeed speed,
|
||||||
uint8 endpointAddress,
|
uint8 endpointAddress,
|
||||||
@@ -319,7 +311,8 @@ virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_BULK_PIPE; };
|
|||||||
|
|
||||||
class IsochronousPipe : public Pipe {
|
class IsochronousPipe : public Pipe {
|
||||||
public:
|
public:
|
||||||
IsochronousPipe(Device *device,
|
IsochronousPipe(BusManager *bus,
|
||||||
|
int8 deviceAddress,
|
||||||
pipeDirection direction,
|
pipeDirection direction,
|
||||||
pipeSpeed speed,
|
pipeSpeed speed,
|
||||||
uint8 endpointAddress,
|
uint8 endpointAddress,
|
||||||
@@ -338,7 +331,9 @@ virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_ISO_PIPE; };
|
|||||||
|
|
||||||
class Interface : public ControlPipe {
|
class Interface : public ControlPipe {
|
||||||
public:
|
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; };
|
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; };
|
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,
|
virtual status_t GetDescriptor(uint8 descriptorType,
|
||||||
uint8 index, uint16 languageID,
|
uint8 index, uint16 languageID,
|
||||||
void *data, size_t dataLength,
|
void *data, size_t dataLength,
|
||||||
@@ -394,7 +386,6 @@ protected:
|
|||||||
usb_configuration_info *fCurrentConfiguration;
|
usb_configuration_info *fCurrentConfiguration;
|
||||||
bool fInitOK;
|
bool fInitOK;
|
||||||
bool fLowSpeed;
|
bool fLowSpeed;
|
||||||
BusManager *fBus;
|
|
||||||
Device *fParent;
|
Device *fParent;
|
||||||
int8 fDeviceAddress;
|
int8 fDeviceAddress;
|
||||||
size_t fMaxPacketIn[16];
|
size_t fMaxPacketIn[16];
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ struct usb_port_status
|
|||||||
#define PORT_STATUS_RESET 0x0010
|
#define PORT_STATUS_RESET 0x0010
|
||||||
#define PORT_STATUS_POWER 0x0100
|
#define PORT_STATUS_POWER 0x0100
|
||||||
#define PORT_STATUS_LOW_SPEED 0x0200
|
#define PORT_STATUS_LOW_SPEED 0x0200
|
||||||
|
#define PORT_STATUS_HIGH_SPEED 0x0400
|
||||||
|
|
||||||
|
|
||||||
//The feature requests with ports
|
//The feature requests with ports
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include <USB3.h>
|
#include <USB3.h>
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
|
||||||
#define TRACE_USB
|
|
||||||
#include "ehci.h"
|
#include "ehci.h"
|
||||||
|
|
||||||
pci_module_info *EHCI::sPCIModule = NULL;
|
pci_module_info *EHCI::sPCIModule = NULL;
|
||||||
@@ -67,7 +66,10 @@ EHCI::EHCI(pci_info *info, Stack *stack)
|
|||||||
fFinishThread(-1),
|
fFinishThread(-1),
|
||||||
fStopFinishThread(false),
|
fStopFinishThread(false),
|
||||||
fRootHub(NULL),
|
fRootHub(NULL),
|
||||||
fRootHubAddress(0)
|
fRootHubAddress(0),
|
||||||
|
fPortCount(0),
|
||||||
|
fPortResetChange(0),
|
||||||
|
fPortSuspendChange(0)
|
||||||
{
|
{
|
||||||
if (BusManager::InitCheck() < B_OK) {
|
if (BusManager::InitCheck() < B_OK) {
|
||||||
TRACE_ERROR(("usb_ehci: bus manager failed to init\n"));
|
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 capability registers: 0x%08x\n", fCapabilityRegisters));
|
||||||
TRACE(("usb_ehci: mapped operational registers: 0x%08x\n", fOperationalRegisters));
|
TRACE(("usb_ehci: mapped operational registers: 0x%08x\n", fOperationalRegisters));
|
||||||
|
|
||||||
|
// read port count from capability register
|
||||||
|
fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f;
|
||||||
|
|
||||||
// disable interrupts
|
// disable interrupts
|
||||||
WriteOpReg(EHCI_USBINTR, 0);
|
WriteOpReg(EHCI_USBINTR, 0);
|
||||||
|
|
||||||
@@ -217,14 +222,11 @@ EHCI::Start()
|
|||||||
status_t
|
status_t
|
||||||
EHCI::SubmitTransfer(Transfer *transfer)
|
EHCI::SubmitTransfer(Transfer *transfer)
|
||||||
{
|
{
|
||||||
return B_ERROR;
|
// short circuit the root hub
|
||||||
}
|
if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
|
||||||
|
return fRootHub->ProcessTransfer(this, transfer);
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
status_t
|
|
||||||
EHCI::SubmitRequest(Transfer *transfer)
|
|
||||||
{
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -301,9 +303,169 @@ EHCI::AddTo(Stack *stack)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
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
|
#ifndef EHCI_H
|
||||||
#define EHCI_H
|
#define EHCI_H
|
||||||
|
|
||||||
|
#define TRACE_USB
|
||||||
#include "usb_p.h"
|
#include "usb_p.h"
|
||||||
#include "ehci_hardware.h"
|
#include "ehci_hardware.h"
|
||||||
|
|
||||||
@@ -36,12 +37,17 @@ public:
|
|||||||
|
|
||||||
status_t Start();
|
status_t Start();
|
||||||
virtual status_t SubmitTransfer(Transfer *transfer);
|
virtual status_t SubmitTransfer(Transfer *transfer);
|
||||||
virtual status_t SubmitRequest(Transfer *transfer);
|
|
||||||
|
|
||||||
static status_t AddTo(Stack *stack);
|
static status_t AddTo(Stack *stack);
|
||||||
|
|
||||||
// Port operations for root hub
|
// 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:
|
private:
|
||||||
// Controller resets
|
// Controller resets
|
||||||
@@ -118,6 +124,11 @@ static pci_module_info *sPCIModule;
|
|||||||
// Root Hub
|
// Root Hub
|
||||||
EHCIRootHub *fRootHub;
|
EHCIRootHub *fRootHub;
|
||||||
uint8 fRootHubAddress;
|
uint8 fRootHubAddress;
|
||||||
|
|
||||||
|
// Port management
|
||||||
|
uint8 fPortCount;
|
||||||
|
uint16 fPortResetChange;
|
||||||
|
uint16 fPortSuspendChange;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -125,12 +136,8 @@ class EHCIRootHub : public Hub {
|
|||||||
public:
|
public:
|
||||||
EHCIRootHub(EHCI *ehci, int8 deviceAddress);
|
EHCIRootHub(EHCI *ehci, int8 deviceAddress);
|
||||||
|
|
||||||
status_t SubmitTransfer(Transfer *transfer);
|
static status_t ProcessTransfer(EHCI *ehci,
|
||||||
void UpdatePortStatus();
|
Transfer *transfer);
|
||||||
|
|
||||||
private:
|
|
||||||
usb_port_status fPortStatus[2];
|
|
||||||
EHCI *fEHCI;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -88,11 +88,13 @@
|
|||||||
#define EHCI_PORTSC_FORCERESUME (1 << 6) // Force Port Resume
|
#define EHCI_PORTSC_FORCERESUME (1 << 6) // Force Port Resume
|
||||||
#define EHCI_PORTSC_OCCHANGE (1 << 5) // Over-Current Change
|
#define EHCI_PORTSC_OCCHANGE (1 << 5) // Over-Current Change
|
||||||
#define EHCI_PORTSC_OCACTIVE (1 << 4) // Over-Current Active
|
#define EHCI_PORTSC_OCACTIVE (1 << 4) // Over-Current Active
|
||||||
#define EHCI_PORTSC_ENDISCHANGE (1 << 3) // Port Enable/Disable Change
|
#define EHCI_PORTSC_ENABLECHANGE (1 << 3) // Port Enable/Disable Change
|
||||||
#define EHCI_PORTSC_ENDIS (1 << 2) // Port Enabled/Disabled
|
#define EHCI_PORTSC_ENABLE (1 << 2) // Port Enabled/Disabled
|
||||||
#define EHCI_PORTSC_CONNCHANGE (1 << 1) // Connect Status Change
|
#define EHCI_PORTSC_CONNCHANGE (1 << 1) // Connect Status Change
|
||||||
#define EHCI_PORTSC_CONNSTATUS (1 << 0) // Current Connect Status
|
#define EHCI_PORTSC_CONNSTATUS (1 << 0) // Current Connect Status
|
||||||
|
|
||||||
|
#define EHCI_PORTSC_DATAMASK 0xffffffd5
|
||||||
|
|
||||||
|
|
||||||
// PCI Registers
|
// PCI Registers
|
||||||
#define PCI_LEGSUP 0xc0 // PCI Legacy Support
|
#define PCI_LEGSUP 0xc0 // PCI Legacy Support
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "ehci.h"
|
#include "ehci.h"
|
||||||
|
|
||||||
|
|
||||||
static usb_device_descriptor sEHCIRootHubDevice =
|
static usb_device_descriptor sEHCIRootHubDevice =
|
||||||
{
|
{
|
||||||
18, // Descriptor length
|
18, // Descriptor length
|
||||||
@@ -75,11 +74,11 @@ static ehci_root_hub_configuration_s sEHCIRootHubConfig =
|
|||||||
9, // Descriptor length (including
|
9, // Descriptor length (including
|
||||||
// deprecated power control mask)
|
// deprecated power control mask)
|
||||||
USB_DESCRIPTOR_HUB, // Descriptor type
|
USB_DESCRIPTOR_HUB, // Descriptor type
|
||||||
2, // Number of ports
|
0x0f, // Number of ports
|
||||||
0x0000, // Hub characteristics
|
0x0000, // Hub characteristics
|
||||||
50, // Power on to power good (in 2ms units)
|
50, // Power on to power good (in 2ms units)
|
||||||
0, // Maximum current (in mA)
|
0, // Maximum current (in mA)
|
||||||
0x00, // Both ports are removable
|
0x00, // All ports are removable
|
||||||
0xff // Depricated power control mask
|
0xff // Depricated power control mask
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -118,22 +117,135 @@ static ehci_root_hub_string_s sEHCIRootHubStrings[3] = {
|
|||||||
EHCIRootHub::EHCIRootHub(EHCI *ehci, int8 deviceAddress)
|
EHCIRootHub::EHCIRootHub(EHCI *ehci, int8 deviceAddress)
|
||||||
: Hub(ehci, NULL, sEHCIRootHubDevice, deviceAddress, false)
|
: Hub(ehci, NULL, sEHCIRootHubDevice, deviceAddress, false)
|
||||||
{
|
{
|
||||||
fEHCI = ehci;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
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
|
// ToDo: define better status codes. We should return a request error.
|
||||||
EHCIRootHub::UpdatePortStatus()
|
uint32 status = B_USB_STATUS_DEVICE_TIMEOUT;
|
||||||
{
|
size_t actualLength = 0;
|
||||||
for (int32 i = 0; i < sEHCIRootHubConfig.hub.num_ports; i++) {
|
switch (request->Request) {
|
||||||
fPortStatus[i].status = 0;
|
case USB_REQUEST_GET_STATUS: {
|
||||||
fPortStatus[i].change = 0;
|
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),
|
fFinishThread(-1),
|
||||||
fStopFinishThread(false),
|
fStopFinishThread(false),
|
||||||
fRootHub(NULL),
|
fRootHub(NULL),
|
||||||
fRootHubAddress(0)
|
fRootHubAddress(0),
|
||||||
|
fPortResetChange(0)
|
||||||
{
|
{
|
||||||
if (!fInitOK) {
|
if (!fInitOK) {
|
||||||
TRACE_ERROR(("usb_uhci: bus manager failed to init\n"));
|
TRACE_ERROR(("usb_uhci: bus manager failed to init\n"));
|
||||||
@@ -481,7 +482,6 @@ UHCI::Start()
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
fPortResetChange[0] = fPortResetChange[1] = false;
|
|
||||||
fRootHubAddress = AllocateAddress();
|
fRootHubAddress = AllocateAddress();
|
||||||
fRootHub = new(std::nothrow) UHCIRootHub(this, fRootHubAddress);
|
fRootHub = new(std::nothrow) UHCIRootHub(this, fRootHubAddress);
|
||||||
if (!fRootHub) {
|
if (!fRootHub) {
|
||||||
@@ -510,7 +510,7 @@ UHCI::SubmitTransfer(Transfer *transfer)
|
|||||||
|
|
||||||
// Short circuit the root hub
|
// Short circuit the root hub
|
||||||
if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
|
if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
|
||||||
return fRootHub->SubmitTransfer(transfer);
|
return fRootHub->ProcessTransfer(this, transfer);
|
||||||
|
|
||||||
if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE)
|
if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE)
|
||||||
return SubmitRequest(transfer);
|
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
|
status_t
|
||||||
UHCI::SetPortStatus(int32 index, uint16 status)
|
UHCI::GetPortStatus(uint8 index, usb_port_status *status)
|
||||||
{
|
{
|
||||||
if (index > 1)
|
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));
|
status->status = status->change = 0;
|
||||||
WriteReg16(UHCI_PORTSC1 + index * 2, status);
|
uint16 portStatus = ReadReg16(UHCI_PORTSC1 + index * 2);
|
||||||
snooze(1000);
|
|
||||||
|
// 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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
UHCI::ResetPort(int32 index)
|
UHCI::SetPortFeature(uint8 index, uint16 feature)
|
||||||
{
|
{
|
||||||
if (index > 1)
|
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));
|
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)));
|
TRACE(("usb_uhci: port was reset: 0x%04x\n", ReadReg16(port)));
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
UHCI::PortResetChange(int32 index)
|
|
||||||
{
|
|
||||||
if (index > 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return fPortResetChange[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
UHCI::SetPortResetChange(int32 index, bool value)
|
|
||||||
{
|
|
||||||
if (index > 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
fPortResetChange[index] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int32
|
int32
|
||||||
UHCI::InterruptHandler(void *data)
|
UHCI::InterruptHandler(void *data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -69,16 +69,16 @@ public:
|
|||||||
|
|
||||||
status_t Start();
|
status_t Start();
|
||||||
virtual status_t SubmitTransfer(Transfer *transfer);
|
virtual status_t SubmitTransfer(Transfer *transfer);
|
||||||
virtual status_t SubmitRequest(Transfer *transfer);
|
status_t SubmitRequest(Transfer *transfer);
|
||||||
|
|
||||||
static status_t AddTo(Stack *stack);
|
static status_t AddTo(Stack *stack);
|
||||||
|
|
||||||
// Port operations
|
// Port operations
|
||||||
uint16 PortStatus(int32 index);
|
status_t GetPortStatus(uint8 index, usb_port_status *status);
|
||||||
status_t SetPortStatus(int32 index, uint16 status);
|
status_t SetPortFeature(uint8 index, uint16 feature);
|
||||||
status_t ResetPort(int32 index);
|
status_t ClearPortFeature(uint8 index, uint16 feature);
|
||||||
bool PortResetChange(int32 index);
|
|
||||||
void SetPortResetChange(int32 index, bool value);
|
status_t ResetPort(uint8 index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Controller resets
|
// Controller resets
|
||||||
@@ -155,7 +155,7 @@ static pci_module_info *sPCIModule;
|
|||||||
// Root hub
|
// Root hub
|
||||||
UHCIRootHub *fRootHub;
|
UHCIRootHub *fRootHub;
|
||||||
uint8 fRootHubAddress;
|
uint8 fRootHubAddress;
|
||||||
bool fPortResetChange[2];
|
uint8 fPortResetChange;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -163,12 +163,8 @@ class UHCIRootHub : public Hub {
|
|||||||
public:
|
public:
|
||||||
UHCIRootHub(UHCI *uhci, int8 deviceAddress);
|
UHCIRootHub(UHCI *uhci, int8 deviceAddress);
|
||||||
|
|
||||||
status_t SubmitTransfer(Transfer *transfer);
|
static status_t ProcessTransfer(UHCI *uhci,
|
||||||
void UpdatePortStatus();
|
Transfer *transfer);
|
||||||
|
|
||||||
private:
|
|
||||||
usb_port_status fPortStatus[2];
|
|
||||||
UHCI *fUHCI;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -147,28 +147,4 @@ typedef struct
|
|||||||
#define QH_NEXT_IS_QH 0x02
|
#define QH_NEXT_IS_QH 0x02
|
||||||
#define QH_LINK_MASK 0xfffffff0
|
#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
|
#endif
|
||||||
|
|||||||
@@ -120,61 +120,56 @@ static uhci_root_hub_string_s sUHCIRootHubStrings[3] = {
|
|||||||
UHCIRootHub::UHCIRootHub(UHCI *uhci, int8 deviceAddress)
|
UHCIRootHub::UHCIRootHub(UHCI *uhci, int8 deviceAddress)
|
||||||
: Hub(uhci, NULL, sUHCIRootHubDevice, deviceAddress, false)
|
: Hub(uhci, NULL, sUHCIRootHubDevice, deviceAddress, false)
|
||||||
{
|
{
|
||||||
fUHCI = uhci;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
UHCIRootHub::SubmitTransfer(Transfer *transfer)
|
UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer)
|
||||||
{
|
{
|
||||||
if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
|
if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
usb_request_data *request = transfer->RequestData();
|
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.
|
// ToDo: define better status codes. We should return a request error.
|
||||||
uint32 status = B_USB_STATUS_DEVICE_TIMEOUT;
|
uint32 status = B_USB_STATUS_DEVICE_TIMEOUT;
|
||||||
size_t actualLength = 0;
|
size_t actualLength = 0;
|
||||||
switch (request->Request) {
|
switch (request->Request) {
|
||||||
case RH_GET_STATUS: {
|
case USB_REQUEST_GET_STATUS: {
|
||||||
if (request->Index == 0) {
|
if (request->Index == 0) {
|
||||||
// Get the hub status -- everything as 0 means all-right
|
// Get the hub status -- everything as 0 means all-right
|
||||||
actualLength = MIN(sizeof(get_status_buffer),
|
actualLength = MIN(sizeof(usb_port_status),
|
||||||
transfer->DataLength());
|
transfer->DataLength());
|
||||||
memset(transfer->Data(), 0, actualLength);
|
memset(transfer->Data(), 0, actualLength);
|
||||||
status = B_USB_STATUS_SUCCESS;
|
status = B_USB_STATUS_SUCCESS;
|
||||||
break;
|
break;
|
||||||
} else if (request->Index > sUHCIRootHubConfig.hub.num_ports) {
|
|
||||||
// This port doesn't exist
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get port status
|
usb_port_status portStatus;
|
||||||
UpdatePortStatus();
|
if (uhci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) {
|
||||||
|
actualLength = MIN(sizeof(usb_port_status), transfer->DataLength());
|
||||||
actualLength = MIN(4, transfer->DataLength());
|
memcpy(transfer->Data(), (void *)&portStatus, actualLength);
|
||||||
memcpy(transfer->Data(),
|
status = B_USB_STATUS_SUCCESS;
|
||||||
(void *)&fPortStatus[request->Index - 1], actualLength);
|
}
|
||||||
status = B_USB_STATUS_SUCCESS;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RH_SET_ADDRESS:
|
case USB_REQUEST_SET_ADDRESS:
|
||||||
if (request->Value >= 128) {
|
if (request->Value >= 128) {
|
||||||
status = B_USB_STATUS_DEVICE_TIMEOUT;
|
status = B_USB_STATUS_DEVICE_TIMEOUT;
|
||||||
break;
|
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;
|
status = B_USB_STATUS_SUCCESS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RH_GET_DESCRIPTOR:
|
case USB_REQUEST_GET_DESCRIPTOR:
|
||||||
TRACE(("usb_uhci_roothub: rh_submit_packet GET_DESC: %d\n", request->Value));
|
TRACE(("usb_uhci_roothub: get descriptor: %d\n", request->Value >> 8));
|
||||||
|
|
||||||
switch (request->Value & 0xff00) {
|
switch (request->Value >> 8) {
|
||||||
case RH_DEVICE_DESCRIPTOR: {
|
case USB_DESCRIPTOR_DEVICE: {
|
||||||
actualLength = MIN(sizeof(usb_device_descriptor),
|
actualLength = MIN(sizeof(usb_device_descriptor),
|
||||||
transfer->DataLength());
|
transfer->DataLength());
|
||||||
memcpy(transfer->Data(), (void *)&sUHCIRootHubDevice,
|
memcpy(transfer->Data(), (void *)&sUHCIRootHubDevice,
|
||||||
@@ -183,7 +178,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RH_CONFIG_DESCRIPTOR: {
|
case USB_DESCRIPTOR_CONFIGURATION: {
|
||||||
actualLength = MIN(sizeof(uhci_root_hub_configuration_s),
|
actualLength = MIN(sizeof(uhci_root_hub_configuration_s),
|
||||||
transfer->DataLength());
|
transfer->DataLength());
|
||||||
memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig,
|
memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig,
|
||||||
@@ -192,7 +187,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RH_STRING_DESCRIPTOR: {
|
case USB_DESCRIPTOR_STRING: {
|
||||||
uint8 index = request->Value & 0x00ff;
|
uint8 index = request->Value & 0x00ff;
|
||||||
if (index > 2)
|
if (index > 2)
|
||||||
break;
|
break;
|
||||||
@@ -205,7 +200,7 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RH_HUB_DESCRIPTOR: {
|
case USB_DESCRIPTOR_HUB: {
|
||||||
actualLength = MIN(sizeof(usb_hub_descriptor),
|
actualLength = MIN(sizeof(usb_hub_descriptor),
|
||||||
transfer->DataLength());
|
transfer->DataLength());
|
||||||
memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig.hub,
|
memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig.hub,
|
||||||
@@ -216,63 +211,33 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RH_SET_CONFIG:
|
case USB_REQUEST_SET_CONFIGURATION:
|
||||||
status = B_USB_STATUS_SUCCESS;
|
status = B_USB_STATUS_SUCCESS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RH_CLEAR_FEATURE: {
|
case USB_REQUEST_CLEAR_FEATURE: {
|
||||||
if (request->Index == 0) {
|
if (request->Index == 0) {
|
||||||
// We don't support any hub changes
|
// We don't support any hub changes
|
||||||
TRACE_ERROR(("usb_uhci_roothub: RH_CLEAR_FEATURE no hub changes!\n"));
|
TRACE_ERROR(("usb_uhci_roothub: 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"));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE(("usb_uhci_roothub: RH_CLEAR_FEATURE called. Feature: %u!\n", request->Value));
|
TRACE(("usb_uhci_roothub: clear feature: %d\n", request->Value));
|
||||||
uint16 portStatus;
|
if (uhci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK)
|
||||||
switch(request->Value) {
|
status = B_USB_STATUS_SUCCESS;
|
||||||
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;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RH_SET_FEATURE: {
|
case USB_REQUEST_SET_FEATURE: {
|
||||||
if (request->Index == 0) {
|
if (request->Index == 0) {
|
||||||
// We don't support any hub changes
|
// we don't support any hub changes
|
||||||
TRACE_ERROR(("usb_uhci_roothub: RH_SET_FEATURE no hub changes!\n"));
|
TRACE_ERROR(("usb_uhci_roothub: 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"));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE(("usb_uhci_roothub: RH_SET_FEATURE called. Feature: %u!\n", request->Value));
|
TRACE(("usb_uhci_roothub: set feature: %d!\n", request->Value));
|
||||||
switch(request->Value) {
|
if (uhci->SetPortFeature(request->Index - 1, request->Value) >= B_OK)
|
||||||
case PORT_RESET:
|
status = B_USB_STATUS_SUCCESS;
|
||||||
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;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,46 +246,3 @@ UHCIRootHub::SubmitTransfer(Transfer *transfer)
|
|||||||
delete transfer;
|
delete transfer;
|
||||||
return B_OK;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user