* Implement inbound isochronous transfer for EHCI, based on UHCI implementation.

* changes next_log to their actual type instead of void*
* the field this_phy now includes the item type, it simplifies things.
* isochronous transfer descriptors are linked in the periodic frame list first,
and points to existing interrupt transfer descriptors.

This is still work in progress. Yet it's worth committing as it doesn't seem to
have impacts, and is required for the UVC SoC project. Tested basically with 
usb_webcam to receive UVC stream headers.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41424 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2011-05-10 21:25:32 +00:00
parent 16d113f9e5
commit 7df33d912b
3 changed files with 910 additions and 102 deletions

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,26 @@ typedef struct transfer_data {
} transfer_data;
// This structure is used to create a list of
// descriptors per isochronous transfer
typedef struct isochronous_transfer_data {
Transfer * transfer;
// The next field is used to keep track
// of every isochronous descriptor as they are NOT
// linked to each other in a queue like in every other
// transfer type
ehci_itd ** descriptors;
uint16 last_to_process;
bool incoming;
bool is_active;
isochronous_transfer_data * link;
size_t buffer_size;
void * buffer_log;
addr_t buffer_phy;
} isochronous_transfer_data;
class EHCI : public BusManager {
public:
EHCI(pci_info *info, Stack *stack);
@ -35,7 +55,9 @@ public:
status_t Start();
virtual status_t SubmitTransfer(Transfer *transfer);
virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force);
status_t CancelQueuedIsochronousTransfers(Pipe *pipe, bool force);
status_t SubmitIsochronous(Transfer *transfer);
virtual status_t NotifyPipeChange(Pipe *pipe,
usb_change change);
@ -66,13 +88,32 @@ static int32 InterruptHandler(void *data);
ehci_qh *queueHead,
ehci_qtd *dataDescriptor,
bool directionIn);
status_t AddPendingIsochronousTransfer(
Transfer *transfer,
ehci_itd **isoRequest, uint32 lastIndex,
bool directionIn, addr_t bufferPhy,
void *bufferLog, size_t bufferSize);
status_t CancelAllPendingTransfers();
static int32 FinishThread(void *data);
void FinishTransfers();
static int32 CleanupThread(void *data);
void Cleanup();
// Isochronous transfer functions
static int32 FinishIsochronousThread(void *data);
void FinishIsochronousTransfers();
isochronous_transfer_data * FindIsochronousTransfer(ehci_itd *itd);
void LinkITDescriptors(ehci_itd *itd,
ehci_itd **last);
void LinkSITDescriptors(ehci_sitd *sitd,
ehci_sitd **last);
void UnlinkITDescriptors(ehci_itd *itd,
ehci_itd **last);
void UnlinkSITDescriptors(ehci_sitd *sitd,
ehci_sitd **last);
// Queue Head functions
ehci_qh * CreateQueueHead();
status_t InitQueueHead(ehci_qh *queueHead,
@ -95,6 +136,9 @@ static int32 CleanupThread(void *data);
ehci_qtd **dataDescriptor,
bool *directionIn);
bool LockIsochronous();
void UnlockIsochronous();
// Descriptor functions
ehci_qtd * CreateDescriptor(
size_t bufferSizeToAllocate,
@ -105,9 +149,15 @@ static int32 CleanupThread(void *data);
ehci_qtd *strayDescriptor,
size_t bufferSizeToAllocate,
uint8 pid);
ehci_itd* CreateItdDescriptor();
ehci_sitd* CreateSitdDescriptor();
void FreeDescriptor(ehci_qtd *descriptor);
void FreeDescriptorChain(ehci_qtd *topDescriptor);
void FreeDescriptor(ehci_itd *descriptor);
void FreeDescriptor(ehci_sitd *descriptor);
void FreeIsochronousData(
isochronous_transfer_data *data);
void LinkDescriptors(ehci_qtd *first,
ehci_qtd *last, ehci_qtd *alt);
@ -120,6 +170,12 @@ static int32 CleanupThread(void *data);
bool *nextDataToggle);
size_t ReadActualLength(ehci_qtd *topDescriptor,
bool *nextDataToggle);
size_t WriteIsochronousDescriptorChain(
isochronous_transfer_data *transfer,
uint32 packetCount,
iovec *vector);
size_t ReadIsochronousDescriptorChain(
isochronous_transfer_data *transfer);
// Operational register functions
inline void WriteOpReg(uint32 reg, uint32 value);
@ -143,6 +199,8 @@ static pci_module_info * sPCIModule;
area_id fPeriodicFrameListArea;
addr_t * fPeriodicFrameList;
interrupt_entry * fInterruptEntries;
ehci_itd ** fItdEntries;
ehci_sitd ** fSitdEntries;
// Async transfer queue management
ehci_qh * fAsyncQueueHead;
@ -153,12 +211,24 @@ static pci_module_info * sPCIModule;
transfer_data * fLastTransfer;
sem_id fFinishTransfersSem;
thread_id fFinishThread;
Pipe * fProcessingPipe;
ehci_qh * fFreeListHead;
sem_id fCleanupSem;
thread_id fCleanupThread;
bool fStopThreads;
ehci_qh * fFreeListHead;
Pipe * fProcessingPipe;
// fFrameBandwidth[n] holds the available bandwidth
// of the nth frame in microseconds
uint16 * fFrameBandwidth;
// Maintain a linked list of isochronous transfers
isochronous_transfer_data * fFirstIsochronousTransfer;
isochronous_transfer_data * fLastIsochronousTransfer;
sem_id fFinishIsochronousTransfersSem;
thread_id fFinishIsochronousThread;
mutex fIsochronousLock;
// Root Hub
EHCIRootHub * fRootHub;
uint8 fRootHubAddress;

View File

@ -16,7 +16,6 @@
#define EHCI_HCCPARAMS 0x08 // Capability Parameters
#define EHCI_HCSP_PORTROUTE 0x0c // Companion Port Route Description
// Host Controller Operational Registers (EHCI Spec 2.3)
#define EHCI_USBCMD 0x00 // USB Command
#define EHCI_USBSTS 0x04 // USB Status
@ -105,22 +104,89 @@
#define EHCI_LEGSUP_OSOWNED (1 << 24) // OS Owned Semaphore
#define EHCI_LEGSUP_BIOSOWNED (1 << 16) // BIOS Owned Semaphore
#define EHCI_HCCPARAMS_IPT_SHIFT 4 // Isochronous Periodic Threshold
#define EHCI_HCCPARAMS_IPT_MASK 0xf
// Data Structures (EHCI Spec 3)
// Periodic Frame List Element Flags (EHCI Spec 3.1)
#define EHCI_PFRAMELIST_TERM (1 << 0) // Terminate
#define EHCI_PFRAMELIST_ITD (0 << 1) // Isochronous Transfer Descriptor
#define EHCI_PFRAMELIST_QH (1 << 1) // Queue Head
#define EHCI_PFRAMELIST_SITD (2 << 1) // Split Transaction Isochronous TD
#define EHCI_PFRAMELIST_FSTN (3 << 1) // Frame Span Traversal Node
// Applies to ehci_qh.next_phy, ehci_sitd.next_phy, ehci_itd.next_phy
#define EHCI_ITEM_TYPE_ITD (0 << 1) // Isochronous Transfer Descriptor
#define EHCI_ITEM_TYPE_QH (1 << 1) // Queue Head
#define EHCI_ITEM_TYPE_SITD (2 << 1) // Split Transaction Isochronous TD
#define EHCI_ITEM_TYPE_FSTN (3 << 1) // Frame Span Traversal Node
#define EHCI_ITEM_TERMINATE (1 << 0) // Terminate
// ToDo: Isochronous (High-Speed) Transfer Descriptors (iTD, EHCI Spec 3.2)
// ToDo: Split Transaction Isochronous Transfer Descriptors (siTD, EHCI Spec 3.3)
// Isochronous (High-Speed) Transfer Descriptors (iTD, EHCI Spec 3.2)
typedef struct ehci_itd {
// Hardware Part
addr_t next_phy;
uint32 token[8];
addr_t buffer_phy[7];
addr_t ext_buffer_phy[7];
// Software Part
addr_t this_phy;
struct ehci_itd *next;
struct ehci_itd *prev;
uint32 last_token;
} ehci_itd;
#define EHCI_ITD_TOFFSET_SHIFT 0
#define EHCI_ITD_TOFFSET_MASK 0x0fff
#define EHCI_ITD_IOC (1 << 15)
#define EHCI_ITD_PG_SHIFT 12
#define EHCI_ITD_PG_MASK 0x07
#define EHCI_ITD_TLENGTH_SHIFT 16
#define EHCI_ITD_TLENGTH_MASK 0x0fff
#define EHCI_ITD_STATUS_SHIFT 28
#define EHCI_ITD_STATUS_MASK 0xf
#define EHCI_ITD_STATUS_ACTIVE (1 << 3) // Active
#define EHCI_ITD_STATUS_BUFFER (1 << 2) // Data Buffer Error
#define EHCI_ITD_STATUS_BABBLE (1 << 1) // Babble Detected
#define EHCI_ITD_STATUS_TERROR (1 << 0) // Transaction Error
#define EHCI_ITD_ADDRESS_SHIFT 0
#define EHCI_ITD_ADDRESS_MASK 0x7f
#define EHCI_ITD_ENDPOINT_SHIFT 8
#define EHCI_ITD_ENDPOINT_MASK 0xf
#define EHCI_ITD_DIR_SHIFT 11
#define EHCI_ITD_MUL_SHIFT 0
#define EHCI_ITD_BUFFERPOINTER_SHIFT 12
#define EHCI_ITD_BUFFERPOINTER_MASK 0xfffff
#define EHCI_ITD_MAXPACKETSIZE_SHIFT 0
#define EHCI_ITD_MAXPACKETSIZE_MASK 0x7ff
// Split Transaction Isochronous Transfer Descriptors (siTD, EHCI Spec 3.3)
typedef struct ehci_sitd {
// Hardware Part
addr_t next_phy;
uint8 port_number;
uint8 hub_address;
uint8 endpoint;
uint8 device_address;
uint16 reserved1;
uint8 cmask;
uint8 smask;
uint16 transfer_length;
uint8 cprogmask;
uint8 status;
addr_t buffer_phy[2];
addr_t back_phy;
addr_t ext_buffer_phy[2];
// Software Part
addr_t this_phy;
struct ehci_sitd *next;
struct ehci_sitd *prev;
size_t buffer_size;
void *buffer_log;
} ehci_sitd;
// Queue Element Transfer Descriptors (qTD, EHCI Spec 3.5)
typedef struct {
typedef struct ehci_qtd {
// Hardware Part
addr_t next_phy;
addr_t alt_next_phy;
@ -130,14 +196,13 @@ typedef struct {
// Software Part
addr_t this_phy;
void *next_log;
struct ehci_qtd *next_log;
void *alt_next_log;
size_t buffer_size;
void *buffer_log;
} ehci_qtd;
#define EHCI_QTD_TERMINATE (1 << 0)
#define EHCI_QTD_DATA_TOGGLE (1 << 31)
#define EHCI_QTD_BYTES_SHIFT 16
#define EHCI_QTD_BYTES_MASK 0x7fff
@ -166,7 +231,7 @@ typedef struct {
// Queue Head (QH, EHCI Spec 3.6)
typedef struct {
typedef struct ehci_qh {
// Hardware Part
addr_t next_phy;
uint32 endpoint_chars;
@ -183,10 +248,10 @@ typedef struct {
// Software Part
addr_t this_phy;
void *next_log;
void *prev_log;
void *stray_log;
void *element_log;
struct ehci_qh *next_log;
struct ehci_qh *prev_log;
ehci_qtd *stray_log;
ehci_qtd *element_log;
} ehci_qh;
@ -195,13 +260,22 @@ typedef struct {
uint32 padding[2];
} interrupt_entry;
typedef struct {
ehci_itd itd;
uint32 padding[5]; // align on 128
} itd_entry;
typedef struct {
ehci_sitd sitd;
uint32 padding[2]; // align on 64
} sitd_entry;
#define EHCI_INTERRUPT_ENTRIES_COUNT (7 + 1) // (log 128 / log 2) + 1
#define EHCI_VFRAMELIST_ENTRIES_COUNT 128
#define EHCI_FRAMELIST_ENTRIES_COUNT 1024
#define MAX_AVAILABLE_BANDWIDTH 125 // Microseconds
// 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