⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbhcdohcilib.c

📁 VxWorks BSP for S3C2510A
💻 C
📖 第 1 页 / 共 5 页
字号:
/* usbHcdOhciLib.c - Host Controller Driver (HCD) for OHCI */

/* Copyright 2000-2002 Wind River Systems, Inc. */

/*
Modification history
--------------------
01p,22may02,wef  Fix SPR 73864 - USB crashes when cable is disconnected while 
		 iscoh transfer is in progress - valid only on PPC, MIPS and 
		 STRONGARM, not X86.
010,29apr02,wef  Fix SPR's 71274, 71273 and clean up fncAttach().
01p,18mar02,h_k  made buffer swap's in several places - spr # 73896 and 73920.
01o,05feb01,wef  explicitly power to ports on initial HC attachment.
01k,13dec01,wef  merge from veloce view
01j,24jul01,wef  Fixed SPR #68617
01i,23jul01,wef  Fixed SPR #68202 and SPR #68209
01h,01jan01,wef  Fixed alignment problems w/ code, general clean up
01g,12apr00,wef  Fixed uninitialized variable warning: controlin assignTds(),
		 fixed a comment that was messing up the man page generation
01f,27mar00,rcb  Fix bug in scheduling interrupt EDs which allowed an ED
		 to be circularly-linked.
01e,20mar00,rcb  Flush all cache buffers during assignTds() to avoid 
		 cache-line boundary problems with some CPU architectures
		 (e.g., MIPS).
01d,17mar00,rcb  Add code to update tdHead in ED structure when removing
		 TDs from queue...corrects bug which allowed OHCI ctlr
		 to try to process an aborted TD.
01c,10mar00,rcb  Fix bug in pipe destroy logic which attempted to free
		 non-existent EDs for root hub.
		 Add "volatile" declaration in HC_DWORD_IN/OUT().
01b,26jan00,rcb  Change references to "bytesPerFrame" to "bandwidth" in
		 pipe creation logic.
		 Modify isoch. timing to maintain rate as specified by
		 pipe bandwidth parameter.
		 Fix big vs. little-endian bug in unscheduleControlIrp()
		 and unscheduleBulkIrp().
01a,05oct99,rcb  First.
*/

/*
DESCRIPTION

This is the HCD (host controller driver) for OHCI.  This file implements
low-level functions required by the client (typically the USBD) to talk to
the underlying USB host controller hardware.  

The <param> to the HRB_ATTACH request should be a pointer to a 
PCI_CFG_HEADER which contains the PCI configuration header for the
OpenHCI host controller to be managed.	Each invocation of the HRB_ATTACH
function will return an HCD_CLIENT_HANDLE for which a single host controller
will be exposed.

NOTE: This HCD implementation assumes that the caller has already initialized
the osServices and handleFuncs libraries by calling ossInitialize() and
usbHandleInitialize(), respectively.  The USBD implementation guarantees that
these libraries have been initialized prior to invoking the HCD.

Regarding IRP callbacks...

There are two callback function pointers in each IRP, <usbdCallback> and
<userCallback>.  By convention, if a non-NULL <usbdCallback> is supplied,
then the HCD invokes only the <usbdCallback> upon IRP completion - and it is
the USBD's responsibility to invoke the <userCallback>.  If no <usbdCallback>
is provided, then the HCD invokes the <userCallback> directly.	Typically, 
all IRPs are delivered to the HCD through the USBD and a non-NULL <usbdCallback>
will in fact be provided.

Regarding OHCI frame lists...

We use the OHCI frame list largely as anticipated in the OpenHCI specification.
Each of the 32 interrupt list heads points either to an interrupt ED (endpoint
descriptor) or to an isochronous ED "anchor" (at which point all 32 lists 
converge).  When one or more interrupt pipes are created, EDs for these pipes 
will be inserted in the interrupt list one or more times, corresponding to the
desired interrupt polling interval.  The last interrupt ED in each list points 
to the common isochronous anchor ED.  While clients can request any interrupt 
service interval they like, the algorithms here always choose an
interval which is the largest power of 2 less than or equal to the client's
desired interval.  For example, if a client requests an interval of 20msec, the
HCD will select a real interval of 16msec.  In each frame work list, the least
frequently scheduled EDs appear ahead of more frequently scheduled EDs.  Since
only a single ED is actually created for each interrupt transfer, the individual
frame lists actually "merge" at each interrupt ED.   

The OpenHCI host controller maintains separate lists for control and bulk
transfers.  OpenHCI allows for a control/bulk service ratio, so the control list
can be serviced n times for each servicing of the bulk list.  In the present
implementation, we use a service ratio of 3:1.

Regarding bus time calculations...

The host controller driver is responsible for ensuring that certain kinds of
scheduled transfers never exceed the time available in a USB frame.  The HCD 
and the USBD work cooperatively to ensure this.  For its part, the USBD never 
allows isochronous and interrupt transfers to be scheduled which would exceed 
90% of the bus bandwidth.  However, the USBD will freely allow control and bulk 
pipes to be created, as these types of transfers take whatever bus time is left 
over after isochronous and interrupt transfers have been schedule - and the
HCD gives priority to control transfers.

The HCD keeps a running total of the worst case amount of bus time alloted to 
active isochronous and interrupt transfers.  As for control and bulk transfers,
the HC theoretically allows us to schedule as many of them as we desire, and it
keeps track of how much time remains in each frame, executing only as many of
these transfers as will fit.  However, the HC requires that the driver schedule
only as many low speed control transfers (as opposed to full speed control
transfers) as can actually fit within the frame.  Therefore, after taking into
account the time already allotted to isochronous and interrupt transfers, the
HCD only schedules as many low speed control transfers as can fit within the
current frame - and full speed control and bulk transfers follow. 
*/


/* includes */

#include "usb/usbPlatform.h"

#include "string.h"

#include "memLib.h"	    /* memory sub-allocation functions */
#include "cacheLib.h"		/* cache functions */
#include "semLib.h"		/* cache functions */
/* Ajay */
#include "iv.h"
/* Ajay */


#include "usb/ossLib.h"
#include "usb/usbHandleLib.h"
#include "usb/pciConstants.h"
#include "usb/usbPciLib.h"

#include "usb/usbLib.h"
#include "drv/usb/usbHcd.h"
#include "drv/usb/usbOhci.h"
#include "drv/usb/usbHcdOhciLib.h"


/* defines */

/* Extra definitions used -Ajay */
#define INVALID_PCI_DEVICE_ID 0xFFFF
#define INVALID_PCI_VENDOR_ID 0xFFFF
/* Extra definitions used -Ajay end */

#define PENDING 	1

#define HCD_HOST_SIG	    ((UINT32) 0x00cd0080)
#define HCD_PIPE_SIG	    ((UINT32) 0x00cd0081)


#define MAX_INT_DEPTH	    8	    /* max depth of pending interrupts */
#define INT_TIMEOUT	5000	/* wait 5 seconds for int routine to exit */
#define BIT_TIMEOUT	1000	/* max time to wait for a bit change */

#define HC_TIMEOUT_SRVC_INTERVAL    1000    /* milliseconds */


/* HC_HOST_DELAY and HC_HUB_LS_SETUP are host-controller specific.
 * The following values are estimates for the OHCI controller.
 */

#define HC_HOST_DELAY	((UINT32) 500L)     /* 500 ns, est. */
#define HC_HUB_LS_SETUP ((UINT32) 500L)     /* 500 ns, est. */


/* OHCI constants unique to this driver implementation. */

#define REQUIRED_OHCI_LEVEL 0x10    /* OHCI rev 1.0 or higher */

#define MAX_FRAME_OVERHEAD  210 /* cf. OHCI spec. sec 5.4 */

#define MAX_ROOT_PORTS	    8	/* max root hub ports we support */
#define OHCI_HUB_CONTR_CURRENT	0   /* root hub controller current */
#define OHCI_HUB_INTERVAL   255 /* root hub polling interval */

#define TD_COUNT_GEN	    2	/* count of TDs for generic pipe */
#define TD_COUNT_ISO	    16	/* count of TDs for isoch pipe */

#ifndef USB_BUFFER_SWAP
#define USB_BUFFER_SWAP(pBuf,len)   /* default: don't swap buffers */
#endif  /* USB_BUFFER_SWAP */

#ifndef SYS_OHCI_RESET
#define SYS_OHCI_RESET()	/* default: don't need reset */
#endif  /* SYS_OHCI_RESET */


/*
 * MEMORY
 * 
 * To improve performance, a single block of (probably) "non-cached"
 * memory is allocated.  Then, all OHCI control structures are sub-allocated
 * from this block as needed.  The vxWorks CACHE_DMA_FLUSH/INVALIDATE macros
 * are used to ensure that this memory is flushed/invalidated at the correct
 * times (assuming that cacheable-memory *might* be allocated).
 */

#define DMA_MEMORY_SIZE 	0x10000 /* 64k */

/*  Ensure that alignment is actually a multiple of the cache line size */

#ifdef _CACHE_ALIGN_SIZE
#define DMA_MALLOC(bytes, alignment)    \
    memPartAlignedAlloc (pHost->memPartId, \
			 bytes, \
			 max(alignment, _CACHE_ALIGN_SIZE))
#else
#define DMA_MALLOC(bytes, alignment)    \
    memPartAlignedAlloc (pHost->memPartId, bytes, alignment)
#endif

#define DMA_FREE(pBfr)		memPartFree (pHost->memPartId, (char *) pBfr)

#define DMA_FLUSH(pBfr, bytes)	    CACHE_DMA_FLUSH (pBfr, bytes)
#define DMA_INVALIDATE(pBfr, bytes) CACHE_DMA_INVALIDATE (pBfr, bytes)

#define USER_FLUSH(pBfr, bytes)     CACHE_USER_FLUSH (pBfr, bytes)
#define USER_INVALIDATE(pBfr,bytes) CACHE_USER_INVALIDATE (pBfr, bytes)


/* HC I/O access macros.
 *
 * NOTE: These macros assume that the calling function defines pHost.
 * 
 * NOTE: These macros also require that the register offset, p, be evenly
 * divisible by 4, e.g., UINT32 access only.
 */


#define HC_DWORD_IN(p)     ohciLongRead(pHost, p)
#define HC_DWORD_OUT(p,d)   *((volatile UINT32 *) (pHost->memBase \
					 + (p) / 4))  = TO_LITTLEL (d)

#define HC_SET_BITS(p,bits) HC_DWORD_OUT (p, HC_DWORD_IN (p) | (bits))
#define HC_CLR_BITS(p,bits) HC_DWORD_OUT (p, HC_DWORD_IN (p) & ~(bits))


/* FINDEX() creates a valid OHCI frame number from the argument. */

#define FINDEX(f)   ((f) & (OHCI_FRAME_WINDOW - 1))


/*
 * The HCD adds HC_FRAME_SKIP to the current frame counter to determine
 * the first available frame for scheduling. This introduces a latency at
 * the beginning of each IRP, but also helps to ensure that the HC won't
 * run ahead of the HCD while the HCD is scheduling a transaction.
 */

#define HC_FRAME_SKIP	    2


/* defaults for IRPs which don't specify corresponding values */

#define DEFAULT_PACKET_SIZE 8	/* max packet size */
#define DEFAULT_INTERVAL    32	/* interrupt pipe srvc interval */


/* defines for emulated USB descriptors */

#define USB_RELEASE	0x0110	/* USB level supported by this code */

#define HC_MAX_PACKET_SIZE  8
    
#define HC_CONFIG_VALUE     1

#define HC_STATUS_ENDPOINT_ADRS (1 | USB_ENDPOINT_IN)


/* string identifiers */

#define UNICODE_ENGLISH     0x409

#define HC_STR_MFG	1
#define HC_STR_MFG_VAL	    "Wind River Systems"

#define HC_STR_PROD	2
#define HC_STR_PROD_VAL     "OHCI Root Hub"


/* PCI pointer macros */
#if 0
#define TO_PCIPTR(p)	    (((p) == NULL) ? 0 : USB_MEM_TO_PCI (p))
#define FROM_PCIPTR(d)	    (((d) == 0) ? 0 : USB_PCI_TO_MEM (d))

#else /* --changed by Ajay for AHB based S3C2510 OHCI host controller */


/* 
 * Following macros assumes
 * 1. AHB based S3C2510 OHCI host controller fakes its vendorId and deviceId
 *    as OxFFFF
 * 2. Calling function defines the pHost
 */
#define TO_PCIPTR(p)  (((p) == NULL)? 0 :\
                        (((pHost->pciCfgHdr.vendorId == INVALID_PCI_VENDOR_ID) && \
                          (pHost->pciCfgHdr.deviceId == INVALID_PCI_DEVICE_ID))?(UINT32)(p):\
                         USB_MEM_TO_PCI (p)))
                         
#define FROM_PCIPTR(d) (((d) == 0)? 0 :\
                        (((pHost->pciCfgHdr.vendorId == INVALID_PCI_VENDOR_ID) && \
                          (pHost->pciCfgHdr.deviceId == INVALID_PCI_DEVICE_ID))?(void *)(d):\
                         USB_PCI_TO_MEM (d)))

#endif/* PCI pointer macros */

#define ED_FROM_PCIPTR(d)   ((pED_WRAPPER) (FROM_PCIPTR (FROM_LITTLEL (d))))
#define TD_FROM_PCIPTR(d)   ((pTD_WRAPPER) (FROM_PCIPTR (FROM_LITTLEL (d))))


/* interrupt definitions */
#define INT_ENABLE_MASK \
    (OHCI_INT_WDH | OHCI_INT_RD | OHCI_INT_UE | OHCI_INT_RHSC | OHCI_INT_MIE)

/* typedefs */

/*
 * ED_WRAPPER
 *
 * ED_WRAPPER combines the OHCI_ED with software-specific data.
 */

typedef union ed_wrapper
    {
    VOLATILE OHCI_ED ed;	/* OHCI ED, 16 bytes */
    struct
	{
	UINT8 resvd [sizeof (OHCI_ED)];	/* space used by OHCI ED */
	struct hcd_pipe *pPipe;		/* pointer to owning pipe */
	} sw;
    } ED_WRAPPER, *pED_WRAPPER;


/*
 * TD_WRAPPER
 *
 * OHCI defines two TD formats: "general" for ctl/bulk/int and "isochronous".
 * The TD_WRAPPER combines these structures with software-specific data.
 */

typedef union td_wrapper
    {
    VOLATILE OHCI_TD_GEN tdg;		/* ctl/bulk/int OHCI TD, 16 bytes */
    VOLATILE OHCI_TD_ISO tdi;		/* isochronous OHCI TD, 32 bytes */
    struct
	{
	UINT8 resvd [sizeof (OHCI_TD_ISO)]; /* space used by OHCI TD */
	struct irp_workspace *pWork;	/* pointer to IRP workspace */
	UINT32 nanoseconds; 		/* exec time for this TD */
	UINT32 curBfrPtr;		/* original cbp for this TD */
	union td_wrapper *doneLink;     /* used when handling done queue */
	UINT32 inUse;			/* non-zero if TD in use */
	UINT32 pad [3];			/* pad to an even 64 bytes */
	} sw;
    } TD_WRAPPER, *pTD_WRAPPER;

#define TD_WRAPPER_LEN	    64			/* expected TD_WRAPPER length */
#define TD_WRAPPER_ACTLEN   sizeof (TD_WRAPPER)	/* actual */


/*
 * HCD_PIPE
 *
 * HCD_PIPE maintains all information about an active pipe.
 */

typedef struct hcd_pipe
    {
    HCD_PIPE_HANDLE pipeHandle;	/* handle assigned to pipe */

    LINK link;			/* linked list of pipes */

    UINT16 busAddress;		/* bus address of USB device */
    UINT16 endpoint;		/* device endpoint */
    UINT16 transferType;	/* transfer type */
    UINT16 direction;		/* transfer/pipe direction */
    UINT16 speed;		/* transfer speed */
    UINT16 maxPacketSize;	/* packet size */
    UINT32 bandwidth;		/* bandwidth required by pipe */
    UINT16 interval;		/* service interval */
    UINT16 actInterval; 	/* service interval we really use */

    UINT32 time;		/* bandwidth (time) allocated to pipe */

    pED_WRAPPER pEd;		/* ED allocated for this pipe */

    UINT16 tdCount;		/* number of TDs allocated for pipe */
    UINT16 freeTdCount; 	/* count of TDs currently available */
    UINT16 freeTdIndex; 	/* first available TD */
    pTD_WRAPPER pTds;		/* pointer to TD(s) */

    } HCD_PIPE, *pHCD_PIPE;


/*
 * IRP_WORKSPACE
 *
 * Associates EDs and TDs with the IRPs they are currently servicing.
 */

typedef struct irp_workspace
    {
    pHCD_PIPE pPipe;		/* pointer to pipe for this IRP */
    pUSB_IRP pIrp;		    /* pointer to parent IRP */

    UINT16 bfrNo;		/* highest IRP bfrList[] serviced */
    UINT32 bfrOffset;		/* offset into bfrList[].pBfr */
    BOOL zeroLenMapped; 	/* TRUE when zero len bfrList [] serviced */

    UINT32 isochTdsCreated;	/* count of isoch TDs created, in total */
    UINT32 frameCount;		/* count of frames used for isoch pipe */
    UINT32 bytesSoFar;		/* bytes transferred so far for isoch pipe */

    UINT16 isochNext;		/* next isoch frame number to schedule */

    BOOL irpRunning;		/* TRUE once IRP scheduled onto bus */
    UINT32 startTime;		/* time when IRP was scheduled onto bus */

    } IRP_WORKSPACE, *pIRP_WORKSPACE;


/*
 * HCD_HOST
 *
 * HCD_HOST maintains all information about a connection to a specific
 * host controller (HC).
 */

typedef struct hcd_host
    {
    HCD_CLIENT_HANDLE handle;	/* handle associated with host */
    BOOL shutdown;		/* TRUE during shutdown */

    PCI_CFG_HEADER pciCfgHdr;	/* PCI config header for HC */
    VOLATILE UINT32 * memBase;	    /* Base address */

    USB_HCD_MNGMT_CALLBACK mngmtCallback; /* callback routine for mngmt evt */
    pVOID mngmtCallbackParam;	/* caller-defined parameter */

    MUTEX_HANDLE hostMutex;	/* guards host structure */

    THREAD_HANDLE intThread;	/* Thread used to handle interrupts */
    SEM_HANDLE intPending;	/* semaphore indicates int pending */
    BOOL intThreadExitRequest;	/* TRUE when intThread should terminate */
    SEM_HANDLE intThreadExit;	/* signalled when int thread exits */
    UINT32 intCount;		/* number of interrupts processed */
    BOOL intInstalled;		/* TRUE when h/w int handler installed */

    UINT16 rootAddress; 	/* current address of root hub */
    UINT8 configValue;		/* current configuration value */

    UINT16 numPorts;		/* number of root ports */
    UINT16 pwrOn2PwrGood;	/* Power ON to power good time. */

    pUINT32 pRhPortChange;	/* port change status */

    USB_DEVICE_DESCR devDescr;	    /* standard device descriptor */
    USB_CONFIG_DESCR configDescr;   /* standard config descriptor */
    USB_INTERFACE_DESCR ifDescr;    /* standard interface descriptor */
    USB_ENDPOINT_DESCR endpntDescr; /* standard endpoint descriptor */
    USB_HUB_DESCR hubDescr;	/* root hub descriptor */

    LIST_HEAD pipes;		/* active pipes */

    UINT16 rootIrpCount;	/* count of entries on pRootIrps */
    LIST_HEAD rootIrps; 	/* IRPs pending on root hub */

    LIST_HEAD busIrps;		/* IRPs pending on devices not */
				/* including root hub */

    char *dmaPool;		/* memory alloc'd by cacheDmaMalloc() */
    PART_ID memPartId;		/* memory partition ID */

    pOHCI_HCCA pHcca;		/* OHCI HCCA */

    pED_WRAPPER pIsochAnchorEd;	/* Anchor for isochronous transfers */

    UINT32 nanoseconds; 	/* current worst case of bus time */
				/* required for scheduled TDs */

    UINT16 sofInterval; 	/* current SOF interval */

    BOOL suspended;		/* TRUE when global suspend is TRUE */

    UINT32 errScheduleOverrun;	/* count of schedule overrun errors */
    UINT32 errUnrecoverable;	/* count of unrecoverabl HC errors */

    UINT32 pHcControlReg;	/* Control Register Copy */
    SEM_ID hcSyncSem;		/* syncronization semaphore */

    } HCD_HOST, *pHCD_HOST;


/* locals */

/* Language descriptor */

LOCAL USB_LANGUAGE_DESCR langDescr =
    {sizeof (USB_LANGUAGE_DESCR), USB_DESCR_STRING, 
    {TO_LITTLEW (UNICODE_ENGLISH)}};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -