* Adding skeleton EHCI driver. Some parts filled from the specs and the UHCI driver.

* Corrected some errors I found while reading UHCI.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18626 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2006-08-25 21:43:21 +00:00
parent f8b41f8219
commit 9e857d24ca
13 changed files with 1117 additions and 26 deletions
@@ -133,7 +133,7 @@ Stack::Stack()
if (get_module(moduleName, (module_info **)&module) != B_OK)
continue;
if (module->add_to(*this) != B_OK)
if (module->add_to(this) < B_OK)
continue;
TRACE(("usb stack: module %s successfully loaded\n", moduleName));
+1 -1
View File
@@ -37,7 +37,7 @@ class Object;
struct host_controller_info {
module_info info;
status_t (*control)(uint32 op, void *data, size_t length);
bool (*add_to)(Stack &stack);
status_t (*add_to)(Stack *stack);
};
+6
View File
@@ -24,3 +24,9 @@ KernelAddon <usb>ohci : [ FDirName kernel busses usb ] :
: ohci.rdef
;
KernelAddon <usb>ehci : [ FDirName kernel busses usb ] :
ehci.cpp
ehci_rh.cpp
: libusb.a
: ehci.rdef
;
+575
View File
@@ -0,0 +1,575 @@
/*
* Copyright 2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <[email protected]>
*/
#include <module.h>
#include <PCI.h>
#include <USB3.h>
#include <KernelExport.h>
#include "ehci.h"
pci_module_info *EHCI::sPCIModule = NULL;
static int32
ehci_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
TRACE(("usb_ehci_module: init module\n"));
return B_OK;
case B_MODULE_UNINIT:
TRACE(("usb_ehci_module: uninit module\n"));
return B_OK;
}
return EINVAL;
}
host_controller_info ehci_module = {
{
"busses/usb/ehci",
NULL,
ehci_std_ops
},
NULL,
EHCI::AddTo
};
module_info *modules[] = {
(module_info *)&ehci_module,
NULL
};
//
// #pragma mark -
//
EHCI::EHCI(pci_info *info, Stack *stack)
: BusManager(stack),
fPCIInfo(info),
fStack(stack),
fPeriodicFrameListArea(-1),
fPeriodicFrameList(NULL),
fAsyncFrameListArea(-1),
fAsyncFrameList(NULL),
fFirstTransfer(NULL),
fLastTransfer(NULL),
fFinishTransfers(false),
fFinishThread(-1),
fStopFinishThread(false),
fRootHub(NULL),
fRootHubAddress(0)
{
if (!fInitOK) {
TRACE_ERROR(("usb_ehci: bus manager failed to init\n"));
return;
}
TRACE(("usb_ehci: constructing new EHCI Host Controller Driver\n"));
fInitOK = false;
fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus,
fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4);
fRegisterBase &= PCI_address_io_mask;
TRACE(("usb_ehci: register base: 0x%08x\n", fRegisterBase));
// enable pci address access
uint16 command = PCI_command_io | PCI_command_master | PCI_command_memory;
command |= sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device,
fPCIInfo->function, PCI_command, 2);
sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
fPCIInfo->function, PCI_command, 2, command);
// make sure we take the controller away from BIOS
sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 2,
PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN);
// disable interrupts
WriteReg16(EHCI_USBINTR, 0);
// reset the host controller
// ToDo...
// allocate the periodic frame list
void *physicalAddress;
fPeriodicFrameListArea = fStack->AllocateArea((void **)&fPeriodicFrameList,
&physicalAddress, B_PAGE_SIZE, "USB EHCI Periodic Framelist");
if (fPeriodicFrameListArea < B_OK) {
TRACE_ERROR(("usb_ehci: unable to allocate periodic framelist\n"));
return;
}
WriteReg32(EHCI_PERIODICLISTBASE, (uint32)physicalAddress);
// allocate the async frame list
fAsyncFrameListArea = fStack->AllocateArea((void **)&fAsyncFrameList,
&physicalAddress, B_PAGE_SIZE, "USB EHCI Async Framelist");
if (fAsyncFrameListArea < B_OK) {
TRACE_ERROR(("usb_ehci: unable to allocate async framelist\n"));
}
WriteReg32(EHCI_ASYNCLISTADDR, (uint32)physicalAddress);
// create finisher service thread
fFinishThread = spawn_kernel_thread(FinishThread, "ehci finish thread",
B_NORMAL_PRIORITY, (void *)this);
resume_thread(fFinishThread);
// install the interrupt handler and enable interrupts
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
InterruptHandler, (void *)this, 0);
WriteReg16(EHCI_USBINTR, EHCI_USBINTR_HOSTSYSERR
| EHCI_USBINTR_USBERRINT | EHCI_USBINTR_USBINT);
TRACE(("usb_ehci: EHCI Host Controller Driver constructed\n"));
fInitOK = true;
}
EHCI::~EHCI()
{
TRACE(("usb_ehci: tear down EHCI Host Controller Driver\n"));
int32 result = 0;
fStopFinishThread = true;
wait_for_thread(fFinishThread, &result);
CancelAllPendingTransfers();
delete fRootHub;
delete_area(fPeriodicFrameListArea);
delete_area(fAsyncFrameListArea);
put_module(B_PCI_MODULE_NAME);
}
status_t
EHCI::Start()
{
TRACE(("usb_ehci: starting EHCI Host Controller\n"));
TRACE(("usb_ehci: usbcmd: 0x%08x; usbsts: 0x%08x\n", ReadReg32(EHCI_USBCMD), ReadReg32(EHCI_USBSTS)));
WriteReg32(EHCI_USBCMD, ReadReg32(EHCI_USBCMD) | EHCI_USBCMD_RUNSTOP);
bool running = false;
for (int32 i = 0; i < 10; i++) {
uint32 status = ReadReg32(EHCI_USBSTS);
TRACE(("usb_ehci: try %ld: status 0x%08x\n", i, status));
if (status & EHCI_USBSTS_HCHALTED) {
snooze(10000);
} else {
running = true;
break;
}
}
if (!running) {
TRACE(("usb_ehci: Host Controller didn't start\n"));
return B_ERROR;
}
fRootHubAddress = AllocateAddress();
fRootHub = new(std::nothrow) EHCIRootHub(this, fRootHubAddress);
if (!fRootHub) {
TRACE_ERROR(("usb_ehci: no memory to allocate root hub\n"));
return B_NO_MEMORY;
}
if (fRootHub->InitCheck() < B_OK) {
TRACE_ERROR(("usb_ehci: root hub failed init check\n"));
return fRootHub->InitCheck();
}
SetRootHub(fRootHub);
TRACE(("usb_ehci: Host Controller started\n"));
return BusManager::Start();
}
status_t
EHCI::SubmitTransfer(Transfer *transfer)
{
return B_ERROR;
}
status_t
EHCI::SubmitRequest(Transfer *transfer)
{
return B_ERROR;
}
status_t
EHCI::AddTo(Stack *stack)
{
#ifdef TRACE_USB
set_dprintf_enabled(true);
load_driver_symbols("ehci");
#endif
if (!sPCIModule) {
status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule);
if (status < B_OK) {
TRACE_ERROR(("usb_ehci: getting pci module failed! 0x%08lx\n", status));
return status;
}
}
TRACE(("usb_ehci: searching devices\n"));
bool found = false;
pci_info *item = new(std::nothrow) pci_info;
if (!item) {
sPCIModule = NULL;
put_module(B_PCI_MODULE_NAME);
return B_NO_MEMORY;
}
for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) {
// class_base: 0C (Serial Bus); class_sub: 03 (USB); class_api: 20 (EHCI)
if (item->class_base == 0x0C && item->class_sub == 0x03
&& item->class_api == 0x20) {
if (item->u.h0.interrupt_line == 0
|| item->u.h0.interrupt_line == 0xFF) {
TRACE_ERROR(("usb_ehci: found device with invalid IRQ - check IRQ assignement\n"));
continue;
}
TRACE(("usb_ehci: found device at IRQ %u\n", item->u.h0.interrupt_line));
EHCI *bus = new(std::nothrow) EHCI(item, stack);
if (!bus) {
delete item;
sPCIModule = NULL;
put_module(B_PCI_MODULE_NAME);
return B_NO_MEMORY;
}
if (bus->InitCheck() < B_OK) {
TRACE_ERROR(("usb_ehci: bus failed init check\n"));
delete bus;
continue;
}
// the bus took it away
item = new(std::nothrow) pci_info;
bus->Start();
stack->AddBusManager(bus);
found = true;
}
}
if (!found) {
TRACE_ERROR(("usb_ehci: no devices found\n"));
delete item;
sPCIModule = NULL;
put_module(B_PCI_MODULE_NAME);
return ENODEV;
}
delete item;
return B_OK;
}
status_t
EHCI::ResetPort(int32 index)
{
return B_ERROR;
}
status_t
EHCI::ControllerReset()
{
return B_ERROR;
}
status_t
EHCI::LightReset()
{
return B_ERROR;
}
int32
EHCI::InterruptHandler(void *data)
{
cpu_status status = disable_interrupts();
spinlock lock = 0;
acquire_spinlock(&lock);
int32 result = ((EHCI *)data)->Interrupt();
release_spinlock(&lock);
restore_interrupts(status);
return result;
}
int32
EHCI::Interrupt()
{
return B_UNHANDLED_INTERRUPT;
}
status_t
EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead,
ehci_qtd *firstDescriptor, ehci_qtd *dataDescriptor,
ehci_qtd *lastDescriptor, bool directionIn)
{
transfer_data *data = new(std::nothrow) transfer_data();
if (!data)
return B_NO_MEMORY;
data->transfer = transfer;
data->queue_head = queueHead;
data->first_descriptor = firstDescriptor;
data->data_descriptor = dataDescriptor;
data->last_descriptor = lastDescriptor;
data->incoming = directionIn;
data->link = NULL;
if (!Lock()) {
delete data;
return B_ERROR;
}
if (fLastTransfer)
fLastTransfer->link = data;
else
fFirstTransfer = data;
fLastTransfer = data;
Unlock();
return B_OK;
}
status_t
EHCI::CancelPendingTransfer(Transfer *transfer)
{
if (!Lock())
return B_ERROR;
transfer_data *last = NULL;
transfer_data *current = fFirstTransfer;
while (current) {
if (current->transfer == transfer) {
current->transfer->Finished(B_USB_STATUS_IRP_CANCELLED_BY_REQUEST, 0);
delete current->transfer;
if (last)
last->link = current->link;
else
fFirstTransfer = current->link;
if (fLastTransfer == current)
fLastTransfer = last;
delete current;
Unlock();
return B_OK;
}
last = current;
current = current->link;
}
Unlock();
return B_BAD_VALUE;
}
status_t
EHCI::CancelAllPendingTransfers()
{
if (!Lock())
return B_ERROR;
transfer_data *transfer = fFirstTransfer;
while (transfer) {
transfer->transfer->Finished(B_USB_STATUS_IRP_CANCELLED_BY_REQUEST, 0);
delete transfer->transfer;
transfer_data *next = transfer->link;
delete transfer;
transfer = next;
}
Unlock();
return B_OK;
}
int32
EHCI::FinishThread(void *data)
{
((EHCI *)data)->FinishTransfers();
return B_OK;
}
void
EHCI::FinishTransfers()
{
while (!fStopFinishThread) {
while (!fFinishTransfers) {
if (fStopFinishThread)
return;
snooze(1000);
}
fFinishTransfers = false;
if (!Lock())
continue;
TRACE(("usb_ehci: finishing transfers\n"));
transfer_data *lastTransfer = NULL;
transfer_data *transfer = fFirstTransfer;
Unlock();
while (transfer) {
bool transferDone = false;
// ToDo...
if (transferDone) {
if (Lock()) {
if (lastTransfer)
lastTransfer->link = transfer->link;
if (transfer == fFirstTransfer)
fFirstTransfer = transfer->link;
if (transfer == fLastTransfer)
fLastTransfer = lastTransfer;
transfer_data *next = transfer->link;
delete transfer->transfer;
delete transfer;
transfer = next;
Unlock();
}
} else {
lastTransfer = transfer;
transfer = transfer->link;
}
}
}
}
ehci_qtd *
EHCI::CreateDescriptor(Pipe *pipe, size_t bufferSize)
{
return NULL;
}
status_t
EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **firstDescriptor,
ehci_qtd **lastDescriptor, size_t bufferSize)
{
*firstDescriptor = NULL;
*lastDescriptor = NULL;
return B_ERROR;
}
void
EHCI::FreeDescriptor(ehci_qtd *descriptor)
{
}
void
EHCI::FreeDescriptorChain(ehci_qtd *topDescriptor)
{
}
void
EHCI::LinkDescriptors(ehci_qtd *first, ehci_qtd *last)
{
}
size_t
EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
size_t vectorCount)
{
return 0;
}
size_t
EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
size_t vectorCount, uint8 *lastDataToggle)
{
return 0;
}
size_t
EHCI::ReadActualLength(ehci_qtd *topDescriptor, uint8 *lastDataToggle)
{
return 0;
}
inline void
EHCI::WriteReg8(uint32 reg, uint8 value)
{
sPCIModule->write_io_8(fRegisterBase + reg, value);
}
inline void
EHCI::WriteReg16(uint32 reg, uint16 value)
{
sPCIModule->write_io_16(fRegisterBase + reg, value);
}
inline void
EHCI::WriteReg32(uint32 reg, uint32 value)
{
sPCIModule->write_io_32(fRegisterBase + reg, value);
}
inline uint8
EHCI::ReadReg8(uint32 reg)
{
return sPCIModule->read_io_8(fRegisterBase + reg);
}
inline uint16
EHCI::ReadReg16(uint32 reg)
{
return sPCIModule->read_io_16(fRegisterBase + reg);
}
inline uint32
EHCI::ReadReg32(uint32 reg)
{
return sPCIModule->read_io_32(fRegisterBase + reg);
}
+136
View File
@@ -0,0 +1,136 @@
/*
* Copyright 2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <[email protected]>
*/
#ifndef EHCI_H
#define EHCI_H
#include "usb_p.h"
#include "ehci_hardware.h"
struct pci_info;
struct pci_module_info;
class EHCIRootHub;
typedef struct transfer_data_s {
Transfer *transfer;
ehci_qh *queue_head;
ehci_qtd *first_descriptor;
ehci_qtd *data_descriptor;
ehci_qtd *last_descriptor;
bool incoming;
transfer_data_s *link;
} transfer_data;
class EHCI : public BusManager {
public:
EHCI(pci_info *info, Stack *stack);
~EHCI();
status_t Start();
virtual status_t SubmitTransfer(Transfer *transfer);
virtual status_t SubmitRequest(Transfer *transfer);
static status_t AddTo(Stack *stack);
// Port operations for root hub
status_t ResetPort(int32 index);
private:
// Controller resets
status_t ControllerReset();
status_t LightReset();
// Interrupt functions
static int32 InterruptHandler(void *data);
int32 Interrupt();
// Transfer management
status_t AddPendingTransfer(Transfer *transfer,
ehci_qh *queueHead,
ehci_qtd *firstDescriptor,
ehci_qtd *dataDescriptor,
ehci_qtd *lastDescriptor,
bool directionIn);
status_t CancelPendingTransfer(Transfer *transfer);
status_t CancelAllPendingTransfers();
static int32 FinishThread(void *data);
void FinishTransfers();
// Descriptor functions
ehci_qtd *CreateDescriptor(Pipe *pipe,
size_t bufferSizeToAllocate);
status_t CreateDescriptorChain(Pipe *pipe,
ehci_qtd **firstDescriptor,
ehci_qtd **lastDescriptor,
size_t bufferSizeToAllocate);
void FreeDescriptor(ehci_qtd *descriptor);
void FreeDescriptorChain(ehci_qtd *topDescriptor);
void LinkDescriptors(ehci_qtd *first,
ehci_qtd *last);
size_t WriteDescriptorChain(ehci_qtd *topDescriptor,
iovec *vector, size_t vectorCount);
size_t ReadDescriptorChain(ehci_qtd *topDescriptor,
iovec *vector, size_t vectorCount,
uint8 *lastDataToggle);
size_t ReadActualLength(ehci_qtd *topDescriptor,
uint8 *lastDataToggle);
// Register functions
inline void WriteReg8(uint32 reg, uint8 value);
inline void WriteReg16(uint32 reg, uint16 value);
inline void WriteReg32(uint32 reg, uint32 value);
inline uint8 ReadReg8(uint32 reg);
inline uint16 ReadReg16(uint32 reg);
inline uint32 ReadReg32(uint32 reg);
static pci_module_info *sPCIModule;
uint32 fRegisterBase;
pci_info *fPCIInfo;
Stack *fStack;
// Framelist memory
area_id fPeriodicFrameListArea;
addr_t *fPeriodicFrameList;
area_id fAsyncFrameListArea;
addr_t *fAsyncFrameList;
// Maintain a linked list of transfers
transfer_data *fFirstTransfer;
transfer_data *fLastTransfer;
bool fFinishTransfers;
thread_id fFinishThread;
bool fStopFinishThread;
// Root Hub
EHCIRootHub *fRootHub;
uint8 fRootHubAddress;
};
class EHCIRootHub : public Hub {
public:
EHCIRootHub(EHCI *ehci, int8 deviceAddress);
status_t SubmitTransfer(Transfer *transfer);
void UpdatePortStatus();
private:
usb_port_status fPortStatus[2];
EHCI *fEHCI;
};
#endif // !EHCI_H
+15
View File
@@ -0,0 +1,15 @@
/*
* ehci.rdef
*/
resource app_signature "application/x-vnd.haiku-ehci";
resource app_version {
major = 0,
middle = 0,
minor = 1,
variety = 0,
internal = 0,
short_info = "EHCI host controller driver",
long_info = "Haiku EHCI HCD - Copyright 2006, Haiku Inc."
};
@@ -0,0 +1,225 @@
/*
* Copyright 2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <[email protected]>
*/
#ifndef EHCI_HARDWARE_H
#define EHCI_HARDWARE_H
// Host Controller Operational Registers (EHCI Spec 2.3)
#define EHCI_USBCMD 0x00 // USB Command
#define EHCI_USBSTS 0x04 // USB Status
#define EHCI_USBINTR 0x08 // USB Interrupt Enable
#define EHCI_FRINDEX 0x0c // USB Frame Index
#define EHCI_CTRDSSEGMENT 0x10 // 4GB Segment Selector
#define EHCI_PERIODICLISTBASE 0x14 // Frame List Base Address
#define EHCI_ASYNCLISTADDR 0x18 // Next Asynchronous List Address
#define EHCI_CONFIGFLAG 0x40 // Configured Flag Register
#define EHCI_PORTSC 0x44 // Port Status/Control
// USB Command Register (EHCI Spec 2.3.1)
#define EHCI_USBCMD_ITC_SHIFT 16 // Interrupt Threshold Control
#define EHCI_USBCMD_ITC_MASK 0xff
#define EHCI_USBCMD_ASPME (1 << 11) // Async Schedule Park Mode Enable
#define EHCI_USBCMD_ASPMC_SHIFT 8 // Async Schedule Park Mode Count
#define EHCI_USBCMD_ASPMC_MASK 0x03
#define EHCI_USBCMD_LHCRESET (1 << 7) // Light Host Controller Reset
#define EHCI_USBCMD_INTONAAD (1 << 6) // Interrupt on Async Advance Dorbell
#define EHCI_USBCMD_ASENABLE (1 << 5) // Asynchronous Schedule Enable
#define EHCI_USBCMD_PSENABLE (1 << 4) // Periodic Schedule Enable
#define EHCI_USBCMD_FLS_SHIFT 2 // Frame List Size
#define EHCI_USBCMD_FLS_MASK 0x03
#define EHCI_USBCMD_HCRESET (1 << 1) // Host Controller Reset
#define EHCI_USBCMD_RUNSTOP (1 << 0) // Run/Stop
// USB Status Register (EHCI Spec 2.3.2)
#define EHCI_USBSTS_ASSTATUS (1 << 15) // Asynchronous Schedule Status
#define EHCI_USBSTS_PSSTATUS (1 << 14) // Periodic Schedule Status
#define EHCI_USBSTS_RECLAMATION (1 << 13) // Reclamation
#define EHCI_USBSTS_HCHALTED (1 << 12) // Host Controller Halted
#define EHCI_USBSTS_INTONAA (1 << 5) // Interrupt on Async Advance
#define EHCI_USBSTS_HOSTSYSERR (1 << 4) // Host System Error
#define EHCI_USBSTS_FLROLLOVER (1 << 3) // Frame List Rollover
#define EHCI_USBSTS_PORTCHANGE (1 << 2) // Port Change Detected
#define EHCI_USBSTS_USBERRINT (1 << 1) // USB Error Interrupt
#define EHCI_USBSTS_USBINT (1 << 0) // USB Interrupt
// USB Interrupt Enable Register (EHCI Spec 2.3.3)
#define EHCI_USBINTR_INTONAA (1 << 5) // Interrupt on Async Advance Enable
#define EHCI_USBINTR_HOSTSYSERR (1 << 4) // Host System Error Enable
#define EHCI_USBINTR_FLROLLOVER (1 << 3) // Frame List Rollover Enable
#define EHCI_USBINTR_PORTCHANGE (1 << 2) // Port Change Interrupt Enable
#define EHCI_USBINTR_USBERRINT (1 << 1) // USB Error Interrupt Enable
#define EHCI_USBINTR_USBINT (1 << 0) // USB Interrupt Enable
// Configure Flag Register (EHCI Spec 2.3.8)
#define EHCI_CONFIGFLAG_FLAG (1 << 0) // Configure Flag
// Port Status and Control (EHCI Spec 2.3.9)
#define EHCI_PORTSC_WAKEOVERCUR (1 << 22) // Wake on Over-Current Enable
#define EHCI_PORTSC_WAKEDISCON (1 << 21) // Wake on Disconnect Enable
#define EHCI_PORTSC_WAKECONNECT (1 << 20) // Wake on Connect Enable
#define EHCI_PORTSC_PTC_SHIFT 16 // Port Test Control
#define EHCI_PORTSC_PTC_MASK 0x07
#define EHCI_PORTSC_PIC_SHIFT 14 // Port Indicator Control
#define EHCI_PORTSC_PIC_MASK 0x03
#define EHCI_PORTSC_PORTOWNER (1 << 13) // Port Owner
#define EHCI_PORTSC_PORTPOWER (1 << 12) // Port Power
#define EHCI_PORTSC_DPLUS (1 << 11) // Logical Level of D+
#define EHCI_PORTSC_DMINUS (1 << 10) // Logical Level of D-
#define EHCI_PORTSC_PORTRESET (1 << 8) // Port Reset
#define EHCI_PORTSC_SUSPEND (1 << 7) // Suspend
#define EHCI_PORTSC_FORCERESUME (1 << 6) // Force Port Resume
#define EHCI_PORTSC_OCCHANGE (1 << 5) // Over-Current Change
#define EHCI_PORTSC_OCACTIVE (1 << 4) // Over-Current Active
#define EHCI_PORTSC_ENDISCHANGE (1 << 3) // Port Enable/Disable Change
#define EHCI_PORTSC_ENDIS (1 << 2) // Port Enabled/Disabled
#define EHCI_PORTSC_CONNCHANGE (1 << 1) // Connect Status Change
#define EHCI_PORTSC_CONNSTATUS (1 << 0) // Current Connect Status
// PCI Registers
#define PCI_LEGSUP 0xc0 // PCI Legacy Support
#define PCI_LEGSUP_USBPIRQDEN 0x2000 // USBP IRQ Deny
// Data Structures (EHCI Spec 3)
// Periodic Frame List Element Flags (EHCI Spec 3.1)
#define EHCI_PFRAMELIST_ITD 0x00 // Isochronous Transfer Descriptor
#define EHCI_PFRAMELIST_QH 0x01 // Queue Head
#define EHCI_PFRAMELIST_SITD 0x10 // Split Transaction Isochronous TD
#define EHCI_PFRAMELIST_FSTN 0x11 // Frame Span Traversal Node
// ToDo: Isochronous (High-Speed) Transfer Descriptors (iTD, EHCI Spec 3.2)
// ToDo: Split Transaction Isochronous Transfer Descriptors (siTD, EHCI Spec 3.3)
// Queue Element Transfer Descriptors (qTD, EHCI Spec 3.5)
typedef struct {
// Hardware Part
addr_t next_phy;
addr_t alt_next_phy;
uint32 status_token;
addr_t buffer_phy[5];
// Software Part
addr_t this_phy;
void *next_log;
void *alt_next_log;
size_t buffer_size;
void *buffer_log;
} ehci_qtd;
#define EHCI_QTD_TERMINATE (1 << 0)
#define EHCI_QTD_BYTES_SHIFT 16
#define EHCI_QTD_BYTES_MASK 0xffff
#define EHCI_QTD_IOC (1 << 15)
#define EHCI_QTD_PAGE_SHIFT 12
#define EHCI_QTD_PAGE_MASK 0x07
#define EHCI_QTD_ERRCOUNT_SHIFT 10
#define EHCI_QTD_ERRCOUNT_MASK 0x03
#define EHCI_QTD_PID_SHIFT 8
#define EHCI_QTD_PID_MASK 0x03
#define EHCI_QTD_STATUS_SHIFT 0
#define EHCI_QTD_STATUS_MASK 0x7f
#define EHCI_QTD_STATUS_ACTIVE (1 << 7) // Active
#define EHCI_QTD_STATUS_HALTED (1 << 6) // Halted
#define EHCI_QTD_STATUS_BUFFER (1 << 5) // Data Buffer Error
#define EHCI_QTD_STATUS_BABBLE (1 << 4) // Babble Detected
#define EHCI_QTD_STATUS_TERROR (1 << 3) // Transaction Error
#define EHCI_QTD_STATUS_MISSED (1 << 2) // Missed Micro-Frame
#define EHCI_QTD_STATUS_SPLIT (1 << 1) // Split Transaction State
#define EHCI_QTD_STATUS_PING (1 << 0) // Ping State
// Queue Head (QH, EHCI Spec 3.6)
typedef struct {
// Hardware Part
addr_t link_phy;
uint32 endpoint_chars;
uint32 endpoint_caps;
addr_t current_qtd_phy;
uint32 overlay[8];
// Software Part
addr_t this_phy;
void *link_log;
void *element_log;
} ehci_qh;
// Applies to ehci_qh.link_phy
#define EHCI_QH_TYPE_ITD (0 << 1)
#define EHCI_QH_TYPE_QH (1 << 1)
#define EHCI_QH_TYPE_SITD (2 << 1)
#define EHCI_QH_TYPE_FSTN (3 << 1)
#define EHCI_QH_TERMINATE (1 << 0)
// Applies to ehci_qh.endpoint_chars
#define EHCI_QH_CHARS_RL_SHIFT 28 // NAK Count Reload
#define EHCI_QH_CHARS_RL_MASK 0x07
#define EHCI_QH_CHARS_CONTROL (1 << 27) // Control Endpoint Flag
#define EHCI_QH_CHARS_MPL_SHIFT 16 // Max Packet Length
#define EHCI_QH_CHARS_MPL_MASK 0x03ff
#define EHCI_QH_CHARS_RECHEAD (1 << 15) // Head of Reclamation List Flag
#define EHCI_QH_CHARS_TOGGLE (1 << 14) // Data Toggle Control
#define EHCI_QH_CHARS_EPS_FULL (0 << 12) // Endpoint is Full-Speed
#define EHCI_QH_CHARS_EPS_LOW (1 << 12) // Endpoint is Low-Speed
#define EHCI_QH_CHARS_EPS_HIGH (2 << 12) // Endpoint is High-Speed
#define EHCI_QH_CHARS_EPT_SHIFT 8 // Endpoint Number
#define EHCI_QH_CHARS_EPT_MASK 0x0f
#define EHCI_QH_CHARS_INACTIVE (1 << 7) // Inactive on Next Transaction
#define EHCI_QH_CHARS_DEV_SHIFT 0 // Device Address
#define EHCI_QH_CHARS_DEV_MASK 0x7f
// Applies to ehci_qh.endpoint_caps
#define EHCI_QH_CAPS_MULT_SHIFT 30 // Transactions per Micro-Frame
#define EHCI_QH_CAPS_MULT_MASK 0x03
#define EHCI_QH_CAPS_PORT_SHIFT 23 // Port Number
#define EHCI_QH_CAPS_PORT_MASK 0x7f
#define EHCI_QH_CAPS_HUB_SHIFT 16 // Hub Address
#define EHCI_QH_CAPS_HUB_MASK 0x7f
#define EHCI_QH_CAPS_SCM_SHIFT 8 // Split Completion Mask
#define EHCI_QH_CAPS_SCM_MASK 0xff
#define EHCI_QH_CAPS_ISM_SHIFT 0 // Interrupt Schedule Mask
#define EHCI_QH_CAPS_ISM_MASK 0xff
// Applies to ehci_qh.overlay[EHCI_QH_OL_*_INDEX]
#define EHCI_QH_OL_NAK_INDEX 1 // NAK Counter
#define EHCI_QH_OL_NAK_SHIFT 1
#define EHCI_QH_OL_NAK_MASK 0x0f
#define EHCI_QH_OL_TOGGLE_INDEX 2 // Data Toggle
#define EHCI_QH_OL_TOGGLE (1 << 31)
#define EHCI_QH_OL_IOC_INDEX 2 // Interrupt on Complete
#define EHCI_QH_OL_IOC (1 << 15)
#define EHCI_QH_OL_ERRC_INDEX 2 // Error Counter
#define EHCI_QH_OL_ERRC_SHIFT 10
#define EHCI_QH_OL_ERRC_MASK 0x03
#define EHCI_QH_OL_PING_INDEX 2 // Ping State
#define EHCI_QH_OL_PING (1 << 0)
#define EHCI_QH_OL_CPROG_INDEX 4 // Split-Transaction Complete-Split Progress
#define EHCI_QH_OL_CPROG_SHIFT 0
#define EHCI_QH_OL_CPROG_MASK 0xff
#define EHCI_QH_OL_FTAG_INDEX 5 // Split-Transaction Frame Tag
#define EHCI_QH_OL_FTAG_SHIFT 0
#define EHCI_QH_OL_FTAG_MASK 0x0f
#define EHCI_QH_OL_BYTES_INDEX 5 // Transfered Bytes
#define EHCI_QH_OL_BYTES_SHIFT 5
#define EHCI_QH_OL_BYTES_MASK 0x7f
// ToDo: Periodic Frame Span Traversal Node (FSTN, EHCI Spec 3.7)
#endif // !EHCI_HARDWARE_H
+139
View File
@@ -0,0 +1,139 @@
/*
* Copyright 2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <[email protected]>
*/
#include "ehci.h"
static usb_device_descriptor sEHCIRootHubDevice =
{
18, // Descriptor length
USB_DESCRIPTOR_DEVICE, // Descriptor type
0x200, // USB 2.0
0x09, // Class (9 = Hub)
0, // Subclass
0, // Protocol
64, // Max packet size on endpoint 0
0, // Vendor ID
0, // Product ID
0x200, // Version
1, // Index of manufacturer string
2, // Index of product string
0, // Index of serial number string
1 // Number of configurations
};
struct ehci_root_hub_configuration_s {
usb_configuration_descriptor configuration;
usb_interface_descriptor interface;
usb_endpoint_descriptor endpoint;
usb_hub_descriptor hub;
} _PACKED;
static ehci_root_hub_configuration_s sEHCIRootHubConfig =
{
{ // configuration descriptor
9, // Descriptor length
USB_DESCRIPTOR_CONFIGURATION, // Descriptor type
34, // Total length of configuration (including
// interface, endpoint and hub descriptors)
1, // Number of interfaces
1, // Value of this configuration
0, // Index of configuration string
0x40, // Attributes (0x40 = self powered)
0 // Max power (0, since self powered)
},
{ // interface descriptor
9, // Descriptor length
USB_DESCRIPTOR_INTERFACE, // Descriptor type
0, // Interface number
0, // Alternate setting
1, // Number of endpoints
0x09, // Interface class (9 = Hub)
0, // Interface subclass
0, // Interface protocol
0, // Index of interface string
},
{ // endpoint descriptor
7, // Descriptor length
USB_DESCRIPTOR_ENDPOINT, // Descriptor type
USB_REQTYPE_DEVICE_IN | 1, // Endpoint address (first in IN endpoint)
0x03, // Attributes (0x03 = interrupt endpoint)
8, // Max packet size
0xFF // Interval
},
{ // hub descriptor
9, // Descriptor length (including
// deprecated power control mask)
USB_DESCRIPTOR_HUB, // Descriptor type
2, // Number of ports
0x0000, // Hub characteristics
50, // Power on to power good (in 2ms units)
0, // Maximum current (in mA)
0x00, // Both ports are removable
0xff // Depricated power control mask
}
};
struct ehci_root_hub_string_s {
uint8 length;
uint8 descriptor_type;
uint16 unicode_string[12];
} _PACKED;
static ehci_root_hub_string_s sEHCIRootHubStrings[3] = {
{
4, // Descriptor length
USB_DESCRIPTOR_STRING, // Descriptor type
0x0409 // Supported language IDs (English US)
},
{
12, // Descriptor length
USB_DESCRIPTOR_STRING, // Descriptor type
'H', 'A', 'I', 'K', 'U', ' ', // Characters
'I', 'n', 'c', '.'
},
{
26, // Descriptor length
USB_DESCRIPTOR_STRING, // Descriptor type
'E', 'H', 'C', 'I', ' ', 'R', // Characters
'o', 'o', 't', 'H', 'u', 'b'
}
};
EHCIRootHub::EHCIRootHub(EHCI *ehci, int8 deviceAddress)
: Hub(ehci, NULL, sEHCIRootHubDevice, deviceAddress, false)
{
fEHCI = ehci;
}
status_t
EHCIRootHub::SubmitTransfer(Transfer *transfer)
{
return B_ERROR;
}
void
EHCIRootHub::UpdatePortStatus()
{
for (int32 i = 0; i < sEHCIRootHubConfig.hub.num_ports; i++) {
fPortStatus[i].status = 0;
fPortStatus[i].change = 0;
}
}
+4 -4
View File
@@ -87,8 +87,8 @@ ohci_std_ops( int32 op , ... )
// - &stack: reference to a stack instance form stack.cpp
//------------------------------------------------------------------------
static bool
ohci_add_to( Stack &stack )
static status_t
ohci_add_to( Stack *stack )
{
status_t status;
pci_info *item;
@@ -126,14 +126,14 @@ ohci_add_to( Stack &stack )
continue;
}
TRACE("USB OHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line);
OHCI *bus = new OHCI( item , &stack );
OHCI *bus = new OHCI( item , stack );
if ( bus->InitCheck() != B_OK )
{
delete bus;
break;
}
stack.AddBusManager( bus );
stack->AddBusManager( bus );
bus->Start();
found = true;
break;
+8 -6
View File
@@ -792,8 +792,6 @@ UHCI::FinishTransfers()
transfer = transfer->link;
}
}
Unlock();
}
}
@@ -988,8 +986,8 @@ UHCI::Interrupt()
}
bool
UHCI::AddTo(Stack &stack)
status_t
UHCI::AddTo(Stack *stack)
{
#ifdef TRACE_USB
set_dprintf_enabled(true);
@@ -1026,7 +1024,7 @@ UHCI::AddTo(Stack &stack)
}
TRACE(("usb_uhci: AddTo(): found at IRQ %u\n", item->u.h0.interrupt_line));
UHCI *bus = new(std::nothrow) UHCI(item, &stack);
UHCI *bus = new(std::nothrow) UHCI(item, stack);
if (!bus) {
delete item;
sPCIModule = NULL;
@@ -1040,8 +1038,11 @@ UHCI::AddTo(Stack &stack)
continue;
}
// the bus took it away
item = new(std::nothrow) pci_info;
bus->Start();
stack.AddBusManager(bus);
stack->AddBusManager(bus);
found = true;
}
}
@@ -1054,6 +1055,7 @@ UHCI::AddTo(Stack &stack)
return ENODEV;
}
delete item;
return B_OK;
}
+2 -9
View File
@@ -71,7 +71,7 @@ public:
virtual status_t SubmitTransfer(Transfer *transfer);
virtual status_t SubmitRequest(Transfer *transfer);
static bool AddTo(Stack &stack);
static status_t AddTo(Stack *stack);
// Port operations
uint16 PortStatus(int32 index);
@@ -161,22 +161,15 @@ static pci_module_info *sPCIModule;
class UHCIRootHub : public Hub {
public:
UHCIRootHub(UHCI *uhci, int8 deviceNum);
UHCIRootHub(UHCI *uhci, int8 deviceAddress);
status_t SubmitTransfer(Transfer *transfer);
void UpdatePortStatus();
private:
usb_port_status fPortStatus[2];
UHCI *fUHCI;
};
struct hostcontroller_priv {
uhci_qh *topqh;
uhci_td *firsttd;
uhci_td *lasttd;
};
#endif
@@ -74,7 +74,7 @@
* Hardware structs *
************************************************************/
//A framelist thingie
// Framelist flags
#define FRAMELIST_TERMINATE 0x1
#define FRAMELIST_NEXT_IS_QH 0x2
@@ -82,7 +82,7 @@
// Represents a Transfer Descriptor (TD)
typedef struct
{
//Hardware part
// Hardware part
addr_t link_phy; // Link to the next TD/QH
uint32 status; // Status field
uint32 token; // Contains the packet header (where it needs to be sent)
+3 -3
View File
@@ -91,7 +91,7 @@ struct uhci_root_hub_string_s {
uint8 length;
uint8 descriptor_type;
uint16 unicode_string[12];
};
} _PACKED;
static uhci_root_hub_string_s sUHCIRootHubStrings[3] = {
@@ -117,8 +117,8 @@ static uhci_root_hub_string_s sUHCIRootHubStrings[3] = {
};
UHCIRootHub::UHCIRootHub(UHCI *uhci, int8 devicenum)
: Hub(uhci, NULL, sUHCIRootHubDevice, devicenum, false)
UHCIRootHub::UHCIRootHub(UHCI *uhci, int8 deviceAddress)
: Hub(uhci, NULL, sUHCIRootHubDevice, deviceAddress, false)
{
fUHCI = uhci;
}