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

VxWorks

开发平台:

C/C++

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