usbHcdOhciLib.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:100k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* usbHcdOhciLib.c - Host Controller Driver (HCD) for OHCI */
  2. /* Copyright 2000-2002 Wind River Systems, Inc. */
  3. /*
  4. Modification history
  5. --------------------
  6. 01p,22may02,wef  Fix SPR 73864 - USB crashes when cable is disconnected while 
  7.  iscoh transfer is in progress - valid only on PPC, MIPS and 
  8.  STRONGARM, not X86.
  9. 010,29apr02,wef  Fix SPR's 71274, 71273 and clean up fncAttach().
  10. 01p,18mar02,h_k  made buffer swap's in several places - spr # 73896 and 73920.
  11. 01o,05feb01,wef  explicitly power to ports on initial HC attachment.
  12. 01k,13dec01,wef  merge from veloce view
  13. 01j,24jul01,wef  Fixed SPR #68617
  14. 01i,23jul01,wef  Fixed SPR #68202 and SPR #68209
  15. 01h,01jan01,wef  Fixed alignment problems w/ code, general clean up
  16. 01g,12apr00,wef  Fixed uninitialized variable warning: controlin assignTds(),
  17.  fixed a comment that was messing up the man page generation
  18. 01f,27mar00,rcb  Fix bug in scheduling interrupt EDs which allowed an ED
  19.  to be circularly-linked.
  20. 01e,20mar00,rcb  Flush all cache buffers during assignTds() to avoid 
  21.  cache-line boundary problems with some CPU architectures
  22.  (e.g., MIPS).
  23. 01d,17mar00,rcb  Add code to update tdHead in ED structure when removing
  24.  TDs from queue...corrects bug which allowed OHCI ctlr
  25.  to try to process an aborted TD.
  26. 01c,10mar00,rcb  Fix bug in pipe destroy logic which attempted to free
  27.  non-existent EDs for root hub.
  28.  Add "volatile" declaration in HC_DWORD_IN/OUT().
  29. 01b,26jan00,rcb  Change references to "bytesPerFrame" to "bandwidth" in
  30.  pipe creation logic.
  31.  Modify isoch. timing to maintain rate as specified by
  32.  pipe bandwidth parameter.
  33.  Fix big vs. little-endian bug in unscheduleControlIrp()
  34.  and unscheduleBulkIrp().
  35. 01a,05oct99,rcb  First.
  36. */
  37. /*
  38. DESCRIPTION
  39. This is the HCD (host controller driver) for OHCI.  This file implements
  40. low-level functions required by the client (typically the USBD) to talk to
  41. the underlying USB host controller hardware.  
  42. The <param> to the HRB_ATTACH request should be a pointer to a 
  43. PCI_CFG_HEADER which contains the PCI configuration header for the
  44. OpenHCI host controller to be managed. Each invocation of the HRB_ATTACH
  45. function will return an HCD_CLIENT_HANDLE for which a single host controller
  46. will be exposed.
  47. NOTE: This HCD implementation assumes that the caller has already initialized
  48. the osServices and handleFuncs libraries by calling ossInitialize() and
  49. usbHandleInitialize(), respectively.  The USBD implementation guarantees that
  50. these libraries have been initialized prior to invoking the HCD.
  51. Regarding IRP callbacks...
  52. There are two callback function pointers in each IRP, <usbdCallback> and
  53. <userCallback>.  By convention, if a non-NULL <usbdCallback> is supplied,
  54. then the HCD invokes only the <usbdCallback> upon IRP completion - and it is
  55. the USBD's responsibility to invoke the <userCallback>.  If no <usbdCallback>
  56. is provided, then the HCD invokes the <userCallback> directly. Typically, 
  57. all IRPs are delivered to the HCD through the USBD and a non-NULL <usbdCallback>
  58. will in fact be provided.
  59. Regarding OHCI frame lists...
  60. We use the OHCI frame list largely as anticipated in the OpenHCI specification.
  61. Each of the 32 interrupt list heads points either to an interrupt ED (endpoint
  62. descriptor) or to an isochronous ED "anchor" (at which point all 32 lists 
  63. converge).  When one or more interrupt pipes are created, EDs for these pipes 
  64. will be inserted in the interrupt list one or more times, corresponding to the
  65. desired interrupt polling interval.  The last interrupt ED in each list points 
  66. to the common isochronous anchor ED.  While clients can request any interrupt 
  67. service interval they like, the algorithms here always choose an
  68. interval which is the largest power of 2 less than or equal to the client's
  69. desired interval.  For example, if a client requests an interval of 20msec, the
  70. HCD will select a real interval of 16msec.  In each frame work list, the least
  71. frequently scheduled EDs appear ahead of more frequently scheduled EDs.  Since
  72. only a single ED is actually created for each interrupt transfer, the individual
  73. frame lists actually "merge" at each interrupt ED.   
  74. The OpenHCI host controller maintains separate lists for control and bulk
  75. transfers.  OpenHCI allows for a control/bulk service ratio, so the control list
  76. can be serviced n times for each servicing of the bulk list.  In the present
  77. implementation, we use a service ratio of 3:1.
  78. Regarding bus time calculations...
  79. The host controller driver is responsible for ensuring that certain kinds of
  80. scheduled transfers never exceed the time available in a USB frame.  The HCD 
  81. and the USBD work cooperatively to ensure this.  For its part, the USBD never 
  82. allows isochronous and interrupt transfers to be scheduled which would exceed 
  83. 90% of the bus bandwidth.  However, the USBD will freely allow control and bulk 
  84. pipes to be created, as these types of transfers take whatever bus time is left 
  85. over after isochronous and interrupt transfers have been schedule - and the
  86. HCD gives priority to control transfers.
  87. The HCD keeps a running total of the worst case amount of bus time alloted to 
  88. active isochronous and interrupt transfers.  As for control and bulk transfers,
  89. the HC theoretically allows us to schedule as many of them as we desire, and it
  90. keeps track of how much time remains in each frame, executing only as many of
  91. these transfers as will fit.  However, the HC requires that the driver schedule
  92. only as many low speed control transfers (as opposed to full speed control
  93. transfers) as can actually fit within the frame.  Therefore, after taking into
  94. account the time already allotted to isochronous and interrupt transfers, the
  95. HCD only schedules as many low speed control transfers as can fit within the
  96. current frame - and full speed control and bulk transfers follow. 
  97. */
  98. /* includes */
  99. #include "usb/usbPlatform.h"
  100. #include "string.h"
  101. #include "memLib.h"     /* memory sub-allocation functions */
  102. #include "cacheLib.h" /* cache functions */
  103. #include "semLib.h" /* cache functions */
  104. #include "usb/ossLib.h"
  105. #include "usb/usbHandleLib.h"
  106. #include "usb/pciConstants.h"
  107. #include "usb/usbPciLib.h"
  108. #include "usb/usbLib.h"
  109. #include "drv/usb/usbHcd.h"
  110. #include "drv/usb/usbOhci.h"
  111. #include "drv/usb/usbHcdOhciLib.h"
  112. /* defines */
  113. #define PENDING  1
  114. #define HCD_HOST_SIG     ((UINT32) 0x00cd0080)
  115. #define HCD_PIPE_SIG     ((UINT32) 0x00cd0081)
  116. #define MAX_INT_DEPTH     8     /* max depth of pending interrupts */
  117. #define INT_TIMEOUT 5000 /* wait 5 seconds for int routine to exit */
  118. #define BIT_TIMEOUT 1000 /* max time to wait for a bit change */
  119. #define HC_TIMEOUT_SRVC_INTERVAL    1000    /* milliseconds */
  120. /* HC_HOST_DELAY and HC_HUB_LS_SETUP are host-controller specific.
  121.  * The following values are estimates for the OHCI controller.
  122.  */
  123. #define HC_HOST_DELAY ((UINT32) 500L)     /* 500 ns, est. */
  124. #define HC_HUB_LS_SETUP ((UINT32) 500L)     /* 500 ns, est. */
  125. /* OHCI constants unique to this driver implementation. */
  126. #define REQUIRED_OHCI_LEVEL 0x10    /* OHCI rev 1.0 or higher */
  127. #define MAX_FRAME_OVERHEAD  210 /* cf. OHCI spec. sec 5.4 */
  128. #define MAX_ROOT_PORTS     8 /* max root hub ports we support */
  129. #define OHCI_HUB_CONTR_CURRENT 0   /* root hub controller current */
  130. #define OHCI_HUB_INTERVAL   255 /* root hub polling interval */
  131. #define TD_COUNT_GEN     2 /* count of TDs for generic pipe */
  132. #define TD_COUNT_ISO     16 /* count of TDs for isoch pipe */
  133. #ifndef USB_BUFFER_SWAP
  134. #define USB_BUFFER_SWAP(pBuf,len)   /* default: don't swap buffers */
  135. #endif  /* USB_BUFFER_SWAP */
  136. #ifndef SYS_OHCI_RESET
  137. #define SYS_OHCI_RESET() /* default: don't need reset */
  138. #endif  /* SYS_OHCI_RESET */
  139. /*
  140.  * MEMORY
  141.  * 
  142.  * To improve performance, a single block of (probably) "non-cached"
  143.  * memory is allocated.  Then, all OHCI control structures are sub-allocated
  144.  * from this block as needed.  The vxWorks CACHE_DMA_FLUSH/INVALIDATE macros
  145.  * are used to ensure that this memory is flushed/invalidated at the correct
  146.  * times (assuming that cacheable-memory *might* be allocated).
  147.  */
  148. #define DMA_MEMORY_SIZE  0x10000 /* 64k */
  149. /*  Ensure that alignment is actually a multiple of the cache line size */
  150. #ifdef _CACHE_ALIGN_SIZE
  151. #define DMA_MALLOC(bytes, alignment)    
  152.     memPartAlignedAlloc (pHost->memPartId, 
  153.  bytes, 
  154.  max(alignment, _CACHE_ALIGN_SIZE))
  155. #else
  156. #define DMA_MALLOC(bytes, alignment)    
  157.     memPartAlignedAlloc (pHost->memPartId, bytes, alignment)
  158. #endif
  159. #define DMA_FREE(pBfr) memPartFree (pHost->memPartId, (char *) pBfr)
  160. #define DMA_FLUSH(pBfr, bytes)     CACHE_DMA_FLUSH (pBfr, bytes)
  161. #define DMA_INVALIDATE(pBfr, bytes) CACHE_DMA_INVALIDATE (pBfr, bytes)
  162. #define USER_FLUSH(pBfr, bytes)     CACHE_USER_FLUSH (pBfr, bytes)
  163. #define USER_INVALIDATE(pBfr,bytes) CACHE_USER_INVALIDATE (pBfr, bytes)
  164. /* HC I/O access macros.
  165.  *
  166.  * NOTE: These macros assume that the calling function defines pHost.
  167.  * 
  168.  * NOTE: These macros also require that the register offset, p, be evenly
  169.  * divisible by 4, e.g., UINT32 access only.
  170.  */
  171. #define HC_DWORD_IN(p)     ohciLongRead(pHost, p)
  172. #define HC_DWORD_OUT(p,d)   *((volatile UINT32 *) (pHost->memBase 
  173.  + (p) / 4))  = TO_LITTLEL (d)
  174. #define HC_SET_BITS(p,bits) HC_DWORD_OUT (p, HC_DWORD_IN (p) | (bits))
  175. #define HC_CLR_BITS(p,bits) HC_DWORD_OUT (p, HC_DWORD_IN (p) & ~(bits))
  176. /* FINDEX() creates a valid OHCI frame number from the argument. */
  177. #define FINDEX(f)   ((f) & (OHCI_FRAME_WINDOW - 1))
  178. /*
  179.  * The HCD adds HC_FRAME_SKIP to the current frame counter to determine
  180.  * the first available frame for scheduling. This introduces a latency at
  181.  * the beginning of each IRP, but also helps to ensure that the HC won't
  182.  * run ahead of the HCD while the HCD is scheduling a transaction.
  183.  */
  184. #define HC_FRAME_SKIP     2
  185. /* defaults for IRPs which don't specify corresponding values */
  186. #define DEFAULT_PACKET_SIZE 8 /* max packet size */
  187. #define DEFAULT_INTERVAL    32 /* interrupt pipe srvc interval */
  188. /* defines for emulated USB descriptors */
  189. #define USB_RELEASE 0x0110 /* USB level supported by this code */
  190. #define HC_MAX_PACKET_SIZE  8
  191.     
  192. #define HC_CONFIG_VALUE     1
  193. #define HC_STATUS_ENDPOINT_ADRS (1 | USB_ENDPOINT_IN)
  194. /* string identifiers */
  195. #define UNICODE_ENGLISH     0x409
  196. #define HC_STR_MFG 1
  197. #define HC_STR_MFG_VAL     "Wind River Systems"
  198. #define HC_STR_PROD 2
  199. #define HC_STR_PROD_VAL     "OHCI Root Hub"
  200. /* PCI pointer macros */
  201. #define TO_PCIPTR(p)     (((p) == NULL) ? 0 : USB_MEM_TO_PCI (p))
  202. #define FROM_PCIPTR(d)     (((d) == 0) ? 0 : USB_PCI_TO_MEM (d))
  203. #define ED_FROM_PCIPTR(d)   ((pED_WRAPPER) (FROM_PCIPTR (FROM_LITTLEL (d))))
  204. #define TD_FROM_PCIPTR(d)   ((pTD_WRAPPER) (FROM_PCIPTR (FROM_LITTLEL (d))))
  205. /* interrupt definitions */
  206. #define INT_ENABLE_MASK 
  207.     (OHCI_INT_WDH | OHCI_INT_RD | OHCI_INT_UE | OHCI_INT_RHSC | OHCI_INT_MIE)
  208. /* typedefs */
  209. /*
  210.  * ED_WRAPPER
  211.  *
  212.  * ED_WRAPPER combines the OHCI_ED with software-specific data.
  213.  */
  214. typedef union ed_wrapper
  215.     {
  216.     VOLATILE OHCI_ED ed; /* OHCI ED, 16 bytes */
  217.     struct
  218. {
  219. UINT8 resvd [sizeof (OHCI_ED)]; /* space used by OHCI ED */
  220. struct hcd_pipe *pPipe; /* pointer to owning pipe */
  221. } sw;
  222.     } ED_WRAPPER, *pED_WRAPPER;
  223. /*
  224.  * TD_WRAPPER
  225.  *
  226.  * OHCI defines two TD formats: "general" for ctl/bulk/int and "isochronous".
  227.  * The TD_WRAPPER combines these structures with software-specific data.
  228.  */
  229. typedef union td_wrapper
  230.     {
  231.     VOLATILE OHCI_TD_GEN tdg; /* ctl/bulk/int OHCI TD, 16 bytes */
  232.     VOLATILE OHCI_TD_ISO tdi; /* isochronous OHCI TD, 32 bytes */
  233.     struct
  234. {
  235. UINT8 resvd [sizeof (OHCI_TD_ISO)]; /* space used by OHCI TD */
  236. struct irp_workspace *pWork; /* pointer to IRP workspace */
  237. UINT32 nanoseconds;  /* exec time for this TD */
  238. UINT32 curBfrPtr; /* original cbp for this TD */
  239. union td_wrapper *doneLink;     /* used when handling done queue */
  240. UINT32 inUse; /* non-zero if TD in use */
  241. UINT32 pad [3]; /* pad to an even 64 bytes */
  242. } sw;
  243.     } TD_WRAPPER, *pTD_WRAPPER;
  244. #define TD_WRAPPER_LEN     64 /* expected TD_WRAPPER length */
  245. #define TD_WRAPPER_ACTLEN   sizeof (TD_WRAPPER) /* actual */
  246. /*
  247.  * HCD_PIPE
  248.  *
  249.  * HCD_PIPE maintains all information about an active pipe.
  250.  */
  251. typedef struct hcd_pipe
  252.     {
  253.     HCD_PIPE_HANDLE pipeHandle; /* handle assigned to pipe */
  254.     LINK link; /* linked list of pipes */
  255.     UINT16 busAddress; /* bus address of USB device */
  256.     UINT16 endpoint; /* device endpoint */
  257.     UINT16 transferType; /* transfer type */
  258.     UINT16 direction; /* transfer/pipe direction */
  259.     UINT16 speed; /* transfer speed */
  260.     UINT16 maxPacketSize; /* packet size */
  261.     UINT32 bandwidth; /* bandwidth required by pipe */
  262.     UINT16 interval; /* service interval */
  263.     UINT16 actInterval;  /* service interval we really use */
  264.     UINT32 time; /* bandwidth (time) allocated to pipe */
  265.     pED_WRAPPER pEd; /* ED allocated for this pipe */
  266.     UINT16 tdCount; /* number of TDs allocated for pipe */
  267.     UINT16 freeTdCount;  /* count of TDs currently available */
  268.     UINT16 freeTdIndex;  /* first available TD */
  269.     pTD_WRAPPER pTds; /* pointer to TD(s) */
  270.     } HCD_PIPE, *pHCD_PIPE;
  271. /*
  272.  * IRP_WORKSPACE
  273.  *
  274.  * Associates EDs and TDs with the IRPs they are currently servicing.
  275.  */
  276. typedef struct irp_workspace
  277.     {
  278.     pHCD_PIPE pPipe; /* pointer to pipe for this IRP */
  279.     pUSB_IRP pIrp;     /* pointer to parent IRP */
  280.     UINT16 bfrNo; /* highest IRP bfrList[] serviced */
  281.     UINT32 bfrOffset; /* offset into bfrList[].pBfr */
  282.     BOOL zeroLenMapped;  /* TRUE when zero len bfrList [] serviced */
  283.     UINT32 isochTdsCreated; /* count of isoch TDs created, in total */
  284.     UINT32 frameCount; /* count of frames used for isoch pipe */
  285.     UINT32 bytesSoFar; /* bytes transferred so far for isoch pipe */
  286.     UINT16 isochNext; /* next isoch frame number to schedule */
  287.     BOOL irpRunning; /* TRUE once IRP scheduled onto bus */
  288.     UINT32 startTime; /* time when IRP was scheduled onto bus */
  289.     } IRP_WORKSPACE, *pIRP_WORKSPACE;
  290. /*
  291.  * HCD_HOST
  292.  *
  293.  * HCD_HOST maintains all information about a connection to a specific
  294.  * host controller (HC).
  295.  */
  296. typedef struct hcd_host
  297.     {
  298.     HCD_CLIENT_HANDLE handle; /* handle associated with host */
  299.     BOOL shutdown; /* TRUE during shutdown */
  300.     PCI_CFG_HEADER pciCfgHdr; /* PCI config header for HC */
  301.     VOLATILE UINT32 * memBase;     /* Base address */
  302.     USB_HCD_MNGMT_CALLBACK mngmtCallback; /* callback routine for mngmt evt */
  303.     pVOID mngmtCallbackParam; /* caller-defined parameter */
  304.     MUTEX_HANDLE hostMutex; /* guards host structure */
  305.     THREAD_HANDLE intThread; /* Thread used to handle interrupts */
  306.     SEM_HANDLE intPending; /* semaphore indicates int pending */
  307.     BOOL intThreadExitRequest; /* TRUE when intThread should terminate */
  308.     SEM_HANDLE intThreadExit; /* signalled when int thread exits */
  309.     UINT32 intCount; /* number of interrupts processed */
  310.     BOOL intInstalled; /* TRUE when h/w int handler installed */
  311.     UINT16 rootAddress;  /* current address of root hub */
  312.     UINT8 configValue; /* current configuration value */
  313.     UINT16 numPorts; /* number of root ports */
  314.     UINT16 pwrOn2PwrGood; /* Power ON to power good time. */
  315.     pUINT32 pRhPortChange; /* port change status */
  316.     USB_DEVICE_DESCR devDescr;     /* standard device descriptor */
  317.     USB_CONFIG_DESCR configDescr;   /* standard config descriptor */
  318.     USB_INTERFACE_DESCR ifDescr;    /* standard interface descriptor */
  319.     USB_ENDPOINT_DESCR endpntDescr; /* standard endpoint descriptor */
  320.     USB_HUB_DESCR hubDescr; /* root hub descriptor */
  321.     LIST_HEAD pipes; /* active pipes */
  322.     UINT16 rootIrpCount; /* count of entries on pRootIrps */
  323.     LIST_HEAD rootIrps;  /* IRPs pending on root hub */
  324.     LIST_HEAD busIrps; /* IRPs pending on devices not */
  325. /* including root hub */
  326.     char *dmaPool; /* memory alloc'd by cacheDmaMalloc() */
  327.     PART_ID memPartId; /* memory partition ID */
  328.     pOHCI_HCCA pHcca; /* OHCI HCCA */
  329.     pED_WRAPPER pIsochAnchorEd; /* Anchor for isochronous transfers */
  330.     UINT32 nanoseconds;  /* current worst case of bus time */
  331. /* required for scheduled TDs */
  332.     UINT16 sofInterval;  /* current SOF interval */
  333.     BOOL suspended; /* TRUE when global suspend is TRUE */
  334.     UINT32 errScheduleOverrun; /* count of schedule overrun errors */
  335.     UINT32 errUnrecoverable; /* count of unrecoverabl HC errors */
  336.     UINT32 pHcControlReg; /* Control Register Copy */
  337.     SEM_ID hcSyncSem; /* syncronization semaphore */
  338.     } HCD_HOST, *pHCD_HOST;
  339. /* locals */
  340. /* Language descriptor */
  341. LOCAL USB_LANGUAGE_DESCR langDescr =
  342.     {sizeof (USB_LANGUAGE_DESCR), USB_DESCR_STRING, 
  343.     {TO_LITTLEW (UNICODE_ENGLISH)}};
  344. /***************************************************************************
  345. *
  346. * ohciLongRead - Read a 32 bit value from the OHCI controller.
  347. *
  348. * RETURNS: A big-endian adjusted UINT32 
  349. */
  350. LOCAL UINT32 ohciLongRead
  351.     (
  352.     pHCD_HOST pHost,
  353.     UINT32 offset
  354.     )
  355.     {
  356.     CACHE_PIPE_FLUSH ();
  357.     return FROM_LITTLEL (*((volatile UINT32 *) (pHost->memBase + 
  358. (offset) / 4)));
  359.     }
  360. /***************************************************************************
  361. *
  362. * waitOnBits - wait for a word register bit to reach the desired state
  363. *
  364. * RETURNS: TRUE if successful, else FALSE if desired bit state not detected
  365. */
  366. LOCAL BOOL waitOnBits
  367.     (
  368.     pHCD_HOST pHost,
  369.     UINT32 p,
  370.     UINT32 bitMask,
  371.     UINT32 bitState
  372.     )
  373.     {
  374.     UINT32 start = OSS_TIME ();
  375.     BOOL desiredState;
  376.     while (!(desiredState = ((HC_DWORD_IN (p) & bitMask) == bitState)) && 
  377.     OSS_TIME () - start < BIT_TIMEOUT)
  378. ;
  379.     return desiredState;    
  380.     }
  381. /***************************************************************************
  382. *
  383. * getFrameNo - returns current hardware frame number
  384. *
  385. * RETURNS: value of current frame number
  386. */
  387. LOCAL UINT16 getFrameNo
  388.     (
  389.     pHCD_HOST pHost
  390.     )
  391.     {
  392.     return OHCI_FMN_FN (HC_DWORD_IN (OHCI_HC_FM_NUMBER));
  393.     }
  394. /***************************************************************************
  395. *
  396. * setFrameInterval - sets OHCI frame interval 
  397. *
  398. * RETURNS: N/A
  399. */
  400. LOCAL VOID setFrameInterval
  401.     (
  402.     pHCD_HOST pHost,
  403.     UINT16 sofInterval
  404.     )
  405.     {
  406.     UINT32 fmi;
  407.     fmi = HC_DWORD_IN (OHCI_HC_FM_INTERVAL) & ~OHCI_FMI_FIT;
  408.     fmi ^= OHCI_FMI_FIT;
  409.     fmi |= OHCI_FMI_FI_FMT (sofInterval);
  410.     fmi |= OHCI_FMI_FSMPS_FMT (((sofInterval - MAX_FRAME_OVERHEAD) * 6) / 7);
  411.     HC_DWORD_OUT (OHCI_HC_FM_INTERVAL, fmi);
  412.     pHost->sofInterval = sofInterval;
  413.     }
  414. /***************************************************************************
  415. *
  416. * hcSynch - give the host controller a chance to synchronize
  417. *
  418. * RETURNS: N/A
  419. */
  420. LOCAL VOID hcSynch
  421.     (
  422.     pHCD_HOST pHost
  423.     )
  424.     {
  425.     UINT16 currentFrameNo = getFrameNo (pHost);
  426.     while (getFrameNo (pHost) == currentFrameNo);
  427. semTake (pHost->hcSyncSem, 1);
  428. semTake (pHost->hcSyncSem, 1);
  429.     }
  430. /***************************************************************************
  431. *
  432. * setIrpResult - sets result in IRP and executes IRP callback
  433. *
  434. * RETURNS: value from Irp result field
  435. */
  436. LOCAL int setIrpResult
  437.     (
  438.     pUSB_IRP pIrp,
  439.     int result
  440.     )
  441.     {
  442.     if (result != PENDING)
  443. {
  444. pIrp->result = result;
  445. if (pIrp->usbdCallback != NULL)
  446.     (*pIrp->usbdCallback) (pIrp);
  447. else if (pIrp->userCallback != NULL)
  448.     (*pIrp->userCallback) (pIrp);
  449. }
  450.     return result;
  451.     }
  452. /***************************************************************************
  453. *
  454. * calcIntInterval - calculates the scheduling interval for interrupt transfer
  455. *
  456. * RETURNS: Actual interval to be used for interrupt transfer
  457. */
  458. LOCAL UINT16 calcIntInterval
  459.     (
  460.     UINT16 interval /* 1 <= requested interval <= OHCI_INT_ED_COUNT */
  461.     )
  462.     {
  463.     UINT16 i;
  464.     /* Select an interval which is the largest power of two less than or
  465.      * equal to the requested interval.
  466.      */
  467.     for (i = 2; i < OHCI_INT_ED_COUNT + 1; i <<= 1)
  468. {
  469. if (i > interval)
  470.     break;
  471. }
  472.     return i >> 1;
  473.     }
  474. /***************************************************************************
  475. *
  476. * freeIrpWorkspace - releases IRP_WORKSPACE
  477. *
  478. * Releases the IRP_WORKSPACE associated with an IRP (if there is one).
  479. *
  480. * RETURNS: N/A
  481. */
  482. LOCAL VOID freeIrpWorkspace
  483.     (
  484.     pHCD_HOST pHost,
  485.     pUSB_IRP pIrp
  486.     )
  487.     {
  488.     pIRP_WORKSPACE pWork = (pIRP_WORKSPACE) pIrp->hcdPtr;
  489.     if (pWork != NULL)
  490. {
  491. OSS_FREE (pWork);
  492. pIrp->hcdPtr = NULL;
  493. }
  494.     }
  495. /***************************************************************************
  496. *
  497. * allocIrpWorkspace - creates workspace for IRP
  498. *
  499. * Creates an IRP_WORKSPACE structure to manage the IRP data transfer.
  500. *
  501. * RETURNS: TRUE if successful, else FALSE
  502. */
  503. LOCAL BOOL allocIrpWorkspace
  504.     (
  505.     pHCD_HOST pHost,
  506.     pHCD_PIPE pPipe,
  507.     pUSB_IRP pIrp
  508.     )
  509.     {
  510.     pIRP_WORKSPACE pWork;
  511.     /* Allocate IRP_WORKSPACE */
  512.     if ((pWork = OSS_CALLOC (sizeof (*pWork))) == NULL)
  513. return FALSE;
  514.     pIrp->hcdPtr = pWork;
  515.     pWork->pPipe = pPipe;
  516.     pWork->pIrp = pIrp;
  517.     return TRUE;
  518.     }
  519. /***************************************************************************
  520. *
  521. * isBandwidthTracked - determines if bandwidth is tracked for this transfer
  522. *
  523. * Since the USBD has already reserved adequate bandwidth for isochronous
  524. * and interrupt transfers, we only track low speed control transfers.
  525. *
  526. * RETURNS: TRUE if bandwidth tracked, else FALSE.
  527. */
  528. LOCAL BOOL isBandwidthTracked
  529.     (
  530.     pHCD_PIPE pPipe
  531.     )
  532.     {
  533.     if (pPipe->transferType == USB_XFRTYPE_CONTROL && 
  534.        pPipe->speed == USB_SPEED_LOW)
  535. return TRUE;
  536.     return FALSE;
  537.     }
  538. /***************************************************************************
  539. *
  540. * dirFromPid - returns USB_DIR_xxxx based on USB_PID_xxxx
  541. *
  542. * RETURNS: USB_DIR_xxxx
  543. */
  544. LOCAL UINT16 dirFromPid
  545.     (
  546.     UINT16 pid
  547.     )
  548.     {
  549.     switch (pid)
  550. {
  551. case USB_PID_SETUP:
  552. case USB_PID_OUT:
  553. return USB_DIR_OUT;
  554. case USB_PID_IN:
  555. return USB_DIR_IN;
  556. default:     
  557. return USB_DIR_IN;
  558. }
  559.     }
  560. /***************************************************************************
  561. *
  562. * unscheduleIsochPipe - removes an isoch pipe from the schedule
  563. *
  564. * RETURNS: N/A
  565. */
  566. LOCAL VOID unscheduleIsochPipe
  567.     (
  568.     pHCD_HOST pHost,
  569.     pHCD_PIPE pPipe
  570.     )
  571.     {
  572.     pUINT32 pPciPtrToEd;
  573.     pED_WRAPPER pCurEd;
  574.     /* Note: Instead of halting periodic transfers before delinking, we 
  575.      * immediately delink them and afterward wait for the next frame to start...
  576.      * This ensures that caller won't de-allocate the structures while the
  577.      * HC may still be referencing them.
  578.      */
  579.     /* Walk the isoch. list until we find the ED to be removed. */
  580.     pPciPtrToEd = (pUINT32) &pHost->pIsochAnchorEd->ed.nextEd;
  581.     while ((pCurEd = ED_FROM_PCIPTR (*pPciPtrToEd)) != pPipe->pEd)
  582. {
  583. pPciPtrToEd = (pUINT32) &pCurEd->ed.nextEd;
  584. }
  585.     *pPciPtrToEd = pPipe->pEd->ed.nextEd;
  586.     DMA_FLUSH (pPciPtrToEd, sizeof (*pPciPtrToEd));
  587.     /*  
  588.      * shutOffListProcessing() halts isoch, interrupt and bulk transfers 
  589.      * when a device is disconnected, we make sure they are re-enabled.
  590.      */
  591.  
  592.     HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_PLE);
  593.     HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_IE);
  594.     HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_BLE);
  595.     /* Wait for the HC to make sure the structure is really released. */
  596.     hcSynch (pHost);
  597.     }
  598.     
  599. /***************************************************************************
  600. *
  601. * scheduleIsochPipe - inserts isoch pipe into the schedule
  602. *
  603. * Schedules an isochronous transfer for the first time.
  604. *
  605. * RETURNS: N/A
  606. */
  607. LOCAL VOID scheduleIsochPipe
  608.     (
  609.     pHCD_HOST pHost,
  610.     pHCD_PIPE pPipe
  611.     )
  612.     {
  613.     pED_WRAPPER pLastEd;
  614.     pED_WRAPPER pNextEd;
  615.     /* Flush the ED out of the cache before giving it to the HC. */
  616.     DMA_FLUSH (pPipe->pEd, sizeof (*pPipe->pEd));
  617.     /* Append this ED to the end of the isoch. list. */
  618.     pLastEd = pHost->pIsochAnchorEd;
  619.     while ((pNextEd = ED_FROM_PCIPTR (pLastEd->ed.nextEd)) != NULL)
  620. pLastEd = pNextEd;
  621.     pLastEd->ed.nextEd = TO_LITTLEL (TO_PCIPTR (pPipe->pEd));
  622.     DMA_FLUSH (&pLastEd->ed.nextEd, sizeof (pLastEd->ed.nextEd));
  623.     }
  624. /***************************************************************************
  625. *
  626. * unscheduleInterruptPipe - removes interrupt pipe from the schedule
  627. *
  628. * RETURNS: N/A
  629. */
  630. LOCAL VOID unscheduleInterruptPipe
  631.     (
  632.     pHCD_HOST pHost,
  633.     pHCD_PIPE pPipe
  634.     )
  635.     {
  636.     pUINT32 pPciPtrToEd;
  637.     pED_WRAPPER pCurEd;
  638.     UINT16 i;
  639.     /* Note: Instead of halting periodic transfers before delinking, we 
  640.      * immediately delink them and afterward wait for the next frame to start...
  641.      * This ensures that caller won't de-allocate the structures while the
  642.      * HC may still be referencing them.
  643.      */
  644.     /* Remove the pipe from the interrupt lists. */
  645.     for (i = 0; i < OHCI_INT_ED_COUNT; i += pPipe->actInterval)
  646. {
  647. /* Walk this list until we find the ED to be removed. */
  648. pPciPtrToEd = &pHost->pHcca->intEdTable [i];
  649. while ((pCurEd = ED_FROM_PCIPTR (*pPciPtrToEd)) != pHost->pIsochAnchorEd &&
  650. pCurEd->sw.pPipe->actInterval >= pPipe->actInterval &&
  651. pCurEd != pPipe->pEd)
  652.     {
  653.     pPciPtrToEd = (pUINT32) &pCurEd->ed.nextEd;
  654.     }
  655. if (pCurEd == pPipe->pEd)
  656.     {
  657.     *pPciPtrToEd = pPipe->pEd->ed.nextEd;
  658.     DMA_FLUSH (pPciPtrToEd, sizeof (*pPciPtrToEd));
  659.     }
  660. }
  661.     /*  
  662.      * shutOffListProcessing() halts isoch, interrupt and bulk transfers 
  663.      * when a device is disconnected, we make sure they are re-enabled.
  664.      */                 
  665.  
  666.     HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_PLE);
  667.     HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_IE);
  668.     HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_BLE);
  669.     /* Wait for the HC to make sure the structure is really released. */
  670.     hcSynch (pHost);
  671.     }
  672.     
  673. /***************************************************************************
  674. *
  675. * scheduleInterruptPipe - inserts interrupt pipe into the schedule
  676. *
  677. * Schedules an interrupt transfer repeatedly in the frame list as
  678. * indicated by the service interval.
  679. *
  680. * RETURNS: N/A
  681. */
  682. LOCAL VOID scheduleInterruptPipe
  683.     (
  684.     pHCD_HOST pHost,
  685.     pHCD_PIPE pPipe
  686.     )
  687.     {
  688.     pUINT32 pPciPtrToEd;
  689.     pED_WRAPPER pCurEd;
  690.     UINT16 i;
  691.     /* Schedule the pipe onto the interrupt lists. */
  692.     for (i = 0; i < OHCI_INT_ED_COUNT; i += pPipe->actInterval)
  693. {
  694. /* Walk this list until we hit the isoch. anchor or until we
  695.  * find an pipe with a smaller interval (higher frequency).
  696.  */
  697. pPciPtrToEd = &pHost->pHcca->intEdTable [i];
  698. while ((pCurEd = ED_FROM_PCIPTR (*pPciPtrToEd)) != pHost->pIsochAnchorEd &&
  699. pCurEd->sw.pPipe->actInterval >= pPipe->actInterval &&
  700. pCurEd != pPipe->pEd)
  701.     {
  702.     pPciPtrToEd = (pUINT32) &pCurEd->ed.nextEd;
  703.     }
  704. if (pCurEd != pPipe->pEd)
  705.     {
  706.     if (i == 0)
  707. {
  708. pPipe->pEd->ed.nextEd = *pPciPtrToEd;
  709. DMA_FLUSH (pPipe->pEd, sizeof (*pPipe->pEd));
  710. }
  711.     *pPciPtrToEd = TO_LITTLEL (TO_PCIPTR (pPipe->pEd));
  712.     DMA_FLUSH (pPciPtrToEd, sizeof (*pPciPtrToEd));
  713.     }
  714. }
  715.     }
  716. /***************************************************************************
  717. *
  718. * unscheduleControlPipe - removes control pipe from the schedule
  719. *
  720. * RETURNS: N/A
  721. */
  722. LOCAL VOID unscheduleControlPipe
  723.     (
  724.     pHCD_HOST pHost,
  725.     pHCD_PIPE pPipe
  726.     )
  727.     {
  728.     pED_WRAPPER pCurEd;
  729.     pED_WRAPPER pNextEd;
  730.     /* We need to halt processing of control transfers before de-linking. */
  731.     HC_CLR_BITS (OHCI_HC_CONTROL, OHCI_CTL_CLE);
  732.     hcSynch (pHost);
  733.     /* Find the pipe's ED and de-link it. */
  734.     if ((pCurEd = FROM_PCIPTR (HC_DWORD_IN (OHCI_HC_CONTROL_HEAD_ED)))
  735.       == pPipe->pEd)
  736. {
  737. /* ED is the head of the list */
  738. HC_DWORD_OUT (OHCI_HC_CONTROL_HEAD_ED, 
  739.       FROM_LITTLEL (pPipe->pEd->ed.nextEd));
  740. }
  741.     else
  742. {
  743. /* Walk the list looking for the ED.
  744.  *
  745.  * NOTE: We know the ED must be on the list, so there's no need
  746.  * to check for the end of list as we proceed. 
  747.  */
  748. while ((pNextEd = ED_FROM_PCIPTR (pCurEd->ed.nextEd)) != pPipe->pEd)
  749.   pCurEd = pNextEd;
  750. pCurEd->ed.nextEd = pPipe->pEd->ed.nextEd;
  751. }
  752.     /*  
  753.      * shutOffListProcessing() halts isoch, interrupt and bulk transfers 
  754.      * when a device is disconnected, we make sure they are re-enabled.
  755.      */                 
  756.  
  757.     HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_PLE);
  758.     HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_IE);
  759.     HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_BLE);
  760.     /* Re-enable the control list. */
  761.     HC_SET_BITS (OHCI_HC_CONTROL, OHCI_CTL_CLE);
  762.     }
  763.     
  764. /***************************************************************************
  765. *
  766. * scheduleControlPipe - inserts control pipe into the schedule
  767. *
  768. * Inserts the control transfer into the portion of the frame list 
  769. * appropriate for control transfers.
  770. *
  771. * RETURNS: N/A
  772. */
  773. LOCAL VOID scheduleControlPipe
  774.     (
  775.     pHCD_HOST pHost,
  776.     pHCD_PIPE pPipe
  777.     )
  778.     {
  779.     pED_WRAPPER pLastEd = FROM_PCIPTR (HC_DWORD_IN (OHCI_HC_CONTROL_HEAD_ED));
  780.     pED_WRAPPER pNextEd;
  781.     /* Flush the ED out of the cache before giving it to the HC. */
  782.     DMA_FLUSH (pPipe->pEd, sizeof (*pPipe->pEd));
  783.     if (pLastEd == NULL)
  784. {
  785. /* This will be the first ED on the control list. */
  786. HC_DWORD_OUT (OHCI_HC_CONTROL_HEAD_ED, TO_PCIPTR (pPipe->pEd));
  787. }
  788.     else
  789. {
  790. /* Append this ED to the end of the control list. */
  791. while ((pNextEd = ED_FROM_PCIPTR (pLastEd->ed.nextEd)) != NULL)
  792.     pLastEd = pNextEd;
  793. pLastEd->ed.nextEd = TO_LITTLEL (TO_PCIPTR (pPipe->pEd));
  794. DMA_FLUSH (&pLastEd->ed.nextEd, sizeof (pLastEd->ed.nextEd));
  795. }
  796.     }
  797. /***************************************************************************
  798. *
  799. * unscheduleBulkPipe - removes bulk transfer from the schedule
  800. *
  801. * RETURNS: N/A
  802. */
  803. LOCAL VOID unscheduleBulkPipe
  804.     (
  805.     pHCD_HOST pHost,
  806.     pHCD_PIPE pPipe
  807.     )
  808.     {
  809.     pED_WRAPPER pCurEd;
  810.     pED_WRAPPER pNextEd;
  811.     /* We need to halt processing of bulk transfers before de-linking. */
  812.     HC_CLR_BITS (OHCI_HC_CONTROL, OHCI_CTL_BLE);
  813.     hcSynch (pHost);
  814.     /* Find the pipe's ED and de-link it. */
  815.     if ((pCurEd = FROM_PCIPTR (HC_DWORD_IN (OHCI_HC_BULK_HEAD_ED)))
  816. == pPipe->pEd)
  817. {
  818. /* ED is the head of the list. */
  819. HC_DWORD_OUT (OHCI_HC_BULK_HEAD_ED, 
  820.       FROM_LITTLEL (pPipe->pEd->ed.nextEd));
  821. }
  822.     else
  823. {
  824. /* Walk the list looking for the ED.
  825.  *
  826.  * NOTE: We know the ED must be on the list, so there's no need
  827.  * to check for the end of list as we proceed. 
  828.  */
  829. while ((pNextEd = ED_FROM_PCIPTR (pCurEd->ed.nextEd)) != pPipe->pEd)
  830.   pCurEd = pNextEd;
  831. pCurEd->ed.nextEd = pPipe->pEd->ed.nextEd;
  832. }
  833.     /*  
  834.      * shutOffListProcessing() halts isoch, interrupt and bulk transfers 
  835.      * when a device is disconnected, we make sure they are re-enabled.
  836.      */                 
  837.  
  838.     HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_PLE);
  839.     HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_IE);
  840.     HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_BLE);
  841.     }
  842.     
  843. /***************************************************************************
  844. *
  845. * scheduleBulkPipe - inserts bulk pipe into the schedule
  846. *
  847. * Inserts the bulk transfer into the portion of the frame list appropriate 
  848. * for bulk transfers.
  849. *
  850. * RETURNS: N/A
  851. */
  852. LOCAL VOID scheduleBulkPipe
  853.     (
  854.     pHCD_HOST pHost,
  855.     pHCD_PIPE pPipe
  856.     )
  857.     {
  858.     pED_WRAPPER pLastEd = FROM_PCIPTR (HC_DWORD_IN (OHCI_HC_BULK_HEAD_ED));
  859.     pED_WRAPPER pNextEd;
  860.     /* Flush the ED out of the cache before giving it to the HC. */
  861.     DMA_FLUSH (pPipe->pEd, sizeof (*pPipe->pEd));
  862.     if (pLastEd == NULL)
  863. {
  864. /* This will be the first ED on the bulk list. */
  865. HC_DWORD_OUT (OHCI_HC_BULK_HEAD_ED, TO_PCIPTR (pPipe->pEd));
  866. }
  867.     else
  868. {
  869. /* Append this ED to the end of the bulk list. */
  870. while ((pNextEd = ED_FROM_PCIPTR (pLastEd->ed.nextEd)) != NULL) 
  871.     pLastEd = pNextEd;
  872. pLastEd->ed.nextEd = TO_LITTLEL (TO_PCIPTR (pPipe->pEd));
  873. DMA_FLUSH (&pLastEd->ed.nextEd, sizeof (pLastEd->ed.nextEd));
  874. }
  875.     }
  876. /***************************************************************************
  877. *
  878. * unschedulePipe - Removes pipe from schedule
  879. *
  880. * RETURNS: N/A
  881. */
  882. LOCAL VOID unschedulePipe
  883.     (
  884.     pHCD_HOST pHost,
  885.     pHCD_PIPE pPipe
  886.     )
  887.     {
  888.     /* un-Scheduling proceeds differently for each transaction type. */
  889.     switch (pPipe->transferType)
  890. {
  891. case USB_XFRTYPE_ISOCH:
  892.     unscheduleIsochPipe (pHost, pPipe);
  893.     break;
  894. case USB_XFRTYPE_INTERRUPT: 
  895.     unscheduleInterruptPipe (pHost, pPipe);
  896.     break;
  897. case USB_XFRTYPE_CONTROL:
  898.     unscheduleControlPipe (pHost, pPipe);
  899.     break;
  900. case USB_XFRTYPE_BULK:
  901.     unscheduleBulkPipe (pHost, pPipe);
  902.     break;
  903. }
  904.     }
  905. /***************************************************************************
  906. *
  907. * schedulePipe - Adds a pipe to the schedule
  908. *
  909. * RETURNS: N/A
  910. */
  911. LOCAL VOID schedulePipe
  912.     (
  913.     pHCD_HOST pHost,
  914.     pHCD_PIPE pPipe
  915.     )
  916.     {
  917.     /* Scheduling proceeds differently for each transaction type. */
  918.     switch (pPipe->transferType)
  919. {
  920. case USB_XFRTYPE_ISOCH:
  921.     scheduleIsochPipe (pHost, pPipe);
  922.     break;
  923. case USB_XFRTYPE_INTERRUPT: 
  924.     scheduleInterruptPipe (pHost, pPipe);
  925.     break;
  926. case USB_XFRTYPE_CONTROL:
  927.     scheduleControlPipe (pHost, pPipe);
  928.     break;
  929. case USB_XFRTYPE_BULK:
  930.     scheduleBulkPipe (pHost, pPipe);
  931.     break;
  932. }
  933.     }
  934. /***************************************************************************
  935. *
  936. * assignTds - assign TDs for each IRP bfrList[] entry
  937. *
  938. * Assigns and initializes TDs to map the next bfrList[] entry in the IRP.  
  939. * Stops when all all bfrList[] entries have been mapped, when all TDs for 
  940. * the IRP have been exhausted, or when buffer bandwidth calculations indicate 
  941. * we shouldn't map any more TDs at this time.  
  942. *
  943. * This function also updates the pHost->nanoseconds field with the bandwidth
  944. * required by this transfer if appropriate.
  945. *
  946. * NOTE: We choose to map only one bfrList[] entry at a time to simplify the
  947. * the handling of input underrun.  When an underrun occurs, the 
  948. * releaseTd() function releases all TDs scheduled up through that point.
  949. * We then schedule TDs for the following bfrList[] entries if any.
  950. *
  951. * RETURNS: N/A
  952. */
  953. LOCAL VOID assignTds
  954.     (
  955.     pHCD_HOST pHost,
  956.     pHCD_PIPE pPipe,
  957.     pUSB_IRP pIrp,
  958.     pIRP_WORKSPACE pWork
  959.     )
  960.     {
  961.     pUSB_BFR_LIST pBfrList;
  962.     pTD_WRAPPER pTd;
  963.     UINT32 bytesThroughFrameCount;
  964.     UINT16 bytesThisFrame;
  965.     UINT16 isochLen;
  966.     UINT32 isochOffset;
  967.     UINT16 maxLen;
  968.     UINT32 nanoseconds;
  969.     UINT32 control = 0;
  970.     UINT32 curBfrPtr;
  971.     UINT32 bfrEnd;
  972.     UINT16 frameCount;
  973.     UINT16 psw;
  974.     UINT32 pciPtrToNextFree;
  975.     UINT16 i;
  976.     /* Assign TDs to map the current bfrList[] entry.  Stop when the buffer is 
  977.      * fully mapped, when we run out of TDs, or when bus bandwidth calculations 
  978.      * indicate we should not allocate more TDs at this time.
  979.      */
  980.     if (pWork->bfrNo == pIrp->bfrCount)
  981. return;
  982.     pBfrList = &pIrp->bfrList [pWork->bfrNo];
  983.     while ((pWork->bfrOffset < pBfrList->bfrLen ||
  984.     (pBfrList->bfrLen == 0 && 
  985.     !pWork->zeroLenMapped)) && 
  986.     pPipe->freeTdCount > 0)
  987.      {
  988.         /* Calculate the length of this TD and determine if there are any
  989.          * bandwidth limitations which would prevent scheduling it at this time.
  990.          *
  991.          * NOTE: Since the USBD has already checked bandwidth availability for
  992.          * isochronous and interrupt transfers, we need only check bandwidth
  993.          * availability for low speed control transfers.
  994.          */
  995.         if (isBandwidthTracked (pPipe))
  996.     {
  997.          nanoseconds = usbTransferTime (pPipe->transferType, 
  998.    dirFromPid (pBfrList->pid), 
  999.    pPipe->speed, 
  1000.    min (pBfrList->bfrLen - pWork->bfrOffset, 
  1001.   pPipe->maxPacketSize), 
  1002.    HC_HOST_DELAY, 
  1003.    HC_HUB_LS_SETUP);
  1004.        if (pHost->nanoseconds + nanoseconds > USB_LIMIT_ALL)
  1005. {
  1006.      /* There isn't enough bandwidth at this time.  Stop scheduling 
  1007.        * for this transfer.
  1008.                */
  1009.      break;
  1010.      }
  1011.     }
  1012.         else
  1013.     {
  1014.     nanoseconds = 0;
  1015.     }
  1016.        /* If this is the first time we've mapped a part of this bfrList[] entry,
  1017.          * then flush the cache.  Note that we do this for input buffers as well
  1018.          * since we don't know where the user's buffer is allocated and some CPU
  1019.          * cache architectures may get confused near cache-line boundaries.
  1020.       */
  1021.         if (pWork->bfrOffset == 0 && pBfrList->bfrLen > 0)
  1022.     {
  1023.     /* 
  1024.      * By default USB_BUFFER_SWAP is a no-op, but it can be
  1025.      * overridden in BSP stubs as necessary.
  1026.      */
  1027.     USB_BUFFER_SWAP ((pVOID *) pBfrList->pBfr, pBfrList->bfrLen);
  1028.     USER_FLUSH (pBfrList->pBfr, pBfrList->bfrLen);
  1029.     }
  1030.         /* Grab the first free TD for our use...Then advance the "free TD 
  1031.          * index" so that it points to the next free TD.  (Since freeTdCount
  1032.          * is initialized to be one less than tdCount, we are guaranteed that
  1033.          * there are always at least two free TDs when we reach this point in
  1034.          * the code.
  1035.          */
  1036.         pTd = &pPipe->pTds [pPipe->freeTdIndex];
  1037.         pTd->sw.inUse = 1;
  1038.         pPipe->freeTdCount--;
  1039.         do
  1040.          {
  1041.     if (++pPipe->freeTdIndex == pPipe->tdCount)
  1042. pPipe->freeTdIndex = 0;
  1043.     }
  1044.         while (pPipe->pTds [pPipe->freeTdIndex].sw.inUse != 0);
  1045.         /* OHCI TD's can span up to two, 4k pages. Based on this limit,
  1046.          * calculate the maximum amount of data we'll try to transfer with
  1047.          * this TD.
  1048.          */
  1049.         curBfrPtr = TO_PCIPTR ((pVOID) &pBfrList->pBfr [pWork->bfrOffset]);
  1050.         maxLen = OHCI_PAGE_SIZE - (curBfrPtr & ~OHCI_PAGE_MASK) + 
  1051.  OHCI_PAGE_SIZE;
  1052.         maxLen = min (maxLen, pBfrList->bfrLen - pWork->bfrOffset);
  1053.         /* Initialize TD. 
  1054.          *
  1055.          * NOTE: By convention, TD is always cleared to 0's at initialization
  1056.          * or after being discarded by the previous transfer.
  1057.          */
  1058.         switch (pBfrList->pid)
  1059.          {
  1060.          case USB_PID_SETUP: 
  1061. control = OHCI_TGCTL_PID_SETUP; 
  1062. break;
  1063.     case USB_PID_OUT:   
  1064. control = OHCI_TGCTL_PID_OUT;   
  1065. break;
  1066.     case USB_PID_IN:    
  1067. control = OHCI_TGCTL_PID_IN;    
  1068. break;
  1069.     }
  1070.         if (pPipe->transferType == USB_XFRTYPE_ISOCH)
  1071.     {
  1072.     /* Isochronous TD */
  1073.     /* Map up to a complete TD (eight frames). */
  1074.     frameCount = 0;
  1075.     isochOffset = 0;
  1076.     for (i = 0; i < OHCI_ISO_PSW_CNT && maxLen > 0; i++)
  1077. {
  1078. /* Calculate the packet length for the next frame. */
  1079. bytesThroughFrameCount = (pWork->frameCount + 1) * 
  1080.   pPipe->bandwidth / 1000L;
  1081. bytesThisFrame = bytesThroughFrameCount - pWork->bytesSoFar;
  1082. /* NOTE: If maxLen is less than the desired number of bytes
  1083.  * for this frame *AND* we are not yet at the end of this
  1084.  * BFR_LIST entry, then don't schedule any more frames for
  1085.  * this TD...For this situation to arise we must be near a
  1086.  * page boundary crossing...The next TD will begin one page
  1087.  * later and will allow us to schedule the full frame as
  1088.  * desired.
  1089.  */
  1090. if (maxLen < bytesThisFrame &&
  1091.     pWork->bfrOffset + maxLen != pBfrList->bfrLen)
  1092.     break;
  1093. isochLen = min (bytesThisFrame, maxLen);
  1094. isochLen = min (isochLen, pPipe->maxPacketSize);
  1095. if (pIrp->dataBlockSize != 0 && isochLen > pIrp->dataBlockSize)
  1096.     {
  1097.     isochLen = (isochLen / pIrp->dataBlockSize) * 
  1098.     pIrp->dataBlockSize;
  1099.     }
  1100. pWork->bytesSoFar += isochLen;
  1101. maxLen -= isochLen;
  1102. pWork->frameCount++;
  1103. frameCount++;
  1104. /* Initialize the TD PSW for this frame. */
  1105. psw = OHCI_TIPSW_CC_FMT (OHCI_CC_NOT_ACCESSED);
  1106. psw |= (curBfrPtr + isochOffset) & OHCI_ISO_OFFSET_MASK;
  1107.     
  1108. if ((curBfrPtr & OHCI_PAGE_MASK) != 
  1109.     ((curBfrPtr + isochOffset) & OHCI_PAGE_MASK))
  1110.     {
  1111.     psw |= OHCI_ISO_OFFSET_BE;
  1112.     }
  1113. pTd->tdi.psw [i] = TO_LITTLEW (psw);
  1114. isochOffset += isochLen;
  1115. }
  1116.     /*
  1117.      * Packet status words need to be swapped before sending on
  1118.      * some particular controllers.
  1119.      * By default USB_BUFFER_SWAP is a no-op, but it can be
  1120.      * overridden in BSP stubs as necessary.
  1121.      */
  1122.     USB_BUFFER_SWAP ((pVOID *) &pTd->tdi.psw [0],
  1123.      frameCount * sizeof (UINT16));
  1124.     bfrEnd = curBfrPtr + isochOffset - 1;
  1125.     pWork->bfrOffset += isochOffset;
  1126.     /* Initialize remaining fields in isochronous TD. */
  1127.     control |= OHCI_TICTL_FC_FMT (frameCount);
  1128.     control |= OHCI_TICTL_SF_FMT (pWork->isochNext);
  1129.     pWork->isochNext = FINDEX (pWork->isochNext + frameCount);
  1130.     pTd->tdi.control = TO_LITTLEL (control);
  1131.     pTd->tdi.bp0 = TO_LITTLEL (curBfrPtr & OHCI_PAGE_MASK);
  1132.     pTd->tdi.be = TO_LITTLEL (bfrEnd);
  1133.     }
  1134. else
  1135.     {
  1136.     /* General TD */
  1137.     control |= OHCI_TGCTL_BFR_RND | OHCI_TGCTL_TOGGLE_USETD;
  1138.     /* If this transfer does not complete the BFR_LIST entry, then
  1139.      * truncate it to an even number of frames. 
  1140.      */
  1141.     if (maxLen > pPipe->maxPacketSize &&
  1142. pWork->bfrOffset + maxLen != pBfrList->bfrLen)
  1143. {
  1144. maxLen = (maxLen / pPipe->maxPacketSize) * pPipe->maxPacketSize;
  1145. }
  1146.     if (maxLen == 0)
  1147. {
  1148. pWork->zeroLenMapped = TRUE;
  1149. curBfrPtr = bfrEnd = 0;
  1150. }
  1151.     else
  1152. {
  1153. bfrEnd = curBfrPtr + maxLen - 1;
  1154. }
  1155.     pWork->bfrOffset += maxLen;
  1156.     /* The last BFR_LIST entry for a control transfer (the status
  1157.      * packet) is alwasy DATA1. 
  1158.      */
  1159.     if (pPipe->transferType == USB_XFRTYPE_CONTROL &&
  1160. pWork->bfrNo == pIrp->bfrCount - 1)
  1161. {
  1162. control |= OHCI_TGCTL_TOGGLE_DATA1;
  1163. }
  1164.     else
  1165. {
  1166. control |= (pIrp->dataToggle == USB_DATA0) ? 
  1167. OHCI_TGCTL_TOGGLE_DATA0 :
  1168. OHCI_TGCTL_TOGGLE_DATA1;
  1169. }
  1170.     pTd->tdg.control = TO_LITTLEL (control);
  1171.     pTd->tdg.cbp = TO_LITTLEL (curBfrPtr);
  1172.     pTd->tdg.be = TO_LITTLEL (bfrEnd);
  1173.     }
  1174. pTd->sw.curBfrPtr = curBfrPtr;
  1175. /* Link the TD back to the workspace for the IRP. */
  1176. pTd->sw.pWork = pWork;
  1177. /* Store the time required to execute this TD */
  1178. pHost->nanoseconds += nanoseconds;
  1179. pTd->sw.nanoseconds = nanoseconds;
  1180. /* Append TD to the end of the ED's TD queue. 
  1181.  *
  1182.  * NOTE: pTd->tdg.nextTd == pTd->tdi.nextTd. */
  1183. pciPtrToNextFree = TO_LITTLEL (TO_PCIPTR (&pPipe->pTds [pPipe->freeTdIndex]));
  1184. pTd->tdg.nextTd = pciPtrToNextFree;
  1185. DMA_FLUSH (pTd, sizeof (OHCI_TD_ISO)+sizeof(OHCI_TD_GEN));
  1186. pPipe->pEd->ed.tdTail = pciPtrToNextFree;
  1187. DMA_FLUSH (&pPipe->pEd->ed.tdTail, sizeof (pPipe->pEd->ed.tdTail));
  1188. /* If necessary, notify the HC that new a new transfer is ready. */
  1189. switch (pPipe->transferType)
  1190.     {
  1191.     case USB_XFRTYPE_CONTROL:
  1192. HC_SET_BITS (OHCI_HC_COMMAND_STATUS, OHCI_CS_CLF);
  1193. break;
  1194.     case USB_XFRTYPE_BULK:
  1195. HC_SET_BITS (OHCI_HC_COMMAND_STATUS, OHCI_CS_BLF);
  1196. break;
  1197.     }
  1198. }
  1199.     }
  1200. /***************************************************************************
  1201. *
  1202. * scheduleOtherIrps - schedules other IRPs if TDs are available on a pipe
  1203. *
  1204. * RETURNS: N/A
  1205. */
  1206. LOCAL VOID scheduleOtherIrps
  1207.     (
  1208.     pHCD_HOST pHost,
  1209.     pHCD_PIPE pPipe
  1210.     )
  1211.     {
  1212.     pUSB_IRP pIrp;
  1213.     pUSB_IRP pNextIrp;
  1214.     pIRP_WORKSPACE pWork;
  1215.     pIrp = usbListFirst (&pHost->busIrps);
  1216.     while (pIrp != NULL && pPipe->freeTdCount > 0)
  1217. {
  1218. pNextIrp = usbListNext (&pIrp->hcdLink);
  1219. pWork = (pIRP_WORKSPACE) pIrp->hcdPtr;
  1220. if (pWork->pPipe == pPipe)
  1221.     assignTds (pHost, pPipe, pIrp, pWork);
  1222. pIrp = pNextIrp;
  1223. }
  1224.     }
  1225. /***************************************************************************
  1226. *
  1227. * releaseTd - Update an IRP based on a completed IRP.
  1228. *
  1229. * Sets <result> field in <pIrp> to OK or S_usbHcdLib_xxx if IRP completed.
  1230. *
  1231. * NOTE: Automatically reschedules TDs.
  1232. *
  1233. * RETURNS: N/A
  1234. */
  1235. LOCAL VOID releaseTd
  1236.     (
  1237.     pHCD_HOST pHost,
  1238.     pHCD_PIPE pPipe,
  1239.     pUSB_IRP pIrp,
  1240.     pIRP_WORKSPACE pWork,
  1241.     pTD_WRAPPER pTd
  1242.     )
  1243.     {
  1244.     pUSB_BFR_LIST pBfrList;
  1245.     UINT32 control;
  1246.     UINT32 curBfrPtr;
  1247.     UINT32 bfrEnd;
  1248.     UINT32 tdHead;
  1249.     UINT16 frameCount;
  1250.     UINT16 psw;
  1251.     UINT16 actLen;
  1252.     BOOL underrun = FALSE;
  1253.     UINT16 i;
  1254.     
  1255.     /*
  1256.      * In some case, transmitted data is still used at either drivers or
  1257.      * applications and need to be re-swapped if they are swapped before
  1258.      * sending.
  1259.      */
  1260.     if (pIrp->bfrList[pWork->bfrNo].pid == USB_PID_SETUP ||
  1261. pIrp->bfrList[pWork->bfrNo].pid == USB_PID_OUT)
  1262. {
  1263. if (pTd->sw.curBfrPtr != 0)
  1264.     {
  1265.     if (FROM_LITTLEL (pTd->tdg.cbp) == 0)
  1266. {
  1267. /*
  1268.  * By default USB_BUFFER_SWAP is a no-op, but it can be
  1269.  * overridden in BSP stubs as necessary.
  1270.  */
  1271. USB_BUFFER_SWAP ((pVOID *) pTd->sw.curBfrPtr,
  1272. FROM_LITTLEL (pTd->tdg.be) - pTd->sw.curBfrPtr + 1);
  1273. }
  1274.     else
  1275. {
  1276. /*
  1277.  * By default USB_BUFFER_SWAP is a no-op, but it can be
  1278.  * overridden in BSP stubs as necessary.
  1279.  */
  1280. USB_BUFFER_SWAP ((pVOID *) pTd->sw.curBfrPtr,
  1281. FROM_LITTLEL (pTd->tdg.cbp) - pTd->sw.curBfrPtr + 1);
  1282. }
  1283.     }
  1284. }
  1285.     /* Release the bandwidth this TD was consuming. */
  1286.     pHost->nanoseconds -= pTd->sw.nanoseconds;
  1287.     /* Examine the TD. */
  1288.     control = FROM_LITTLEL (pTd->tdg.control);
  1289.     switch (OHCI_TGCTL_CC (control))
  1290. {
  1291. case OHCI_CC_NO_ERROR:
  1292. break;
  1293. case OHCI_CC_CRC:
  1294. case OHCI_CC_NO_RESPONSE:
  1295. pIrp->result = S_usbHcdLib_CRC_TIMEOUT; 
  1296. break;
  1297. case OHCI_CC_BITSTUFF:
  1298. pIrp->result = S_usbHcdLib_BITSTUFF_FAULT;  
  1299. break;
  1300. case OHCI_CC_STALL:     
  1301. pIrp->result = S_usbHcdLib_STALLED;     
  1302. break;
  1303. case OHCI_CC_DATA_TOGGLE:
  1304. pIrp->result = S_usbHcdLib_DATA_TOGGLE_FAULT; 
  1305. break;
  1306. case OHCI_CC_PID_CHECK:
  1307. case OHCI_CC_UNEXPECTED_PID: 
  1308. pIrp->result = S_usbHcdLib_PID_FAULT;
  1309. break;
  1310. case OHCI_CC_DATA_OVERRUN:
  1311. case OHCI_CC_DATA_UNDERRUN:
  1312. case OHCI_CC_BFR_OVERRUN:
  1313. case OHCI_CC_BFR_UNDERRUN:
  1314. pIrp->result = S_usbHcdLib_DATA_BFR_FAULT;  
  1315. break;
  1316. default:
  1317. pIrp->result = S_usbHcdLib_GENERAL_FAULT;   
  1318. break;
  1319. }
  1320.     /* If there was an error, then the HC will have halted the ED.  Un-halt
  1321.      * it so future transfers can take place.
  1322.      */
  1323.     tdHead = FROM_LITTLEL (pPipe->pEd->ed.tdHead);
  1324.     if (pIrp->result != PENDING)
  1325. {
  1326. pPipe->pEd->ed.tdHead = TO_LITTLEL (tdHead & ~OHCI_PTR_HALTED);
  1327. DMA_FLUSH (&pPipe->pEd->ed.tdHead, sizeof (pPipe->pEd->ed.tdHead));
  1328. }
  1329.     /* If ok so far, calculate the actual amount of data transferred. */
  1330.     if (pIrp->result == PENDING)
  1331. {
  1332. pBfrList = &pIrp->bfrList [pWork->bfrNo];
  1333. /* Note: In following assignment: pTd->tdg.be == pTd->tdi.be */
  1334. bfrEnd = FROM_LITTLEL (pTd->tdg.be);
  1335. if (pPipe->transferType == USB_XFRTYPE_ISOCH)
  1336.     {
  1337.     /* For an isoch transfer make sure each frame was executed. */
  1338.     frameCount = OHCI_TICTL_FC (control);
  1339.     /*
  1340.      * Re-swap packet status words before reading if they are swapped
  1341.      * at transmit.
  1342.      * By default USB_BUFFER_SWAP is a no-op, but it can be
  1343.      * overridden in BSP stubs as necessary.
  1344.      */
  1345.     USB_BUFFER_SWAP ((pVOID *) &pTd->tdi.psw [0],
  1346.      frameCount * sizeof (UINT16));
  1347.     for (actLen = i = 0; i < frameCount; i++)
  1348. {
  1349. psw = FROM_LITTLEW (pTd->tdi.psw [i]);
  1350. if (OHCI_TIPSW_CC (psw) != OHCI_CC_NO_ERROR)
  1351.     {
  1352.     pIrp->result = S_usbHcdLib_ISOCH_FAULT;
  1353.     break;
  1354.     }
  1355. }
  1356.     actLen = bfrEnd - pTd->sw.curBfrPtr + 1;
  1357.     }
  1358. else
  1359.     {
  1360.     /* For a general transfer, calculate the actual data transferred */
  1361.     curBfrPtr = FROM_LITTLEL (pTd->tdg.cbp);
  1362.     if (pTd->sw.curBfrPtr == 0)
  1363. {
  1364. /* we requested a 0-length transfer */
  1365. actLen = 0;
  1366. }
  1367.     else
  1368. {
  1369. /* we requested a transfer of non-zero length */
  1370. if (curBfrPtr == 0)
  1371.     {
  1372.     /* transfer was successful...full length requested. */
  1373.     actLen = bfrEnd - pTd->sw.curBfrPtr + 1;
  1374.     }
  1375. else
  1376.     {
  1377.     /* short packet was transferred.  curBfrPtr addresses
  1378.      * the byte following the last byte transferred.
  1379.      */
  1380.     actLen = curBfrPtr - pTd->sw.curBfrPtr;
  1381.     }
  1382. }
  1383.     /* Update the IRP's data toggle. */
  1384.     pIrp->dataToggle = ((tdHead & OHCI_PTR_TGL_CARRY) == 0) ? 
  1385.     USB_DATA0 : USB_DATA1;
  1386.     } 
  1387. /* Update the BFR_LIST entry and check for underrun. */
  1388. pBfrList->actLen += actLen;
  1389. if (pTd->sw.curBfrPtr != 0 &&
  1390.     actLen < bfrEnd - pTd->sw.curBfrPtr + 1)
  1391.     {
  1392.     underrun = TRUE;
  1393.     if ((pIrp->flags & USB_FLAG_SHORT_FAIL) != 0)
  1394. {
  1395. pIrp->result = S_usbHcdLib_SHORT_PACKET;
  1396. }
  1397.     }
  1398. if (pBfrList->actLen == pBfrList->bfrLen || underrun)
  1399.     {
  1400.     pWork->bfrNo++;
  1401.     pWork->bfrOffset = 0;
  1402.     pWork->zeroLenMapped = FALSE;
  1403.     }
  1404. }
  1405.     /* Indicate that the TD is no longer in use. */
  1406.     memset (pTd, 0, sizeof (*pTd));
  1407.     pPipe->freeTdCount++;
  1408.     
  1409.     /* Check if the IRP is complete. */
  1410.     if (pIrp->result == PENDING)
  1411. {
  1412. if (pWork->bfrNo == pIrp->bfrCount)
  1413.     {
  1414.     /* Yes, all buffers for the IRP have been processed. */
  1415.     pIrp->result = OK;
  1416.     }
  1417. else
  1418.     {
  1419.     /* No, schedule more work for the IRP. */
  1420.     assignTds (pHost, pPipe, pIrp, pWork);
  1421.     }
  1422. }
  1423.     /* If this is an isochronous pipe and if we've fully mapped the current
  1424.      * IRP, then check if there are other IRPs which need to be scheduled.
  1425.      */
  1426.     if (pPipe->transferType == USB_XFRTYPE_ISOCH &&
  1427.        ((pWork->bfrNo + 1 == pIrp->bfrCount && 
  1428.        pWork->bfrOffset == 
  1429.        pIrp->bfrList [pWork->bfrNo].bfrLen) ||
  1430.        pWork->bfrNo == pIrp->bfrCount))
  1431. {
  1432. scheduleOtherIrps (pHost, pPipe);
  1433. }
  1434.     /* If the IRP is complete, invalidate the cache for any input buffers. */
  1435.     if (pIrp->result != PENDING)
  1436. {
  1437. for (i = 0; i < pIrp->bfrCount; i++)
  1438.     {
  1439.     pBfrList = &pIrp->bfrList [i];
  1440.     if (pBfrList->pid == USB_PID_IN && pBfrList->actLen > 0)
  1441. {
  1442. USER_INVALIDATE (pBfrList->pBfr, pBfrList->actLen);
  1443. /* 
  1444.    * By default USB_BUFFER_SWAP is a no-op, but can be
  1445.  * overridden in BSP stubs as necessary.
  1446.    */
  1447. USB_BUFFER_SWAP ((pVOID *) pBfrList->pBfr, pBfrList->actLen);
  1448. }
  1449.     }
  1450. }
  1451.     }
  1452. /***************************************************************************
  1453. *
  1454. * unscheduleIrp - unschedules IRP
  1455. *
  1456. * RETURNS: N/A
  1457. */
  1458. LOCAL VOID unscheduleIrp
  1459.     (
  1460.     pHCD_HOST pHost,
  1461.     pUSB_IRP pIrp,
  1462.     pIRP_WORKSPACE pWork    
  1463.     )
  1464.     {
  1465.     pHCD_PIPE pPipe = pWork->pPipe;
  1466.     UINT16 i;
  1467.     UINT16 tdIndex;
  1468.     BOOL tdDeleted;
  1469.     /* If the IRP has no workspace, then it cannot be using TDs, so return 
  1470.      * immediately.
  1471.      */
  1472.     if (pWork == NULL)
  1473. return;
  1474.     /* Halt processing on this ED. */
  1475.     pPipe->pEd->ed.control |= TO_LITTLEL (OHCI_EDCTL_SKIP);
  1476.     DMA_FLUSH (&pPipe->pEd->ed.control, sizeof (pPipe->pEd->ed.control));
  1477.     hcSynch (pHost);
  1478.     /* Search the pipe which owns this IRP to see if any of its TDs are
  1479.      * in use by this IRP.  If so, release them and allow another IRP (if
  1480.      * one exists) to use them.
  1481.      */
  1482.     tdIndex = pPipe->freeTdIndex;
  1483.     for (i = 0; i < pPipe->tdCount; i++)
  1484. {
  1485. tdDeleted = FALSE;
  1486. if (pPipe->pTds [tdIndex].sw.pWork == pWork)
  1487.     {
  1488.     pPipe->freeTdCount++;
  1489.     memset (&pPipe->pTds [tdIndex], 0, sizeof (pPipe->pTds [tdIndex]));
  1490.     tdDeleted = TRUE;
  1491.     }
  1492. if (++tdIndex == pPipe->tdCount)
  1493.     tdIndex = 0;
  1494. /* If we deleted this TD, then advance head of TD list. */
  1495. if (tdDeleted)
  1496.     {
  1497.     pPipe->pEd->ed.tdHead = 
  1498.     TO_LITTLEL (TO_PCIPTR (&pPipe->pTds [tdIndex]));
  1499.     DMA_FLUSH (&pPipe->pEd->ed.tdHead, sizeof (pPipe->pEd->ed.tdHead));
  1500.     }
  1501. }
  1502.     
  1503.     /* Allow the ED to resume. */
  1504.     pPipe->pEd->ed.control &= ~(TO_LITTLEL (OHCI_EDCTL_SKIP));
  1505.     DMA_FLUSH (&pPipe->pEd->ed.control, sizeof (pPipe->pEd->ed.control));
  1506.     }
  1507. /***************************************************************************
  1508. *
  1509. * serviceBusIrps - Services completed USB transactions
  1510. *
  1511. * RETURNS: N/A
  1512. */
  1513. LOCAL VOID serviceBusIrps
  1514.     (
  1515.     pHCD_HOST pHost
  1516.     )
  1517.     {
  1518.     UINT32 pciPtrToTd;
  1519.     pTD_WRAPPER pFirstTd;
  1520.     pTD_WRAPPER pTd;
  1521.     pUSB_IRP pIrp;
  1522.     pIRP_WORKSPACE pWork;
  1523.     LIST_HEAD completeIrps = {0};
  1524.     /* Walk the list of complete TDs and update the status of their
  1525.      * respective IRPs.
  1526.      *
  1527.      * NOTE: TDs are in reverse order on the list...That is, the TDs
  1528.      * which executed first are behind TDs which executed later.  We
  1529.      * need to process them in the order in which they executed.
  1530.      */
  1531.     DMA_INVALIDATE (&pHost->pHcca->doneHead, sizeof (pHost->pHcca->doneHead));
  1532.     pFirstTd = NULL;
  1533.     pciPtrToTd = pHost->pHcca->doneHead & TO_LITTLEL (OHCI_PTR_MEM_MASK);
  1534.     while ((pTd = TD_FROM_PCIPTR (pciPtrToTd)) != NULL)
  1535. {
  1536. DMA_INVALIDATE (pTd, sizeof (*pTd));
  1537. pTd->sw.doneLink = pFirstTd;
  1538. pFirstTd = pTd;
  1539. pciPtrToTd = pTd->tdg.nextTd & TO_LITTLEL (OHCI_PTR_MEM_MASK);
  1540. }
  1541.     /* pFirstTd now points to a list of TDs in the order in which they
  1542.      * were completed.
  1543.      */
  1544.     while (pFirstTd != NULL)
  1545. {
  1546. pTd = pFirstTd;
  1547. pFirstTd = pTd->sw.doneLink;
  1548. pIrp = pTd->sw.pWork->pIrp;
  1549. releaseTd (pHost, pTd->sw.pWork->pPipe, pIrp, pTd->sw.pWork, pTd);
  1550. if (pIrp->result != PENDING)
  1551.     {
  1552.     /* IRP is finished...move it to the list of completed IRPs. */
  1553.     usbListUnlink (&pIrp->hcdLink);
  1554.     usbListLink (&completeIrps, pIrp, &pIrp->hcdLink, LINK_TAIL);
  1555.     }
  1556. }
  1557.     /* Invoke IRP callbacks for all completed IRPs. */
  1558.     while ((pIrp = usbListFirst (&completeIrps)) != NULL)
  1559. {
  1560. usbListUnlink (&pIrp->hcdLink);
  1561. /* See if other IRPs can take advantage of freed TDs. */
  1562. pWork = (pIRP_WORKSPACE) pIrp->hcdPtr;
  1563. if (pIrp->result != OK)
  1564.     unscheduleIrp (pHost, pIrp, pWork);
  1565. scheduleOtherIrps (pHost, pWork->pPipe);
  1566. /* Release IRP workspace and invoke callback. */
  1567. freeIrpWorkspace (pHost, pIrp);
  1568. setIrpResult (pIrp, pIrp->result);
  1569. }
  1570.     }
  1571. /***************************************************************************
  1572. *
  1573. * scheduleIrp - schedules IRP for execution
  1574. *
  1575. * RETURNS: N/A
  1576. */
  1577. LOCAL VOID scheduleIrp
  1578.     (
  1579.     pHCD_HOST pHost,
  1580.     pHCD_PIPE pPipe,
  1581.     pUSB_IRP pIrp
  1582.     )
  1583.     {
  1584.     pIRP_WORKSPACE pWork = (pIRP_WORKSPACE) pIrp->hcdPtr;
  1585.     /* Mark the time the IRP started */
  1586.     pWork->irpRunning = TRUE;     /* running... */
  1587.     pWork->startTime = OSS_TIME (); /* and its start time */
  1588.     /* Assign starting frame number for isoch transfers */
  1589.     if (pPipe->transferType == USB_XFRTYPE_ISOCH)
  1590. {
  1591. if ((pIrp->flags & USB_FLAG_ISO_ASAP) != 0)
  1592.     pWork->isochNext = FINDEX (getFrameNo (pHost) + HC_FRAME_SKIP);
  1593. else
  1594.     pWork->isochNext = FINDEX (pIrp->startFrame);
  1595. }
  1596.     /* Assign TDs to direct data transfer. */
  1597.     assignTds (pHost, pPipe, pIrp, pWork);
  1598.     }
  1599. /***************************************************************************
  1600. *
  1601. * cancelIrp - cancel's an outstanding IRP
  1602. *
  1603. * If the IRP's result code is not PENDING, then we cannot cancel
  1604. * the IRP as it has either already completed or it is not yet enqueued.
  1605. *
  1606. * RETURNS: OK if IRP canceled
  1607. *      S_usbHcdLib_CANNOT_CANCEL if IRP already completed
  1608. */
  1609. LOCAL int cancelIrp
  1610.     (
  1611.     pHCD_HOST pHost,
  1612.     pUSB_IRP pIrp,
  1613.     int result     /* error to assign to IRP */
  1614.     )
  1615.     {
  1616.     pIRP_WORKSPACE pWork;
  1617.     pHCD_PIPE pPipe;
  1618.     int s = OK;
  1619.     if (pIrp->result != PENDING)
  1620. s = S_usbHcdLib_CANNOT_CANCEL;
  1621.     else
  1622. {
  1623. /* The IRP is pending.  Unlink it. */
  1624. usbListUnlink (&pIrp->hcdLink);
  1625. /* If this IRP is a "bus" IRP - as opposed to a root IRP - then
  1626.  * remove it from the HC's work list.
  1627.  */
  1628. if ((pWork = (pIRP_WORKSPACE) pIrp->hcdPtr) != NULL &&
  1629.     pWork->pPipe->busAddress != pHost->rootAddress)
  1630.     {
  1631.     /* Remove QHs/TDs from the work list and release workspace. */
  1632.     pPipe = pWork->pPipe;
  1633.     unscheduleIrp (pHost, pIrp, pWork);
  1634.     freeIrpWorkspace (pHost, pIrp);
  1635.     /* This may create an opportunity to schedule other IRPs. */
  1636.     scheduleOtherIrps (pHost, pPipe);
  1637.     }
  1638. setIrpResult (pIrp, result);    
  1639. }
  1640.     return s;
  1641.     }
  1642. /***************************************************************************
  1643. *
  1644. * shutOffListProcessing - shut of host controller interrupts for list proc.
  1645. *
  1646. * Permits the host controller from processing the periodic, interrupt and bulk
  1647. * TD lists.
  1648. *
  1649. * RETURNS: N/A.
  1650. */
  1651. LOCAL void shutOffListProcessing
  1652.     (
  1653.     pHCD_HOST pHost
  1654.     )
  1655.     {
  1656.     UINT32 controlRegChange;
  1657.     hcSynch (pHost);
  1658.     /* 
  1659.      * Read the register and mask off the bits that denote list processing 
  1660.      * is enabled 
  1661.      */
  1662.     /*  Periodic List = Isoc transfers */
  1663.     controlRegChange = HC_DWORD_IN (OHCI_HC_CONTROL) & (OHCI_CTL_PLE);
  1664.     pHost->pHcControlReg = controlRegChange;
  1665.     HC_CLR_BITS (OHCI_HC_CONTROL, pHost->pHcControlReg);
  1666.     /*  Interrupt List = Interrupt transfers */
  1667.     controlRegChange = HC_DWORD_IN (OHCI_HC_CONTROL) &(OHCI_CTL_IE);
  1668.     pHost->pHcControlReg = controlRegChange;
  1669.     HC_CLR_BITS (OHCI_HC_CONTROL, pHost->pHcControlReg);
  1670.     /*  Bulk List = Bulk transfers */
  1671.     controlRegChange = HC_DWORD_IN (OHCI_HC_CONTROL) & OHCI_CTL_BLE;
  1672.     pHost->pHcControlReg = controlRegChange; 
  1673.     HC_CLR_BITS (OHCI_HC_CONTROL, pHost->pHcControlReg);
  1674.     }
  1675. /***************************************************************************
  1676. *
  1677. * isHubStatus - checks status on root hub
  1678. *
  1679. * RETURNS: hub and port status bitmap as defined by USB
  1680. */
  1681. LOCAL UINT8 isHubStatus
  1682.     (
  1683.     pHCD_HOST pHost
  1684.     )
  1685.     {
  1686.     UINT8 hubStatus = 0;
  1687.     UINT16 port;
  1688.     UINT32 portRegOffset;
  1689.     UINT32 portChange;
  1690.     UINT32 hcRhPortStatusReg;
  1691.     for (port = 0; port < pHost->numPorts; port++)
  1692. {
  1693. portRegOffset = OHCI_HC_RH_PORT_STATUS + port * sizeof (UINT32);
  1694. /* Read & clear pending change status */
  1695. hcRhPortStatusReg = HC_DWORD_IN (portRegOffset);
  1696. portChange = hcRhPortStatusReg & 
  1697.      (OHCI_RHPS_CSC | 
  1698.      OHCI_RHPS_PESC | 
  1699.      OHCI_RHPS_PSSC | 
  1700.      OHCI_RHPS_OCIC | 
  1701.      OHCI_RHPS_PRSC);
  1702. if (portChange != 0)
  1703.     HC_DWORD_OUT (portRegOffset, portChange);
  1704.         hcSynch (pHost);
  1705. /* Combine the change bits reported by the HC with those we
  1706.  * already know about.  Then report if a change is pending.
  1707.  */
  1708. pHost->pRhPortChange [port] |= portChange;
  1709. if ((pHost->pRhPortChange [port] & 
  1710.     (OHCI_RHPS_CSC | 
  1711.     OHCI_RHPS_PESC | 
  1712.     OHCI_RHPS_PSSC | 
  1713.     OHCI_RHPS_OCIC | 
  1714.     OHCI_RHPS_PRSC)) != 0)
  1715.     {
  1716.     hubStatus |= USB_HUB_ENDPOINT_STS_PORT0 << port;
  1717.     }
  1718. /*  there was a change - a device has been plugged, or unplugged */
  1719. if ( (hcRhPortStatusReg & OHCI_RHPS_CSC) !=0)
  1720.     /*  A device has been unplugged */
  1721.     if ( (hcRhPortStatusReg & OHCI_RHPS_CCS) == 0 )
  1722. {
  1723. /* Stop the host controller from processing TD's */
  1724.         shutOffListProcessing (pHost);
  1725. }
  1726. }
  1727.     return hubStatus;
  1728.     }
  1729. /***************************************************************************
  1730. *
  1731. * serviceRootIrps - Services root hub transactions
  1732. *
  1733. * RETURNS: N/A
  1734. */
  1735. LOCAL VOID serviceRootIrps
  1736.     (
  1737.     pHCD_HOST pHost
  1738.     )
  1739.     {
  1740.     UINT8 hubStatus;
  1741.     UINT16 irpCount;
  1742.     pUSB_IRP pIrp;
  1743.     if ((hubStatus = isHubStatus (pHost)) != 0)
  1744. {
  1745. for (irpCount = pHost->rootIrpCount; irpCount > 0; irpCount--)
  1746.     {
  1747.     pIrp = usbListFirst (&pHost->rootIrps);
  1748.     --pHost->rootIrpCount;
  1749.     usbListUnlink (&pIrp->hcdLink);
  1750.     *(pIrp->bfrList [0].pBfr) = hubStatus;
  1751.     pIrp->bfrList [0].actLen = 1;
  1752.     setIrpResult (pIrp, OK);
  1753.     }
  1754. }
  1755.     }
  1756. /***************************************************************************
  1757. *
  1758. * processInterrupt - process a hardware interrupt from the HC
  1759. *
  1760. * Determine the cause of a hardware interrupt and service it.  If the
  1761. * interrupt results in the completion of one or more IRPs, handle the
  1762. * completion processing for those IRPs.
  1763. *
  1764. * RETURNS: N/A
  1765. */
  1766. LOCAL VOID processInterrupt
  1767.     (
  1768.     pHCD_HOST pHost
  1769.     )
  1770.     {
  1771.     UINT32 intBits = HC_DWORD_IN (OHCI_HC_INT_STATUS) & INT_ENABLE_MASK;
  1772.     /* evaluate the interrupt condition */
  1773.     if ((intBits & OHCI_INT_SO) != 0)
  1774. {
  1775. /* Scheduling overrun detected.  Record it. */
  1776. pHost->errScheduleOverrun++;
  1777. HC_DWORD_OUT (OHCI_HC_INT_STATUS, OHCI_INT_SO); /* acknowledge */
  1778. }
  1779.     if ((intBits & OHCI_INT_UE) != 0)
  1780. {
  1781. /* Unrecoverable error detected.  Record it. */
  1782. pHost->errUnrecoverable++;
  1783. HC_DWORD_OUT (OHCI_HC_INT_STATUS, OHCI_INT_UE); /* acknowledge */
  1784. }
  1785.     if ((intBits & OHCI_INT_RD) != 0)
  1786. {
  1787. /* Resume detected. */
  1788. if (pHost->mngmtCallback != NULL)
  1789.     (*pHost->mngmtCallback) (pHost->mngmtCallbackParam, 
  1790.      pHost->handle,
  1791.      0 /* bus number */, 
  1792.      HCD_MNGMT_RESUME);
  1793. HC_DWORD_OUT (OHCI_HC_INT_STATUS, OHCI_INT_RD); /* acknowledge */
  1794. }
  1795.     if ((intBits & OHCI_INT_RHSC) != 0)
  1796. {
  1797. /* Root host change detected. */
  1798. serviceRootIrps (pHost);
  1799. HC_DWORD_OUT (OHCI_HC_INT_STATUS, OHCI_INT_RHSC); /* acknowledge */
  1800. }
  1801.     if ((intBits & OHCI_INT_WDH) != 0)
  1802. {
  1803. /* The HC has updated the done queue.  This implies completion 
  1804.  * of one or more USB transactions detected. 
  1805.  */
  1806. serviceBusIrps (pHost);
  1807. pHost->pHcca->doneHead = 0;
  1808. HC_DWORD_OUT (OHCI_HC_INT_STATUS, OHCI_INT_WDH); /* acknowledge */
  1809. }
  1810.     /* Re-enable HC interrupts */
  1811.     HC_DWORD_OUT (OHCI_HC_INT_ENABLE, INT_ENABLE_MASK);
  1812.     }
  1813. /***************************************************************************
  1814. *
  1815. * checkIrpTimeout - Checks for IRPs which may have timed-out
  1816. *
  1817. * RETURNS: N/A
  1818. */
  1819. LOCAL VOID checkIrpTimeout
  1820.     (
  1821.     pHCD_HOST pHost /* host to check */
  1822.     )
  1823.     {
  1824.     pUSB_IRP pIrp;
  1825.     pUSB_IRP pNextIrp;
  1826.     pIRP_WORKSPACE pWork;
  1827.     UINT32 now;
  1828.     /* Search for one or more IRPs which have been completed
  1829.      * (or partially completed).
  1830.      */
  1831.     now = OSS_TIME ();
  1832.     pIrp = usbListFirst (&pHost->busIrps);
  1833.     while (pIrp != NULL)
  1834. {
  1835. pNextIrp = usbListNext (&pIrp->hcdLink);
  1836.     
  1837. pWork = (pIRP_WORKSPACE) pIrp->hcdPtr;
  1838. if (pIrp->timeout != USB_TIMEOUT_NONE && pWork->irpRunning &&
  1839.     now - pWork->startTime > pIrp->timeout)
  1840.     {
  1841.     /* This IRP has exceeded its run time. */
  1842.     cancelIrp (pHost, pIrp, S_usbHcdLib_TIMEOUT);
  1843.     }
  1844. pIrp = pNextIrp;
  1845. }
  1846.     }
  1847. /***************************************************************************
  1848. *
  1849. * intThread - Thread invoked when hardware interrupts are detected
  1850. *
  1851. * By convention, the <param> to this thread is a pointer to an HCD_HOST.
  1852. * This thread waits on the intPending semaphore in the HCD_HOST which is
  1853. * signalled by the actual interrupt handler.  This thread will continue
  1854. * to process interrupts until intThreadExitRequest is set to TRUE in the
  1855. * HCD_HOST structure.
  1856. *
  1857. * This thread wakes up every HC_TIMEOUT_SRVC_INTERVAL milliseconds and 
  1858. * checks for IRPs which may have timed-out.
  1859. *
  1860. * RETURNS: N/A
  1861. */
  1862. LOCAL VOID intThread
  1863.     (
  1864.     pVOID param
  1865.     )
  1866.     {
  1867.     pHCD_HOST pHost = (pHCD_HOST) param;
  1868.     UINT32 interval;
  1869.     UINT32 now;
  1870.     UINT32 lastTime = OSS_TIME ();
  1871.     do
  1872. {
  1873. /* Wait for an interrupt to be signalled. */
  1874. now = OSS_TIME ();
  1875. interval = HC_TIMEOUT_SRVC_INTERVAL - 
  1876.    min (now - lastTime, HC_TIMEOUT_SRVC_INTERVAL);
  1877. if (OSS_SEM_TAKE (pHost->intPending, interval) == OK)
  1878.     {
  1879.     /* semaphore was signalled, int pending */
  1880.     if (!pHost->intThreadExitRequest)
  1881. {
  1882. OSS_MUTEX_TAKE (pHost->hostMutex, OSS_BLOCK);
  1883. processInterrupt (pHost);
  1884. OSS_MUTEX_RELEASE (pHost->hostMutex);
  1885. }
  1886.     }
  1887. if ((now = OSS_TIME ()) - lastTime >= HC_TIMEOUT_SRVC_INTERVAL)
  1888.     {
  1889.     /* check for timed-out IRPs */
  1890.     lastTime = now;
  1891.     /* Look for IRPs which may have timed-out. */
  1892.     OSS_MUTEX_TAKE (pHost->hostMutex, OSS_BLOCK);
  1893.     checkIrpTimeout (pHost);
  1894.     OSS_MUTEX_RELEASE (pHost->hostMutex);
  1895.     }
  1896. }
  1897.     while (!pHost->intThreadExitRequest);
  1898.     /* Signal that we've acknowledged the exit request */
  1899.     OSS_SEM_GIVE (pHost->intThreadExit);
  1900.     }
  1901. /***************************************************************************
  1902. *
  1903. * intHandler - hardware interrupt handler
  1904. *
  1905. * This is the actual routine which receives hardware interrupts from the
  1906. * HC.  This routine immediately reflects the interrupt to the intThread.
  1907. * interrupt handlers have execution restrictions which are not imposed
  1908. * on normal threads...So, this scheme gives the intThread complete
  1909. * flexibility to call other services and libraries while processing the
  1910. * interrupt condition.
  1911. *
  1912. * RETURNS: N/A
  1913. */
  1914. LOCAL VOID intHandler
  1915.     (
  1916.     pVOID param
  1917.     )
  1918.     {
  1919.     pHCD_HOST pHost = (pHCD_HOST) param;
  1920.     /* Is there an interrupt pending in the OHCI interrupt status reg? */
  1921.     if ((HC_DWORD_IN (OHCI_HC_INT_STATUS) & INT_ENABLE_MASK) != 0)
  1922. {
  1923. pHost->intCount++;
  1924. /* Disable further interrupts until the intThread takes over */
  1925. HC_DWORD_OUT (OHCI_HC_INT_DISABLE, OHCI_INT_MIE);
  1926. /* Signal the interrupt thread to process the interrupt. */
  1927. OSS_SEM_GIVE (pHost->intPending);
  1928. }
  1929.     /* Prevent the hcSync routine from busy waiting. */
  1930.     if(pHost->hcSyncSem) 
  1931. semGive (pHost->hcSyncSem);
  1932.     }
  1933. /***************************************************************************
  1934. *
  1935. * validateHrb - validate an HRB
  1936. *
  1937. * Checks the HRB length set in the HRB_HEADER against the <expectedLen>
  1938. * passed by the caller. 
  1939. *
  1940. * RETURNS: S_usbHcdLib_xxxx
  1941. */
  1942. LOCAL int validateHrb
  1943.     (
  1944.     pVOID pHrb,
  1945.     UINT16 expectedLen
  1946.     )
  1947.     {
  1948.     pHRB_HEADER pHeader = (pHRB_HEADER) pHrb;
  1949.     if (pHeader->hrbLength != expectedLen)
  1950. return S_usbHcdLib_BAD_PARAM;
  1951.     return OK;
  1952.     }
  1953. /***************************************************************************
  1954. *
  1955. * destroyPipe - tears down an HCD_PIPE
  1956. *
  1957. * RETURNS: N/A
  1958. */
  1959. LOCAL void destroyPipe
  1960.     (
  1961.     pHCD_HOST pHost,
  1962.     pHCD_PIPE pPipe
  1963.     )
  1964.     {
  1965.     if (pPipe->pEd != NULL) 
  1966. {
  1967. /* Release ED allocated for pipe. */
  1968. unschedulePipe (pHost, pPipe);
  1969. DMA_FREE (pPipe->pEd);
  1970. }
  1971.     /* Release bandwidth associated with pipe. */
  1972.     pHost->nanoseconds -= pPipe->time;
  1973.     /* Release pipe */
  1974.     usbListUnlink (&pPipe->link);
  1975.     usbHandleDestroy (pPipe->pipeHandle);
  1976.     OSS_FREE (pPipe);
  1977.     }
  1978. /***************************************************************************
  1979. *
  1980. * destroyHost - tears down an HCD_HOST
  1981. *
  1982. * RETURNS: N/A
  1983. */
  1984. LOCAL VOID destroyHost
  1985.     (
  1986.     pHCD_HOST pHost
  1987.     )
  1988.     
  1989.     {
  1990.     pUSB_IRP pIrp;
  1991.     pHCD_PIPE pPipe;
  1992.     /* Mark host as being shut down */
  1993.     pHost->shutdown = TRUE;
  1994.     /* release any pending IRPs */
  1995.     while ((pIrp = usbListFirst (&pHost->rootIrps)) != NULL)
  1996. cancelIrp (pHost, pIrp, S_usbHcdLib_IRP_CANCELED);
  1997.     while ((pIrp = usbListFirst (&pHost->busIrps)) != NULL)
  1998. cancelIrp (pHost, pIrp, S_usbHcdLib_IRP_CANCELED);
  1999.     /* release any pending pipes */
  2000.     while ((pPipe = usbListFirst (&pHost->pipes)) != NULL)
  2001. destroyPipe (pHost, pPipe);
  2002.     /* Disable the HC */
  2003.     HC_DWORD_OUT (OHCI_HC_CONTROL, 0);
  2004.     HC_DWORD_OUT (OHCI_HC_COMMAND_STATUS, OHCI_CS_HCR);
  2005.     /* 
  2006.      * By default SYS_OHCI_RESET is a no-op, but it can be overridden
  2007.      * in BSP stubs as necessary.
  2008.      */
  2009.     SYS_OHCI_RESET();
  2010.     /* restore original interrupt handler */
  2011.     if (pHost->intInstalled)
  2012. usbPciIntRestore (intHandler, pHost, pHost->pciCfgHdr.intLine);
  2013.     /* terminate/destroy interrupt handler thread */
  2014.     if (pHost->intThread != NULL)
  2015. {
  2016. /* Terminate the interrupt service thread */
  2017. pHost->intThreadExitRequest = TRUE;
  2018. OSS_SEM_GIVE (pHost->intPending);
  2019. OSS_SEM_TAKE (pHost->intThreadExit, INT_TIMEOUT);
  2020. OSS_THREAD_DESTROY (pHost->intThread);
  2021. }
  2022.     /* release other resources */
  2023.     if (pHost->hostMutex != NULL)
  2024. OSS_MUTEX_DESTROY (pHost->hostMutex);
  2025.     if (pHost->intThreadExit != NULL)
  2026. OSS_SEM_DESTROY (pHost->intThreadExit);
  2027.     if (pHost->intPending != NULL)
  2028. OSS_SEM_DESTROY (pHost->intPending);
  2029.     if (pHost->handle != NULL)
  2030. usbHandleDestroy (pHost->handle);
  2031.     /* release root hub per-port data */
  2032.     if (pHost->pRhPortChange != NULL)
  2033. OSS_FREE (pHost->pRhPortChange);
  2034.     /* eliminate DMA memory pool.
  2035.      *
  2036.      * NOTE: This automatically deletes any objects allocated within the
  2037.      * DMA memory pool, e.g., the OHCI HCCA.
  2038.      */
  2039.     if (pHost->dmaPool != NULL)
  2040. cacheDmaFree (pHost->dmaPool);
  2041.     OSS_FREE (pHost);
  2042.     }
  2043. /***************************************************************************
  2044. *
  2045. * fncAttach - Initialize the HCD and attach to specified bus(es)
  2046. *
  2047. * The convention for the OHCI HCD is that the param passed in the HRB
  2048. * is a pointer to a PCI_CFG_HEADER structure for the HC to be managed.
  2049. *
  2050. * RETURNS: S_usbHcdLib_xxxx
  2051. */
  2052. LOCAL int fncAttach
  2053.     (
  2054.     pHRB_ATTACH pHrb
  2055.     )
  2056.     {
  2057.     pHCD_HOST pHost;
  2058.     pPCI_CFG_HEADER pCfgHdr;
  2059.     UINT32 memBase;
  2060.     int i;
  2061.     int s;
  2062.     /* validate parameters */
  2063.     if ((s = validateHrb (pHrb, sizeof (*pHrb))) != OK)
  2064. return s;
  2065.     /* Check to make sure structures compiled to correct size */
  2066.     if (OHCI_HCCA_ACTLEN != OHCI_HCCA_LEN || 
  2067. OHCI_ED_ACTLEN != OHCI_ED_LEN ||
  2068. OHCI_TD_GEN_ACTLEN != OHCI_TD_GEN_LEN ||
  2069. OHCI_TD_ISO_ACTLEN != OHCI_TD_ISO_LEN ||
  2070. TD_WRAPPER_ACTLEN != TD_WRAPPER_LEN)
  2071. {
  2072. return S_usbHcdLib_STRUCT_SIZE_FAULT;
  2073. }
  2074.     /* determine io base address */
  2075.     pCfgHdr = (pPCI_CFG_HEADER) pHrb->param;
  2076.     memBase = 0;
  2077.     for (i = 0; i < PCI_CFG_NUM_BASE_REG; i++)
  2078. if ((pCfgHdr->baseReg [i] & PCI_CFG_BASE_IO) == 0 &&
  2079.     (memBase = pCfgHdr->baseReg [i] & PCI_CFG_MEMBASE_MASK) != 0)
  2080.     break;
  2081.     if (memBase == 0)
  2082. return S_usbHcdLib_HW_NOT_READY;
  2083.     /* create/initialize an HCD_HOST structure to manage the HC. */
  2084.     if ((pHost = OSS_CALLOC (sizeof (*pHost))) == NULL)
  2085. return S_usbHcdLib_OUT_OF_MEMORY;
  2086.     memcpy (&pHost->pciCfgHdr, pCfgHdr, sizeof (*pCfgHdr));
  2087.     pHost->mngmtCallback = pHrb->mngmtCallback;
  2088.     pHost->mngmtCallbackParam = pHrb->mngmtCallbackParam;
  2089.     /* initialize pHost->memBase...cannot use HC_SET_BITS, etc. until 
  2090.      * ioBase is initialized.
  2091.      */
  2092.     pHost->memBase = (pUINT32) (memBase + USB_PCI_MEMIO_OFFSET());
  2093.     /* 
  2094.      * Create a semaphore to syncronize the host controller.  This is used
  2095.      * to make the HC wait a frame for traffic to settle 
  2096.      */
  2097.     pHost->hcSyncSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
  2098.     if (pHost->hcSyncSem == NULL)
  2099.         return S_usbHcdLib_OUT_OF_RESOURCES;    
  2100.     /* Check the hardware revision level */
  2101.     if ((HC_DWORD_IN (OHCI_HC_REVISION) & OHCI_RREV_REV_MASK) 
  2102. < REQUIRED_OHCI_LEVEL)
  2103.     
  2104. return S_usbHcdLib_HW_NOT_READY;
  2105.     /* reset the host controller.
  2106.      *
  2107.      * NOTE: At the same time, we disable anything else which may be
  2108.      * enabled in the OHCI control register.
  2109.      *
  2110.      * NOTE: We allow the HC to revert to the nominal (default) frame
  2111.      * interval in response to the reset.
  2112.      */
  2113.     /* Initiate software reset */
  2114.     HC_SET_BITS (OHCI_HC_COMMAND_STATUS, OHCI_CS_HCR);
  2115.     /* Make ports power swiched */
  2116.     HC_CLR_BITS (OHCI_HC_RH_DESCR_A, OHCI_RHDA_NPS);
  2117.  
  2118.     /* All ports are powered at the same time */
  2119.     HC_CLR_BITS (OHCI_HC_RH_DESCR_A, OHCI_RHDA_PSM);
  2120.     HC_DWORD_OUT (OHCI_HC_CONTROL, 0);
  2121.     /*  Wait for propper reset signaling to occur. */
  2122.     OSS_THREAD_SLEEP (USB_TIME_RESET);
  2123.     /* 
  2124.      * By default SYS_OHCI_RESET is a no-op, but it can be overridden
  2125.      * in BSP stubs as necessary.
  2126.      */
  2127.     SYS_OHCI_RESET();
  2128.     if (!waitOnBits (pHost, OHCI_HC_COMMAND_STATUS, OHCI_CS_HCR, 0))
  2129. {
  2130. destroyHost (pHost);
  2131. return S_usbHcdLib_HW_NOT_READY;
  2132. }
  2133.     if ((pHost->dmaPool = cacheDmaMalloc (DMA_MEMORY_SIZE))  == NULL || 
  2134. (pHost->memPartId = memPartCreate (pHost->dmaPool, 
  2135.    DMA_MEMORY_SIZE)) == NULL || 
  2136. (pHost->pRhPortChange = OSS_CALLOC (pHost->numPorts * sizeof (UINT32))) == NULL || 
  2137. (pHost->pHcca = DMA_MALLOC (sizeof (*pHost->pHcca), 
  2138.     OHCI_HCCA_ALIGNMENT)) == NULL || 
  2139. (pHost->pIsochAnchorEd = DMA_MALLOC (sizeof (*pHost->pIsochAnchorEd), 
  2140.      OHCI_TD_ISO_ALIGNMENT)) == NULL || 
  2141. usbHandleCreate (HCD_HOST_SIG, 
  2142. pHost, 
  2143. &pHost->handle) != OK || 
  2144. OSS_SEM_CREATE (MAX_INT_DEPTH, 
  2145. 0, 
  2146. &pHost->intPending) != OK || 
  2147. OSS_SEM_CREATE (1, 
  2148. 0, 
  2149. &pHost->intThreadExit) != OK || 
  2150. OSS_MUTEX_CREATE (&pHost->hostMutex) != OK || 
  2151. OSS_THREAD_CREATE (intThread, 
  2152.    pHost, 
  2153.    OSS_PRIORITY_INTERRUPT,
  2154.    "tOhciInt", 
  2155.    &pHost->intThread) != OK)
  2156. {
  2157. destroyHost (pHost);
  2158. return S_usbHcdLib_OUT_OF_RESOURCES;
  2159. }
  2160.     /* 
  2161.      *  Provide an empty HCCA before the first reset of the part, so that
  2162.      *  the controller has a valid spot to write its frame count.
  2163.      */
  2164.     memset (pHost->pHcca, 0, sizeof(*pHost->pHcca));
  2165.     DMA_FLUSH (pHost->pHcca, sizeof (*pHost->pHcca));
  2166.     HC_DWORD_OUT (OHCI_HC_HCCA, USB_MEM_TO_PCI (pHost->pHcca));
  2167.     /* Determine the number of ports supported by this host controller. */
  2168.     pHost->numPorts = OHCI_RHDA_NDP (HC_DWORD_IN (OHCI_HC_RH_DESCR_A));
  2169.     pHost->numPorts = min (pHost->numPorts, MAX_ROOT_PORTS);
  2170.     /* Determine root hub power characteristics. */
  2171.     pHost->pwrOn2PwrGood = OHCI_RHDA_POTPGT (HC_DWORD_IN (OHCI_HC_RH_DESCR_A));
  2172.     /* Place the HC in the operational state so we can start talking
  2173.      * to it (e.g., cannot necessarily write to OHCI_HC_RH_STATUS unless
  2174.      * HC is in operational state).
  2175.      */
  2176.     HC_DWORD_OUT (OHCI_HC_CONTROL, OHCI_CTL_HCFS_OP);
  2177.     hcSynch (pHost);
  2178.     /* Explictly enable power to the USB ports. */
  2179.     HC_SET_BITS (OHCI_HC_RH_DESCR_A, OHCI_RHDA_NPS);
  2180.     HC_SET_BITS (OHCI_HC_RH_DESCR_A, OHCI_RHDA_PSM);
  2181.     /* initialize the emulated root hub descriptor */
  2182.     pHost->hubDescr.length = USB_HUB_DESCR_LEN;
  2183.     pHost->hubDescr.descriptorType = USB_DESCR_HUB;
  2184.     pHost->hubDescr.nbrPorts = pHost->numPorts;
  2185.     pHost->hubDescr.hubCharacteristics = 
  2186.     TO_LITTLEW (USB_HUB_INDIVIDUAL_POWER | 
  2187. USB_HUB_NOT_COMPOUND | 
  2188. USB_HUB_INDIVIDUAL_OVERCURRENT);
  2189.     pHost->hubDescr.pwrOn2PwrGood = pHost->pwrOn2PwrGood;
  2190.     pHost->hubDescr.hubContrCurrent = OHCI_HUB_CONTR_CURRENT;
  2191.     pHost->hubDescr.deviceRemovable [0] = 0;
  2192.     pHost->hubDescr.portPwrCtrlMask [0] = 0xff; /* per hub spec. */
  2193.     /* initialize the emulated endpoint descriptor */
  2194.     pHost->endpntDescr.length = USB_ENDPOINT_DESCR_LEN;
  2195.     pHost->endpntDescr.descriptorType = USB_DESCR_ENDPOINT;
  2196.     pHost->endpntDescr.endpointAddress = HC_STATUS_ENDPOINT_ADRS;
  2197.     pHost->endpntDescr.attributes = USB_ATTR_INTERRUPT;
  2198.     pHost->endpntDescr.maxPacketSize = TO_LITTLEW (HC_MAX_PACKET_SIZE);
  2199.     pHost->endpntDescr.interval = OHCI_HUB_INTERVAL;
  2200.     /* initialize the emulated interface descriptor */
  2201.     pHost->ifDescr.length = USB_INTERFACE_DESCR_LEN;
  2202.     pHost->ifDescr.descriptorType = USB_DESCR_INTERFACE;
  2203.     pHost->ifDescr.numEndpoints = 1;
  2204.     pHost->ifDescr.interfaceClass = USB_CLASS_HUB;
  2205.     /* initialize the emulated configuration descriptor */
  2206.     pHost->configDescr.length = USB_CONFIG_DESCR_LEN;
  2207.     pHost->configDescr.descriptorType = USB_DESCR_CONFIGURATION;
  2208.     pHost->configDescr.totalLength = 
  2209.     TO_LITTLEW (pHost->configDescr.length + 
  2210. pHost->ifDescr.length + 
  2211. pHost->endpntDescr.length);
  2212.     pHost->configDescr.numInterfaces = 1;
  2213.     pHost->configDescr.configurationValue = HC_CONFIG_VALUE;
  2214.     pHost->configDescr.attributes = USB_ATTR_SELF_POWERED;
  2215.     pHost->configDescr.maxPower = OHCI_HUB_CONTR_CURRENT;
  2216.     /* initialize the emulated device descriptor */
  2217.     pHost->devDescr.length = USB_DEVICE_DESCR_LEN;
  2218.     pHost->devDescr.descriptorType = USB_DESCR_DEVICE;
  2219.     pHost->devDescr.bcdUsb = TO_LITTLEW (USB_RELEASE);
  2220.     pHost->devDescr.deviceClass = USB_CLASS_HUB;
  2221.     pHost->devDescr.maxPacketSize0 = HC_MAX_PACKET_SIZE;
  2222.     pHost->devDescr.manufacturerIndex = HC_STR_MFG;
  2223.     pHost->devDescr.productIndex = HC_STR_PROD;
  2224.     pHost->devDescr.numConfigurations = 1;
  2225.     /* initialize other hub/port state information */
  2226.     pHost->rootAddress = 0;
  2227.     pHost->configValue = 0;
  2228.     
  2229.     /* initialize the interrupt ED list and program the HCCA register */
  2230.     memset (pHost->pHcca, 0, sizeof (*pHost->pHcca));
  2231.     memset (pHost->pIsochAnchorEd, 0, sizeof (*pHost->pIsochAnchorEd));
  2232.     pHost->pIsochAnchorEd->ed.control = 
  2233.     TO_LITTLEL (OHCI_EDCTL_FMT_ISO | OHCI_EDCTL_SKIP);
  2234.     for (i = 0; i < OHCI_INT_ED_COUNT; i++)
  2235. pHost->pHcca->intEdTable [i] = TO_LITTLEL (TO_PCIPTR (pHost->pIsochAnchorEd));
  2236.     DMA_FLUSH (pHost->pIsochAnchorEd, sizeof (*pHost->pIsochAnchorEd));
  2237.     DMA_FLUSH (pHost->pHcca, sizeof (*pHost->pHcca));
  2238.     HC_DWORD_OUT (OHCI_HC_HCCA, USB_MEM_TO_PCI (pHost->pHcca));
  2239.     /* hook the hardware interrupt for the HC */
  2240.     if (usbPciIntConnect (intHandler, pHost, pHost->pciCfgHdr.intLine) != OK)
  2241. {
  2242. destroyHost (pHost);
  2243. return S_usbHcdLib_INT_HOOK_FAILED;
  2244. }
  2245.     pHost->intInstalled = TRUE;
  2246.     /* Set up the frame interval register. */
  2247.     setFrameInterval (pHost, OHCI_FMI_FI_DEFAULT);
  2248.     /* Set the periodic start equal to the frame interval.
  2249.      *
  2250.      * NOTE: The OHCI spec. suggests setting periodic start equal to 90% of
  2251.      * the frame interval.  However, in this implementation, we set periodic
  2252.      * start equal to 100% of frame interval.  This should force all periodic
  2253.      * transfers to start at the beginning of each frame.  Elsewhere, we
  2254.      * ensure that no more than 90% of the bus is allocated to periodic
  2255.      * (interrupt and isoch) transfers, so we achieve the same outcome.
  2256.      */
  2257.     HC_DWORD_OUT (OHCI_HC_PERIODIC_START, OHCI_PS_PS_FMT (OHCI_FMI_FI_DEFAULT));
  2258.     /* Enable root hub port pwr */
  2259.     HC_DWORD_OUT (OHCI_HC_RH_STATUS, OHCI_RHS_SET_GPWR);
  2260.     /* Enable the HC (operational state was set earlier) */
  2261.     HC_SET_BITS (OHCI_HC_CONTROL, 
  2262. OHCI_CTL_CBSR_3TO1 |
  2263. OHCI_CTL_PLE | 
  2264. OHCI_CTL_IE | 
  2265. OHCI_CTL_CLE | 
  2266. OHCI_CTL_BLE |
  2267. OHCI_CTL_RWC | 
  2268. OHCI_CTL_RWE);
  2269.     /* Enable interrupts */
  2270.     HC_DWORD_OUT (OHCI_HC_INT_ENABLE, INT_ENABLE_MASK);
  2271.     /* return handle to caller */
  2272.     pHrb->header.handle = pHost->handle;
  2273.     pHrb->busCount = 1;
  2274.     return OK;
  2275.     }
  2276. /***************************************************************************
  2277. *
  2278. * fncDetach - Disconnect from specified bus(es) and shut down
  2279. *
  2280. * RETURNS: S_usbHcdLib_xxxx
  2281. */
  2282. LOCAL int fncDetach
  2283.     (
  2284.     pHRB_DETACH pHrb,
  2285.     pHCD_HOST pHost
  2286.     )
  2287.     {
  2288.     int s;
  2289.     /* validate parameters */
  2290.     if ((s = validateHrb (pHrb, sizeof (*pHrb))) != OK)
  2291. return s;
  2292.     /* Release resources associated with this HCD_HOST */
  2293.     destroyHost (pHost);
  2294.     return OK;
  2295.     }
  2296. /***************************************************************************
  2297. *
  2298. * fncSetBusState - Sets bus suspend/resume state
  2299. *
  2300. * RETURNS: S_usbHcdLib_xxxx
  2301. */
  2302. LOCAL int fncSetBusState
  2303.     (
  2304.     pHRB_SET_BUS_STATE pHrb,
  2305.     pHCD_HOST pHost
  2306.     )
  2307.     {
  2308.     if ((pHrb->busState & HCD_BUS_SUSPEND) != 0)
  2309. {
  2310. /* SUSPEND bus */
  2311. if (!pHost->suspended)
  2312.     {
  2313.     pHost->suspended = TRUE;
  2314.     /* Set the operational state to suspend...
  2315.      *
  2316.      * As a biproduct of this, all outstanding ERPs will
  2317.      * eventually time-out.
  2318.      */
  2319.     HC_DWORD_OUT (OHCI_HC_CONTROL, 
  2320.   (HC_DWORD_IN (OHCI_HC_CONTROL) & 
  2321.   ~OHCI_CTL_HCFS_MASK) | 
  2322.   OHCI_CTL_HCFS_SUSPEND);
  2323.     }
  2324. }
  2325.     if ((pHrb->busState & HCD_BUS_RESUME) != 0)
  2326. {
  2327. /* RESUME bus */
  2328. if (pHost->suspended)
  2329.     {
  2330.     pHost->suspended = FALSE;
  2331.     /* Force global resume */
  2332.     HC_DWORD_OUT (OHCI_HC_CONTROL, 
  2333.   (HC_DWORD_IN (OHCI_HC_CONTROL) & 
  2334.   ~OHCI_CTL_HCFS_MASK) | 
  2335.   OHCI_CTL_HCFS_RESUME);
  2336.     OSS_THREAD_SLEEP (USB_TIME_RESUME);
  2337.     HC_DWORD_OUT (OHCI_HC_CONTROL, 
  2338.   (HC_DWORD_IN (OHCI_HC_CONTROL) & 
  2339.   ~OHCI_CTL_HCFS_MASK) | 
  2340.   OHCI_CTL_HCFS_OP);
  2341.     }
  2342. }
  2343.     return OK;
  2344.     }
  2345. /***************************************************************************
  2346. *
  2347. * fncSofIntervalGet - retrieves current SOF interval
  2348. *
  2349. * RETURNS: S_usbdHcdLib_xxxx
  2350. */
  2351. LOCAL int fncSofIntervalGet
  2352.     (
  2353.     pHRB_SOF_INTERVAL_GET_SET pHrb,
  2354.     pHCD_HOST pHost
  2355.     )
  2356.     {
  2357.     int s;
  2358.     /* validate parameters */
  2359.     if ((s = validateHrb (pHrb, sizeof (*pHrb))) != OK)
  2360. return s;
  2361.     if (pHrb->busNo != 0)
  2362. return S_usbHcdLib_BAD_PARAM;
  2363.     /* Retrieve the current SOF interval. */
  2364.     pHrb->sofInterval = OHCI_FMI_FI (HC_DWORD_IN (OHCI_HC_FM_INTERVAL));
  2365.     return OK;
  2366.     }
  2367. /***************************************************************************
  2368. *
  2369. * fncSofIntervalSet - set new SOF interval
  2370. *
  2371. * RETURNS: S_usbdHcdLib_xxxx
  2372. */
  2373. LOCAL int fncSofIntervalSet
  2374.     (
  2375.     pHRB_SOF_INTERVAL_GET_SET pHrb,
  2376.     pHCD_HOST pHost
  2377.     )
  2378.     {
  2379.     int s;
  2380.     /* validate parameters */
  2381.     if ((s = validateHrb (pHrb, sizeof (*pHrb))) != OK)
  2382. return s;
  2383.     if (pHrb->busNo != 0)
  2384. return S_usbHcdLib_BAD_PARAM;
  2385.     /* Set the new SOF interval. */
  2386.     setFrameInterval (pHost, pHrb->sofInterval);
  2387.     return OK;
  2388.     }
  2389. /***************************************************************************
  2390. *
  2391. * fncCurrentFrameGet - Return current bus frame number
  2392. *
  2393. * RETURNS: S_usbHcdLib_xxxx
  2394. */
  2395. LOCAL int fncCurrentFrameGet
  2396.     (
  2397.     pHRB_CURRENT_FRAME_GET pHrb,
  2398.     pHCD_HOST pHost
  2399.     )
  2400.     {
  2401.     int s;
  2402.     /* validate parameters */
  2403.     if ((s = validateHrb (pHrb, sizeof (*pHrb))) != OK)
  2404. return s;
  2405.     /* Return the current frame number and the size of the frame 
  2406.      * scheduling window
  2407.      */
  2408.     pHrb->frameNo = getFrameNo (pHost);
  2409.     /* NOTE: We don't expose the HC's frame counter for the frame
  2410.      * scheduling window.  Instead, we expose the size of the frame
  2411.      * list.  Otherwise, we would need to keep track of each time the
  2412.      * frame counter rolls over.
  2413.      */
  2414.     pHrb->frameWindow = OHCI_FRAME_WINDOW;
  2415.     return OK;
  2416.     }
  2417. /***************************************************************************
  2418. *
  2419. * rootFeature - sets/clears a root feature
  2420. *
  2421. * RETURNS: S_usbHcdLib_xxxx
  2422. */
  2423. LOCAL int rootFeature
  2424.     (
  2425.     pHCD_HOST pHost,
  2426.     pUSB_SETUP pSetup,
  2427.     BOOL setFeature
  2428.     )
  2429.     {
  2430.     UINT16 port;
  2431.     UINT32 portReg;
  2432.     int s = OK;
  2433.     if ((pSetup->requestType & ~USB_RT_DEV_TO_HOST) == 
  2434. (USB_RT_CLASS | USB_RT_DEVICE))
  2435. {
  2436. /* hub class features, directed to hub itself */
  2437. switch (FROM_LITTLEW (pSetup->value))
  2438.     {
  2439.     case USB_HUB_FSEL_C_HUB_LOCAL_POWER:
  2440.     case USB_HUB_FSEL_C_HUB_OVER_CURRENT:
  2441.     /* Not implemented */
  2442.     break;
  2443.     }
  2444. }
  2445.     else if ((pSetup->requestType & ~USB_RT_DEV_TO_HOST) ==
  2446.      (USB_RT_CLASS | USB_RT_OTHER))
  2447. {
  2448. /* port class features, directed to port */
  2449. /* NOTE: port parameter is 1-based, not 0-based, in Setup packet. */
  2450. if ((port = FROM_LITTLEW (pSetup->index) - 1) >= pHost->numPorts)
  2451.     return S_usbHcdLib_BAD_PARAM;
  2452. portReg = OHCI_HC_RH_PORT_STATUS + port * sizeof (UINT32);
  2453. switch (FROM_LITTLEW (pSetup->value))
  2454.     {
  2455.     case USB_HUB_FSEL_PORT_ENABLE:
  2456. if (setFeature)
  2457.     HC_SET_BITS (portReg, OHCI_RHPS_SET_PE);
  2458. else
  2459.     HC_SET_BITS (portReg, OHCI_RHPS_CLR_PE);
  2460. break;
  2461.     case USB_HUB_FSEL_PORT_SUSPEND:
  2462. if (setFeature)
  2463.     HC_SET_BITS (portReg, OHCI_RHPS_SET_PS);
  2464. else
  2465.     HC_SET_BITS (portReg, OHCI_RHPS_CLR_PS);
  2466. break;
  2467.     
  2468.     case USB_HUB_FSEL_PORT_RESET:
  2469. if (setFeature)
  2470.     {
  2471.     /* Note: The port is supposed to be enabled upon 
  2472.      * completion of reset.
  2473.      */
  2474.     HC_SET_BITS (portReg, OHCI_RHPS_PRS | OHCI_RHPS_PES);
  2475.     OSS_THREAD_SLEEP (USB_TIME_RESET);
  2476.     if (waitOnBits (pHost, 
  2477.     portReg, 
  2478.     OHCI_RHPS_PRSC, 
  2479.     OHCI_RHPS_PRSC))
  2480. {
  2481. OSS_THREAD_SLEEP (USB_TIME_RESET_RECOVERY);
  2482. }
  2483.     else
  2484. {
  2485. s = S_usbHcdLib_HW_NOT_READY;
  2486. }
  2487.     }
  2488. break;
  2489.     case USB_HUB_FSEL_PORT_POWER:
  2490. if (setFeature)
  2491.     HC_SET_BITS (portReg, OHCI_RHPS_SET_PWR);
  2492. else
  2493.     HC_SET_BITS (portReg, OHCI_RHPS_CLR_PWR);
  2494. break;
  2495.     case USB_HUB_FSEL_C_PORT_CONNECTION:
  2496. if (!setFeature)
  2497.     pHost->pRhPortChange [port] &= ~OHCI_RHPS_CSC;
  2498. break;
  2499.     case USB_HUB_FSEL_C_PORT_ENABLE:
  2500. if (!setFeature)
  2501.     pHost->pRhPortChange [port] &= ~OHCI_RHPS_PESC;
  2502. break;
  2503.     case USB_HUB_FSEL_C_PORT_SUSPEND:
  2504. if (!setFeature)
  2505.     pHost->pRhPortChange [port] &= ~OHCI_RHPS_PSSC;
  2506. break;
  2507.     case USB_HUB_FSEL_C_PORT_OVER_CURRENT:
  2508. if (!setFeature)
  2509.     pHost->pRhPortChange [port] &= ~OHCI_RHPS_OCIC;
  2510. break;
  2511.     case USB_HUB_FSEL_C_PORT_RESET:
  2512. if (!setFeature) 
  2513.     pHost->pRhPortChange [port] &= ~OHCI_RHPS_PRSC;
  2514. break;
  2515.     }
  2516. }
  2517.     return s;
  2518.     }
  2519. /***************************************************************************
  2520. *
  2521. * rootGetDescriptor - process a get descriptor request
  2522. *
  2523. * RETURNS: S_usbHcdLib_xxxx
  2524. */
  2525. LOCAL int rootGetDescriptor
  2526.     (
  2527.     pHCD_HOST pHost,
  2528.     pUSB_IRP pIrp,
  2529.     pUSB_SETUP pSetup
  2530.     )
  2531.     {
  2532.     UINT8 bfr [USB_CONFIG_DESCR_LEN + USB_INTERFACE_DESCR_LEN
  2533.     + USB_ENDPOINT_DESCR_LEN];
  2534.     int s = OK;
  2535.     if (pIrp->bfrCount < 2 || pIrp->bfrList [1].pBfr == NULL)
  2536.     return S_usbHcdLib_BAD_PARAM;
  2537.     if (pSetup->requestType == (USB_RT_DEV_TO_HOST | 
  2538. USB_RT_STANDARD | 
  2539. USB_RT_DEVICE))
  2540. {
  2541. switch (MSB (FROM_LITTLEW (pSetup->value)))
  2542.     {
  2543.     case USB_DESCR_DEVICE:
  2544. usbDescrCopy32 (pIrp->bfrList [1].
  2545. pBfr, &pHost->devDescr, 
  2546. pIrp->bfrList [1].bfrLen, 
  2547. &pIrp->bfrList [1].actLen);
  2548. break;
  2549.     case USB_DESCR_CONFIGURATION:
  2550. memcpy (bfr, &pHost->configDescr, USB_CONFIG_DESCR_LEN);
  2551. memcpy (&bfr [USB_CONFIG_DESCR_LEN], 
  2552. &pHost->ifDescr,
  2553. USB_INTERFACE_DESCR_LEN);
  2554. memcpy (&bfr [USB_CONFIG_DESCR_LEN + USB_INTERFACE_DESCR_LEN],
  2555. &pHost->endpntDescr, 
  2556. USB_ENDPOINT_DESCR_LEN);
  2557. pIrp->bfrList [1].actLen = min (pIrp->bfrList [1].bfrLen,
  2558. USB_CONFIG_DESCR_LEN + 
  2559. USB_INTERFACE_DESCR_LEN +
  2560. USB_ENDPOINT_DESCR_LEN);
  2561. memcpy (pIrp->bfrList [1].pBfr, bfr, pIrp->bfrList [1].actLen);
  2562. break;
  2563.     case USB_DESCR_INTERFACE:
  2564. usbDescrCopy32 (pIrp->bfrList [1].pBfr, 
  2565. &pHost->ifDescr, 
  2566. pIrp->bfrList [1].bfrLen, 
  2567. &pIrp->bfrList [1].actLen);
  2568. break;
  2569.     case USB_DESCR_ENDPOINT:
  2570. usbDescrCopy32 (pIrp->bfrList [1].pBfr, 
  2571. &pHost->endpntDescr, 
  2572. pIrp->bfrList [1].bfrLen, 
  2573. &pIrp->bfrList [1].actLen);
  2574. break;
  2575.     case USB_DESCR_STRING:
  2576. switch (LSB (FROM_LITTLEW (pSetup->value)))
  2577.     {
  2578.     case 0: /* language descriptor */
  2579. usbDescrCopy32 (pIrp->bfrList [1].pBfr, 
  2580. &langDescr, 
  2581. pIrp->bfrList [1].bfrLen, 
  2582. &pIrp->bfrList [1].actLen);
  2583. break;
  2584.     case HC_STR_MFG:
  2585. usbDescrStrCopy32 (pIrp->bfrList [1].pBfr, 
  2586.    HC_STR_MFG_VAL, 
  2587.    pIrp->bfrList [1].bfrLen, 
  2588.    &pIrp->bfrList [1].actLen);
  2589. break;
  2590.     case HC_STR_PROD:
  2591. usbDescrStrCopy32 (pIrp->bfrList [1].pBfr, 
  2592.    HC_STR_PROD_VAL, 
  2593.    pIrp->bfrList [1].bfrLen, 
  2594.    &pIrp->bfrList [1].actLen);
  2595. break;
  2596.     }
  2597. break;
  2598.     }
  2599. }
  2600.     else if (pSetup->requestType == (USB_RT_DEV_TO_HOST | 
  2601.      USB_RT_CLASS | 
  2602.      USB_RT_DEVICE))
  2603. {
  2604. if (MSB (FROM_LITTLEW (pSetup->value)) == USB_DESCR_HUB)
  2605.     usbDescrCopy32 (pIrp->bfrList [1].pBfr, 
  2606.     &pHost->hubDescr, 
  2607.     pIrp->bfrList [1].bfrLen, 
  2608.     &pIrp->bfrList [1].actLen);
  2609. }
  2610.     return s;
  2611.     }
  2612. /***************************************************************************
  2613. *
  2614. * copyStatus - copies status
  2615. *
  2616. * RETURNS: N/A
  2617. */
  2618. LOCAL VOID copyStatus
  2619.     (
  2620.     pUSB_BFR_LIST pBfrList,
  2621.     pVOID pStatus,
  2622.     UINT16 maxLen
  2623.     )
  2624.     {
  2625.     pBfrList->actLen = min (pBfrList->bfrLen, maxLen);
  2626.     memcpy (pBfrList->pBfr, pStatus, pBfrList->actLen);
  2627.     }
  2628. /***************************************************************************
  2629. *
  2630. * rootGetStatus - process a get status request
  2631. *
  2632. * RETURNS: S_usbHcdLib_xxxx
  2633. */
  2634. LOCAL int rootGetStatus
  2635.     (
  2636.     pHCD_HOST pHost,
  2637.     pUSB_IRP pIrp,
  2638.     pUSB_SETUP pSetup
  2639.     )
  2640.     {
  2641.     union 
  2642. {
  2643. USB_STANDARD_STATUS std;
  2644. USB_HUB_STATUS hub;
  2645. } status;
  2646.     
  2647.     UINT16 port;
  2648.     UINT32 portReg;
  2649.     UINT32 portStatus;
  2650.     /* validate parameters */
  2651.     if (pIrp->bfrCount < 2 || pIrp->bfrList [1].pBfr == NULL)
  2652. return S_usbHcdLib_BAD_PARAM;
  2653.     /* return status based on type of request received */
  2654.     memset (&status, 0, sizeof (status));
  2655.     if (pSetup->requestType ==(USB_RT_DEV_TO_HOST | 
  2656.        USB_RT_STANDARD | 
  2657.        USB_RT_DEVICE))
  2658. {
  2659. /* retrieve standard device status */
  2660. status.std.status = TO_LITTLEW (USB_DEV_STS_LOCAL_POWER);
  2661. copyStatus (&pIrp->bfrList [1], &status.std, sizeof (status.std));
  2662. }
  2663.     else if (pSetup->requestType == (USB_RT_DEV_TO_HOST | 
  2664.      USB_RT_STANDARD | 
  2665.      USB_RT_INTERFACE))
  2666. {
  2667. /* retrieve status of interface */
  2668. status.std.status = TO_LITTLEW (0);
  2669. copyStatus (&pIrp->bfrList [1], &status.std, sizeof (status.std));
  2670. }
  2671.     else if (pSetup->requestType == (USB_RT_DEV_TO_HOST | 
  2672.      USB_RT_STANDARD | 
  2673.      USB_RT_ENDPOINT))
  2674. {
  2675. /* retrieve status of endpoint */
  2676. status.std.status = TO_LITTLEW (0);
  2677. copyStatus (&pIrp->bfrList [1], &status.std, sizeof (status.std));
  2678. }
  2679.     else if (pSetup->requestType == (USB_RT_DEV_TO_HOST | 
  2680.      USB_RT_CLASS | 
  2681.      USB_RT_DEVICE))
  2682. {
  2683. /* retrieve hub status */
  2684. status.hub.status = TO_LITTLEW (USB_HUB_STS_LOCAL_POWER);
  2685. status.hub.change = TO_LITTLEW (0);
  2686. copyStatus (&pIrp->bfrList [1], &status.hub, sizeof (status.hub));
  2687. }
  2688.     else if (pSetup->requestType == (USB_RT_DEV_TO_HOST | 
  2689.      USB_RT_CLASS | 
  2690.      USB_RT_OTHER))
  2691. {
  2692. /* retrieve hub port status */
  2693. /* NOTE: port index is 1-based, not 0-based, in Setup packet. */
  2694. if ((port = FROM_LITTLEW (pSetup->index) - 1) >= pHost->numPorts)
  2695.     return S_usbHcdLib_BAD_PARAM;
  2696. portReg = OHCI_HC_RH_PORT_STATUS + port * sizeof (UINT32);
  2697. portStatus = HC_DWORD_IN (portReg) | pHost->pRhPortChange [port];
  2698. status.hub.status = TO_LITTLEW (portStatus & 0xffff);
  2699. status.hub.change = TO_LITTLEW (portStatus >> 16);
  2700. copyStatus (&pIrp->bfrList [1], &status.hub, sizeof (status.hub));
  2701. }
  2702.     return OK;
  2703.     }
  2704. /***************************************************************************
  2705. *
  2706. * rootControl - interprets a transfer to the root hub control pipe
  2707. *
  2708. * RETURNS: S_usbHcdLib_xxxx
  2709. */
  2710. LOCAL int rootControl
  2711.     (
  2712.     pHCD_HOST pHost,
  2713.     pUSB_IRP pIrp
  2714.     )
  2715.     {
  2716.     pUSB_SETUP pSetup;
  2717.     int s = OK;
  2718.     /* Control transfers always place the Setup packet in the first
  2719.      * USB_BFR_LIST entry in the IRP and any optional data is placed
  2720.      * in the second.
  2721.      */
  2722.     if (pIrp->bfrCount < 1 || 
  2723. pIrp->bfrList [0].bfrLen < sizeof (USB_SETUP) || 
  2724. (pSetup = (pUSB_SETUP) pIrp->bfrList [0].pBfr) == NULL)
  2725.     
  2726. return S_usbHcdLib_BAD_PARAM;
  2727.     /* execute request */
  2728.     switch (pSetup->request)
  2729.     {
  2730.     case USB_REQ_CLEAR_FEATURE:
  2731. s = rootFeature (pHost, pSetup, FALSE);
  2732. break;
  2733.     case USB_REQ_SET_FEATURE:
  2734. s = rootFeature (pHost, pSetup, TRUE);
  2735. break;
  2736.     case USB_REQ_GET_CONFIGURATION:
  2737. if (pIrp->bfrCount < 2 || pIrp->bfrList [1].pBfr == NULL)
  2738.     {
  2739.     s = S_usbHcdLib_BAD_PARAM;
  2740.     break;
  2741.     }
  2742. *pIrp->bfrList [1].pBfr = pHost->configValue;
  2743. break;
  2744.     case USB_REQ_SET_CONFIGURATION:
  2745. pHost->configValue = LSB (FROM_LITTLEW (pSetup->value));
  2746. break;
  2747.     case USB_REQ_GET_DESCRIPTOR:
  2748. s = rootGetDescriptor (pHost, pIrp, pSetup);
  2749. break;
  2750.     case USB_REQ_GET_STATUS:
  2751. s = rootGetStatus (pHost, pIrp, pSetup);
  2752. break;
  2753.     case USB_REQ_SET_ADDRESS:
  2754. pHost->rootAddress = FROM_LITTLEW (pSetup->value);
  2755. break;
  2756.     default:
  2757. s = S_usbHcdLib_NOT_SUPPORTED;
  2758. break;
  2759.     }
  2760.     return s;
  2761.     }
  2762. /***************************************************************************
  2763. *
  2764. * rootInterrupt - interprets an interrupt endpoint request
  2765. *
  2766. * RETURNS: S_usbHcdLib_xxxx
  2767. */
  2768. LOCAL int rootInterrupt
  2769.     (
  2770.     pHCD_HOST pHost,
  2771.     pHCD_PIPE pPipe,
  2772.     pUSB_IRP pIrp
  2773.     )
  2774.     {
  2775.     /* make sure the request is to the correct endpoint, etc. */
  2776.     if (pPipe->endpoint != HC_STATUS_ENDPOINT_ADRS ||
  2777. pIrp->bfrCount < 1 || pIrp->bfrList [0].pBfr == NULL)
  2778.     return S_usbHcdLib_BAD_PARAM;
  2779.     /* link this IRP to the list of root IRPs */
  2780.     usbListLink (&pHost->rootIrps, pIrp, &pIrp->hcdLink, LINK_TAIL);
  2781.     ++pHost->rootIrpCount;
  2782.     /* See if there is anything to report. */
  2783.     serviceRootIrps (pHost);
  2784.     return PENDING;
  2785.     }
  2786. /***************************************************************************
  2787. *
  2788. * rootIrpHandler - interprets and executes IRPs sent to the root hub
  2789. *
  2790. * NOTE: Unlike IRPs which are routed to the actual USB, IRPs which are
  2791. * diverted to the rootHandler() execute synchronously. Therefore, we
  2792. * force a callback completion at the end of this function.
  2793. *
  2794. * RETURNS: S_usbHcdLib_xxxx
  2795. */
  2796. LOCAL int rootIrpHandler
  2797.     (
  2798.     pHCD_HOST pHost,
  2799.     pHCD_PIPE pPipe,
  2800.     pUSB_IRP pIrp
  2801.     )
  2802.     {
  2803.     int s;
  2804.     /* fan-out based on the type of transfer to the root */
  2805.     switch (pPipe->transferType)
  2806.     {
  2807.     case USB_XFRTYPE_CONTROL:
  2808. s = rootControl (pHost, pIrp);
  2809. break;
  2810.     case USB_XFRTYPE_INTERRUPT: 
  2811. s = rootInterrupt (pHost, pPipe, pIrp);
  2812. break;
  2813.     case USB_XFRTYPE_ISOCH:
  2814.     case USB_XFRTYPE_BULK:
  2815.     default:
  2816. s = S_usbHcdLib_BAD_PARAM;
  2817. break;
  2818.     }
  2819.     return s;
  2820.     }
  2821. /***************************************************************************
  2822. *
  2823. * busIrpHandler - schedule an IRP for execution on the bus
  2824. *
  2825. * RETURNS: S_usbHcdLib_xxxx
  2826. */
  2827. LOCAL int busIrpHandler
  2828.     (
  2829.     pHCD_HOST pHost,
  2830.     pHCD_PIPE pPipe,
  2831.     pUSB_IRP pIrp
  2832.     )
  2833.     {
  2834.     /* Allocate workspace for this IRP */
  2835.     if (!allocIrpWorkspace (pHost, pPipe, pIrp))
  2836. return S_usbHcdLib_OUT_OF_MEMORY;
  2837.     /* Add this IRP to the scheduling list and invoke the IRP scheduler. */
  2838.     usbListLink (&pHost->busIrps, pIrp, &pIrp->hcdLink, LINK_TAIL);
  2839.     scheduleIrp (pHost, pPipe, pIrp);
  2840.     return PENDING;
  2841.     }
  2842. /***************************************************************************
  2843. *
  2844. * fncIrpSubmit - Queue an IRP for execution
  2845. *
  2846. * If this function returns a result other than PENDING, then
  2847. * the IRP callback routine will already have been invoked.  If the
  2848. * result is PENDING, then the IRP's callback routine will be
  2849. * called asynchronously to signal IRP completion.
  2850. *
  2851. * RETURNS: S_usbHcdLib_xxxx
  2852. */
  2853. LOCAL int fncIrpSubmit
  2854.     (
  2855.     pHRB_IRP_SUBMIT pHrb,
  2856.     pHCD_HOST pHost
  2857.     )
  2858.     {
  2859.     pHCD_PIPE pPipe;
  2860.     pUSB_IRP pIrp;
  2861.     int s;
  2862.     int index;
  2863.     /* validate parameters */
  2864.     if ((s = validateHrb (pHrb, sizeof (*pHrb))) != OK)
  2865. return s;
  2866.     if (usbHandleValidate (pHrb->pipeHandle, 
  2867.    HCD_PIPE_SIG, 
  2868.    (pVOID *) &pPipe) != OK)
  2869. return S_usbHcdLib_BAD_HANDLE;
  2870.     if ((pIrp = pHrb->pIrp) == NULL)
  2871. return S_usbHcdLib_BAD_PARAM;
  2872.     /*
  2873.      * Since buffers that are handed to us are not garaunteed to be
  2874.      * cache safe, we need to flush them to memory before passing
  2875.      * them off to the host controller
  2876.      */
  2877.     for (index = 0; index < pIrp->bfrCount; index++)
  2878.         USER_FLUSH (pIrp->bfrList[index].pBfr, pIrp->bfrList[index].bfrLen);
  2879.  
  2880.     /* If this IRP is intended for the root hub, then divert it to the
  2881.      * root hub handler.
  2882.      */
  2883.     pIrp->result = PENDING; /* Mark IRP as pending */
  2884.     if (pPipe->busAddress == pHost->rootAddress)
  2885. s = rootIrpHandler (pHost, pPipe, pIrp);
  2886.     else
  2887. s = busIrpHandler (pHost, pPipe, pIrp);
  2888.     return setIrpResult (pIrp, s);
  2889.     }
  2890. /***************************************************************************
  2891. *
  2892. * fncIrpCancel - Attempts to cancel a pending IRP
  2893. *
  2894. * Attempts to cancel the specified IRP.
  2895. *
  2896. * RETURNS: OK if IRP canceled.
  2897. *      S_usbHcdLib_CANNOT_CANCEL if IRP already completed.
  2898. */
  2899. LOCAL int fncIrpCancel
  2900.     (
  2901.     pHRB_IRP_CANCEL pHrb,
  2902.     pHCD_HOST pHost
  2903.     )
  2904.     {
  2905.     pUSB_IRP pIrp;
  2906.     int s;
  2907.     /* validate parameters */
  2908.     if ((s = validateHrb (pHrb, sizeof (*pHrb))) != OK)
  2909. return s;
  2910.     if ((pIrp = pHrb->pIrp) == NULL)
  2911. return S_usbHcdLib_BAD_PARAM;
  2912.     
  2913.     /* cancel the IRP */
  2914.     return cancelIrp (pHost, pIrp, S_usbHcdLib_IRP_CANCELED);
  2915.     }
  2916. /***************************************************************************
  2917. *
  2918. * fncPipeCreate - create pipe & calculate / reserve bandwidth
  2919. *
  2920. * RETURNS: S_usbHcdLib_xxxx
  2921. */
  2922. LOCAL int fncPipeCreate
  2923.     (
  2924.     pHRB_PIPE_CREATE pHrb,
  2925.     pHCD_HOST pHost
  2926.     )
  2927.     {
  2928.     pHCD_PIPE pPipe;
  2929.     UINT32 control;
  2930.     UINT16 tdLen;
  2931.     int s;
  2932.     /* validate parameters */
  2933.     if ((s = validateHrb (pHrb, sizeof (*pHrb))) != OK)
  2934. return s;
  2935.     
  2936.     /* Calculate the time to transfer a packet of the indicated size. */
  2937.     pHrb->time = usbRecurringTime (pHrb->transferType, 
  2938.    pHrb->direction, 
  2939.    pHrb->speed, 
  2940.    pHrb->maxPacketSize, 
  2941.    pHrb->bandwidth, 
  2942.    HC_HOST_DELAY, 
  2943.    HC_HUB_LS_SETUP);
  2944.     /* Is the indicated amount of bandwidth available? */
  2945.     if (pHost->nanoseconds + pHrb->time > USB_LIMIT_ISOCH_INT)
  2946. return S_usbHcdLib_BANDWIDTH_FAULT;
  2947.     /* Create a pipe structure to describe this pipe */
  2948.     if ((pPipe = OSS_CALLOC (sizeof (*pPipe))) == NULL)
  2949. return S_usbHcdLib_OUT_OF_MEMORY;
  2950.     if (usbHandleCreate (HCD_PIPE_SIG, pPipe, &pPipe->pipeHandle) != OK)
  2951. {
  2952. destroyPipe (pHost, pPipe);
  2953. return S_usbHcdLib_OUT_OF_RESOURCES;
  2954. }
  2955.     pPipe->busAddress = pHrb->busAddress;
  2956.     pPipe->endpoint = pHrb->endpoint;
  2957.     pPipe->transferType = pHrb->transferType;
  2958.     pPipe->direction = pHrb->direction;
  2959.     pPipe->speed = pHrb->speed;
  2960.     pPipe->maxPacketSize = pHrb->maxPacketSize;
  2961.     pPipe->bandwidth = pHrb->bandwidth;
  2962.     pPipe->interval = pHrb->interval;
  2963.     pPipe->actInterval = calcIntInterval (pPipe->interval);
  2964.     pPipe->time = pHrb->time;
  2965.     if (pPipe->busAddress != pHost->rootAddress)
  2966. {
  2967. /* Initialize TDs for pipe. */
  2968. pPipe->tdCount = (pPipe->transferType == USB_XFRTYPE_ISOCH) ? 
  2969.   TD_COUNT_ISO : 
  2970.   TD_COUNT_GEN;
  2971. pPipe->freeTdCount = pPipe->tdCount - 1;
  2972. /* one always not used */
  2973. /* cf OHCI sec. 5.2.8.2 */
  2974. tdLen = pPipe->tdCount * sizeof (TD_WRAPPER);
  2975. if ((pPipe->pTds = DMA_MALLOC (tdLen, OHCI_TD_ISO_ALIGNMENT)) == NULL)
  2976.     {
  2977.     destroyPipe (pHost, pPipe);
  2978.     return S_usbHcdLib_OUT_OF_MEMORY;
  2979.     }
  2980. memset (pPipe->pTds, 0, tdLen);
  2981. /* Initialize ED (endpoint descriptor) for pipe. */
  2982. if ((pPipe->pEd = DMA_MALLOC (sizeof (*pPipe->pEd), 
  2983.       OHCI_ED_ALIGNMENT)) == NULL)
  2984.     {
  2985.     destroyPipe (pHost, pPipe);
  2986.     return S_usbHcdLib_OUT_OF_MEMORY;
  2987.     }
  2988. memset (pPipe->pEd, 0, sizeof (*pPipe->pEd));
  2989. control = OHCI_EDCTL_FA_FMT (pPipe->busAddress) | 
  2990.      OHCI_EDCTL_EN_FMT (pPipe->endpoint) | 
  2991.      OHCI_EDCTL_DIR_TD | 
  2992.      OHCI_EDCTL_MPS_FMT (pPipe->maxPacketSize);
  2993. control |= (pPipe->speed == USB_SPEED_LOW) ? 
  2994.    OHCI_EDCTL_SPD_LOW : 
  2995.    OHCI_EDCTL_SPD_FULL;
  2996. control |= (pPipe->transferType == USB_XFRTYPE_ISOCH) ? 
  2997.    OHCI_EDCTL_FMT_ISO : 
  2998.    OHCI_EDCTL_FMT_GEN;
  2999. pPipe->pEd->ed.control = TO_LITTLEL (control);
  3000. pPipe->pEd->ed.tdTail = pPipe->pEd->ed.tdHead =
  3001. TO_LITTLEL (TO_PCIPTR (pPipe->pTds));
  3002. pPipe->pEd->sw.pPipe = pPipe;
  3003. schedulePipe (pHost, pPipe);
  3004. }
  3005.     /* Link pipe to host controller */
  3006.     usbListLink (&pHost->pipes, pPipe, &pPipe->link, LINK_TAIL);
  3007.     /* Record bandwidth in use. */
  3008.     pHost->nanoseconds += pHrb->time;
  3009.     /* Return pipe handle to caller */
  3010.     pHrb->pipeHandle = pPipe->pipeHandle;
  3011.     return OK;
  3012.     }
  3013. /***************************************************************************
  3014. *
  3015. * fncPipeDestroy - destroy pipe and release associated bandwidth
  3016. *
  3017. * RETURNS: S_usbdHcdLib_xxxx
  3018. */
  3019. LOCAL int fncPipeDestroy
  3020.     (
  3021.     pHRB_PIPE_DESTROY pHrb,
  3022.     pHCD_HOST pHost
  3023.     )
  3024.     {
  3025.     pHCD_PIPE pPipe;
  3026.     int s;
  3027.     /* validate parameters */
  3028.     if ((s = validateHrb (pHrb, sizeof (*pHrb))) != OK)
  3029. return s;
  3030.     if (usbHandleValidate (pHrb->pipeHandle, 
  3031.    HCD_PIPE_SIG, 
  3032.    (pVOID *) &pPipe) != OK)
  3033. return S_usbHcdLib_BAD_HANDLE;
  3034.     /* destroy pipe */
  3035.     destroyPipe (pHost, pPipe);
  3036.     return OK;
  3037.     }
  3038. /***************************************************************************
  3039. *
  3040. * fncPipeModify - modify pipe characteristics
  3041. *
  3042. * RETURNS: S_usbdHcdLib_xxxx
  3043. */
  3044. LOCAL int fncPipeModify
  3045.     (
  3046.     pHRB_PIPE_MODIFY pHrb,
  3047.     pHCD_HOST pHost
  3048.     )
  3049.     {
  3050.     pHCD_PIPE pPipe;
  3051.     UINT32 control;
  3052.     int s;
  3053.     /* validate parameters */
  3054.     if ((s = validateHrb (pHrb, sizeof (*pHrb))) != OK)
  3055. return s;
  3056.     if (usbHandleValidate (pHrb->pipeHandle, 
  3057.    HCD_PIPE_SIG, 
  3058.    (pVOID *) &pPipe) != OK)
  3059. return S_usbHcdLib_BAD_HANDLE;
  3060.     /* update pipe charactistics */
  3061.     if (pHrb->busAddress != 0)
  3062. pPipe->busAddress = pHrb->busAddress;
  3063.     if (pHrb->maxPacketSize != 0)
  3064. pPipe->maxPacketSize = pHrb->maxPacketSize;
  3065.     if (pPipe->pEd != NULL)
  3066. {
  3067. /* Modify OHCI_ED allocated for this pipe. */
  3068. control = FROM_LITTLEL (pPipe->pEd->ed.control);
  3069. control &= ~(OHCI_EDCTL_FA_MASK | OHCI_EDCTL_MPS_MASK);
  3070. control |= OHCI_EDCTL_FA_FMT (pPipe->busAddress) | 
  3071.       OHCI_EDCTL_MPS_FMT (pPipe->maxPacketSize);
  3072. pPipe->pEd->ed.control = TO_LITTLEL (control);
  3073. DMA_FLUSH (&pPipe->pEd->ed.control, sizeof (pPipe->pEd->ed.control));
  3074. }
  3075.     return OK;
  3076.     }
  3077. /***************************************************************************
  3078. *
  3079. * usbHcdOhciExec - HCD_EXEC_FUNC entry point for OHCI HCD
  3080. *
  3081. * RETURNS: OK or ERROR
  3082. *
  3083. * ERRNO:
  3084. *  S_usbHcdLib_BAD_PARAM
  3085. *  S_usbHcdLib_BAD_HANDLE
  3086. *  S_usbHcdLib_SHUTDOWN
  3087. */
  3088. STATUS usbHcdOhciExec
  3089.     (
  3090.     pVOID pHrb     /* HRB to be executed */
  3091.     )
  3092.     {
  3093.     pHRB_HEADER pHeader = (pHRB_HEADER) pHrb;
  3094.     pHCD_HOST pHost;
  3095.     int s;
  3096.  
  3097.     /* Validate parameters */
  3098.     if (pHeader == NULL || pHeader->hrbLength < sizeof (HRB_HEADER))
  3099. return ossStatus (S_usbHcdLib_BAD_PARAM);
  3100.     if (pHeader->function != HCD_FNC_ATTACH)
  3101. {
  3102. if (usbHandleValidate (pHeader->handle, 
  3103.        HCD_HOST_SIG, 
  3104.        (pVOID *) &pHost) != OK)
  3105.     return ossStatus (S_usbHcdLib_BAD_HANDLE);
  3106. if (pHost->shutdown)
  3107.     return ossStatus (S_usbHcdLib_SHUTDOWN);
  3108. }
  3109.     /* Guard against other tasks */
  3110.     if (pHeader->function != HCD_FNC_ATTACH && 
  3111.      pHeader->function != HCD_FNC_DETACH)
  3112. {
  3113. OSS_MUTEX_TAKE (pHost->hostMutex, OSS_BLOCK);
  3114. }
  3115.     /* Fan-out to appropriate function processor */
  3116.     switch (pHeader->function)
  3117. {
  3118. case HCD_FNC_ATTACH:
  3119.     s = fncAttach ((pHRB_ATTACH) pHeader);
  3120.     break;
  3121. case HCD_FNC_DETACH:
  3122.     s = fncDetach ((pHRB_DETACH) pHeader, pHost);
  3123.     break;
  3124. case HCD_FNC_SET_BUS_STATE:
  3125.     s = fncSetBusState ((pHRB_SET_BUS_STATE) pHeader, pHost);
  3126.     break;
  3127. case HCD_FNC_SOF_INTERVAL_GET:
  3128.     s = fncSofIntervalGet ((pHRB_SOF_INTERVAL_GET_SET) pHeader, pHost);
  3129.     break;
  3130. case HCD_FNC_SOF_INTERVAL_SET:
  3131.     s = fncSofIntervalSet ((pHRB_SOF_INTERVAL_GET_SET) pHeader, pHost);
  3132.     break;
  3133. case HCD_FNC_CURRENT_FRAME_GET:
  3134.     s = fncCurrentFrameGet ((pHRB_CURRENT_FRAME_GET) pHeader, pHost);
  3135.     break;
  3136. case HCD_FNC_IRP_SUBMIT:
  3137.     s = fncIrpSubmit ((pHRB_IRP_SUBMIT) pHeader, pHost);
  3138.     break;
  3139. case HCD_FNC_IRP_CANCEL:
  3140.     s = fncIrpCancel ((pHRB_IRP_CANCEL) pHeader, pHost);
  3141.     break;
  3142. case HCD_FNC_PIPE_CREATE:
  3143.     s = fncPipeCreate ((pHRB_PIPE_CREATE) pHeader, pHost);
  3144.     break;
  3145. case HCD_FNC_PIPE_DESTROY:
  3146.     s = fncPipeDestroy ((pHRB_PIPE_DESTROY) pHeader, pHost);
  3147.     break;
  3148. case HCD_FNC_PIPE_MODIFY:
  3149.     s = fncPipeModify ((pHRB_PIPE_MODIFY) pHeader, pHost);
  3150.     break;
  3151. default:
  3152.     s = S_usbHcdLib_BAD_PARAM;
  3153.     break;
  3154. }
  3155.     /* Release guard mutex */
  3156.     if (pHeader->function != HCD_FNC_ATTACH && 
  3157. pHeader->function != HCD_FNC_DETACH)
  3158. {
  3159. OSS_MUTEX_RELEASE (pHost->hostMutex);
  3160. }
  3161.     /* Return status */
  3162.     if (s == OK || s == PENDING)
  3163. return OK;
  3164.     else
  3165. return ossStatus (s);
  3166.     }
  3167. /* End of file. */