* Implemented most qTD and qH functions for EHCI async transfers.

* Implementing control and bulk (async) transfers. They don't work yet though.
* Corrected the legacy support handling in EHCI
* Fixed the bit mask for total bytes in qTDs and added the data toggle bit
* Changed the boolean low speed flags to usb_speed enum that allows for low, full and highspeed

Also wrote a memory allocator that takes over memory management from the stack. It is similar to a buddy allocator. This does on the one hand remove some ugly code from the stack and is on the other hand far more scalable than the previous free list approach. This scalability is needed for proper EHCI support where buffers can go up to a size of 5 pages. The allocator is not perfect and it's memory overhead is quite high compared to the managed memory (depends on the managed block sizes), but it's quik and works well so far.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18849 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2006-09-14 21:59:14 +00:00
parent 770684cf94
commit f452f9dc78
16 changed files with 1192 additions and 288 deletions

View File

@ -12,8 +12,6 @@
BusManager::BusManager(Stack *stack) BusManager::BusManager(Stack *stack)
: fInitOK(false), : fInitOK(false),
fDefaultPipe(NULL),
fDefaultPipeLowSpeed(NULL),
fRootHub(NULL), fRootHub(NULL),
fExploreThread(-1) fExploreThread(-1)
{ {
@ -31,15 +29,14 @@ 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(fRootObject, 0, 0, for (int32 i = 0; i <= USB_SPEED_MAX; i++) {
Pipe::FullSpeed, 8); fDefaultPipes[i] = new(std::nothrow) ControlPipe(fRootObject, 0, 0,
if (!fDefaultPipe) (usb_speed)i, 8);
return; if (!fDefaultPipes[i]) {
TRACE_ERROR(("usb BusManager: failed to allocate default pipes\n"));
fDefaultPipeLowSpeed = new(std::nothrow) ControlPipe(fRootObject, 0, 0, return;
Pipe::LowSpeed, 8); }
if (!fDefaultPipeLowSpeed) }
return;
fInitOK = true; fInitOK = true;
} }
@ -118,7 +115,7 @@ BusManager::AllocateAddress()
Device * Device *
BusManager::AllocateNewDevice(Hub *parent, bool lowSpeed) BusManager::AllocateNewDevice(Hub *parent, usb_speed speed)
{ {
// Check if there is a free entry in the device map (for the device number) // Check if there is a free entry in the device map (for the device number)
int8 deviceAddress = AllocateAddress(); int8 deviceAddress = AllocateAddress();
@ -128,7 +125,7 @@ BusManager::AllocateNewDevice(Hub *parent, bool lowSpeed)
} }
TRACE(("usb BusManager::AllocateNewDevice(): setting device address to %d\n", deviceAddress)); TRACE(("usb BusManager::AllocateNewDevice(): setting device address to %d\n", deviceAddress));
ControlPipe *defaultPipe = (lowSpeed ? fDefaultPipeLowSpeed : fDefaultPipe); ControlPipe *defaultPipe = fDefaultPipes[speed];
status_t result = B_ERROR; status_t result = B_ERROR;
for (int32 i = 0; i < 15; i++) { for (int32 i = 0; i < 15; i++) {
@ -158,8 +155,7 @@ BusManager::AllocateNewDevice(Hub *parent, bool lowSpeed)
snooze(USB_DELAY_SET_ADDRESS); snooze(USB_DELAY_SET_ADDRESS);
// Create a temporary pipe with the new address // Create a temporary pipe with the new address
ControlPipe pipe(parent, deviceAddress, 0, ControlPipe pipe(parent, deviceAddress, 0, speed, 8);
lowSpeed ? Pipe::LowSpeed : Pipe::FullSpeed, 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
@ -197,7 +193,7 @@ BusManager::AllocateNewDevice(Hub *parent, bool lowSpeed)
if (deviceDescriptor.device_class == 0x09) { if (deviceDescriptor.device_class == 0x09) {
TRACE(("usb BusManager::AllocateNewDevice(): creating new hub\n")); TRACE(("usb BusManager::AllocateNewDevice(): creating new hub\n"));
Hub *hub = new(std::nothrow) Hub(parent, deviceDescriptor, Hub *hub = new(std::nothrow) Hub(parent, deviceDescriptor,
deviceAddress, lowSpeed); deviceAddress, speed);
if (!hub) { if (!hub) {
TRACE_ERROR(("usb BusManager::AllocateNewDevice(): no memory to allocate hub\n")); TRACE_ERROR(("usb BusManager::AllocateNewDevice(): no memory to allocate hub\n"));
return NULL; return NULL;
@ -214,7 +210,7 @@ BusManager::AllocateNewDevice(Hub *parent, bool lowSpeed)
TRACE(("usb BusManager::AllocateNewDevice(): creating new device\n")); TRACE(("usb BusManager::AllocateNewDevice(): creating new device\n"));
Device *device = new(std::nothrow) Device(parent, deviceDescriptor, Device *device = new(std::nothrow) Device(parent, deviceDescriptor,
deviceAddress, lowSpeed); deviceAddress, speed);
if (!device) { if (!device) {
TRACE_ERROR(("usb BusManager::AllocateNewDevice(): no memory to allocate device\n")); TRACE_ERROR(("usb BusManager::AllocateNewDevice(): no memory to allocate device\n"));
return NULL; return NULL;

View File

@ -11,13 +11,13 @@
Device::Device(Object *parent, usb_device_descriptor &desc, int8 deviceAddress, Device::Device(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
bool lowSpeed) usb_speed speed)
: Object(parent), : Object(parent),
fDeviceDescriptor(desc), fDeviceDescriptor(desc),
fInitOK(false), fInitOK(false),
fConfigurations(NULL), fConfigurations(NULL),
fCurrentConfiguration(NULL), fCurrentConfiguration(NULL),
fLowSpeed(lowSpeed), fSpeed(speed),
fDeviceAddress(deviceAddress), fDeviceAddress(deviceAddress),
fLock(-1), fLock(-1),
fNotifyCookie(NULL) fNotifyCookie(NULL)
@ -33,8 +33,7 @@ Device::Device(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
set_sem_owner(fLock, B_SYSTEM_TEAM); set_sem_owner(fLock, B_SYSTEM_TEAM);
fDefaultPipe = new(std::nothrow) ControlPipe(this, deviceAddress, 0, fDefaultPipe = new(std::nothrow) ControlPipe(this, deviceAddress, 0,
fLowSpeed ? Pipe::LowSpeed : Pipe::FullSpeed, fSpeed, fDeviceDescriptor.max_packet_size_0);
fDeviceDescriptor.max_packet_size_0);
if (!fDefaultPipe) { if (!fDefaultPipe) {
TRACE_ERROR(("USB Device: could not allocate default pipe\n")); TRACE_ERROR(("USB Device: could not allocate default pipe\n"));
return; return;
@ -189,8 +188,7 @@ Device::Device(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
endpoint = new(std::nothrow) ControlPipe(this, endpoint = new(std::nothrow) ControlPipe(this,
fDeviceAddress, fDeviceAddress,
endpointDescriptor->endpoint_address & 0x0f, endpointDescriptor->endpoint_address & 0x0f,
fLowSpeed ? Pipe::LowSpeed : Pipe::FullSpeed, fSpeed, endpointDescriptor->max_packet_size);
endpointDescriptor->max_packet_size);
break; break;
case 0x01: /* Isochronous Endpoint */ case 0x01: /* Isochronous Endpoint */
@ -198,8 +196,7 @@ Device::Device(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
fDeviceAddress, fDeviceAddress,
endpointDescriptor->endpoint_address & 0x0f, endpointDescriptor->endpoint_address & 0x0f,
(endpointDescriptor->endpoint_address & 0x80) > 0 ? Pipe::In : Pipe::Out, (endpointDescriptor->endpoint_address & 0x80) > 0 ? Pipe::In : Pipe::Out,
fLowSpeed ? Pipe::LowSpeed : Pipe::FullSpeed, fSpeed, endpointDescriptor->max_packet_size);
endpointDescriptor->max_packet_size);
break; break;
case 0x02: /* Bulk Endpoint */ case 0x02: /* Bulk Endpoint */
@ -207,8 +204,7 @@ Device::Device(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
fDeviceAddress, fDeviceAddress,
endpointDescriptor->endpoint_address & 0x0f, endpointDescriptor->endpoint_address & 0x0f,
(endpointDescriptor->endpoint_address & 0x80) > 0 ? Pipe::In : Pipe::Out, (endpointDescriptor->endpoint_address & 0x80) > 0 ? Pipe::In : Pipe::Out,
fLowSpeed ? Pipe::LowSpeed : Pipe::FullSpeed, fSpeed, endpointDescriptor->max_packet_size);
endpointDescriptor->max_packet_size);
break; break;
case 0x03: /* Interrupt Endpoint */ case 0x03: /* Interrupt Endpoint */
@ -216,8 +212,7 @@ Device::Device(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
fDeviceAddress, fDeviceAddress,
endpointDescriptor->endpoint_address & 0x0f, endpointDescriptor->endpoint_address & 0x0f,
(endpointDescriptor->endpoint_address & 0x80) > 0 ? Pipe::In : Pipe::Out, (endpointDescriptor->endpoint_address & 0x80) > 0 ? Pipe::In : Pipe::Out,
fLowSpeed ? Pipe::LowSpeed : Pipe::FullSpeed, fSpeed, endpointDescriptor->max_packet_size);
endpointDescriptor->max_packet_size);
break; break;
} }

View File

@ -12,8 +12,8 @@
Hub::Hub(Object *parent, usb_device_descriptor &desc, int8 deviceAddress, Hub::Hub(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
bool lowSpeed) usb_speed speed)
: Device(parent, desc, deviceAddress, lowSpeed) : Device(parent, desc, deviceAddress, speed)
{ {
TRACE(("USB Hub is being initialised\n")); TRACE(("USB Hub is being initialised\n"));
@ -23,7 +23,7 @@ Hub::Hub(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
} }
// Set to false again for the hub init. // Set to false again for the hub init.
fInitOK = false; fInitOK = false;
for (int32 i = 0; i < 8; i++) for (int32 i = 0; i < 8; i++)
fChildren[i] = NULL; fChildren[i] = NULL;
@ -178,8 +178,14 @@ Hub::Explore()
continue; continue;
} }
usb_speed speed = USB_SPEED_FULLSPEED;
if (fPortStatus[i].status & PORT_STATUS_LOW_SPEED)
speed = USB_SPEED_LOWSPEED;
if (fPortStatus[i].status & PORT_STATUS_HIGH_SPEED)
speed = USB_SPEED_HIGHSPEED;
Device *newDevice = GetBusManager()->AllocateNewDevice(this, Device *newDevice = GetBusManager()->AllocateNewDevice(this,
(fPortStatus[i].status & PORT_STATUS_LOW_SPEED) > 0); speed);
if (newDevice) { if (newDevice) {
fChildren[i] = newDevice; fChildren[i] = newDevice;

View File

@ -19,6 +19,7 @@ KernelStaticLibrary libusb.a :
Pipe.cpp Pipe.cpp
Interface.cpp Interface.cpp
Object.cpp Object.cpp
PhysicalMemoryAllocator.cpp
: -fno-pic : -fno-pic
; ;

View File

@ -0,0 +1,340 @@
/*
* Copyright 2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#include <malloc.h>
#include <string.h>
#include <KernelExport.h>
#include "PhysicalMemoryAllocator.h"
//#define TRACE_PHYSICAL_MEMORY_ALLOCATOR
#ifdef TRACE_PHYSICAL_MEMORY_ALLOCATOR
#define TRACE(x) dprintf x
#define TRACE_ERROR(x) dprintf x
#else
#define TRACE(x) /* nothing */
#define TRACE_ERROR(x) dprintf x
#endif
PhysicalMemoryAllocator::PhysicalMemoryAllocator(const char *name,
size_t minSize, size_t maxSize, uint32 minCountPerBlock)
: fOverhead(0)
{
fName = strdup(name);
if (benaphore_init(&fLock, fName) < B_OK) {
TRACE_ERROR(("PMA: failed to create benaphore lock\n"));
return;
}
fArrayCount = 1;
size_t biggestSize = minSize;
while (biggestSize < maxSize) {
fArrayCount++;
biggestSize *= 2;
}
size_t size = fArrayCount * sizeof(uint8 *);
fArray = (uint8 **)malloc(size);
fOverhead += size;
size = fArrayCount * sizeof(size_t);
fBlockSize = (size_t *)malloc(size);
fArrayLength = (size_t *)malloc(size);
fArrayOffset = (size_t *)malloc(size);
fOverhead += size * 3;
size_t arraySlots = biggestSize / minSize;
for (int32 i = 0; i < fArrayCount; i++) {
size = arraySlots * minCountPerBlock * sizeof(uint8);
fArrayLength[i] = arraySlots * minCountPerBlock;
fBlockSize[i] = biggestSize / arraySlots;
fArrayOffset[i] = fArrayLength[i] - 1;
fArray[i] = (uint8 *)malloc(size);
memset(fArray[i], 0, fArrayLength[i]);
fOverhead += size;
arraySlots /= 2;
}
fManagedMemory = fBlockSize[0] * fArrayLength[0];
size_t roundedSize = biggestSize * minCountPerBlock;
roundedSize = (roundedSize + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
fArea = create_area(fName, &fLogicalBase, B_ANY_KERNEL_ADDRESS,
roundedSize, B_FULL_LOCK | B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
if (fArea < B_OK) {
TRACE_ERROR(("PMA: failed to create memory area\n"));
return;
}
physical_entry physicalEntry;
if (get_memory_map(fLogicalBase, roundedSize, &physicalEntry, 1) < B_OK) {
TRACE_ERROR(("PMA: failed to get memory map\n"));
return;
}
fPhysicalBase = physicalEntry.address;
}
PhysicalMemoryAllocator::~PhysicalMemoryAllocator()
{
_Lock();
for (int32 i = 0; i < fArrayCount; i++)
free(fArray[i]);
free(fArray);
free(fArrayLength);
free(fBlockSize);
free(fArrayOffset);
free(fName);
delete_area(fArea);
benaphore_destroy(&fLock);
}
bool
PhysicalMemoryAllocator::_Lock()
{
return (benaphore_lock(&fLock) == B_OK);
}
void
PhysicalMemoryAllocator::_Unlock()
{
benaphore_unlock(&fLock);
}
status_t
PhysicalMemoryAllocator::Allocate(size_t size, void **logicalAddress,
void **physicalAddress)
{
if (size == 0 || size > fBlockSize[fArrayCount - 1]) {
TRACE_ERROR(("PMA: bad value for allocate (%ld bytes)\n", size));
return B_BAD_VALUE;
}
size_t arrayLength = 0;
int32 arrayToUse = 0;
for (int32 i = 0; i < fArrayCount; i++) {
if (fBlockSize[i] >= size) {
arrayToUse = i;
arrayLength = fArrayLength[i];
break;
}
}
if (!_Lock())
return B_ERROR;
TRACE(("PMA: will use array %ld (blocksize: %ld) to allocate %ld bytes\n", arrayToUse, fBlockSize[arrayToUse], size));
uint8 *targetArray = fArray[arrayToUse];
uint32 arrayOffset = fArrayOffset[arrayToUse] % arrayLength;
for (size_t i = arrayOffset + 1; i != arrayOffset; i++) {
if (i >= arrayLength)
i -= arrayLength;
if (targetArray[i] == 0) {
// found a free slot
fArrayOffset[arrayToUse] = i;
// fill upwards to the smallest block
uint32 fillSize = 1;
uint32 arrayIndex = i;
for (int32 j = arrayToUse; j >= 0; j--) {
memset(&fArray[j][arrayIndex], 1, fillSize);
fillSize <<= 1;
arrayIndex <<= 1;
}
// fill downwards to the biggest block
arrayIndex = i >> 1;
for (int32 j = arrayToUse + 1; j < fArrayCount; j++) {
fArray[j][arrayIndex]++;
if (fArray[j][arrayIndex] > 1)
break;
arrayIndex >>= 1;
}
_Unlock();
size_t offset = fBlockSize[arrayToUse] * i;
*logicalAddress = (void *)((uint8 *)fLogicalBase + offset);
*physicalAddress = (void *)((uint8 *)fPhysicalBase + offset);
return B_OK;
}
}
// no slot found
_Unlock();
TRACE_ERROR(("PMA: found no free slot to store %ld bytes\n", size));
return B_NO_MEMORY;
}
status_t
PhysicalMemoryAllocator::Deallocate(size_t size, void *logicalAddress,
void *physicalAddress)
{
if (size == 0 || size > fBlockSize[fArrayCount - 1]) {
TRACE_ERROR(("PMA: bad value for deallocate (%ld bytes)\n", size));
return B_BAD_VALUE;
}
int32 arrayToUse = 0;
for (int32 i = 0; i < fArrayCount; i++) {
if (fBlockSize[i] >= size) {
arrayToUse = i;
break;
}
}
uint32 offset;
if (logicalAddress)
offset = (uint32)logicalAddress - (uint32)fLogicalBase;
else if (physicalAddress)
offset = (uint32)physicalAddress - (uint32)fPhysicalBase;
else {
TRACE_ERROR(("PMA: no value given for either physical or logical address\n"));
return B_BAD_VALUE;
}
uint32 index = offset / fBlockSize[arrayToUse];
if (index >= fArrayLength[arrayToUse]) {
TRACE_ERROR(("PMA: provided address resulted in invalid index\n"));
return B_BAD_VALUE;
}
TRACE(("PMA: will use array %ld (index: %ld) to deallocate %ld bytes\n", arrayToUse, index, size));
if (fArray[arrayToUse][index] == 0) {
TRACE_ERROR(("PMA: address was not allocated!\n"));
return B_BAD_VALUE;
}
if (!_Lock())
return B_ERROR;
// clear upwards to the smallest block
uint32 fillSize = 1;
uint32 arrayIndex = index;
for (int32 i = arrayToUse; i >= 0; i--) {
memset(&fArray[i][arrayIndex], 0, fillSize);
fillSize <<= 1;
arrayIndex <<= 1;
}
// clear downwards to the biggest block
arrayIndex = index >> 1;
for (int32 i = arrayToUse + 1; i < fArrayCount; i++) {
fArray[i][arrayIndex]--;
if (fArray[i][arrayIndex] > 0)
break;
arrayIndex >>= 1;
}
_Unlock();
return B_OK;
}
void
PhysicalMemoryAllocator::PrintToStream()
{
dprintf("PhysicalMemoryAllocator \"%s\":\n", fName);
dprintf("\tMin block size:\t\t\t%ld bytes\n", fBlockSize[0]);
dprintf("\tMax block size:\t\t\t%ld bytes\n", fBlockSize[fArrayCount - 1]);
dprintf("\tMin count per block:\t%ld\n\n", fArrayLength[fArrayCount - 1]);
dprintf("\tArray count:\t\t\t%ld\n", fArrayCount);
dprintf("\tArray slots:\t\t\t% 8ld", fArrayLength[0]);
for (int32 i = 1; i < fArrayCount; i++)
dprintf(", % 8ld", fArrayLength[i]);
dprintf("\n");
DumpFreeSlots();
dprintf("\tBlock sizes:\t\t\t% 8ld", fBlockSize[0]);
for (int32 i = 1; i < fArrayCount; i++)
dprintf(", % 8ld", fBlockSize[i]);
dprintf("\n");
DumpLastArray();
dprintf("\n");
dprintf("\tManaged memory:\t\t\t%ld bytes\n", fManagedMemory);
dprintf("\tGranularity:\t\t\t%ld bytes\n", fBlockSize[0]);
dprintf("\tMemory overhead:\t\t%ld bytes\n", fOverhead);
}
void
PhysicalMemoryAllocator::DumpArrays()
{
uint32 padding = 2;
for (int32 i = 0; i < fArrayCount; i++) {
dprintf("\tArray(%ld):\t", i);
for (size_t j = 0; j < fArrayLength[i]; j++) {
if (padding > 2) {
for (uint32 k = 0; k < (padding - 2) / 4; k++)
dprintf(" ");
dprintf("\\");
for (uint32 k = 0; k < (padding - 2) / 4; k++)
dprintf("-");
dprintf("%d", fArray[i][j]);
for (uint32 k = 0; k < (padding - 2) / 4; k++)
dprintf("-");
dprintf("/");
for (uint32 k = 0; k < (padding - 2) / 4 + 1; k++)
dprintf(" ");
} else {
dprintf("%d ", fArray[i][j]);
}
}
padding *= 2;
dprintf("\n");
}
dprintf("\n");
}
void
PhysicalMemoryAllocator::DumpLastArray()
{
dprintf("\tLast array:\t\t\t\t");
for (size_t i = 0; i < fArrayLength[fArrayCount - 1]; i++)
dprintf("%d", fArray[fArrayCount - 1][i]);
dprintf("\n");
}
void
PhysicalMemoryAllocator::DumpFreeSlots()
{
dprintf("\tFree slots:\t\t\t\t");
for (int32 i = 0; i < fArrayCount; i++) {
uint32 freeSlots = 0;
for (size_t j = 0; j < fArrayLength[i]; j++) {
if (fArray[i][j] == 0)
freeSlots++;
}
if (i > 0)
dprintf(", % 8ld", freeSlots);
else
dprintf("% 8ld", freeSlots);
}
dprintf("\n");
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef _PHYSICAL_MEMORY_ALLOCATOR_H_
#define _PHYSICAL_MEMORY_ALLOCATOR_H_
#include <SupportDefs.h>
#include <lock.h>
class PhysicalMemoryAllocator {
public:
PhysicalMemoryAllocator(const char *name,
size_t minSize,
size_t maxSize,
uint32 minCountPerBlock);
~PhysicalMemoryAllocator();
status_t Allocate(size_t size,
void **logicalAddress,
void **physicalAddress);
// one of both addresses needs to be provided, the other may be NULL
status_t Deallocate(size_t size,
void *logicalAddress,
void *physicalAddress);
void PrintToStream();
void DumpArrays();
void DumpLastArray();
void DumpFreeSlots();
private:
bool _Lock();
void _Unlock();
char *fName;
size_t fOverhead;
size_t fManagedMemory;
benaphore fLock;
area_id fArea;
void *fLogicalBase;
void *fPhysicalBase;
int32 fArrayCount;
size_t *fBlockSize;
size_t *fArrayLength;
size_t *fArrayOffset;
uint8 **fArray;
};
#endif // !_PHYSICAL_MEMORY_ALLOCATOR_H_

View File

@ -11,7 +11,7 @@
Pipe::Pipe(Object *parent, int8 deviceAddress, uint8 endpointAddress, Pipe::Pipe(Object *parent, int8 deviceAddress, uint8 endpointAddress,
pipeDirection direction, pipeSpeed speed, size_t maxPacketSize) pipeDirection direction, usb_speed speed, size_t maxPacketSize)
: Object(parent), : Object(parent),
fDeviceAddress(deviceAddress), fDeviceAddress(deviceAddress),
fEndpointAddress(endpointAddress), fEndpointAddress(endpointAddress),
@ -94,7 +94,7 @@ Pipe::GetStatus(uint16 *status)
InterruptPipe::InterruptPipe(Object *parent, int8 deviceAddress, InterruptPipe::InterruptPipe(Object *parent, int8 deviceAddress,
uint8 endpointAddress, pipeDirection direction, pipeSpeed speed, uint8 endpointAddress, pipeDirection direction, usb_speed speed,
size_t maxPacketSize) size_t maxPacketSize)
: Pipe(parent, deviceAddress, endpointAddress, direction, speed, : Pipe(parent, deviceAddress, endpointAddress, direction, speed,
maxPacketSize) maxPacketSize)
@ -126,7 +126,7 @@ InterruptPipe::QueueInterrupt(void *data, size_t dataLength,
BulkPipe::BulkPipe(Object *parent, int8 deviceAddress, uint8 endpointAddress, BulkPipe::BulkPipe(Object *parent, int8 deviceAddress, uint8 endpointAddress,
pipeDirection direction, pipeSpeed speed, size_t maxPacketSize) pipeDirection direction, usb_speed speed, size_t maxPacketSize)
: Pipe(parent, deviceAddress, endpointAddress, direction, speed, : Pipe(parent, deviceAddress, endpointAddress, direction, speed,
maxPacketSize) maxPacketSize)
{ {
@ -175,7 +175,7 @@ BulkPipe::QueueBulkV(iovec *vector, size_t vectorCount,
IsochronousPipe::IsochronousPipe(Object *parent, int8 deviceAddress, IsochronousPipe::IsochronousPipe(Object *parent, int8 deviceAddress,
uint8 endpointAddress, pipeDirection direction, pipeSpeed speed, uint8 endpointAddress, pipeDirection direction, usb_speed speed,
size_t maxPacketSize) size_t maxPacketSize)
: Pipe(parent, deviceAddress, endpointAddress, direction, speed, : Pipe(parent, deviceAddress, endpointAddress, direction, speed,
maxPacketSize) maxPacketSize)
@ -206,7 +206,7 @@ typedef struct transfer_result_data_s {
ControlPipe::ControlPipe(Object *parent, int8 deviceAddress, ControlPipe::ControlPipe(Object *parent, int8 deviceAddress,
uint8 endpointAddress, pipeSpeed speed, size_t maxPacketSize) uint8 endpointAddress, usb_speed speed, size_t maxPacketSize)
: Pipe(parent, deviceAddress, endpointAddress, Default, speed, : Pipe(parent, deviceAddress, endpointAddress, Default, speed,
maxPacketSize) maxPacketSize)
{ {

View File

@ -10,6 +10,7 @@
#include <module.h> #include <module.h>
#include <util/kernel_cpp.h> #include <util/kernel_cpp.h>
#include "usb_p.h" #include "usb_p.h"
#include "PhysicalMemoryAllocator.h"
Stack::Stack() Stack::Stack()
@ -29,96 +30,13 @@ Stack::Stack()
fObjectArray = (Object **)malloc(objectArraySize); fObjectArray = (Object **)malloc(objectArraySize);
memset(fObjectArray, 0, objectArraySize); memset(fObjectArray, 0, objectArraySize);
// Initialise the memory chunks: create 8, 16 and 32 byte-heaps fAllocator = new(std::nothrow) PhysicalMemoryAllocator("USB Stack Allocator",
// NOTE: This is probably the most ugly code you will see in the 8, B_PAGE_SIZE * 4, 50);
// whole stack. Unfortunately this is needed because of the fact if (!fAllocator) {
// that the compiler doesn't like us to apply pointer arithmethic TRACE_ERROR(("usb stack: failed to allocate the allocator\n"));
// to (void *) pointers.
// 8-byte heap
fAreaFreeCount[0] = 0;
fAreas[0] = AllocateArea(&fLogical[0], &fPhysical[0], B_PAGE_SIZE,
"8-byte chunk area");
if (fAreas[0] < B_OK) {
TRACE_ERROR(("usb stack: 8-byte chunk area failed to initialise\n"));
return; return;
} }
fListhead8 = (addr_t)fLogical[0];
for (int32 i = 0; i < B_PAGE_SIZE / 8; i++) {
memory_chunk *chunk = (memory_chunk *)((addr_t)fLogical[0] + 8 * i);
chunk->physical = (addr_t)fPhysical[0] + 8 * i;
if (i < B_PAGE_SIZE / 8 - 1)
chunk->next_item = (addr_t)fLogical[0] + 8 * (i + 1);
else
chunk->next_item = 0;
}
// 16-byte heap
fAreaFreeCount[1] = 0;
fAreas[1] = AllocateArea(&fLogical[1], &fPhysical[1], B_PAGE_SIZE,
"16-byte chunk area");
if (fAreas[1] < B_OK) {
TRACE_ERROR(("usb stack: 16-byte chunk area failed to initialise\n"));
return;
}
fListhead16 = (addr_t)fLogical[1];
for (int32 i = 0; i < B_PAGE_SIZE / 16; i++) {
memory_chunk *chunk = (memory_chunk *)((addr_t)fLogical[1] + 16 * i);
chunk->physical = (addr_t)fPhysical[1] + 16 * i;
if (i < B_PAGE_SIZE / 16 - 1)
chunk->next_item = (addr_t)fLogical[1] + 16 * (i + 1);
else
chunk->next_item = 0;
}
// 32-byte heap
fAreaFreeCount[2] = 0;
fAreas[2] = AllocateArea(&fLogical[2], &fPhysical[2], B_PAGE_SIZE,
"32-byte chunk area");
if (fAreas[2] < B_OK) {
TRACE_ERROR(("usb stack: 32-byte chunk area failed to initialise\n"));
return;
}
fListhead32 = (addr_t)fLogical[2];
for (int32 i = 0; i < B_PAGE_SIZE / 32; i++) {
memory_chunk *chunk = (memory_chunk *)((addr_t)fLogical[2] + 32 * i);
chunk->physical = (addr_t)fPhysical[2] + 32 * i;
if (i < B_PAGE_SIZE / 32 - 1)
chunk->next_item = (addr_t)fLogical[2] + 32 * (i + 1);
else
chunk->next_item = 0;
}
// 64-byte heap
fAreaFreeCount[3] = 0;
fAreas[3] = AllocateArea(&fLogical[3], &fPhysical[3], B_PAGE_SIZE,
"64-byte chunk area");
if (fAreas[3] < B_OK) {
TRACE_ERROR(("usb stack: 64-byte chunk area failed to initialise\n"));
return;
}
fListhead64 = (addr_t)fLogical[3];
for (int32 i = 0; i < B_PAGE_SIZE / 64; i++) {
memory_chunk *chunk = (memory_chunk *)((addr_t)fLogical[3] + 64 * i);
chunk->physical = (addr_t)fPhysical[3] + 64 * i;
if (i < B_PAGE_SIZE / 64 - 1)
chunk->next_item = (addr_t)fLogical[3] + 64 * (i + 1);
else
chunk->next_item = 0;
}
// Check for host controller modules // Check for host controller modules
void *moduleList = open_module_list("busses/usb"); void *moduleList = open_module_list("busses/usb");
char moduleName[B_PATH_NAME_LENGTH]; char moduleName[B_PATH_NAME_LENGTH];
@ -155,9 +73,7 @@ Stack::~Stack()
delete (*i); delete (*i);
} }
delete_area(fAreas[0]); delete fAllocator;
delete_area(fAreas[1]);
delete_area(fAreas[2]);
} }
@ -255,93 +171,16 @@ Stack::IndexOfBusManager(BusManager *busManager)
status_t status_t
Stack::AllocateChunk(void **logicalAddress, void **physicalAddress, uint8 size) Stack::AllocateChunk(void **logicalAddress, void **physicalAddress, size_t size)
{ {
Lock(); return fAllocator->Allocate(size, logicalAddress, physicalAddress);
addr_t listhead;
if (size <= 8)
listhead = fListhead8;
else if (size <= 16)
listhead = fListhead16;
else if (size <= 32)
listhead = fListhead32;
else if (size <= 64)
listhead = fListhead64;
else {
TRACE_ERROR(("usb stack: Chunk size %d to big\n", size));
Unlock();
return B_ERROR;
}
if (listhead == 0) {
TRACE_ERROR(("usb stack: Out of memory on this list\n"));
Unlock();
return B_ERROR;
}
TRACE(("usb stack: Stack::Allocate() listhead: 0x%08x\n", listhead));
memory_chunk *chunk = (memory_chunk *)listhead;
*logicalAddress = (void *)listhead;
*physicalAddress = (void *)chunk->physical;
if (chunk->next_item == 0) {
//TODO: allocate more memory
listhead = 0;
} else {
listhead = chunk->next_item;
}
// Update our listhead pointers
if (size <= 8)
fListhead8 = listhead;
else if (size <= 16)
fListhead16 = listhead;
else if (size <= 32)
fListhead32 = listhead;
else if (size <= 64)
fListhead64 = listhead;
Unlock();
TRACE(("usb stack: allocated a new chunk with size %u\n", size));
return B_OK;
} }
status_t status_t
Stack::FreeChunk(void *logicalAddress, void *physicalAddress, uint8 size) Stack::FreeChunk(void *logicalAddress, void *physicalAddress, size_t size)
{ {
Lock(); return fAllocator->Deallocate(size, logicalAddress, physicalAddress);
addr_t listhead;
if (size <= 8)
listhead = fListhead8;
else if (size <= 16)
listhead = fListhead16;
else if (size <= 32)
listhead = fListhead32;
else if (size <= 64)
listhead = fListhead64;
else {
TRACE_ERROR(("usb stack: Chunk size %d invalid\n", size));
Unlock();
return B_ERROR;
}
memory_chunk *chunk = (memory_chunk *)logicalAddress;
chunk->next_item = listhead;
chunk->physical = (addr_t)physicalAddress;
if (size <= 8)
fListhead8 = (addr_t)logicalAddress;
else if (size <= 16)
fListhead16 = (addr_t)logicalAddress;
else if (size <= 32)
fListhead32 = (addr_t)logicalAddress;
else if (size <= 64)
fListhead64 = (addr_t)logicalAddress;
Unlock();
return B_OK;
} }

View File

@ -32,6 +32,7 @@ class Transfer;
class BusManager; class BusManager;
class ControlPipe; class ControlPipe;
class Object; class Object;
class PhysicalMemoryAllocator;
struct host_controller_info { struct host_controller_info {
@ -51,6 +52,14 @@ struct usb_driver_info {
}; };
typedef enum {
USB_SPEED_LOWSPEED = 0,
USB_SPEED_FULLSPEED,
USB_SPEED_HIGHSPEED,
USB_SPEED_MAX = USB_SPEED_HIGHSPEED
} usb_speed;
#define USB_OBJECT_NONE 0x00000000 #define USB_OBJECT_NONE 0x00000000
#define USB_OBJECT_PIPE 0x00000001 #define USB_OBJECT_PIPE 0x00000001
#define USB_OBJECT_CONTROL_PIPE 0x00000002 #define USB_OBJECT_CONTROL_PIPE 0x00000002
@ -80,9 +89,9 @@ public:
int32 IndexOfBusManager(BusManager *bus); int32 IndexOfBusManager(BusManager *bus);
status_t AllocateChunk(void **logicalAddress, status_t AllocateChunk(void **logicalAddress,
void **physicalAddress, uint8 size); void **physicalAddress, size_t size);
status_t FreeChunk(void *logicalAddress, status_t FreeChunk(void *logicalAddress,
void *physicalAddress, uint8 size); void *physicalAddress, size_t size);
area_id AllocateArea(void **logicalAddress, area_id AllocateArea(void **logicalAddress,
void **physicalAddress, void **physicalAddress,
@ -105,15 +114,7 @@ private:
Vector<BusManager *> fBusManagers; Vector<BusManager *> fBusManagers;
benaphore fLock; benaphore fLock;
area_id fAreas[USB_MAX_AREAS]; PhysicalMemoryAllocator *fAllocator;
void *fLogical[USB_MAX_AREAS];
void *fPhysical[USB_MAX_AREAS];
uint16 fAreaFreeCount[USB_MAX_AREAS];
addr_t fListhead8;
addr_t fListhead16;
addr_t fListhead32;
addr_t fListhead64;
uint32 fObjectIndex; uint32 fObjectIndex;
uint32 fObjectMaxCount; uint32 fObjectMaxCount;
@ -140,7 +141,7 @@ virtual status_t InitCheck();
int8 AllocateAddress(); int8 AllocateAddress();
Device *AllocateNewDevice(Hub *parent, Device *AllocateNewDevice(Hub *parent,
bool lowSpeed); usb_speed speed);
virtual status_t Start(); virtual status_t Start();
virtual status_t Stop(); virtual status_t Stop();
@ -160,8 +161,7 @@ static int32 ExploreThread(void *data);
benaphore fLock; benaphore fLock;
bool fDeviceMap[128]; bool fDeviceMap[128];
ControlPipe *fDefaultPipe; ControlPipe *fDefaultPipes[USB_SPEED_MAX + 1];
ControlPipe *fDefaultPipeLowSpeed;
Hub *fRootHub; Hub *fRootHub;
thread_id fExploreThread; thread_id fExploreThread;
Object *fRootObject; Object *fRootObject;
@ -202,20 +202,19 @@ private:
class Pipe : public Object { class Pipe : public Object {
public: public:
enum pipeDirection { In, Out, Default }; enum pipeDirection { In, Out, Default };
enum pipeSpeed { LowSpeed, FullSpeed, HighSpeed };
Pipe(Object *parent, Pipe(Object *parent,
int8 deviceAddress, int8 deviceAddress,
uint8 endpointAddress, uint8 endpointAddress,
pipeDirection direction, pipeDirection direction,
pipeSpeed speed, usb_speed speed,
size_t maxPacketSize); size_t maxPacketSize);
virtual ~Pipe(); virtual ~Pipe();
virtual uint32 Type() { return USB_OBJECT_PIPE; }; virtual uint32 Type() { return USB_OBJECT_PIPE; };
int8 DeviceAddress() { return fDeviceAddress; }; int8 DeviceAddress() { return fDeviceAddress; };
pipeSpeed Speed() { return fSpeed; }; usb_speed Speed() { return fSpeed; };
pipeDirection Direction() { return fDirection; }; pipeDirection Direction() { return fDirection; };
int8 EndpointAddress() { return fEndpointAddress; }; int8 EndpointAddress() { return fEndpointAddress; };
size_t MaxPacketSize() { return fMaxPacketSize; }; size_t MaxPacketSize() { return fMaxPacketSize; };
@ -235,7 +234,7 @@ private:
int8 fDeviceAddress; int8 fDeviceAddress;
uint8 fEndpointAddress; uint8 fEndpointAddress;
pipeDirection fDirection; pipeDirection fDirection;
pipeSpeed fSpeed; usb_speed fSpeed;
size_t fMaxPacketSize; size_t fMaxPacketSize;
bool fDataToggle; bool fDataToggle;
}; };
@ -246,7 +245,7 @@ public:
ControlPipe(Object *parent, ControlPipe(Object *parent,
int8 deviceAddress, int8 deviceAddress,
uint8 endpointAddress, uint8 endpointAddress,
pipeSpeed speed, usb_speed speed,
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; };
@ -283,7 +282,7 @@ public:
int8 deviceAddress, int8 deviceAddress,
uint8 endpointAddress, uint8 endpointAddress,
pipeDirection direction, pipeDirection direction,
pipeSpeed speed, usb_speed speed,
size_t maxPacketSize); size_t maxPacketSize);
virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_INTERRUPT_PIPE; }; virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_INTERRUPT_PIPE; };
@ -301,7 +300,7 @@ public:
int8 deviceAddress, int8 deviceAddress,
uint8 endpointAddress, uint8 endpointAddress,
pipeDirection direction, pipeDirection direction,
pipeSpeed speed, usb_speed speed,
size_t maxPacketSize); size_t maxPacketSize);
virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_BULK_PIPE; }; virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_BULK_PIPE; };
@ -323,7 +322,7 @@ public:
int8 deviceAddress, int8 deviceAddress,
uint8 endpointAddress, uint8 endpointAddress,
pipeDirection direction, pipeDirection direction,
pipeSpeed speed, usb_speed speed,
size_t maxPacketSize); size_t maxPacketSize);
virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_ISO_PIPE; }; virtual uint32 Type() { return USB_OBJECT_PIPE | USB_OBJECT_ISO_PIPE; };
@ -356,7 +355,8 @@ class Device : public Object {
public: public:
Device(Object *parent, Device(Object *parent,
usb_device_descriptor &desc, usb_device_descriptor &desc,
int8 deviceAddress, bool lowSpeed); int8 deviceAddress,
usb_speed speed);
status_t InitCheck(); status_t InitCheck();
@ -397,7 +397,7 @@ protected:
private: private:
usb_configuration_info *fConfigurations; usb_configuration_info *fConfigurations;
usb_configuration_info *fCurrentConfiguration; usb_configuration_info *fCurrentConfiguration;
bool fLowSpeed; usb_speed fSpeed;
int8 fDeviceAddress; int8 fDeviceAddress;
size_t fMaxPacketIn[16]; size_t fMaxPacketIn[16];
size_t fMaxPacketOut[16]; size_t fMaxPacketOut[16];
@ -411,7 +411,8 @@ class Hub : public Device {
public: public:
Hub(Object *parent, Hub(Object *parent,
usb_device_descriptor &desc, usb_device_descriptor &desc,
int8 deviceAddress, bool lowSpeed); int8 deviceAddress,
usb_speed speed);
virtual uint32 Type() { return USB_OBJECT_DEVICE | USB_OBJECT_HUB; }; virtual uint32 Type() { return USB_OBJECT_DEVICE | USB_OBJECT_HUB; };

View File

@ -54,6 +54,48 @@ module_info *modules[] = {
// //
#ifdef TRACE_USB
void
print_descriptor_chain(ehci_qtd *descriptor)
{
while (descriptor) {
dprintf(" %08x n%08x a%08x t%08x %08x %08x %08x %08x %08x s%d\n",
descriptor->this_phy, descriptor->next_phy,
descriptor->alt_next_phy, descriptor->token,
descriptor->buffer_phy[0], descriptor->buffer_phy[1],
descriptor->buffer_phy[2], descriptor->buffer_phy[3],
descriptor->buffer_phy[4], descriptor->buffer_size);
if (descriptor->next_phy & EHCI_QTD_TERMINATE)
break;
descriptor = (ehci_qtd *)descriptor->next_log;
}
}
void
print_queue(ehci_qh *queueHead)
{
dprintf("queue: t%08x n%08x ch%08x ca%08x cu%08x\n",
queueHead->this_phy, queueHead->next_phy, queueHead->endpoint_chars,
queueHead->endpoint_caps, queueHead->current_qtd_phy);
dprintf("overlay: n%08x a%08x t%08x %08x %08x %08x %08x %08x\n",
queueHead->overlay.next_phy, queueHead->overlay.alt_next_phy,
queueHead->overlay.token, queueHead->overlay.buffer_phy[0],
queueHead->overlay.buffer_phy[1], queueHead->overlay.buffer_phy[2],
queueHead->overlay.buffer_phy[3], queueHead->overlay.buffer_phy[4]);
print_descriptor_chain((ehci_qtd *)queueHead->element_log);
}
#endif // TRACE_USB
//
// #pragma mark -
//
EHCI::EHCI(pci_info *info, Stack *stack) EHCI::EHCI(pci_info *info, Stack *stack)
: BusManager(stack), : BusManager(stack),
fPCIInfo(info), fPCIInfo(info),
@ -79,10 +121,6 @@ EHCI::EHCI(pci_info *info, Stack *stack)
TRACE(("usb_ehci: constructing new EHCI Host Controller Driver\n")); TRACE(("usb_ehci: constructing new EHCI Host Controller Driver\n"));
fInitOK = false; fInitOK = false;
// make sure we take the controller away from BIOS
sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 2,
PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN);
// enable busmaster and memory mapped access // enable busmaster and memory mapped access
uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus, uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus,
fPCIInfo->device, fPCIInfo->function, PCI_command, 2); fPCIInfo->device, fPCIInfo->function, PCI_command, 2);
@ -116,9 +154,52 @@ EHCI::EHCI(pci_info *info, Stack *stack)
// read port count from capability register // read port count from capability register
fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f; fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f;
uint32 extendedCapPointer = ReadCapReg32(EHCI_HCCPARAMS) >> EHCI_ECP_SHIFT;
extendedCapPointer &= EHCI_ECP_MASK;
if (extendedCapPointer > 0) {
TRACE(("usb_ehci: extended capabilities register at %d\n", extendedCapPointer));
uint32 legacySupport = sPCIModule->read_pci_config(fPCIInfo->bus,
fPCIInfo->device, fPCIInfo->function, extendedCapPointer, 4);
if ((legacySupport & EHCI_LEGSUP_CAPID_MASK) == EHCI_LEGSUP_CAPID) {
if (legacySupport & EHCI_LEGSUP_BIOSOWNED) {
TRACE(("usb_ehci: the host controller is bios owned\n"));
}
TRACE(("usb_ehci: claiming ownership of the host controller\n"));
sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
fPCIInfo->function, extendedCapPointer, 4, EHCI_LEGSUP_OSOWNED);
for (int32 i = 0; i < 10; i++) {
legacySupport = sPCIModule->read_pci_config(fPCIInfo->bus,
fPCIInfo->device, fPCIInfo->function, extendedCapPointer, 4);
if (legacySupport & EHCI_LEGSUP_BIOSOWNED) {
TRACE(("usb_ehci: controller is still bios owned, waiting\n"));
snooze(50000);
} else
break;
}
if (legacySupport & EHCI_LEGSUP_BIOSOWNED) {
TRACE_ERROR(("usb_ehci: bios won't give up control over the host controller\n"));
return;
} else if (legacySupport & EHCI_LEGSUP_OSOWNED) {
TRACE(("usb_ehci: successfully took ownership of the host controller\n"));
}
} else {
TRACE(("usb_ehci: extended capability is not a legacy support register\n"));
}
} else {
TRACE(("usb_ehci: no extended capabilities register\n"));
}
// disable interrupts // disable interrupts
WriteOpReg(EHCI_USBINTR, 0); WriteOpReg(EHCI_USBINTR, 0);
// reset the segment register
WriteOpReg(EHCI_CTRDSSEGMENT, 0);
// reset the host controller // reset the host controller
if (ControllerReset() < B_OK) { if (ControllerReset() < B_OK) {
TRACE_ERROR(("usb_ehci: host controller failed to reset\n")); TRACE_ERROR(("usb_ehci: host controller failed to reset\n"));
@ -150,11 +231,26 @@ EHCI::EHCI(pci_info *info, Stack *stack)
WriteOpReg(EHCI_PERIODICLISTBASE, (uint32)physicalAddress); WriteOpReg(EHCI_PERIODICLISTBASE, (uint32)physicalAddress);
// route all ports to us // allocate a queue head that will always stay in the async frame list
WriteOpReg(EHCI_CONFIGFLAG, EHCI_CONFIGFLAG_FLAG); fAsyncQueueHead = CreateQueueHead();
if (!fAsyncQueueHead) {
TRACE_ERROR(("usb_ehci: unable to allocate stray async queue head\n"));
return;
}
fAsyncQueueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH;
fAsyncQueueHead->next_log = fAsyncQueueHead;
fAsyncQueueHead->prev_log = fAsyncQueueHead;
fAsyncQueueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH | EHCI_QH_CHARS_RECHEAD;
fAsyncQueueHead->endpoint_caps = 1 << EHCI_QH_CAPS_MULT_SHIFT;
fAsyncQueueHead->current_qtd_phy = EHCI_QTD_TERMINATE;
fAsyncQueueHead->overlay.next_phy = EHCI_QTD_TERMINATE;
WriteOpReg(EHCI_ASYNCLISTADDR, (uint32)fAsyncQueueHead->this_phy
| EHCI_QH_TYPE_QH);
TRACE(("usb_ehci: EHCI Host Controller Driver constructed\n"));
fInitOK = true; fInitOK = true;
TRACE(("usb_ehci: EHCI Host Controller Driver constructed\n"));
} }
@ -167,6 +263,8 @@ EHCI::~EHCI()
wait_for_thread(fFinishThread, &result); wait_for_thread(fFinishThread, &result);
CancelAllPendingTransfers(); CancelAllPendingTransfers();
WriteOpReg(EHCI_USBCMD, 0);
WriteOpReg(EHCI_CONFIGFLAG, 0);
delete fRootHub; delete fRootHub;
delete_area(fPeriodicFrameListArea); delete_area(fPeriodicFrameListArea);
@ -181,7 +279,15 @@ EHCI::Start()
TRACE(("usb_ehci: starting EHCI Host Controller\n")); TRACE(("usb_ehci: starting EHCI Host Controller\n"));
TRACE(("usb_ehci: usbcmd: 0x%08x; usbsts: 0x%08x\n", ReadOpReg(EHCI_USBCMD), ReadOpReg(EHCI_USBSTS))); TRACE(("usb_ehci: usbcmd: 0x%08x; usbsts: 0x%08x\n", ReadOpReg(EHCI_USBCMD), ReadOpReg(EHCI_USBSTS)));
WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_RUNSTOP); uint32 frameListSize = (ReadOpReg(EHCI_USBCMD) >> EHCI_USBCMD_FLS_SHIFT)
& EHCI_USBCMD_FLS_MASK;
WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_RUNSTOP
| EHCI_USBCMD_ASENABLE /*| EHCI_USBCMD_PSENABLE*/
| (frameListSize << EHCI_USBCMD_FLS_SHIFT)
| (2 << EHCI_USBCMD_ITC_SHIFT));
// route all ports to us
WriteOpReg(EHCI_CONFIGFLAG, EHCI_CONFIGFLAG_FLAG);
bool running = false; bool running = false;
for (int32 i = 0; i < 10; i++) { for (int32 i = 0; i < 10; i++) {
@ -226,10 +332,108 @@ EHCI::SubmitTransfer(Transfer *transfer)
if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress) if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
return fRootHub->ProcessTransfer(this, transfer); return fRootHub->ProcessTransfer(this, transfer);
uint32 type = transfer->TransferPipe()->Type();
if ((type & USB_OBJECT_CONTROL_PIPE) > 0
|| (type & USB_OBJECT_BULK_PIPE) > 0) {
TRACE(("usb_ehci: submitting async transfer\n"));
return SubmitAsyncTransfer(transfer);
}
if ((type & USB_OBJECT_INTERRUPT_PIPE) > 0
|| (type & USB_OBJECT_ISO_PIPE) > 0) {
TRACE(("usb_ehci: submitting periodic transfer\n"));
return SubmitPeriodicTransfer(transfer);
}
TRACE_ERROR(("usb_ehci: tried to submit transfer for unknown pipe type %lu\n", type));
return B_ERROR; return B_ERROR;
} }
status_t
EHCI::SubmitAsyncTransfer(Transfer *transfer)
{
ehci_qh *queueHead = CreateQueueHead();
if (!queueHead) {
TRACE_ERROR(("usb_ehci: failed to allocate async queue head\n"));
return B_NO_MEMORY;
}
Pipe *pipe = transfer->TransferPipe();
switch (pipe->Speed()) {
case USB_SPEED_LOWSPEED:
queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_LOW;
break;
case USB_SPEED_FULLSPEED:
queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_FULL;
break;
case USB_SPEED_HIGHSPEED:
queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH;
break;
default:
TRACE_ERROR(("usb_ehci: unknown pipe speed\n"));
FreeQueueHead(queueHead);
return B_ERROR;
}
if (pipe->Type() & USB_OBJECT_CONTROL_PIPE) {
queueHead->endpoint_chars |= EHCI_QH_CHARS_TOGGLE
| (pipe->Speed() != USB_SPEED_HIGHSPEED ? EHCI_QH_CHARS_CONTROL : 0);
}
queueHead->endpoint_chars |= (3 << EHCI_QH_CHARS_RL_SHIFT)
| (pipe->MaxPacketSize() << EHCI_QH_CHARS_MPL_SHIFT)
| (pipe->EndpointAddress() << EHCI_QH_CHARS_EPT_SHIFT)
| (pipe->DeviceAddress() << EHCI_QH_CHARS_DEV_SHIFT);
queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT)
| (0x1c << EHCI_QH_CAPS_SCM_SHIFT);
status_t result;
bool directionIn;
ehci_qtd *dataDescriptor;
if (pipe->Type() & USB_OBJECT_CONTROL_PIPE)
result = FillQueueWithRequest(transfer, queueHead, &dataDescriptor,
&directionIn);
else
result = FillQueueWithData(transfer, queueHead, &dataDescriptor,
&directionIn);
if (result < B_OK) {
TRACE_ERROR(("usb_ehci: failed to fill transfer queue with data\n"));
FreeQueueHead(queueHead);
return result;
}
result = AddPendingTransfer(transfer, queueHead, dataDescriptor, directionIn);
if (result < B_OK) {
TRACE_ERROR(("usb_ehci: failed to add pending transfer\n"));
FreeQueueHead(queueHead);
return result;
}
#ifdef TRACE_USB
TRACE(("usb_ehci: linking queue\n"));
print_queue(queueHead);
#endif
result = LinkQueueHead(queueHead);
if (result < B_OK) {
TRACE_ERROR(("usb_ehci: failed to link queue head to the async list\n"));
FreeQueueHead(queueHead);
return result;
}
return B_OK;
}
status_t
EHCI::SubmitPeriodicTransfer(Transfer *transfer)
{
return B_ERROR;
}
status_t status_t
EHCI::AddTo(Stack *stack) EHCI::AddTo(Stack *stack)
{ {
@ -472,6 +676,11 @@ EHCI::SuspendPort(uint8 index)
status_t status_t
EHCI::ControllerReset() EHCI::ControllerReset()
{ {
// halt the controller first
WriteOpReg(EHCI_USBCMD, 0);
snooze(10000);
// then reset it
WriteOpReg(EHCI_USBCMD, EHCI_USBCMD_HCRESET); WriteOpReg(EHCI_USBCMD, EHCI_USBCMD_HCRESET);
int32 tries = 5; int32 tries = 5;
@ -510,14 +719,58 @@ EHCI::InterruptHandler(void *data)
int32 int32
EHCI::Interrupt() EHCI::Interrupt()
{ {
return B_UNHANDLED_INTERRUPT; // check if any interrupt was generated
uint32 status = ReadOpReg(EHCI_USBSTS);
if ((status & EHCI_USBSTS_INTMASK) == 0)
return B_UNHANDLED_INTERRUPT;
uint32 acknowledge = 0;
if (status & EHCI_USBSTS_USBINT) {
TRACE(("usb_ehci: transfer finished\n"));
acknowledge |= EHCI_USBSTS_USBINT;
fFinishTransfers = true;
}
if (status & EHCI_USBSTS_USBERRINT) {
TRACE(("usb_ehci: transfer error\n"));
acknowledge |= EHCI_USBSTS_USBERRINT;
fFinishTransfers = true;
}
if (status & EHCI_USBSTS_PORTCHANGE) {
TRACE(("usb_ehci: port change detected\n"));
acknowledge |= EHCI_USBSTS_PORTCHANGE;
}
if (status & EHCI_USBSTS_FLROLLOVER) {
TRACE(("usb_ehci: frame list rolled over\n"));
acknowledge |= EHCI_USBSTS_FLROLLOVER;
}
if (status & EHCI_USBSTS_INTONAA) {
TRACE(("usb_ehci: interrupt on async advance\n"));
acknowledge |= EHCI_USBSTS_INTONAA;
}
if (status & EHCI_USBSTS_HOSTSYSERR) {
TRACE_ERROR(("usb_ehci: host system error!\n"));
acknowledge |= EHCI_USBSTS_HOSTSYSERR;
print_queue(fAsyncQueueHead);
if (fAsyncQueueHead->next_log) {
print_queue((ehci_qh *)fAsyncQueueHead->next_log);
}
}
if (acknowledge)
WriteOpReg(EHCI_USBSTS, acknowledge);
return B_HANDLED_INTERRUPT;
} }
status_t status_t
EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead, EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead,
ehci_qtd *firstDescriptor, ehci_qtd *dataDescriptor, ehci_qtd *dataDescriptor, bool directionIn)
ehci_qtd *lastDescriptor, bool directionIn)
{ {
transfer_data *data = new(std::nothrow) transfer_data(); transfer_data *data = new(std::nothrow) transfer_data();
if (!data) if (!data)
@ -525,9 +778,7 @@ EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead,
data->transfer = transfer; data->transfer = transfer;
data->queue_head = queueHead; data->queue_head = queueHead;
data->first_descriptor = firstDescriptor;
data->data_descriptor = dataDescriptor; data->data_descriptor = dataDescriptor;
data->last_descriptor = lastDescriptor;
data->incoming = directionIn; data->incoming = directionIn;
data->link = NULL; data->link = NULL;
@ -599,6 +850,8 @@ EHCI::CancelAllPendingTransfers()
transfer = next; transfer = next;
} }
fFirstTransfer = NULL;
fLastTransfer = NULL;
Unlock(); Unlock();
return B_OK; return B_OK;
} }
@ -661,38 +914,298 @@ EHCI::FinishTransfers()
} }
ehci_qtd * ehci_qh *
EHCI::CreateDescriptor(Pipe *pipe, size_t bufferSize) EHCI::CreateQueueHead()
{ {
return NULL; ehci_qh *result;
void *physicalAddress;
if (fStack->AllocateChunk((void **)&result, &physicalAddress,
sizeof(ehci_qh)) < B_OK) {
TRACE_ERROR(("usb_ehci: failed to allocate queue head\n"));
return NULL;
}
result->this_phy = (addr_t)physicalAddress;
result->next_phy = EHCI_QH_TERMINATE;
result->next_log = NULL;
result->prev_log = NULL;
ehci_qtd *descriptor = CreateDescriptor(0, 0);
if (!descriptor) {
TRACE_ERROR(("usb_ehci: failed to allocate initial qtd for queue head\n"));
fStack->FreeChunk(result, (void *)result->this_phy, sizeof(ehci_qh));
return NULL;
}
descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
result->stray_log = descriptor;
result->element_log = descriptor;
result->current_qtd_phy = EHCI_QTD_TERMINATE;
result->overlay.next_phy = descriptor->this_phy;
result->overlay.alt_next_phy = EHCI_QTD_TERMINATE;
result->overlay.token = 0;
result->overlay.buffer_phy[0] = 0;
result->overlay.buffer_phy[1] = 0;
result->overlay.buffer_phy[2] = 0;
result->overlay.buffer_phy[3] = 0;
result->overlay.buffer_phy[4] = 0;
return result;
}
void
EHCI::FreeQueueHead(ehci_qh *queueHead)
{
if (!queueHead)
return;
FreeDescriptor((ehci_qtd *)queueHead->stray_log);
fStack->FreeChunk(queueHead, (void *)queueHead->this_phy, sizeof(ehci_qh));
} }
status_t status_t
EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **firstDescriptor, EHCI::LinkQueueHead(ehci_qh *queueHead)
ehci_qtd **lastDescriptor, size_t bufferSize) {
if (!Lock())
return B_ERROR;
ehci_qh *prevHead = (ehci_qh *)fAsyncQueueHead->prev_log;
queueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH;
queueHead->next_log = fAsyncQueueHead;
queueHead->prev_log = prevHead;
fAsyncQueueHead->prev_log = queueHead;
prevHead->next_log = queueHead;
prevHead->next_phy = queueHead->this_phy | EHCI_QH_TYPE_QH;
Unlock();
return B_OK;
}
status_t
EHCI::UnlinkQueueHead(ehci_qh *queueHead)
{
if (!Lock())
return B_ERROR;
ehci_qh *prevHead = (ehci_qh *)queueHead->prev_log;
ehci_qh *nextHead = (ehci_qh *)queueHead->next_log;
prevHead->next_phy = queueHead->next_phy | EHCI_QH_TYPE_QH;
prevHead->next_log = queueHead->next_log;
nextHead->prev_log = queueHead->prev_log;
queueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH;
queueHead->next_log = NULL;
queueHead->prev_log = NULL;
Unlock();
return B_OK;
}
status_t
EHCI::FillQueueWithRequest(Transfer *transfer, ehci_qh *queueHead,
ehci_qtd **_dataDescriptor, bool *_directionIn)
{
Pipe *pipe = transfer->TransferPipe();
usb_request_data *requestData = transfer->RequestData();
bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
ehci_qtd *setupDescriptor = CreateDescriptor(sizeof(usb_request_data),
EHCI_QTD_PID_SETUP);
ehci_qtd *statusDescriptor = CreateDescriptor(0,
directionIn ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN);
if (!setupDescriptor || !statusDescriptor) {
TRACE_ERROR(("usb_ehci: failed to allocate descriptors\n"));
FreeDescriptor(setupDescriptor);
FreeDescriptor(statusDescriptor);
return B_NO_MEMORY;
}
iovec vector;
vector.iov_base = requestData;
vector.iov_len = sizeof(usb_request_data);
WriteDescriptorChain(setupDescriptor, &vector, 1);
ehci_qtd *strayDescriptor = (ehci_qtd *)queueHead->stray_log;
statusDescriptor->token |= EHCI_QTD_IOC | EHCI_QTD_DATA_TOGGLE;
LinkDescriptors(statusDescriptor, strayDescriptor, strayDescriptor);
ehci_qtd *dataDescriptor = NULL;
if (transfer->VectorCount() > 0) {
ehci_qtd *lastDescriptor = NULL;
status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
&lastDescriptor, strayDescriptor, transfer->VectorLength(),
directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
if (result < B_OK) {
FreeDescriptor(setupDescriptor);
FreeDescriptor(statusDescriptor);
return result;
}
if (!directionIn) {
WriteDescriptorChain(dataDescriptor, transfer->Vector(),
transfer->VectorCount());
}
LinkDescriptors(setupDescriptor, dataDescriptor, strayDescriptor);
LinkDescriptors(lastDescriptor, statusDescriptor, strayDescriptor);
} else {
// no data: link setup and status descriptors directly
LinkDescriptors(setupDescriptor, statusDescriptor, strayDescriptor);
}
queueHead->element_log = setupDescriptor;
queueHead->overlay.next_phy = setupDescriptor->this_phy;
queueHead->overlay.alt_next_phy = EHCI_QTD_TERMINATE;
*_dataDescriptor = dataDescriptor;
*_directionIn = directionIn;
return B_OK;
}
status_t
EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead,
ehci_qtd **dataDescriptor, bool *directionIn)
{ {
*firstDescriptor = NULL;
*lastDescriptor = NULL;
return B_ERROR; return B_ERROR;
} }
ehci_qtd *
EHCI::CreateDescriptor(size_t bufferSize, uint8 pid)
{
ehci_qtd *result;
void *physicalAddress;
if (fStack->AllocateChunk((void **)&result, &physicalAddress,
sizeof(ehci_qtd)) < B_OK) {
TRACE_ERROR(("usb_ehci: failed to allocate a qtd\n"));
return NULL;
}
result->this_phy = (addr_t)physicalAddress;
result->next_phy = EHCI_QTD_TERMINATE;
result->next_log = NULL;
result->alt_next_phy = EHCI_QTD_TERMINATE;
result->alt_next_log = NULL;
result->buffer_size = bufferSize;
result->token = bufferSize << EHCI_QTD_BYTES_SHIFT;
result->token |= 3 << EHCI_QTD_ERRCOUNT_SHIFT;
result->token |= pid << EHCI_QTD_PID_SHIFT;
result->token |= EHCI_QTD_STATUS_ACTIVE;
if (bufferSize == 0) {
result->buffer_log = NULL;
result->buffer_phy[0] = 0;
result->buffer_phy[1] = 0;
result->buffer_phy[2] = 0;
result->buffer_phy[3] = 0;
result->buffer_phy[4] = 0;
return result;
}
if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress,
bufferSize) < B_OK) {
TRACE_ERROR(("usb_ehci: unable to allocate qtd buffer\n"));
fStack->FreeChunk(result, (void *)result->this_phy, sizeof(ehci_qtd));
return NULL;
}
addr_t physicalBase = (addr_t)physicalAddress;
result->buffer_phy[0] = physicalBase;
for (int32 i = 1; i < 5; i++) {
physicalBase += B_PAGE_SIZE;
result->buffer_phy[i] = physicalBase & EHCI_QTD_PAGE_MASK;
}
return result;
}
status_t
EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor,
ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize,
uint8 pid)
{
size_t packetSize = pipe->MaxPacketSize();
int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
bool dataToggle = pipe->DataToggle();
ehci_qtd *firstDescriptor = NULL;
ehci_qtd *lastDescriptor = *_firstDescriptor;
for (int32 i = 0; i < descriptorCount; i++) {
ehci_qtd *descriptor = CreateDescriptor(min_c(packetSize, bufferSize),
pid);
if (!descriptor) {
FreeDescriptorChain(firstDescriptor);
return B_NO_MEMORY;
}
if (dataToggle)
descriptor->token |= EHCI_QTD_DATA_TOGGLE;
if (lastDescriptor)
LinkDescriptors(lastDescriptor, descriptor, strayDescriptor);
dataToggle = !dataToggle;
bufferSize -= packetSize;
lastDescriptor = descriptor;
if (!firstDescriptor)
firstDescriptor = descriptor;
}
*_firstDescriptor = firstDescriptor;
*_lastDescriptor = lastDescriptor;
return B_OK;
}
void void
EHCI::FreeDescriptor(ehci_qtd *descriptor) EHCI::FreeDescriptor(ehci_qtd *descriptor)
{ {
if (!descriptor)
return;
if (descriptor->buffer_log) {
fStack->FreeChunk(descriptor->buffer_log,
(void *)descriptor->buffer_phy[0], descriptor->buffer_size);
}
fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(ehci_qtd));
} }
void void
EHCI::FreeDescriptorChain(ehci_qtd *topDescriptor) EHCI::FreeDescriptorChain(ehci_qtd *topDescriptor)
{ {
ehci_qtd *current = topDescriptor;
ehci_qtd *next = NULL;
while (current) {
next = (ehci_qtd *)current->next_log;
FreeDescriptor(current);
current = next;
}
} }
void void
EHCI::LinkDescriptors(ehci_qtd *first, ehci_qtd *last) EHCI::LinkDescriptors(ehci_qtd *first, ehci_qtd *last, ehci_qtd *alt)
{ {
first->next_phy = last->this_phy;
first->next_log = last;
if (alt) {
first->alt_next_phy = alt->this_phy;
first->alt_next_log = alt;
} else {
first->alt_next_phy = EHCI_QTD_TERMINATE;
first->alt_next_log = NULL;
}
} }
@ -700,7 +1213,50 @@ size_t
EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
size_t vectorCount) size_t vectorCount)
{ {
return 0; ehci_qtd *current = topDescriptor;
size_t actualLength = 0;
size_t vectorIndex = 0;
size_t vectorOffset = 0;
size_t bufferOffset = 0;
while (current) {
if (!current->buffer_log)
break;
while (true) {
size_t length = min_c(current->buffer_size - bufferOffset,
vector[vectorIndex].iov_len - vectorOffset);
memcpy((uint8 *)current->buffer_log + bufferOffset,
(uint8 *)vector[vectorIndex].iov_base + vectorOffset, length);
actualLength += length;
vectorOffset += length;
bufferOffset += length;
if (vectorOffset >= vector[vectorIndex].iov_len) {
if (++vectorIndex >= vectorCount) {
TRACE(("usb_ehci: wrote descriptor chain (%d bytes, no more vectors)\n", actualLength));
return actualLength;
}
vectorOffset = 0;
}
if (bufferOffset >= current->buffer_size) {
bufferOffset = 0;
break;
}
}
if (current->next_phy & EHCI_QTD_TERMINATE)
break;
current = (ehci_qtd *)current->next_log;
}
TRACE(("usb_ehci: wrote descriptor chain (%d bytes)\n", actualLength));
return actualLength;
} }
@ -708,14 +1264,83 @@ size_t
EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
size_t vectorCount, uint8 *lastDataToggle) size_t vectorCount, uint8 *lastDataToggle)
{ {
return 0; uint32 dataToggle = 0;
ehci_qtd *current = topDescriptor;
size_t actualLength = 0;
size_t vectorIndex = 0;
size_t vectorOffset = 0;
size_t bufferOffset = 0;
while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) > 0) {
if (!current->buffer_log)
break;
dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
size_t bufferSize = 0; // ToDo
while (true) {
size_t length = min_c(bufferSize - bufferOffset,
vector[vectorIndex].iov_len - vectorOffset);
memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
(uint8 *)current->buffer_log + bufferOffset, length);
actualLength += length;
vectorOffset += length;
bufferOffset += length;
if (vectorOffset >= vector[vectorIndex].iov_len) {
if (++vectorIndex >= vectorCount) {
TRACE(("usb_ehci: read descriptor chain (%d bytes, no more vectors)\n", actualLength));
if (lastDataToggle)
*lastDataToggle = dataToggle > 0 ? 1 : 0;
return actualLength;
}
vectorOffset = 0;
}
if (bufferOffset >= bufferSize) {
bufferOffset = 0;
break;
}
}
if (current->next_phy & EHCI_QTD_TERMINATE)
break;
current = (ehci_qtd *)current->next_log;
}
TRACE(("usb_ehci: read descriptor chain (%d bytes)\n", actualLength));
if (lastDataToggle)
*lastDataToggle = dataToggle > 0 ? 1 : 0;
return actualLength;
} }
size_t size_t
EHCI::ReadActualLength(ehci_qtd *topDescriptor, uint8 *lastDataToggle) EHCI::ReadActualLength(ehci_qtd *topDescriptor, uint8 *lastDataToggle)
{ {
return 0; size_t actualLength = 0;
ehci_qtd *current = topDescriptor;
uint32 dataToggle = 0;
while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) > 0) {
dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
size_t length = 0; // ToDo
actualLength += length;
if (current->next_phy & EHCI_QTD_TERMINATE)
break;
current = (ehci_qtd *)current->next_log;
}
TRACE(("usb_ehci: read actual length (%d bytes)\n", actualLength));
if (lastDataToggle)
*lastDataToggle = dataToggle > 0 ? 1 : 0;
return actualLength;
} }

View File

@ -22,9 +22,7 @@ class EHCIRootHub;
typedef struct transfer_data_s { typedef struct transfer_data_s {
Transfer *transfer; Transfer *transfer;
ehci_qh *queue_head; ehci_qh *queue_head;
ehci_qtd *first_descriptor;
ehci_qtd *data_descriptor; ehci_qtd *data_descriptor;
ehci_qtd *last_descriptor;
bool incoming; bool incoming;
transfer_data_s *link; transfer_data_s *link;
} transfer_data; } transfer_data;
@ -37,6 +35,8 @@ public:
status_t Start(); status_t Start();
virtual status_t SubmitTransfer(Transfer *transfer); virtual status_t SubmitTransfer(Transfer *transfer);
status_t SubmitPeriodicTransfer(Transfer *transfer);
status_t SubmitAsyncTransfer(Transfer *transfer);
static status_t AddTo(Stack *stack); static status_t AddTo(Stack *stack);
@ -61,9 +61,7 @@ static int32 InterruptHandler(void *data);
// Transfer management // Transfer management
status_t AddPendingTransfer(Transfer *transfer, status_t AddPendingTransfer(Transfer *transfer,
ehci_qh *queueHead, ehci_qh *queueHead,
ehci_qtd *firstDescriptor,
ehci_qtd *dataDescriptor, ehci_qtd *dataDescriptor,
ehci_qtd *lastDescriptor,
bool directionIn); bool directionIn);
status_t CancelPendingTransfer(Transfer *transfer); status_t CancelPendingTransfer(Transfer *transfer);
status_t CancelAllPendingTransfers(); status_t CancelAllPendingTransfers();
@ -71,19 +69,38 @@ static int32 InterruptHandler(void *data);
static int32 FinishThread(void *data); static int32 FinishThread(void *data);
void FinishTransfers(); void FinishTransfers();
// Queue Head functions
ehci_qh *CreateQueueHead();
void FreeQueueHead(ehci_qh *queueHead);
status_t LinkQueueHead(ehci_qh *queueHead);
status_t UnlinkQueueHead(ehci_qh *queueHead);
// Queue functions
status_t FillQueueWithRequest(Transfer *transfer,
ehci_qh *queueHead,
ehci_qtd **dataDescriptor,
bool *directionIn);
status_t FillQueueWithData(Transfer *transfer,
ehci_qh *queueHead,
ehci_qtd **dataDescriptor,
bool *directionIn);
// Descriptor functions // Descriptor functions
ehci_qtd *CreateDescriptor(Pipe *pipe, ehci_qtd *CreateDescriptor(size_t bufferSizeToAllocate,
size_t bufferSizeToAllocate); uint8 pid);
status_t CreateDescriptorChain(Pipe *pipe, status_t CreateDescriptorChain(Pipe *pipe,
ehci_qtd **firstDescriptor, ehci_qtd **firstDescriptor,
ehci_qtd **lastDescriptor, ehci_qtd **lastDescriptor,
size_t bufferSizeToAllocate); ehci_qtd *strayDescriptor,
size_t bufferSizeToAllocate,
uint8 pid);
void FreeDescriptor(ehci_qtd *descriptor); void FreeDescriptor(ehci_qtd *descriptor);
void FreeDescriptorChain(ehci_qtd *topDescriptor); void FreeDescriptorChain(ehci_qtd *topDescriptor);
void LinkDescriptors(ehci_qtd *first, void LinkDescriptors(ehci_qtd *first,
ehci_qtd *last); ehci_qtd *last, ehci_qtd *alt);
size_t WriteDescriptorChain(ehci_qtd *topDescriptor, size_t WriteDescriptorChain(ehci_qtd *topDescriptor,
iovec *vector, size_t vectorCount); iovec *vector, size_t vectorCount);
@ -114,6 +131,9 @@ static pci_module_info *sPCIModule;
area_id fPeriodicFrameListArea; area_id fPeriodicFrameListArea;
addr_t *fPeriodicFrameList; addr_t *fPeriodicFrameList;
// Async frame list
ehci_qh *fAsyncQueueHead;
// Maintain a linked list of transfers // Maintain a linked list of transfers
transfer_data *fFirstTransfer; transfer_data *fFirstTransfer;
transfer_data *fLastTransfer; transfer_data *fLastTransfer;

View File

@ -56,6 +56,7 @@
#define EHCI_USBSTS_PORTCHANGE (1 << 2) // Port Change Detected #define EHCI_USBSTS_PORTCHANGE (1 << 2) // Port Change Detected
#define EHCI_USBSTS_USBERRINT (1 << 1) // USB Error Interrupt #define EHCI_USBSTS_USBERRINT (1 << 1) // USB Error Interrupt
#define EHCI_USBSTS_USBINT (1 << 0) // USB Interrupt #define EHCI_USBSTS_USBINT (1 << 0) // USB Interrupt
#define EHCI_USBSTS_INTMASK 0x3f
// USB Interrupt Enable Register (EHCI Spec 2.3.3) // USB Interrupt Enable Register (EHCI Spec 2.3.3)
@ -96,9 +97,13 @@
#define EHCI_PORTSC_DATAMASK 0xffffffd5 #define EHCI_PORTSC_DATAMASK 0xffffffd5
// PCI Registers // Extended Capabilities
#define PCI_LEGSUP 0xc0 // PCI Legacy Support #define EHCI_ECP_SHIFT 8 // Extended Capability Pointer
#define PCI_LEGSUP_USBPIRQDEN 0x2000 // USB PIRQ #define EHCI_ECP_MASK 0xff
#define EHCI_LEGSUP_CAPID_MASK 0xff
#define EHCI_LEGSUP_CAPID 0x01
#define EHCI_LEGSUP_OSOWNED (1 << 24) // OS Owned Semaphore
#define EHCI_LEGSUP_BIOSOWNED (1 << 16) // BIOS Owned Semaphore
// Data Structures (EHCI Spec 3) // Data Structures (EHCI Spec 3)
@ -119,7 +124,7 @@ typedef struct {
// Hardware Part // Hardware Part
addr_t next_phy; addr_t next_phy;
addr_t alt_next_phy; addr_t alt_next_phy;
uint32 status_token; uint32 token;
addr_t buffer_phy[5]; addr_t buffer_phy[5];
// Software Part // Software Part
@ -132,15 +137,19 @@ typedef struct {
#define EHCI_QTD_TERMINATE (1 << 0) #define EHCI_QTD_TERMINATE (1 << 0)
#define EHCI_QTD_DATA_TOGGLE (1 << 31)
#define EHCI_QTD_BYTES_SHIFT 16 #define EHCI_QTD_BYTES_SHIFT 16
#define EHCI_QTD_BYTES_MASK 0xffff #define EHCI_QTD_BYTES_MASK 0x7fff
#define EHCI_QTD_IOC (1 << 15) #define EHCI_QTD_IOC (1 << 15)
#define EHCI_QTD_PAGE_SHIFT 12 #define EHCI_QTD_CPAGE_SHIFT 12
#define EHCI_QTD_PAGE_MASK 0x07 #define EHCI_QTD_CPAGE_MASK 0x07
#define EHCI_QTD_ERRCOUNT_SHIFT 10 #define EHCI_QTD_ERRCOUNT_SHIFT 10
#define EHCI_QTD_ERRCOUNT_MASK 0x03 #define EHCI_QTD_ERRCOUNT_MASK 0x03
#define EHCI_QTD_PID_SHIFT 8 #define EHCI_QTD_PID_SHIFT 8
#define EHCI_QTD_PID_MASK 0x03 #define EHCI_QTD_PID_MASK 0x03
#define EHCI_QTD_PID_OUT 0x00
#define EHCI_QTD_PID_IN 0x01
#define EHCI_QTD_PID_SETUP 0x02
#define EHCI_QTD_STATUS_SHIFT 0 #define EHCI_QTD_STATUS_SHIFT 0
#define EHCI_QTD_STATUS_MASK 0x7f #define EHCI_QTD_STATUS_MASK 0x7f
#define EHCI_QTD_STATUS_ACTIVE (1 << 7) // Active #define EHCI_QTD_STATUS_ACTIVE (1 << 7) // Active
@ -151,19 +160,29 @@ typedef struct {
#define EHCI_QTD_STATUS_MISSED (1 << 2) // Missed Micro-Frame #define EHCI_QTD_STATUS_MISSED (1 << 2) // Missed Micro-Frame
#define EHCI_QTD_STATUS_SPLIT (1 << 1) // Split Transaction State #define EHCI_QTD_STATUS_SPLIT (1 << 1) // Split Transaction State
#define EHCI_QTD_STATUS_PING (1 << 0) // Ping State #define EHCI_QTD_STATUS_PING (1 << 0) // Ping State
#define EHCI_QTD_PAGE_MASK 0xfffff000
// Queue Head (QH, EHCI Spec 3.6) // Queue Head (QH, EHCI Spec 3.6)
typedef struct { typedef struct {
// Hardware Part // Hardware Part
addr_t link_phy; addr_t next_phy;
uint32 endpoint_chars; uint32 endpoint_chars;
uint32 endpoint_caps; uint32 endpoint_caps;
addr_t current_qtd_phy; addr_t current_qtd_phy;
uint32 overlay[8];
struct {
addr_t next_phy;
addr_t alt_next_phy;
uint32 token;
addr_t buffer_phy[5];
} overlay;
// Software Part // Software Part
addr_t this_phy; addr_t this_phy;
void *link_log; void *next_log;
void *prev_log;
void *stray_log;
void *element_log; void *element_log;
} ehci_qh; } ehci_qh;

View File

@ -122,7 +122,7 @@ static ehci_root_hub_string_s sEHCIRootHubStrings[3] = {
EHCIRootHub::EHCIRootHub(Object *rootObject, int8 deviceAddress) EHCIRootHub::EHCIRootHub(Object *rootObject, int8 deviceAddress)
: Hub(rootObject, sEHCIRootHubDevice, deviceAddress, false) : Hub(rootObject, sEHCIRootHubDevice, deviceAddress, USB_SPEED_HIGHSPEED)
{ {
} }

View File

@ -88,7 +88,7 @@ usb_hub_descriptor ohci_hubd =
//Implementation //Implementation
OHCIRootHub::OHCIRootHub( OHCI *ohci , int8 devicenum ) OHCIRootHub::OHCIRootHub( OHCI *ohci , int8 devicenum )
: Hub( ohci->RootObject() , ohci_devd , devicenum , false ) : Hub( ohci->RootObject() , ohci_devd , devicenum , USB_SPEED_FULLSPEED )
{ {
m_ohci = ohci; m_ohci = ohci;
} }

View File

@ -99,7 +99,8 @@ Queue::Queue(Stack *stack)
} }
void *physicalAddress; void *physicalAddress;
fStatus = fStack->AllocateChunk((void **)&fQueueHead, &physicalAddress, 32); fStatus = fStack->AllocateChunk((void **)&fQueueHead, &physicalAddress,
sizeof(uhci_qh));
if (fStatus < B_OK) if (fStatus < B_OK)
return; return;
@ -116,10 +117,11 @@ Queue::~Queue()
Lock(); Lock();
benaphore_destroy(&fLock); benaphore_destroy(&fLock);
fStack->FreeChunk(fQueueHead, (void *)fQueueHead->this_phy, 32); fStack->FreeChunk(fQueueHead, (void *)fQueueHead->this_phy, sizeof(uhci_qh));
if (fStrayDescriptor) if (fStrayDescriptor)
fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy, 32); fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy,
sizeof(uhci_td));
} }
@ -168,7 +170,7 @@ Queue::TerminateByStrayDescriptor()
// descriptor in order to get some chipset to work nicely (like the PIIX). // descriptor in order to get some chipset to work nicely (like the PIIX).
void *physicalAddress; void *physicalAddress;
status_t result = fStack->AllocateChunk((void **)&fStrayDescriptor, status_t result = fStack->AllocateChunk((void **)&fStrayDescriptor,
&physicalAddress, 32); &physicalAddress, sizeof(uhci_td));
if (result < B_OK) { if (result < B_OK) {
TRACE_ERROR(("usb_uhci: failed to allocate a stray transfer descriptor\n")); TRACE_ERROR(("usb_uhci: failed to allocate a stray transfer descriptor\n"));
return result; return result;
@ -186,7 +188,7 @@ Queue::TerminateByStrayDescriptor()
if (!Lock()) { if (!Lock()) {
fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy, fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy,
32); sizeof(uhci_td));
return B_ERROR; return B_ERROR;
} }
@ -1104,14 +1106,15 @@ UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, size_t bufferSize)
uhci_td *result; uhci_td *result;
void *physicalAddress; void *physicalAddress;
if (fStack->AllocateChunk((void **)&result, &physicalAddress, 32) < B_OK) { if (fStack->AllocateChunk((void **)&result, &physicalAddress,
sizeof(uhci_td)) < B_OK) {
TRACE_ERROR(("usb_uhci: failed to allocate a transfer descriptor\n")); TRACE_ERROR(("usb_uhci: failed to allocate a transfer descriptor\n"));
return NULL; return NULL;
} }
result->this_phy = (addr_t)physicalAddress; result->this_phy = (addr_t)physicalAddress;
result->status = TD_STATUS_ACTIVE | TD_CONTROL_3_ERRORS | TD_CONTROL_SPD; result->status = TD_STATUS_ACTIVE | TD_CONTROL_3_ERRORS | TD_CONTROL_SPD;
if (pipe->Speed() == Pipe::LowSpeed) if (pipe->Speed() == USB_SPEED_LOWSPEED)
result->status |= TD_CONTROL_LOWSPEED; result->status |= TD_CONTROL_LOWSPEED;
result->buffer_size = bufferSize; result->buffer_size = bufferSize;
@ -1134,7 +1137,7 @@ UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, size_t bufferSize)
if (fStack->AllocateChunk(&result->buffer_log, &result->buffer_phy, if (fStack->AllocateChunk(&result->buffer_log, &result->buffer_phy,
bufferSize) < B_OK) { bufferSize) < B_OK) {
TRACE_ERROR(("usb_uhci: unable to allocate space for the buffer\n")); TRACE_ERROR(("usb_uhci: unable to allocate space for the buffer\n"));
fStack->FreeChunk(result, (void *)result->this_phy, 32); fStack->FreeChunk(result, (void *)result->this_phy, sizeof(uhci_td));
return NULL; return NULL;
} }
@ -1192,7 +1195,7 @@ UHCI::FreeDescriptor(uhci_td *descriptor)
(void *)descriptor->buffer_phy, descriptor->buffer_size); (void *)descriptor->buffer_phy, descriptor->buffer_size);
} }
fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, 32); fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(uhci_td));
} }

View File

@ -126,7 +126,7 @@ static uhci_root_hub_string_s sUHCIRootHubStrings[3] = {
UHCIRootHub::UHCIRootHub(Object *rootObject, int8 deviceAddress) UHCIRootHub::UHCIRootHub(Object *rootObject, int8 deviceAddress)
: Hub(rootObject, sUHCIRootHubDevice, deviceAddress, false) : Hub(rootObject, sUHCIRootHubDevice, deviceAddress, USB_SPEED_FULLSPEED)
{ {
} }