* Changed EHCI register access from port to memory mapped io (which is required)
* Added individual register operations for operational and capability registers * Added resetting the host controller which appearantly actually works Note that you shouldn't install the ehci module if you want uhci to work. It disables the companion host controller drivers (uhci and ohci) because it takes port ownership and does not yet give it back for low and fullspeed devices. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18648 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
a17c3a48b8
commit
01595708f3
@ -11,6 +11,7 @@
|
|||||||
#include <USB3.h>
|
#include <USB3.h>
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
|
||||||
|
#define TRACE_USB
|
||||||
#include "ehci.h"
|
#include "ehci.h"
|
||||||
|
|
||||||
pci_module_info *EHCI::sPCIModule = NULL;
|
pci_module_info *EHCI::sPCIModule = NULL;
|
||||||
@ -60,8 +61,6 @@ EHCI::EHCI(pci_info *info, Stack *stack)
|
|||||||
fStack(stack),
|
fStack(stack),
|
||||||
fPeriodicFrameListArea(-1),
|
fPeriodicFrameListArea(-1),
|
||||||
fPeriodicFrameList(NULL),
|
fPeriodicFrameList(NULL),
|
||||||
fAsyncFrameListArea(-1),
|
|
||||||
fAsyncFrameList(NULL),
|
|
||||||
fFirstTransfer(NULL),
|
fFirstTransfer(NULL),
|
||||||
fLastTransfer(NULL),
|
fLastTransfer(NULL),
|
||||||
fFinishTransfers(false),
|
fFinishTransfers(false),
|
||||||
@ -70,7 +69,7 @@ EHCI::EHCI(pci_info *info, Stack *stack)
|
|||||||
fRootHub(NULL),
|
fRootHub(NULL),
|
||||||
fRootHubAddress(0)
|
fRootHubAddress(0)
|
||||||
{
|
{
|
||||||
if (!fInitOK) {
|
if (BusManager::InitCheck() < B_OK) {
|
||||||
TRACE_ERROR(("usb_ehci: bus manager failed to init\n"));
|
TRACE_ERROR(("usb_ehci: bus manager failed to init\n"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -78,49 +77,49 @@ 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;
|
||||||
|
|
||||||
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
|
// make sure we take the controller away from BIOS
|
||||||
sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 2,
|
sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 2,
|
||||||
PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN);
|
PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN);
|
||||||
|
|
||||||
// disable interrupts
|
// enable busmaster and memory mapped access
|
||||||
WriteReg16(EHCI_USBINTR, 0);
|
uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus,
|
||||||
|
fPCIInfo->device, fPCIInfo->function, PCI_command, 2);
|
||||||
|
command &= ~PCI_command_io;
|
||||||
|
command |= PCI_command_master | PCI_command_memory;
|
||||||
|
|
||||||
// reset the host controller
|
sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
|
||||||
// ToDo...
|
fPCIInfo->function, PCI_command, 2, command);
|
||||||
|
|
||||||
// allocate the periodic frame list
|
// map the registers
|
||||||
void *physicalAddress;
|
uint32 offset = fPCIInfo->u.h0.base_registers[0] & (B_PAGE_SIZE - 1);
|
||||||
fPeriodicFrameListArea = fStack->AllocateArea((void **)&fPeriodicFrameList,
|
addr_t physicalAddress = fPCIInfo->u.h0.base_registers[0] - offset;
|
||||||
&physicalAddress, B_PAGE_SIZE, "USB EHCI Periodic Framelist");
|
size_t mapSize = (fPCIInfo->u.h0.base_register_sizes[0] + offset
|
||||||
if (fPeriodicFrameListArea < B_OK) {
|
+ B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
|
||||||
TRACE_ERROR(("usb_ehci: unable to allocate periodic framelist\n"));
|
|
||||||
|
TRACE(("usb_ehci: map physical memory 0x%08x (base: 0x%08x; offset: %x); size: %d -> %d\n", fPCIInfo->u.h0.base_registers[0], physicalAddress, offset, fPCIInfo->u.h0.base_register_sizes[0], mapSize));
|
||||||
|
fRegisterArea = map_physical_memory("EHCI memory mapped registers",
|
||||||
|
(void *)physicalAddress, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS,
|
||||||
|
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA,
|
||||||
|
(void **)&fCapabilityRegisters);
|
||||||
|
if (fRegisterArea < B_OK) {
|
||||||
|
TRACE(("usb_ehci: failed to map register memory\n"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteReg32(EHCI_PERIODICLISTBASE, (uint32)physicalAddress);
|
fCapabilityRegisters += offset;
|
||||||
|
fOperationalRegisters = fCapabilityRegisters + ReadCapReg8(EHCI_CAPLENGTH);
|
||||||
|
TRACE(("usb_ehci: mapped capability registers: 0x%08x\n", fCapabilityRegisters));
|
||||||
|
TRACE(("usb_ehci: mapped operational registers: 0x%08x\n", fOperationalRegisters));
|
||||||
|
|
||||||
// allocate the async frame list
|
// disable interrupts
|
||||||
fAsyncFrameListArea = fStack->AllocateArea((void **)&fAsyncFrameList,
|
WriteOpReg(EHCI_USBINTR, 0);
|
||||||
&physicalAddress, B_PAGE_SIZE, "USB EHCI Async Framelist");
|
|
||||||
if (fAsyncFrameListArea < B_OK) {
|
// reset the host controller
|
||||||
TRACE_ERROR(("usb_ehci: unable to allocate async framelist\n"));
|
if (ControllerReset() < B_OK) {
|
||||||
|
TRACE_ERROR(("usb_ehci: host controller failed to reset\n"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteReg32(EHCI_ASYNCLISTADDR, (uint32)physicalAddress);
|
|
||||||
|
|
||||||
// create finisher service thread
|
// create finisher service thread
|
||||||
fFinishThread = spawn_kernel_thread(FinishThread, "ehci finish thread",
|
fFinishThread = spawn_kernel_thread(FinishThread, "ehci finish thread",
|
||||||
B_NORMAL_PRIORITY, (void *)this);
|
B_NORMAL_PRIORITY, (void *)this);
|
||||||
@ -129,9 +128,26 @@ EHCI::EHCI(pci_info *info, Stack *stack)
|
|||||||
// install the interrupt handler and enable interrupts
|
// install the interrupt handler and enable interrupts
|
||||||
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
|
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
|
||||||
InterruptHandler, (void *)this, 0);
|
InterruptHandler, (void *)this, 0);
|
||||||
WriteReg16(EHCI_USBINTR, EHCI_USBINTR_HOSTSYSERR
|
WriteOpReg(EHCI_USBINTR, EHCI_USBINTR_HOSTSYSERR
|
||||||
| EHCI_USBINTR_USBERRINT | EHCI_USBINTR_USBINT);
|
| EHCI_USBINTR_USBERRINT | EHCI_USBINTR_USBINT);
|
||||||
|
|
||||||
|
// allocate the periodic frame list
|
||||||
|
fPeriodicFrameListArea = fStack->AllocateArea((void **)&fPeriodicFrameList,
|
||||||
|
(void **)&physicalAddress, B_PAGE_SIZE, "USB EHCI Periodic Framelist");
|
||||||
|
if (fPeriodicFrameListArea < B_OK) {
|
||||||
|
TRACE_ERROR(("usb_ehci: unable to allocate periodic framelist\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// terminate all elements
|
||||||
|
for (int32 i = 0; i < 1024; i++)
|
||||||
|
fPeriodicFrameList[i] = EHCI_PFRAMELIST_TERM;
|
||||||
|
|
||||||
|
WriteOpReg(EHCI_PERIODICLISTBASE, (uint32)physicalAddress);
|
||||||
|
|
||||||
|
// route all ports to us
|
||||||
|
WriteOpReg(EHCI_CONFIGFLAG, EHCI_CONFIGFLAG_FLAG);
|
||||||
|
|
||||||
TRACE(("usb_ehci: EHCI Host Controller Driver constructed\n"));
|
TRACE(("usb_ehci: EHCI Host Controller Driver constructed\n"));
|
||||||
fInitOK = true;
|
fInitOK = true;
|
||||||
}
|
}
|
||||||
@ -149,8 +165,7 @@ EHCI::~EHCI()
|
|||||||
|
|
||||||
delete fRootHub;
|
delete fRootHub;
|
||||||
delete_area(fPeriodicFrameListArea);
|
delete_area(fPeriodicFrameListArea);
|
||||||
delete_area(fAsyncFrameListArea);
|
delete_area(fRegisterArea);
|
||||||
|
|
||||||
put_module(B_PCI_MODULE_NAME);
|
put_module(B_PCI_MODULE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,13 +174,13 @@ status_t
|
|||||||
EHCI::Start()
|
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", ReadReg32(EHCI_USBCMD), ReadReg32(EHCI_USBSTS)));
|
TRACE(("usb_ehci: usbcmd: 0x%08x; usbsts: 0x%08x\n", ReadOpReg(EHCI_USBCMD), ReadOpReg(EHCI_USBSTS)));
|
||||||
|
|
||||||
WriteReg32(EHCI_USBCMD, ReadReg32(EHCI_USBCMD) | EHCI_USBCMD_RUNSTOP);
|
WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_RUNSTOP);
|
||||||
|
|
||||||
bool running = false;
|
bool running = false;
|
||||||
for (int32 i = 0; i < 10; i++) {
|
for (int32 i = 0; i < 10; i++) {
|
||||||
uint32 status = ReadReg32(EHCI_USBSTS);
|
uint32 status = ReadOpReg(EHCI_USBSTS);
|
||||||
TRACE(("usb_ehci: try %ld: status 0x%08x\n", i, status));
|
TRACE(("usb_ehci: try %ld: status 0x%08x\n", i, status));
|
||||||
|
|
||||||
if (status & EHCI_USBSTS_HCHALTED) {
|
if (status & EHCI_USBSTS_HCHALTED) {
|
||||||
@ -295,7 +310,16 @@ EHCI::ResetPort(int32 index)
|
|||||||
status_t
|
status_t
|
||||||
EHCI::ControllerReset()
|
EHCI::ControllerReset()
|
||||||
{
|
{
|
||||||
|
WriteOpReg(EHCI_USBCMD, EHCI_USBCMD_HCRESET);
|
||||||
|
|
||||||
|
int32 tries = 5;
|
||||||
|
while (ReadOpReg(EHCI_USBCMD) & EHCI_USBCMD_HCRESET) {
|
||||||
|
snooze(10000);
|
||||||
|
if (tries-- < 0)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -534,42 +558,35 @@ EHCI::ReadActualLength(ehci_qtd *topDescriptor, uint8 *lastDataToggle)
|
|||||||
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
EHCI::WriteReg8(uint32 reg, uint8 value)
|
EHCI::WriteOpReg(uint32 reg, uint32 value)
|
||||||
{
|
{
|
||||||
sPCIModule->write_io_8(fRegisterBase + reg, value);
|
*(volatile uint32 *)(fOperationalRegisters + 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
|
inline uint32
|
||||||
EHCI::ReadReg32(uint32 reg)
|
EHCI::ReadOpReg(uint32 reg)
|
||||||
{
|
{
|
||||||
return sPCIModule->read_io_32(fRegisterBase + reg);
|
return *(volatile uint32 *)(fOperationalRegisters + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline uint8
|
||||||
|
EHCI::ReadCapReg8(uint32 reg)
|
||||||
|
{
|
||||||
|
return *(volatile uint8 *)(fCapabilityRegisters + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline uint16
|
||||||
|
EHCI::ReadCapReg16(uint32 reg)
|
||||||
|
{
|
||||||
|
return *(volatile uint16 *)(fCapabilityRegisters + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline uint32
|
||||||
|
EHCI::ReadCapReg32(uint32 reg)
|
||||||
|
{
|
||||||
|
return *(volatile uint32 *)(fCapabilityRegisters + reg);
|
||||||
}
|
}
|
||||||
|
@ -87,25 +87,26 @@ static int32 FinishThread(void *data);
|
|||||||
size_t ReadActualLength(ehci_qtd *topDescriptor,
|
size_t ReadActualLength(ehci_qtd *topDescriptor,
|
||||||
uint8 *lastDataToggle);
|
uint8 *lastDataToggle);
|
||||||
|
|
||||||
// Register functions
|
// Operational register functions
|
||||||
inline void WriteReg8(uint32 reg, uint8 value);
|
inline void WriteOpReg(uint32 reg, uint32 value);
|
||||||
inline void WriteReg16(uint32 reg, uint16 value);
|
inline uint32 ReadOpReg(uint32 reg);
|
||||||
inline void WriteReg32(uint32 reg, uint32 value);
|
|
||||||
inline uint8 ReadReg8(uint32 reg);
|
// Capability register functions
|
||||||
inline uint16 ReadReg16(uint32 reg);
|
inline uint8 ReadCapReg8(uint32 reg);
|
||||||
inline uint32 ReadReg32(uint32 reg);
|
inline uint16 ReadCapReg16(uint32 reg);
|
||||||
|
inline uint32 ReadCapReg32(uint32 reg);
|
||||||
|
|
||||||
static pci_module_info *sPCIModule;
|
static pci_module_info *sPCIModule;
|
||||||
|
|
||||||
uint32 fRegisterBase;
|
uint8 *fCapabilityRegisters;
|
||||||
|
uint8 *fOperationalRegisters;
|
||||||
|
area_id fRegisterArea;
|
||||||
pci_info *fPCIInfo;
|
pci_info *fPCIInfo;
|
||||||
Stack *fStack;
|
Stack *fStack;
|
||||||
|
|
||||||
// Framelist memory
|
// Framelist memory
|
||||||
area_id fPeriodicFrameListArea;
|
area_id fPeriodicFrameListArea;
|
||||||
addr_t *fPeriodicFrameList;
|
addr_t *fPeriodicFrameList;
|
||||||
area_id fAsyncFrameListArea;
|
|
||||||
addr_t *fAsyncFrameList;
|
|
||||||
|
|
||||||
// Maintain a linked list of transfers
|
// Maintain a linked list of transfers
|
||||||
transfer_data *fFirstTransfer;
|
transfer_data *fFirstTransfer;
|
||||||
|
@ -9,6 +9,14 @@
|
|||||||
#ifndef EHCI_HARDWARE_H
|
#ifndef EHCI_HARDWARE_H
|
||||||
#define EHCI_HARDWARE_H
|
#define EHCI_HARDWARE_H
|
||||||
|
|
||||||
|
// Host Controller Capability Registers (EHCI Spec 2.2)
|
||||||
|
#define EHCI_CAPLENGTH 0x00 // Capability Register Length
|
||||||
|
#define EHCI_HCIVERSION 0x02 // Interface Version Number
|
||||||
|
#define EHCI_HCSPARAMS 0x04 // Structural Parameters
|
||||||
|
#define EHCI_HCCPARAMS 0x08 // Capability Parameters
|
||||||
|
#define EHCI_HCSP_PORTROUTE 0x0c // Companion Port Route Description
|
||||||
|
|
||||||
|
|
||||||
// Host Controller Operational Registers (EHCI Spec 2.3)
|
// Host Controller Operational Registers (EHCI Spec 2.3)
|
||||||
#define EHCI_USBCMD 0x00 // USB Command
|
#define EHCI_USBCMD 0x00 // USB Command
|
||||||
#define EHCI_USBSTS 0x04 // USB Status
|
#define EHCI_USBSTS 0x04 // USB Status
|
||||||
@ -88,16 +96,17 @@
|
|||||||
|
|
||||||
// PCI Registers
|
// PCI Registers
|
||||||
#define PCI_LEGSUP 0xc0 // PCI Legacy Support
|
#define PCI_LEGSUP 0xc0 // PCI Legacy Support
|
||||||
#define PCI_LEGSUP_USBPIRQDEN 0x2000 // USBP IRQ Deny
|
#define PCI_LEGSUP_USBPIRQDEN 0x2000 // USB PIRQ
|
||||||
|
|
||||||
|
|
||||||
// Data Structures (EHCI Spec 3)
|
// Data Structures (EHCI Spec 3)
|
||||||
|
|
||||||
// Periodic Frame List Element Flags (EHCI Spec 3.1)
|
// Periodic Frame List Element Flags (EHCI Spec 3.1)
|
||||||
#define EHCI_PFRAMELIST_ITD 0x00 // Isochronous Transfer Descriptor
|
#define EHCI_PFRAMELIST_TERM (1 << 0) // Terminate
|
||||||
#define EHCI_PFRAMELIST_QH 0x01 // Queue Head
|
#define EHCI_PFRAMELIST_ITD (0 << 1) // Isochronous Transfer Descriptor
|
||||||
#define EHCI_PFRAMELIST_SITD 0x10 // Split Transaction Isochronous TD
|
#define EHCI_PFRAMELIST_QH (1 << 1) // Queue Head
|
||||||
#define EHCI_PFRAMELIST_FSTN 0x11 // Frame Span Traversal Node
|
#define EHCI_PFRAMELIST_SITD (2 << 1) // Split Transaction Isochronous TD
|
||||||
|
#define EHCI_PFRAMELIST_FSTN (3 << 1) // Frame Span Traversal Node
|
||||||
|
|
||||||
|
|
||||||
// ToDo: Isochronous (High-Speed) Transfer Descriptors (iTD, EHCI Spec 3.2)
|
// ToDo: Isochronous (High-Speed) Transfer Descriptors (iTD, EHCI Spec 3.2)
|
||||||
|
@ -339,10 +339,12 @@ UHCI::UHCI(pci_info *info, Stack *stack)
|
|||||||
fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus,
|
fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus,
|
||||||
fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4);
|
fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4);
|
||||||
fRegisterBase &= PCI_address_io_mask;
|
fRegisterBase &= PCI_address_io_mask;
|
||||||
TRACE(("usb_uhci: iospace offset: 0x%08x\n", fRegisterBase));
|
TRACE_ERROR(("usb_uhci: iospace offset: 0x%08x\n", fRegisterBase));
|
||||||
|
|
||||||
//fRegisterBase = fPCIInfo->u.h0.base_registers[0];
|
if (fRegisterBase == 0) {
|
||||||
//TRACE(("usb_uhci: register base: 0x%08x\n", fRegisterBase));
|
fRegisterBase = fPCIInfo->u.h0.base_registers[0];
|
||||||
|
TRACE_ERROR(("usb_uhci: register base: 0x%08x\n", fRegisterBase));
|
||||||
|
}
|
||||||
|
|
||||||
// enable pci address access
|
// enable pci address access
|
||||||
uint16 command = PCI_command_io | PCI_command_master | PCI_command_memory;
|
uint16 command = PCI_command_io | PCI_command_master | PCI_command_memory;
|
||||||
|
Loading…
Reference in New Issue
Block a user