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

VxWorks

开发平台:

C/C++

  1. /* usbTcdPdiusbd12EvalLib.c - USB target controller driver for Philips PDIUSBD12 */
  2. /* Copyright 2000 Wind River Systems, Inc. */
  3. /*
  4. Modification history
  5. --------------------
  6. 01e,12apr00wef   Fixed uninitialized variable warning: pTarget in 
  7.  usbTcdPdiusbd12EvalExec() 
  8. 01d,17mar00,rcb  Add code to block re-entrant processing of the ERP
  9.  queue...formerly, a fast host could cause the interrupt
  10.  thread to decend endlessly down the stack if the target
  11.  application re-submits an ERP on the ERP completion
  12.  callback.
  13.  Change order in which endpoint interrupt causes are
  14.  evaluated to make sure a Setup transaction received just
  15.  after another transaction doesn't get processed out of
  16.  order.
  17.  Add code in destroyTarget() to cancel outstanding ERPs.
  18. 01c,23nov99,rcb  Change #include ../xxx references to lower case.
  19. 01b,12nov99,rcb  Short path names...affects "#include" directives.
  20. 01a,09aug99,rcb  First.
  21. */
  22. /*
  23. DESCRIPTION
  24. This module implements the USB TCD (Target Controller Driver) for the Philips 
  25. PDIUSBD12 used in conjuction with the PDIUSBD12 ISA evaluation kit from Philips.
  26. This module exports a single entry point, usbTcdPdiusbd12EvalExec().  This is the
  27. USB_TCD_EXEC_FUNC for this TCD.  The caller passes requests to the TCD by 
  28. constructing TRBs, or Target Request Blocks, and passing them to this entry point.
  29. The USB TCD works in conjuction with the usbTargLib module.  In order to simplify
  30. the creation of a TCD for a given USB target controller, the usbTargLib handles
  31. most parameter and logical validation of requests.  The TCD, therefore, is largely
  32. free to execute requests without extensive validation, knowing that usbTargLib
  33. will have validated the requests beforehand.
  34. TCDs are initialized by invoking the TCD_FNC_ATTACH function.  In response to this
  35. function, the TCD returns information about the target controller, including its
  36. USB speed, the number of endpoints it supports, and information about each
  37. endpoint.  
  38. Endpoint information is maintained in an array of USB_TARG_ENDPOINT_INFO
  39. structures.  These structures are allocated and owned by the TCD.  The usbTargLib
  40. and the callers of the usbTargLib are allowed to examine this array, but are not
  41. allowed to modify it.  All modification of the array is performed generally by
  42. invoking the TCDs TCD_FNC_ENDPOINT_ASSIGN and TCD_FNC_ENDPOINT_RELEASE functions.
  43. These functions are invoked upon the creation and deletion of USB pipes,
  44. respectively.
  45. By convention, each endpoint exposed in the array of USB_TARG_ENDPOINT_INFO 
  46. structures is unidirectional, ie., either and OUT or IN endpoint.  The TCD is
  47. required to present the endpoints in this way, even if the underlying hardware
  48. presents the endpoints as bi-directional.  In this way, the calling application
  49. can choose to assign endpoints to pipes as it sees fit.  Also, by convention, the
  50. first two endpoints in the array MUST be the OUT and IN endpoints which are most
  51. appropriate for use as the default control pipe (endpoint #0).
  52. Once pipes have been created, the TCD is instructed to wait for data transfers
  53. initiated by the host USB controller.  The TCD callers pass ERPs (Endpoint
  54. Request Blocks) to the TCD to request and manage data transfers.  It is important
  55. to remember that all USB data transfers are actually initiated by the host, so 
  56. no data transfers will actually be performed by the TCD and target controller
  57. hardware unless the USB host controller is polling the target.
  58. It is also important to note a convention regarding the direction of data
  59. transfers.  The transfer of data is always viewed from the host's perspective.
  60. Therefore, an OUT transfer is a transfer from the host to the device (target) and
  61. an IN transfer is a transfer from the device to the host.  Therefore,
  62. USB_DIR_OUT, USB_PID_SETUP, and USB_PID_OUT refer to host->device transfers 
  63. while USB_DIR_IN and USB_PID_IN refer to device->host transfers.
  64. During TCD_FNC_ATTACH processing, the TCD creates a task to handle target
  65. controller interrupts. Interrupts are first received by a normal interrupt
  66. handler, and this interrupt handler immediately reflects the interrupt to the
  67. interrupt task.  All TCD callbacks to the usbTargLib are made either from the
  68. caller's task or from the interrupt task.  No callbacks are made from the
  69. interrupt context itself.
  70. Conditional code:
  71. The use of DMA (PC XT/AT style 8237 slave-mode DMA) is enabled by defining
  72. the constant D12_USE_DMA.  Leaving this undefined causes the driver to run
  73. exclusively in "programmed-I/O" mode.
  74. In testing the Philips PDIUSBD12 has appeared to set the "data success" bit
  75. incorrectly, causing software to declare a failure.  The use of this bit
  76. can be enabled or disabled by definining the constant D12_CHECK_DATA_SUCCESS_BIT.
  77. Leaving this constant undefined disables error checking.
  78. */
  79. /* includes */
  80. #include "usb/usbPlatform.h"     /* platform definitions */
  81. #include "string.h"
  82. #include "usb/ossLib.h"      /* OS services */
  83. #include "usb/usbListLib.h"     /* linked list functions */
  84. #include "usb/usb.h"     /* USB definitions */
  85. #include "usb/target/usbIsaLib.h"     /* ISA bus functions */
  86. #include "drv/usb/target/usbTcd.h"     /* generic TCD interface */
  87. #include "drv/usb/target/usbPdiusbd12.h"    /* Philips PDIUSBD12 defn */
  88. #include "drv/usb/target/usbPdiusbd12Eval.h"     /* eval board definitions */
  89. #include "drv/usb/target/usbTcdPdiusbd12EvalLib.h"  /* our API */
  90. /* defines */
  91. /* BUILD OPTIONS */
  92. #define D12_USE_DMA /* Allow use of DMA */
  93. #define INT_THREAD_NAME "tD12Int" /* name of int handler thread */
  94. #define INT_THREAD_EXIT_TIMEOUT 5000 /* 5 seconds */
  95. /* macros used to read/write PDIUSBD12 registers */
  96. #define OUT_D12_CMD(b)
  97.     USB_ISA_BYTE_OUT (pTarget->ioBase + D12EVAL_D12REG + D12_CMD_REG, (b))
  98. #define OUT_D12_DATA(b) 
  99.     USB_ISA_BYTE_OUT (pTarget->ioBase + D12EVAL_D12REG + D12_DATA_REG, (b))
  100. #define IN_D12_DATA()
  101.     USB_ISA_BYTE_IN (pTarget->ioBase + D12EVAL_D12REG + D12_DATA_REG)
  102. /* macros used to read/write PDIUSBD12 eval general IN/OUT registers */
  103. #define OUT_EVAL_GOUT(b)    
  104.     USB_ISA_BYTE_OUT (pTarget->ioBase + D12EVAL_GOUT_REG, (b))
  105. #define IN_EVAL_GIN()
  106.     USB_ISA_BYTE_IN (pTarget->ioBase + D12EVAL_GIN_REG)
  107. /* macro to invoke caller's management callback */
  108. #define MNGMT_CALLBACK(pTarget, mngmtCode) 
  109.     (*(pTarget)->mngmtCallback) ((pTarget)->mngmtCallbackParam, 
  110.     (TCD_HANDLE) (pTarget), (mngmtCode))
  111. /* Parameters to certain PDIUSBD12 functions */
  112. #define ENABLE TRUE
  113. #define DISABLE FALSE
  114. /* LEDs on PDIUSBD12 evaluation board used for debugging. */
  115. #define ATTACH_LED D12EVAL_GOUT_LED_D2
  116. #define ENABLE_LED D12EVAL_GOUT_LED_D3
  117. #define INT_THREAD_LED D12EVAL_GOUT_LED_D4
  118. /* typedefs */
  119. /* ERP_WORKSPACE
  120.  *
  121.  * An ERP_WORKSPACE structure is allocated for each ERP as it is enqueued.  The
  122.  * workspace provides storage for TCD-specific data needed to manage the ERP.
  123.  */
  124. typedef struct erp_workspace
  125.     {
  126.     UINT16 curBfr;     /* Current bfrList[] entry being processed */
  127.     UINT16 curBfrOffset;     /* Offset into current bfrList[] entry */
  128.     BOOL inStatusPending;     /* TRUE for ERP on "IN" pipe when waiting */
  129.     /* for packet status from hardware */
  130.     BOOL dmaInUse;     /* TRUE if DMA in use for ERP/endpoint */
  131.     UINT16 dmaXfrLen;     /* length of DMA transfer */
  132.     } ERP_WORKSPACE, *pERP_WORKSPACE;
  133. /* TARGET
  134.  * 
  135.  * TARGET is the primary data structure created to manage an individual target
  136.  * controller.
  137.  */
  138. typedef struct target
  139.     {
  140.     MUTEX_HANDLE tcdMutex;     /* guards TARGET data structure */
  141.     BOOL shutdown;     /* TRUE when target is being shut down */
  142.     UINT32 ioBase;     /* I/O base address */
  143.     UINT16 irq;      /* IRQ channel */
  144.     UINT16 dma;      /* DMA channel */
  145.     pUSB_TARG_ENDPOINT_INFO pEndpoints; /* ptr to array of endpoints */
  146.     USB_TCD_MNGMT_CALLBACK mngmtCallback; /* caller's management callback */
  147.     pVOID mngmtCallbackParam;   /* param to mngmt callback */
  148.     THREAD_HANDLE intThread;     /* Thread used to handle interrupts */
  149.     SEM_HANDLE intPending;     /* semaphore indicates int pending */
  150.     BOOL intThreadExitRequest;     /* TRUE when intThread should terminate */
  151.     SEM_HANDLE intThreadExit;     /* signalled when int thread exits */
  152.     UINT32 intCount;     /* number of interrupts processed */
  153.     BOOL intInstalled;     /* TRUE when h/w int handler installed */
  154.     UINT16 deviceAddress;     /* current address of target */
  155.     BOOL enableFlag;     /* TRUE if device enabled */
  156.     LIST_HEAD erps [D12_NUM_ENDPOINTS];   /* queued ERPs */
  157.     ERP_WORKSPACE workspace [D12_NUM_ENDPOINTS]; /* workspace */
  158.     UINT8 goutByte;     /* bits set for eval GOUT reg */
  159.     UINT8 configByte;     /* bits set for config mode byte */
  160.     UINT8 clkDivByte;     /* bits set for clkdiv mode byte */
  161.     UINT8 dmaByte;     /* bits set for DMA config register */
  162.     UINT16 epMainCount;      /* count of times endpt #2 enabled */
  163.     UINT16 epOneAndTwoCount;     /* count of times endpts #1 & #2 enabled */
  164.     BOOL transPending [D12_NUM_ENDPOINTS]; /* TRUE if transStatus valid */
  165.     UINT8 transStatus [D12_NUM_ENDPOINTS]; /* last trans status for endpoints */
  166.     BOOL dmaInUse;     /* TRUE if DMA in use */
  167.     UINT16 dmaEndpointId;     /* endpoint using DMA */
  168.     pUSB_ERP pDmaErp;     /* pointer to ERP currently using DMA */
  169.     BOOL dmaEot;     /* TRUE when EOT interrupt signalled */
  170.     BOOL endpointNeedsService [D12_NUM_ENDPOINTS];
  171.     } TARGET, *pTARGET;
  172. /* forward declarations */
  173. LOCAL VOID processErpQueue
  174.     (
  175.     pTARGET pTarget,
  176.     UINT16 endpointId
  177.     );
  178. /* globals */
  179. /* The following IMPORTed variables define the location and size of a 
  180.  * low-memory buffer used by the floppy diskette driver.  This buffer
  181.  * is guaranteed to be reachable by the i8237 DMAC (24-bit address
  182.  * range).  In order to demonstrate the proper operation of the Philips
  183.  * PDIUSBD12 with DMA, we use these buffers for DMA transfers.
  184.  */
  185. IMPORT UINT sysFdBuf;     /* physical address of DMA bfr */
  186. IMPORT UINT sysFdBufSize;     /* size of DMA buffer */
  187. /* functions */
  188. /***************************************************************************
  189. *
  190. * d12SetAddress - Issues Set Address/Enable command to PDIUSBD12
  191. *
  192. * RETURNS: N/A
  193. */
  194. LOCAL VOID d12SetAddress
  195.     (
  196.     pTARGET pTarget
  197.     )
  198.     {
  199.     UINT8 byte;
  200.     byte = pTarget->deviceAddress & D12_CMD_SA_ADRS_MASK;
  201.     byte |= (pTarget->enableFlag) ? D12_CMD_SA_ENABLE : 0;
  202.     OUT_D12_CMD (D12_CMD_SET_ADDRESS);
  203.     OUT_D12_DATA (byte);
  204.     }
  205. /***************************************************************************
  206. *
  207. * d12SetEndpointEnable - Issues Set Endpoint Enable command to PDIUSBD12
  208. *
  209. * RETURNS: N/A
  210. */
  211. LOCAL VOID d12SetEndpointEnable
  212.     (
  213.     pTARGET pTarget,
  214.     BOOL enable
  215.     )
  216.     {
  217.     OUT_D12_CMD (D12_CMD_SET_ENDPOINT_ENABLE);
  218.     OUT_D12_DATA ((enable) ? D12_CMD_SEE_ENABLE : 0);
  219.     }
  220. /***************************************************************************
  221. *
  222. * d12SetMode - Issues Set Mode command to PDIUSBD12
  223. *
  224. * RETURNS: N/A
  225. */
  226. LOCAL VOID d12SetMode
  227.     (
  228.     pTARGET pTarget
  229.     )
  230.     {
  231.     OUT_D12_CMD (D12_CMD_SET_MODE);
  232.     OUT_D12_DATA (pTarget->configByte);
  233.     OUT_D12_DATA (pTarget->clkDivByte);
  234.     }
  235. /***************************************************************************
  236. *
  237. * d12SetDma - Issues Set DMA command to PDIUSBD12
  238. *
  239. * RETURNS: N/A
  240. */
  241. LOCAL VOID d12SetDma
  242.     (
  243.     pTARGET pTarget
  244.     )
  245.     {
  246.     OUT_D12_CMD (D12_CMD_SET_DMA);
  247.     OUT_D12_DATA (pTarget->dmaByte);
  248.     }
  249. /***************************************************************************
  250. *
  251. * d12ReadIntReg - Issues Read Interrupt Register commadn to PDIUSBD12
  252. *
  253. * RETURNS: UINT16 value with first byte in LSB and second byte in MSB
  254. */
  255. LOCAL UINT16 d12ReadIntReg
  256.     (
  257.     pTARGET pTarget
  258.     )
  259.     {
  260.     UINT8 firstByte;
  261.     OUT_D12_CMD (D12_CMD_READ_INTERRUPT_REG);
  262.     firstByte = IN_D12_DATA ();
  263.     return firstByte | (IN_D12_DATA () << 8);
  264.     }
  265. /***************************************************************************
  266. *
  267. * d12SelectEndpoint - Issues Select Endpoint command to PDIUSBD12
  268. *
  269. * <endpoint> parameter must be D12_ENDPOINT_xxxx.
  270. *
  271. * RETURNS: UINT8 value read after issuing select endpoint command
  272. */
  273. LOCAL UINT8 d12SelectEndpoint
  274.     (
  275.     pTARGET pTarget,
  276.     UINT16 endpoint
  277.     )
  278.     {
  279.     OUT_D12_CMD (D12_CMD_SELECT_ENDPOINT | endpoint);
  280.     return IN_D12_DATA ();
  281.     }
  282. /***************************************************************************
  283. *
  284. * d12ReadLastTransStatus - Issues Read Last Transaction Status command
  285. *
  286. * <endpoint> parameter must be D12_ENDPOINT_xxxx.
  287. *
  288. * RETURNS: UINT8 value read after issuing command
  289. */
  290. LOCAL UINT8 d12ReadLastTransStatus
  291.     (
  292.     pTARGET pTarget,
  293.     UINT16 endpoint
  294.     )
  295.     {
  296.     OUT_D12_CMD (D12_CMD_READ_LAST_TRANS_STATUS | endpoint);
  297.     return IN_D12_DATA ();
  298.     }
  299. /***************************************************************************
  300. *
  301. * d12ClearBfr - Issues Clear Buffer command to PDIUSBD12
  302. *
  303. * RETURNS: N/A
  304. */
  305. LOCAL VOID d12ClearBfr
  306.     (
  307.     pTARGET pTarget
  308.     )
  309.     {
  310.     OUT_D12_CMD (D12_CMD_CLEAR_BUFFER);
  311.     }
  312. /***************************************************************************
  313. *
  314. * d12ValidateBfr - Issues Validate Buffer command to PDIUSBD12
  315. *
  316. * RETURNS: N/A
  317. */
  318. LOCAL VOID d12ValidateBfr
  319.     (
  320.     pTARGET pTarget
  321.     )
  322.     {
  323.     OUT_D12_CMD (D12_CMD_VALIDATE_BUFFER);
  324.     }
  325. /***************************************************************************
  326. *
  327. * d12ReadBfr - Issues Read Buffer command and reads buffer data
  328. *
  329. * Reads data from the <endpoint> into the next bfrList[] entry/entries
  330. * in the <pErp>. 
  331. *
  332. * NOTE: This function automatically invokes d12ClearBfr() after reading 
  333. * buffer data. In order to avoid losing bytes, the <pErp> passed by the
  334. * caller should be able to accept all data in the buffer.  
  335. *
  336. * RETURNS: N/A
  337. */
  338. LOCAL VOID d12ReadBfr
  339.     (
  340.     pTARGET pTarget,
  341.     pUSB_TARG_ENDPOINT_INFO pEndpoint,
  342.     pUSB_ERP pErp,
  343.     pERP_WORKSPACE pWork
  344.     )
  345.     {
  346.     pUSB_BFR_LIST pBfrList;
  347.     UINT16 actLen;
  348.     /* Select the endpoint */
  349.     d12SelectEndpoint (pTarget, pEndpoint->endpointId);
  350.     /* Read the number of bytes in the buffer. */
  351.     OUT_D12_CMD (D12_CMD_READ_BUFFER);
  352.     actLen = IN_D12_DATA ();     /* throw away first byte */
  353.     actLen = IN_D12_DATA ();
  354.     /* Read buffer data */
  355.     pBfrList = &pErp->bfrList [pWork->curBfr];
  356.     while (actLen > 0 && pWork->curBfrOffset < pBfrList->bfrLen)
  357. {
  358. pBfrList->pBfr [pWork->curBfrOffset] = IN_D12_DATA ();
  359. pBfrList->actLen++;
  360. --actLen;
  361. if (++pWork->curBfrOffset == pBfrList->bfrLen)
  362.     {
  363.     pBfrList = &pErp->bfrList [++pWork->curBfr];
  364.     pWork->curBfrOffset = 0;
  365.     }
  366. if (pWork->curBfr == pErp->bfrCount)
  367.     break;
  368. }
  369.     /* Issue command to flush (clear) buffer */
  370.     d12ClearBfr (pTarget);
  371.     }
  372. /***************************************************************************
  373. *
  374. * d12WriteBfr - Issues Write Buffer command and writes buffer data
  375. *
  376. * <pEndpoint> must point to the USB_TARG_ENDPOINT_INFO structure for the
  377. * endpoint. 
  378. *
  379. * Writes the maximum packet size number of bytes from the next ERP bfrList[]
  380. * entry/entries to the indicated <endpoint>.
  381. *
  382. * NOTE: This function automatically invokes d12ValidateBfr() after
  383. * writing data to the buffer.
  384. *
  385. * RETURNS: N/A
  386. */
  387. LOCAL VOID d12WriteBfr
  388.     (
  389.     pTARGET pTarget,
  390.     pUSB_TARG_ENDPOINT_INFO pEndpoint,
  391.     pUSB_ERP pErp,
  392.     pERP_WORKSPACE pWork
  393.     )
  394.     {
  395.     pUSB_BFR_LIST pBfrList;
  396.     UINT16 bfrAvail;
  397.     UINT16 numWrite;
  398.     UINT16 i;
  399.     /* Select the endpoint */
  400.     d12SelectEndpoint (pTarget, pEndpoint->endpointId);
  401.     /* Sum the amount of data available in the bfrList[]. */
  402.     bfrAvail = pErp->bfrList [pWork->curBfr].bfrLen - pWork->curBfrOffset;
  403.     for (i = pWork->curBfr + 1; i < pErp->bfrCount; i++)
  404. bfrAvail += pErp->bfrList [i].bfrLen;
  405.     numWrite = min (pEndpoint->maxPacketSize, bfrAvail);
  406.     /* Issue write buffer command */
  407.     OUT_D12_CMD (D12_CMD_WRITE_BUFFER);
  408.     OUT_D12_DATA (0);
  409.     OUT_D12_DATA (numWrite);
  410.     /* Write buffer data */
  411.     pBfrList = &pErp->bfrList [pWork->curBfr];
  412.     for (i = 0; i < numWrite; i++)
  413. {
  414. OUT_D12_DATA (pBfrList->pBfr [pWork->curBfrOffset]);
  415. pBfrList->actLen++;
  416. if (++pWork->curBfrOffset == pBfrList->bfrLen)
  417.     {
  418.     pBfrList = &pErp->bfrList [++pWork->curBfr];
  419.     pWork->curBfrOffset = 0;
  420.     }
  421. if (pWork->curBfr == pErp->bfrCount)
  422.     break;
  423. }
  424.     /* Mark buffer as filled (validate it) */
  425.     d12ValidateBfr (pTarget);
  426.     }
  427. /***************************************************************************
  428. *
  429. * d12SetEndpointStatus - Issues Set Endpoint Status command to PDIUSBD12
  430. *
  431. * <endpoint> parameter must be D12_ENDPOINT_xxxx.
  432. *
  433. * RETURNS: N/A
  434. */
  435. LOCAL VOID d12SetEndpointStatus
  436.     (
  437.     pTARGET pTarget,
  438.     UINT16 endpoint,
  439.     UINT8 status
  440.     )
  441.     {
  442.     OUT_D12_CMD (D12_CMD_SET_ENDPOINT_STATUS | endpoint);
  443.     OUT_D12_DATA (status);
  444.     }
  445. #if 0
  446. /***************************************************************************
  447. *
  448. * d12ReadEndpointStatus - Issues Read Endpoint Status command to PDIUSBD12
  449. *
  450. * <endpoint> parameter must be D12_ENDPOINT_xxxx.
  451. *
  452. * RETURNS: UINT8 status value
  453. */
  454. LOCAL UINT8 d12ReadEndpointStatus
  455.     (
  456.     pTARGET pTarget,
  457.     UINT16 endpoint
  458.     )
  459.     {
  460.     OUT_D12_CMD (D12_CMD_READ_ENDPOINT_STATUS | endpoint);
  461.     return IN_D12_DATA ();
  462.     }
  463. #endif /* #if 0 */
  464. /***************************************************************************
  465. *
  466. * d12AckSetup - Issues Acknowledge setup command to PDIUSBD12
  467. *
  468. * <endpoint> parameter must be D12_ENDPOINT_xxxx.
  469. *
  470. * RETURNS: N/A
  471. */
  472. LOCAL VOID d12AckSetup
  473.     (
  474.     pTARGET pTarget,
  475.     UINT16 endpoint
  476.     )
  477.     {
  478.     d12SelectEndpoint (pTarget, endpoint);
  479.     OUT_D12_CMD (D12_CMD_ACK_SETUP);
  480.     }
  481. /***************************************************************************
  482. *
  483. * d12SendResume - Issues Send Resume commadn to PDIUSBD12
  484. *
  485. * RETURNS: N/A
  486. */
  487. LOCAL VOID d12SendResume
  488.     (
  489.     pTARGET pTarget
  490.     )
  491.     {
  492.     OUT_D12_CMD (D12_CMD_SEND_RESUME);
  493.     }
  494. /***************************************************************************
  495. *
  496. * d12ReadCurrentFrameNumber - Issues Read Current Frame Number command
  497. *
  498. * RETURNS: Current frame number returned by PDIUSBD12
  499. */
  500. LOCAL UINT16 d12ReadCurrentFrameNumber
  501.     (
  502.     pTARGET pTarget
  503.     )
  504.     {
  505.     UINT8 firstByte;
  506.     OUT_D12_CMD (D12_CMD_READ_CURRENT_FRAME_NO);
  507.     firstByte = IN_D12_DATA ();
  508.     return firstByte | (IN_D12_DATA () << 8);
  509.     }
  510. /***************************************************************************
  511. *
  512. * d12ReadChipId - Issues Read Chip Id command
  513. *
  514. * RETURNS: chip ID returned by PDIUSBD12
  515. */
  516. LOCAL UINT16 d12ReadChipId
  517.     (
  518.     pTARGET pTarget
  519.     )
  520.     {
  521.     UINT8 firstByte;
  522.     OUT_D12_CMD (D12_CMD_READ_CHIP_ID);
  523.     firstByte = IN_D12_DATA ();
  524.     return firstByte | (IN_D12_DATA () << 8);
  525.     }
  526. /***************************************************************************
  527. *
  528. * finishErp - sets ERP result and invokes ERP callback
  529. *
  530. * NOTE: This function also releases any DMA resources used by the ERP.
  531. *
  532. * RETURNS: ERP result
  533. */
  534. LOCAL int finishErp
  535.     (
  536.     pTARGET pTarget,
  537.     pUSB_ERP pErp,
  538.     int result
  539.     )
  540.     {
  541.     /* unlink ERP */
  542.     usbListUnlink (&pErp->tcdLink);
  543.     /* store result */
  544.     pErp->result = result;
  545.     /* check/release DMA resources */
  546.     if (pTarget->dmaInUse && pTarget->pDmaErp == pErp)
  547. {
  548. pTarget->dmaInUse = FALSE;
  549. /* Disable the D12's DMA and re-enable interrupts for the endpoint */
  550. pTarget->dmaByte &= ~D12_CMD_SD_DMA_ENABLE;
  551. if (pErp->endpointId == D12_ENDPOINT_2_OUT)
  552.     pTarget->dmaByte |= D12_CMD_SD_ENDPT_2_OUT_INTRPT;
  553. else
  554.     pTarget->dmaByte |= D12_CMD_SD_ENDPT_2_IN_INTRPT;
  555. d12SetDma (pTarget);
  556. }
  557.     /* invoke callback */
  558.     if (pErp->targCallback != NULL)
  559. (*pErp->targCallback) (pErp);
  560.     else if (pErp->userCallback != NULL)
  561. (*pErp->userCallback) (pErp);
  562.     return result;
  563.     }
  564. /***************************************************************************
  565. *
  566. * cancelErp - Attempts to cancel an ERP
  567. *
  568. * RETURNS: OK or S_usbTcdLib_xxxx if unable to cancel ERP
  569. */
  570. LOCAL int cancelErp
  571.     (
  572.     pTARGET pTarget,
  573.     pUSB_ERP pErp
  574.     )
  575.     {
  576.     /* If the ERP has completed, then we can cancel it. */
  577.     if (pErp->result != 0)
  578. return S_usbTcdLib_CANNOT_CANCEL;
  579.     /* Store the ERP completion status. */
  580.     finishErp (pTarget, pErp, S_usbTcdLib_ERP_CANCELED);
  581.     return OK;
  582.     }
  583. /***************************************************************************
  584. *
  585. * stallEndpoint - mark an endpoint as stalled
  586. * RETURNS: N/A
  587. */
  588. LOCAL VOID stallEndpoint
  589.     (
  590.     pTARGET pTarget,
  591.     UINT16 endpoint
  592.     )
  593.     {
  594.     d12SetEndpointStatus (pTarget, endpoint, D12_CMD_SES_STALLED);
  595.     }
  596. /***************************************************************************
  597. *
  598. * checkDma - Check if an ERP/endpoint is serviced by DMA and update accordingly
  599. *
  600. * RETURNS: TRUE if ERP was handled, else FALSE if ERP requires non-DMA processing
  601. */
  602. LOCAL BOOL checkDma
  603.     (
  604.     pTARGET pTarget,
  605.     pUSB_TARG_ENDPOINT_INFO pEndpoint,
  606.     pUSB_ERP pErp,
  607.     pERP_WORKSPACE pWork
  608.     )
  609.     {
  610. #ifndef D12_USE_DMA
  611.     return FALSE;
  612. #else /* #ifndef D12_USE_DMA */
  613.     UINT16 direction;
  614.     /* Determine transfer direction based on endpoint in use */
  615.     direction = (pEndpoint->endpointId == D12_ENDPOINT_2_OUT) ?
  616. DMA_MEM_WRITE : DMA_MEM_READ;
  617.     /* If this ERP/endpoint is using DMA, check for completion of the
  618.      * ERP operation.
  619.      */
  620.     if (pWork->dmaInUse && pTarget->dmaEot)
  621. {
  622. /* If this is a write to memory, copy from the temporary buffer. */
  623. if (direction == DMA_MEM_WRITE)
  624.     {
  625.     USB_ISA_MEM_INVALIDATE ((char *) sysFdBuf, pWork->dmaXfrLen);
  626.     memcpy (&pErp->bfrList [pWork->curBfr].pBfr [pWork->curBfrOffset],
  627. (char *) sysFdBuf, pWork->dmaXfrLen);
  628.     }
  629. pWork->curBfrOffset += pWork->dmaXfrLen;
  630. /* Update the buffer counter. */
  631. pErp->bfrList [pWork->curBfr].actLen += pWork->dmaXfrLen;
  632. if (pWork->curBfrOffset == pErp->bfrList [pWork->curBfr].bfrLen)
  633.     {
  634.     pWork->curBfr++;
  635.     pWork->curBfrOffset = 0;
  636.     }
  637. if (pWork->curBfr == pErp->bfrCount)
  638.     {
  639.     /* Mark the ERP as complete. */
  640.     finishErp (pTarget, pErp, OK);
  641.     /* Automatically start the next ERP for this endpoint. */
  642.     processErpQueue (pTarget, pEndpoint->endpointId);
  643.     return TRUE;
  644.     }
  645. }
  646.     /* If DMA has already been started for this ERP/endpoint, then continue 
  647.      * only if we've detected a DMA end-of-transfer 
  648.      */
  649.     if (pWork->dmaInUse && !pTarget->dmaEot)
  650. return TRUE;
  651.     /* If this ERP/endpoint should use DMA, then initialize the dma. */
  652.     if (pTarget->dma != 0 &&
  653. (pEndpoint->endpointId == D12_ENDPOINT_2_OUT ||
  654.  pEndpoint->endpointId == D12_ENDPOINT_2_IN) &&
  655. (!pTarget->dmaInUse || 
  656.  pTarget->dmaEndpointId == pEndpoint->endpointId) &&
  657. (pTarget->pDmaErp == NULL || pTarget->pDmaErp == pErp))
  658. {
  659. /* Initialize DMA controller */
  660. pWork->dmaXfrLen = 
  661.     min (pErp->bfrList [pWork->curBfr].bfrLen - 
  662.     pErp->bfrList [pWork->curBfr].actLen, sysFdBufSize);
  663. if (direction == DMA_MEM_READ)
  664.     {
  665.     memcpy ((char *) sysFdBuf, 
  666. &pErp->bfrList [pWork->curBfr].pBfr [pWork->curBfrOffset],
  667. pWork->dmaXfrLen);
  668.     USB_ISA_MEM_FLUSH ((char *) sysFdBuf, pWork->dmaXfrLen);
  669.     }
  670. USB_ISA_DMA_SETUP (direction, sysFdBuf, pWork->dmaXfrLen, 
  671.     pTarget->dma);
  672. /* Initialize D12 for DMA operation */
  673. pTarget->dmaByte &= ~D12_CMD_SD_DMA_DIRECTION_MASK;
  674. if (pEndpoint->endpointId == D12_ENDPOINT_2_OUT)
  675.     {
  676.     pTarget->dmaByte &= ~D12_CMD_SD_ENDPT_2_OUT_INTRPT;
  677.     pTarget->dmaByte |= D12_CMD_SD_DMA_DIRECTION_READ;
  678.     }
  679. else
  680.     {
  681.     pTarget->dmaByte &= ~D12_CMD_SD_ENDPT_2_IN_INTRPT;
  682.     pTarget->dmaByte |= D12_CMD_SD_DMA_DIRECTION_WRITE;
  683.     }
  684. pTarget->dmaByte |= D12_CMD_SD_DMA_ENABLE;
  685. d12SetDma (pTarget);
  686. /* Update state variables */
  687. pWork->dmaInUse = TRUE;
  688. pTarget->dmaInUse = TRUE;
  689. pTarget->dmaEndpointId = pEndpoint->endpointId;
  690. pTarget->pDmaErp = pErp;
  691. pTarget->dmaEot = FALSE;
  692. /* throw away any pending transaction status for this endpoint. */
  693. pTarget->transPending [pEndpoint->endpointId] = FALSE;
  694. return TRUE;
  695. }
  696.     return FALSE;
  697. #endif /* ifndef D12_USE_DMA */
  698.     }
  699. /***************************************************************************
  700. *
  701. * processInEndpoint - update an ERP for an IN endpoint
  702. *
  703. * Tries to put data from an ERP to an endpoint.  If successful, and if the
  704. * ERP is complete, then stores ERP status.
  705. *
  706. * RETURNS: N/A
  707. */
  708. LOCAL VOID processInEndpoint
  709.     (
  710.     pTARGET pTarget,
  711.     pUSB_TARG_ENDPOINT_INFO pEndpoint,
  712.     pUSB_ERP pErp,
  713.     pERP_WORKSPACE pWork
  714.     )
  715.     {
  716.     UINT8 tStatus;
  717.     /* Check if this ERP/endpoint is handled via DMA */
  718.     if (checkDma (pTarget, pEndpoint, pErp, pWork))
  719. return;
  720.     /* If this ERP is awaiting status, check the status.  If the ERP
  721.      * is not awaiting status, then the status must be stale, so
  722.      * discard it. 
  723.      */
  724.     if (pTarget->transPending [pEndpoint->endpointId])
  725. {
  726. /* "consume" the last status read for this endpoint */
  727. tStatus = pTarget->transStatus [pEndpoint->endpointId];
  728. pTarget->transPending [pEndpoint->endpointId] = FALSE;
  729. if (pWork->inStatusPending)
  730.     {
  731.     /* If the last transaction failed, fail the ERP. */
  732. #ifdef D12_CHECK_DATA_SUCCESS_BIT
  733.     if ((tStatus & D12_CMD_RLTS_DATA_SUCCESS) == 0)
  734. {
  735. finishErp (pTarget, pErp, S_usbTcdLib_COMM_FAULT);
  736. return;
  737. }
  738. #endif /* #ifdef D12_CHECK_DATA_SUCCESS_BIT */
  739.     pWork->inStatusPending = FALSE;
  740.     /* Is the ERP complete? */
  741.     if (pWork->curBfr == pErp->bfrCount ||
  742. (pErp->bfrList [0].pBfr == NULL && pErp->bfrList [0].bfrLen == 0))
  743. {
  744. finishErp (pTarget, pErp, OK);
  745. return;
  746. }
  747.     }
  748. }
  749.     /* If the endpoint can accept data, put data into it now. */
  750.     if ((d12SelectEndpoint (pTarget, pErp->endpointId) &
  751. D12_CMD_SE_FULL_EMPTY) != 0)
  752. return;
  753.     d12WriteBfr (pTarget, pEndpoint, pErp, pWork);
  754.     pWork->inStatusPending = TRUE;
  755.     }
  756. /***************************************************************************
  757. *
  758. * processOutEndpoint - update an ERP for an OUT endpoint
  759. *
  760. * Validates data received by the device on an OUT endpoint and puts the
  761. * data into the indicated ERP. If the ERP completes (successfully or with
  762. * an error), this function sets the ERP status.
  763. *
  764. * RETURNS: N/A
  765. */
  766. LOCAL VOID processOutEndpoint
  767.     (
  768.     pTARGET pTarget,
  769.     pUSB_TARG_ENDPOINT_INFO pEndpoint,
  770.     pUSB_ERP pErp,
  771.     pERP_WORKSPACE pWork
  772.     )
  773.     {
  774.     UINT8 tStatus;
  775.     /* Check if this ERP/endpoint is handled via DMA */
  776.     if (checkDma (pTarget, pEndpoint, pErp, pWork))
  777. return;
  778.     /* Is there a pending transaction for this endpoint? */
  779.     if (!pTarget->transPending [pEndpoint->endpointId])
  780. return;
  781.     /* Pick up the last status read for this endpoint */
  782.     tStatus = pTarget->transStatus [pEndpoint->endpointId];
  783.     /* Check the incoming data against the expected PID. */
  784.     if (pErp->transferType == USB_XFRTYPE_CONTROL)
  785. {
  786. if (((tStatus & D12_CMD_RLTS_SETUP_PACKET) != 0 &&
  787.     pErp->bfrList [0].pid != USB_PID_SETUP) ||
  788.     ((tStatus & D12_CMD_RLTS_SETUP_PACKET) == 0 && 
  789.     pErp->bfrList [0].pid != USB_PID_OUT))
  790.     {
  791.     /* PID mismatch */
  792.     stallEndpoint (pTarget, pEndpoint->endpointId);
  793.     finishErp (pTarget, pErp, S_usbTcdLib_PID_MISMATCH);
  794.     return;
  795.     }
  796. }
  797.     
  798.     /* Now that we're sure we're processing the expected kind of packet,
  799.      * "consume" the endpoint status.
  800.      */
  801.     pTarget->transPending [pEndpoint->endpointId] = FALSE;
  802.     /* If this was a setup packet, let the D12 know we acknowledge it. */
  803.     if ((tStatus & D12_CMD_RLTS_SETUP_PACKET) != 0)
  804. {
  805. d12AckSetup (pTarget, D12_ENDPOINT_CONTROL_IN);
  806. d12AckSetup (pTarget, D12_ENDPOINT_CONTROL_OUT);
  807. }
  808.     /* Was the last transaction successful?  If not, fail the ERP. */
  809. #ifdef D12_CHECK_DATA_SUCCESS_BIT
  810.     if ((tStatus & D12_CMD_RLTS_DATA_SUCCESS) == 0)
  811. {
  812. finishErp (pTarget, pErp, S_usbTcdLib_COMM_FAULT);
  813. return;
  814. }
  815. #endif /* #ifdef D12_CHECK_DATA_SUCCESS_BIT */
  816.     /* Check the DATA0/DATA1 flag against the expected flag */
  817.     if (((tStatus & D12_CMD_RLTS_DATA1) == 0) != (pErp->dataToggle == USB_DATA0))
  818. {
  819. /* Data toggle mismatch */
  820. stallEndpoint (pTarget, pEndpoint->endpointId);
  821. finishErp (pTarget, pErp, S_usbTcdLib_DATA_TOGGLE_FAULT);
  822. return;
  823. }
  824.     pErp->dataToggle = (pErp->dataToggle == USB_DATA0) ? USB_DATA1 : USB_DATA0;
  825.     /* Read data into the ERP. */
  826.     d12ReadBfr (pTarget, pEndpoint, pErp, pWork);
  827.     /* Is the ERP complete? */
  828.     if (pWork->curBfr == pErp->bfrCount ||
  829. (pErp->bfrList [0].pBfr == NULL && pErp->bfrList [0].bfrLen == 0))
  830. {
  831. finishErp (pTarget, pErp, OK);
  832. }
  833.     }
  834. /***************************************************************************
  835. *
  836. * processErpQueue - See if we can update the queue for an endpoint
  837. *
  838. * This function examines the ERP queue for the specified <endpointId>.
  839. * If the queue can be updated - that is, if data can be transferred to/
  840. * from the queue or an error condition can be logged - then we update
  841. * the queue.
  842. *
  843. * RETURNS: N/A
  844. */
  845. LOCAL VOID processErpQueue
  846.     (
  847.     pTARGET pTarget,
  848.     UINT16 endpointId
  849.     )
  850.     {
  851.     pUSB_TARG_ENDPOINT_INFO pEndpoint = &pTarget->pEndpoints [endpointId];
  852.     pUSB_ERP pErp;
  853.     pERP_WORKSPACE pWork;
  854.     
  855.     /* Process the next ERP */
  856.     if ((pErp = usbListFirst (&pTarget->erps [endpointId])) != NULL)
  857. {
  858. /* Get ERP_WORKSPACE for this ERP/endpoint. */
  859. pWork = &pTarget->workspace [endpointId];
  860.     
  861. if (!((BOOL) pErp->tcdPtr))
  862.     {
  863.     pErp->tcdPtr = (pVOID) TRUE;
  864.     memset (pWork, 0, sizeof (*pWork));
  865.     }
  866. /* Fan-out based on OUT or IN endpoint. */
  867. switch (pErp->endpointId)
  868.     {
  869.     case D12_ENDPOINT_CONTROL_OUT:
  870.     case D12_ENDPOINT_1_OUT:
  871.     case D12_ENDPOINT_2_OUT:
  872. processOutEndpoint (pTarget, pEndpoint, pErp, pWork);
  873. break;
  874.     case D12_ENDPOINT_CONTROL_IN:
  875.     case D12_ENDPOINT_1_IN:
  876.     case D12_ENDPOINT_2_IN:
  877. processInEndpoint (pTarget, pEndpoint, pErp, pWork);
  878. break;
  879.     }
  880. }
  881.     else
  882. {
  883. /* There is an interrupt pending, but the ERP queue is empty.  If
  884.  * this is the default control OUT pipe, and if the newly received
  885.  * packet is a setup packet, then we need to abort any pending
  886.  * transfers on the default control IN pipe.
  887.  */
  888. if (endpointId == D12_ENDPOINT_CONTROL_OUT &&
  889.     pTarget->transPending [endpointId] &&
  890.     (pTarget->transStatus [endpointId] & D12_CMD_RLTS_SETUP_PACKET) != 0 &&
  891.     (pErp = usbListFirst (&pTarget->erps [D12_ENDPOINT_CONTROL_IN])) != NULL)
  892.     {
  893.     finishErp (pTarget, pErp, S_usbTcdLib_NEW_SETUP_PACKET);
  894.     }
  895. }
  896.     }
  897. /***************************************************************************
  898. *
  899. * processErpQueueInt - Reads interrupt status and invokes processErpQueue()
  900. *
  901. * RETURNS: N/A
  902. */
  903. LOCAL VOID processErpQueueInt
  904.     (
  905.     pTARGET pTarget,
  906.     UINT16 endpointId
  907.     )
  908.     {
  909.     /* Select the endpoint and read the last transaction status.
  910.      *
  911.      * NOTE: Reading the transaction status clears the interrupt condition
  912.      * associated with a pipe. 
  913.      */
  914.     pTarget->transStatus [endpointId] = 
  915. d12ReadLastTransStatus (pTarget, endpointId);
  916.     pTarget->transPending [endpointId] = TRUE;
  917.     processErpQueue (pTarget, endpointId);
  918.     }
  919. /***************************************************************************
  920. *
  921. * processBusReset - Processes a bus reset event
  922. *
  923. * RETURNS: N/A
  924. */
  925. LOCAL VOID processBusReset
  926.     (
  927.     pTARGET pTarget
  928.     )
  929.     {
  930.     UINT8 ginByte = IN_EVAL_GIN ();
  931.     /* The D12 has reported a bus reset. */
  932.     pTarget->deviceAddress = 0;     /* reverts to power-ON default */
  933.     /* Report the bus reset to our caller. */
  934.     MNGMT_CALLBACK (pTarget, TCD_MNGMT_BUS_RESET);
  935.     /* Follow-up by determining if Vbus is present or not */
  936.     if ((ginByte & D12EVAL_BUS_POWER) == 0)
  937. MNGMT_CALLBACK (pTarget, TCD_MNGMT_VBUS_LOST);
  938.     else
  939. MNGMT_CALLBACK (pTarget, TCD_MNGMT_VBUS_DETECT);
  940.     }
  941. /***************************************************************************
  942. *
  943. * processSuspendChange - Interprets a change in the bus SUSPEND state
  944. *
  945. * RETURNS: N/A
  946. */
  947. LOCAL VOID processSuspendChange
  948.     (
  949.     pTARGET pTarget
  950.     )
  951.     {
  952.     UINT8 ginByte = IN_EVAL_GIN ();
  953.     /* The D12 has reported a change in the suspend state.  Reflect the
  954.      * current suspend state to the caller.
  955.      */
  956.     if ((ginByte & D12EVAL_SUSPEND) == 0)
  957. MNGMT_CALLBACK (pTarget, TCD_MNGMT_RESUME);
  958.     else
  959. MNGMT_CALLBACK (pTarget, TCD_MNGMT_SUSPEND);
  960.     }
  961. /***************************************************************************
  962. *
  963. * processDmaEot - Handles a DMA end-of-transfer
  964. *
  965. * RETURNS: N/A
  966. */
  967. LOCAL VOID processDmaEot
  968.     (
  969.     pTARGET pTarget
  970.     )
  971.     {
  972.     /* The D12 reports that a DMA operation has completed. */
  973.     if (pTarget->dmaInUse)
  974. {
  975. pTarget->dmaEot = TRUE;
  976. processErpQueue (pTarget, pTarget->dmaEndpointId);
  977. }
  978.     }
  979. /***************************************************************************
  980. *
  981. * processD12Int - evaluate and process an interrupt from the PDIUSBD12
  982. *
  983. * RETURNS: N/A
  984. */
  985. LOCAL VOID processD12Int
  986.     (
  987.     pTARGET pTarget
  988.     )
  989.     {
  990.     UINT16 intStatus;
  991.     /* Read interrupt status.
  992.      *
  993.      * NOTE: Reading the interrupt status clears interrupt conditions
  994.      * which are not associated with a specific pipe.
  995.      */
  996.     intStatus = d12ReadIntReg (pTarget);
  997.     /* Examine interrupt conditions.
  998.      *
  999.      * NOTE: Examine control endpoint last...at the end of a transaction,
  1000.      * it is possible for a new setup packet to come in before we've
  1001.      * handled the interrupt associated with the just-ended transaction.
  1002.      */
  1003.     if ((intStatus & D12_CMD_RIR_ENDPOINT_2_IN) != 0)
  1004. processErpQueueInt (pTarget, D12_ENDPOINT_2_IN);
  1005.     if ((intStatus & D12_CMD_RIR_ENDPOINT_2_OUT) != 0)
  1006. processErpQueueInt (pTarget, D12_ENDPOINT_2_OUT);
  1007.     if ((intStatus & D12_CMD_RIR_ENDPOINT_1_IN) != 0)
  1008. processErpQueueInt (pTarget, D12_ENDPOINT_1_IN);
  1009.     if ((intStatus & D12_CMD_RIR_ENDPOINT_1_OUT) != 0)
  1010. processErpQueueInt (pTarget, D12_ENDPOINT_1_OUT);
  1011.     if ((intStatus & D12_CMD_RIR_CONTROL_IN) != 0)
  1012. processErpQueueInt (pTarget, D12_ENDPOINT_CONTROL_IN);
  1013.     if ((intStatus & D12_CMD_RIR_CONTROL_OUT) != 0)
  1014. processErpQueueInt (pTarget, D12_ENDPOINT_CONTROL_OUT);
  1015.     if ((intStatus & D12_CMD_RIR_BUS_RESET) != 0)
  1016. processBusReset (pTarget);
  1017.     if ((intStatus & D12_CMD_RIR_SUSPEND) != 0)
  1018. processSuspendChange (pTarget);
  1019.     if ((intStatus & D12_CMD_RIR_DMA_EOT) != 0)
  1020. processDmaEot (pTarget);
  1021.     }
  1022. /***************************************************************************
  1023. *
  1024. * usbTcdPdiusbd12IntThread - Handles PDIUSBD12 interrupts
  1025. *
  1026. * This thread normally waits on the TARGET.intPending semaphore.  When
  1027. * the semaphore is signalled, this thread interrogates the target controller
  1028. * to determine the cause of the interrupt and serives it.
  1029. *
  1030. * By convention, the <param> to this thread is a pointer to the TARGET
  1031. * structure for this target controller.
  1032. *
  1033. * When this thread exits, it signals the TARGET.intThreadExit semaphore
  1034. * so the foreground thread can no that the thread has terminated successully.
  1035. *
  1036. * RETURNS: N/A
  1037. */
  1038. LOCAL VOID usbTcdPdiusbd12IntThread
  1039.     (
  1040.     pVOID param
  1041.     )
  1042.     {
  1043.     pTARGET pTarget = (pTARGET) param;
  1044.     UINT16 i;
  1045.     do
  1046. {
  1047. /* Wait for an interrupt to be signalled. */
  1048. if (OSS_SEM_TAKE (pTarget->intPending, OSS_BLOCK) == OK)
  1049.     {
  1050.     if (!pTarget->intThreadExitRequest)
  1051. {
  1052. OSS_MUTEX_TAKE (pTarget->tcdMutex, OSS_BLOCK);
  1053. /* Light LED to indicate we're processing an interrupt */
  1054. pTarget->goutByte |= INT_THREAD_LED;
  1055. OUT_EVAL_GOUT (pTarget->goutByte);
  1056. /* Process the interrupt */
  1057. processD12Int (pTarget);
  1058. /* See if any queued ERPs need processing. */
  1059. for (i = 0; i < D12_NUM_ENDPOINTS; i++)
  1060.     {
  1061.     if (pTarget->endpointNeedsService [i])
  1062. {
  1063. pTarget->endpointNeedsService [i] = FALSE;
  1064. processErpQueue (pTarget, i);
  1065. }
  1066.     }
  1067. /* Re-enable interrupts. */
  1068. pTarget->goutByte &= ~INT_THREAD_LED;
  1069. pTarget->goutByte |= D12EVAL_GOUT_INTENB;
  1070. OUT_EVAL_GOUT (pTarget->goutByte);
  1071. OSS_MUTEX_RELEASE (pTarget->tcdMutex);
  1072. }
  1073.     }
  1074. }
  1075.     while (!pTarget->intThreadExitRequest);
  1076.     OSS_SEM_GIVE (pTarget->intThreadExit);
  1077.     }
  1078. /***************************************************************************
  1079. *
  1080. * usbTcdPdiusbd12IntHandler - hardware interrupt handler
  1081. *
  1082. * This is the actual routine which receives hardware interrupts from the
  1083. * target controller.  This routine immediately reflects the interrupt to 
  1084. * the usbTcdPdiusbd12IntThread.  Interrupt handlers have execution 
  1085. * restrictions which are not imposed on normal threads...So, this scheme 
  1086. * gives the usbTcdPdiusbd12IntThread complete flexibility to call other 
  1087. * services and libraries while processing the interrupt condition.
  1088. *
  1089. * RETURNS: N/A
  1090. */
  1091. LOCAL VOID usbTcdPdiusbd12IntHandler
  1092.     (
  1093.     pVOID param
  1094.     )
  1095.     {
  1096.     pTARGET pTarget = (pTARGET) param;
  1097.     /* Is there an interrupt pending in the UHCI status reg? 
  1098.      *
  1099.      * NOTE: INT_N is an active low signal.  The interrupt is asserted
  1100.      * when INT_N == 0.
  1101.      */
  1102.     if ((IN_EVAL_GIN () & D12EVAL_INTN) == 0)
  1103. {
  1104. pTarget->intCount++;
  1105. /* A USB interrupt is pending. Disable interrupts until the
  1106.  * interrupt thread can process it. */
  1107. pTarget->goutByte &= ~D12EVAL_GOUT_INTENB;
  1108. OUT_EVAL_GOUT (pTarget->goutByte);
  1109. /* Signal the interrupt thread to process the interrupt. */
  1110. OSS_SEM_GIVE (pTarget->intPending);
  1111. }
  1112.     }
  1113. /***************************************************************************
  1114. *
  1115. * cancelAllErps - Cancels all outstanding ERPs
  1116. *
  1117. * RETURNS: N/A
  1118. */
  1119. LOCAL VOID cancelAllErps
  1120.     (
  1121.     pTARGET pTarget
  1122.     )
  1123.     {
  1124.     UINT16 i;
  1125.     pUSB_ERP pErp;
  1126.     /* Cancel all pending ERPs */
  1127.     for (i = 0; i < D12_NUM_ENDPOINTS; i++)
  1128. {
  1129. while ((pErp = usbListFirst (&pTarget->erps [i])) != NULL)
  1130.     {
  1131.     finishErp (pTarget, pErp, S_usbTcdLib_ERP_CANCELED);
  1132.     }
  1133. }
  1134.     }
  1135. /***************************************************************************
  1136. *
  1137. * doDisable - Disable the target controller
  1138. *
  1139. * Disables the target controller so it won't appear to be connected to
  1140. * the USB.
  1141. *
  1142. * RETURNS: N/A
  1143. */
  1144. LOCAL VOID doDisable
  1145.     (
  1146.     pTARGET pTarget
  1147.     )
  1148.     {
  1149.     /* Cancel all outstanding ERPs. */
  1150.     cancelAllErps (pTarget);
  1151.     /* Disable controller */
  1152.     pTarget->configByte &= ~D12_CMD_SM_CFG_SOFTCONNECT;
  1153.     d12SetMode (pTarget);
  1154.     pTarget->enableFlag = DISABLE;
  1155.     d12SetAddress (pTarget);
  1156.     pTarget->goutByte &= ~ENABLE_LED;
  1157.     OUT_EVAL_GOUT (pTarget->goutByte);
  1158.     }
  1159. /***************************************************************************
  1160. *
  1161. * destroyTarget - tears down a TARGET structure
  1162. *
  1163. * RETURNS: N/A
  1164. */
  1165. LOCAL VOID destroyTarget
  1166.     (
  1167.     pTARGET pTarget
  1168.     )
  1169.     {
  1170.     if (pTarget)
  1171. {
  1172. /* Cancel all outstanding ERPs. */
  1173. cancelAllErps (pTarget);
  1174. /* Disable interrupts, turn off LEDs */
  1175. if (pTarget->ioBase != 0)
  1176.     OUT_EVAL_GOUT (0);
  1177.     
  1178. if (pTarget->intInstalled)
  1179.     USB_ISA_INT_RESTORE (usbTcdPdiusbd12IntHandler, pTarget, 
  1180. pTarget->irq);
  1181. /* Shut down interrupt handler thread */
  1182. if (pTarget->intThread != NULL)
  1183.     {
  1184.     pTarget->intThreadExitRequest = TRUE;
  1185.     OSS_SEM_GIVE (pTarget->intPending);
  1186.     OSS_SEM_TAKE (pTarget->intThreadExit, INT_THREAD_EXIT_TIMEOUT);
  1187.     OSS_THREAD_DESTROY (pTarget->intThread);
  1188.     }
  1189. if (pTarget->intPending != NULL)
  1190.     OSS_SEM_DESTROY (pTarget->intPending);
  1191. if (pTarget->intThreadExit != NULL)
  1192.     OSS_SEM_DESTROY (pTarget->intThreadExit);
  1193. /* Release target memory */
  1194. if (pTarget->pEndpoints != NULL)
  1195.     OSS_FREE (pTarget->pEndpoints);
  1196. OSS_FREE (pTarget);
  1197. }
  1198.     }
  1199. /***************************************************************************
  1200. *
  1201. * fncAttach - Executes TCD_FNC_ATTACH
  1202. *
  1203. * This function initializes the target controller for operation.
  1204. *
  1205. * RETURNS: OK or S_usbTcdLib_xxxx if an error is detected
  1206. */
  1207. LOCAL int fncAttach
  1208.     (
  1209.     pTRB_ATTACH pTrb
  1210.     )
  1211.     {
  1212.     pUSB_TCD_PDIUSBD12_PARAMS pParams;
  1213.     pTARGET pTarget;
  1214.     pUSB_TARG_ENDPOINT_INFO pEndpoint;
  1215.     UINT16 i;
  1216.     /* Validate parameters */
  1217.     if ((pParams = (pUSB_TCD_PDIUSBD12_PARAMS) pTrb->tcdParam) == NULL ||
  1218. pTrb->mngmtCallback == NULL)
  1219. return S_usbTcdLib_BAD_PARAM;
  1220.     /* Create a TARGET structure to manage this target controller. */
  1221.     if ((pTarget = OSS_CALLOC (sizeof (*pTarget))) == NULL ||
  1222. (pTarget->pEndpoints = OSS_CALLOC (sizeof (USB_TARG_ENDPOINT_INFO) *
  1223.     D12_NUM_ENDPOINTS)) == NULL ||
  1224. OSS_MUTEX_CREATE (&pTarget->tcdMutex) != OK ||
  1225. OSS_SEM_CREATE (1, 0, &pTarget->intPending) != OK ||
  1226. OSS_SEM_CREATE (1, 0, &pTarget->intThreadExit) != OK ||
  1227. OSS_THREAD_CREATE (usbTcdPdiusbd12IntThread, pTarget, 
  1228.     OSS_PRIORITY_INTERRUPT, INT_THREAD_NAME, &pTarget->intThread) != OK)
  1229. {
  1230. destroyTarget (pTarget);
  1231. return S_usbTcdLib_OUT_OF_RESOURCES;
  1232. }
  1233.     pTarget->ioBase = pParams->ioBase;
  1234.     pTarget->irq = pParams->irq;
  1235.     pTarget->dma = pParams->dma;
  1236.     pTarget->mngmtCallback = pTrb->mngmtCallback;
  1237.     pTarget->mngmtCallbackParam = pTrb->mngmtCallbackParam;
  1238.     /* Initialize endpoint information */
  1239.     /* default control OUT endpoint */
  1240.     pEndpoint = &pTarget->pEndpoints [D12_ENDPOINT_CONTROL_OUT];
  1241.     pEndpoint->endpointId = D12_ENDPOINT_CONTROL_OUT;
  1242.     pEndpoint->flags = TCD_ENDPOINT_OUT_OK | TCD_ENDPOINT_CTRL_OK;
  1243.     pEndpoint->endpointNumMask = 0x0001;    /* endpoint #0 only */
  1244.     pEndpoint->ctlMaxPacketSize = D12_MAX_PKT_CONTROL;
  1245.     /* default control IN endpoint */
  1246.     pEndpoint = &pTarget->pEndpoints [D12_ENDPOINT_CONTROL_IN];
  1247.     pEndpoint->endpointId = D12_ENDPOINT_CONTROL_IN;
  1248.     pEndpoint->flags = TCD_ENDPOINT_IN_OK | TCD_ENDPOINT_CTRL_OK;
  1249.     pEndpoint->endpointNumMask = 0x0001;    /* endpoint #0 only */
  1250.     pEndpoint->ctlMaxPacketSize = D12_MAX_PKT_CONTROL;
  1251.     /* bulk or interrupt OUT endpoint */
  1252.     pEndpoint = &pTarget->pEndpoints [D12_ENDPOINT_1_OUT];
  1253.     pEndpoint->endpointId = D12_ENDPOINT_1_OUT;
  1254.     pEndpoint->flags = TCD_ENDPOINT_OUT_OK | TCD_ENDPOINT_BULK_OK |
  1255. TCD_ENDPOINT_INT_OK;
  1256.     pEndpoint->endpointNumMask = 0x0002;    /* endpoint #1 only */
  1257.     pEndpoint->bulkOutMaxPacketSize   = D12_MAX_PKT_ENDPOINT_1;
  1258.     pEndpoint->bulkInOutMaxPacketSize = D12_MAX_PKT_ENDPOINT_1;
  1259.     pEndpoint->intOutMaxPacketSize    = D12_MAX_PKT_ENDPOINT_1;
  1260.     pEndpoint->intInOutMaxPacketSize  = D12_MAX_PKT_ENDPOINT_1;
  1261.     /* bulk or interrupt IN endpoint */
  1262.     pEndpoint = &pTarget->pEndpoints [D12_ENDPOINT_1_IN];
  1263.     pEndpoint->endpointId = D12_ENDPOINT_1_IN;
  1264.     pEndpoint->flags = TCD_ENDPOINT_IN_OK | TCD_ENDPOINT_BULK_OK |
  1265. TCD_ENDPOINT_INT_OK;
  1266.     pEndpoint->endpointNumMask = 0x0002;    /* endpoint #1 only */
  1267.     pEndpoint->bulkInMaxPacketSize    = D12_MAX_PKT_ENDPOINT_1;
  1268.     pEndpoint->bulkInOutMaxPacketSize = D12_MAX_PKT_ENDPOINT_1;
  1269.     pEndpoint->intInMaxPacketSize     = D12_MAX_PKT_ENDPOINT_1;
  1270.     pEndpoint->intInOutMaxPacketSize  = D12_MAX_PKT_ENDPOINT_1;
  1271.     /* main OUT endpoint: bulk, interrupt, or isochronous */
  1272.     pEndpoint = &pTarget->pEndpoints [D12_ENDPOINT_2_OUT];
  1273.     pEndpoint->endpointId = D12_ENDPOINT_2_OUT;
  1274.     pEndpoint->flags = TCD_ENDPOINT_OUT_OK | TCD_ENDPOINT_BULK_OK |
  1275. TCD_ENDPOINT_INT_OK | TCD_ENDPOINT_ISOCH_OK;
  1276.     pEndpoint->bulkOutMaxPacketSize    = D12_MAX_PKT_ENDPOINT_2_NON_ISO;
  1277.     pEndpoint->bulkInOutMaxPacketSize  = D12_MAX_PKT_ENDPOINT_2_NON_ISO;
  1278.     pEndpoint->intOutMaxPacketSize     = D12_MAX_PKT_ENDPOINT_2_NON_ISO;
  1279.     pEndpoint->intInOutMaxPacketSize   = D12_MAX_PKT_ENDPOINT_2_NON_ISO;
  1280.     pEndpoint->isochOutMaxPacketSize   = D12_MAX_PKT_ENDPOINT_2_ISO_OUT;
  1281.     pEndpoint->isochInOutMaxPacketSize = D12_MAX_PKT_ENDPOINT_2_ISO_IO;
  1282.     /* main IN endpoint: bulk, interrupt, or isochronous */
  1283.     pEndpoint = &pTarget->pEndpoints [D12_ENDPOINT_2_IN];
  1284.     pEndpoint->endpointId = D12_ENDPOINT_2_IN;
  1285.     pEndpoint->flags = TCD_ENDPOINT_IN_OK | TCD_ENDPOINT_BULK_OK |
  1286. TCD_ENDPOINT_INT_OK | TCD_ENDPOINT_ISOCH_OK;
  1287.     pEndpoint->bulkInMaxPacketSize     = D12_MAX_PKT_ENDPOINT_2_NON_ISO;
  1288.     pEndpoint->bulkInOutMaxPacketSize  = D12_MAX_PKT_ENDPOINT_2_NON_ISO;
  1289.     pEndpoint->intInMaxPacketSize      = D12_MAX_PKT_ENDPOINT_2_NON_ISO;
  1290.     pEndpoint->intInOutMaxPacketSize   = D12_MAX_PKT_ENDPOINT_2_NON_ISO;
  1291.     pEndpoint->isochInMaxPacketSize    = D12_MAX_PKT_ENDPOINT_2_ISO_IN;
  1292.     pEndpoint->isochInOutMaxPacketSize = D12_MAX_PKT_ENDPOINT_2_ISO_IO;
  1293.     /* Make sure the hardware is present */
  1294.     if ((d12ReadChipId (pTarget) & D12_CHIP_ID_MASK) != D12_CHIP_ID)
  1295. {
  1296. pTarget->ioBase = 0;
  1297. destroyTarget (pTarget);
  1298. return S_usbTcdLib_HW_NOT_READY;
  1299. }
  1300.     /* Initialize hardware */
  1301.     /* disable eval board and address decoding */
  1302.     OUT_EVAL_GOUT (0); /* turn OFF LEDs & interrupts */
  1303.     pTarget->deviceAddress = 0;
  1304.     pTarget->enableFlag = DISABLE;
  1305.     d12SetAddress (pTarget); /* disable device */
  1306.     d12SetEndpointEnable (pTarget, DISABLE); /* disable endpoints 1 & 2 */
  1307.     /* Clear pending status. */
  1308.     for (i = 0; i < D12_NUM_ENDPOINTS; i++)
  1309. {
  1310. d12SelectEndpoint (pTarget, i);
  1311. d12ClearBfr (pTarget);
  1312. d12ReadLastTransStatus (pTarget, i);
  1313. d12ReadLastTransStatus (pTarget, i);
  1314. }
  1315.     d12ReadIntReg (pTarget);
  1316.     /* Hook interrupts */
  1317.     if (USB_ISA_INT_CONNECT (usbTcdPdiusbd12IntHandler, pTarget, pTarget->irq) 
  1318. != OK)
  1319. {
  1320. destroyTarget (pTarget);
  1321. return S_usbTcdLib_INT_HOOK_FAILED;
  1322. }
  1323.     pTarget->intInstalled = TRUE;
  1324.     /* continue initializing hardware */
  1325.     /* set basic operating mode
  1326.      *
  1327.      * NOTE: Setting the "clock running" bit keeps the chip alive even during
  1328.      * suspend in order to facilitate debugging.  In a production environment
  1329.      * where power device power consumption may be an issue, this bit should
  1330.      * not be set.
  1331.      */
  1332.     pTarget->configByte = D12_CMD_SM_CFG_NO_LAZYCLOCK |
  1333. D12_CMD_SM_CFG_CLOCK_RUNNING | D12_CMD_SM_CFG_MODE0_NON_ISO;
  1334.     pTarget->clkDivByte = D12_CMD_SM_CLK_DIV_DEFAULT | 
  1335. D12_CMD_SM_CLK_SET_TO_ONE;
  1336.     d12SetMode (pTarget);
  1337.     /* Set default DMA mode 
  1338.      *
  1339.      * NOTE: Originally when writing this code I set the PDIUSBD12 for
  1340.      * single-cycle DMA mode.  However, I noticed that the D12 would stop 
  1341.      * asserting DRQ mid-transfer.  In examining the Philips evaluation code,
  1342.      * I noticed that they only use "burst 16" DMA mode, and that appears
  1343.      * to work correct.  -rcb
  1344.      */
  1345.     pTarget->dmaByte = D12_CMD_SD_DMA_BURST_16 | 
  1346. D12_CMD_SD_ENDPT_2_OUT_INTRPT | D12_CMD_SD_ENDPT_2_IN_INTRPT;
  1347.     d12SetDma (pTarget);
  1348.     /* The following command enables interrupts.  Since we're using an evaluation
  1349.      * board with some debug LEDs, we also turn on an "LED" to indicate that the
  1350.      * board is configured.
  1351.      */
  1352.     pTarget->goutByte = ATTACH_LED | D12EVAL_GOUT_INTENB;
  1353.     OUT_EVAL_GOUT (pTarget->goutByte);
  1354.     /* Return target information to caller */
  1355.     pTrb->header.handle = (TCD_HANDLE) pTarget;
  1356.     pTrb->speed = USB_SPEED_FULL;
  1357.     pTrb->numEndpoints = D12_NUM_ENDPOINTS;
  1358.     pTrb->pEndpoints = pTarget->pEndpoints;
  1359.     return OK;
  1360.     }
  1361. /***************************************************************************
  1362. *
  1363. * fncDetach - Executes TCD_FNC_DETACH
  1364. *
  1365. * This function shuts down a target controller previously enabled by
  1366. * calling fncAttach().
  1367. *
  1368. * RETURNS: OK or S_usbTcdLib_xxxx if an error is detected
  1369. */
  1370. LOCAL int fncDetach
  1371.     (
  1372.     pTRB_DETACH pTrb,
  1373.     pTARGET pTarget
  1374.     )
  1375.     {
  1376.     destroyTarget (pTarget);
  1377.     return OK;
  1378.     }
  1379. /***************************************************************************
  1380. *
  1381. * fncEnable - Enables a target channel
  1382. *
  1383. * After a TCD has been attached/initialized, it still needs to be enabled
  1384. * before the target controller will appear as a device on the USB. 
  1385. * Separating the enabling of the device into a separate step allows 
  1386. * additional device initialization to be performed before the device is
  1387. * required to respond to requests from the host.
  1388. *
  1389. * RETURNS: OK or S_usbTcdLib_xxxx if an error is detected
  1390. */
  1391. LOCAL int fncEnable
  1392.     (
  1393.     pTRB_ENABLE_DISABLE pTrb,
  1394.     pTARGET pTarget
  1395.     )
  1396.     {
  1397.     pTarget->enableFlag = ENABLE;
  1398.     d12SetAddress (pTarget);
  1399.     pTarget->configByte |= D12_CMD_SM_CFG_SOFTCONNECT;
  1400.     d12SetMode (pTarget);
  1401.     pTarget->goutByte |= ENABLE_LED;
  1402.     OUT_EVAL_GOUT (pTarget->goutByte);
  1403.     return OK;
  1404.     }
  1405. /***************************************************************************
  1406. *
  1407. * fncDisable - Disables a target channel
  1408. *
  1409. * This function disables the target controller from responding on the
  1410. * USB as a device.  
  1411. *
  1412. * RETURNS: OK or S_usbTcdLib_xxxx if an error is detected
  1413. */
  1414. LOCAL int fncDisable
  1415.     (
  1416.     pTRB_ENABLE_DISABLE pTrb,
  1417.     pTARGET pTarget
  1418.     )
  1419.     {
  1420.     doDisable (pTarget);
  1421.     return OK;
  1422.     }
  1423. /***************************************************************************
  1424. *
  1425. * fncAddressSet - Sets the device (target) address
  1426. *
  1427. * After fncAttach() the device defaults to USB address 0.  This function
  1428. * is generally invoked in response to a host request to assign a different
  1429. * address to this device.
  1430. *
  1431. * RETURNS: OK or S_usbTcdLib_xxxx if an error is detected
  1432. */
  1433. LOCAL int fncAddressSet
  1434.     (
  1435.     pTRB_ADDRESS_SET pTrb,
  1436.     pTARGET pTarget
  1437.     )
  1438.     {
  1439.     pTarget->deviceAddress = pTrb->deviceAddress;
  1440.     d12SetAddress (pTarget);
  1441.     return OK;
  1442.     }
  1443. /***************************************************************************
  1444. *
  1445. * pickPacketSize - chooses packets size based on direction
  1446. *
  1447. * RETURNS: selected packet size
  1448. */
  1449. LOCAL UINT16 pickPacketSize
  1450.     (
  1451.     UINT16 direction,
  1452.     UINT16 inMaxPacketSize,
  1453.     UINT16 outMaxPacketSize,
  1454.     UINT16 inOutMaxPacketSize
  1455.     )
  1456.     {
  1457.     switch (direction)
  1458. {
  1459. case USB_DIR_IN:    return inMaxPacketSize;
  1460. case USB_DIR_OUT:   return outMaxPacketSize;
  1461. case USB_DIR_INOUT: return inOutMaxPacketSize;
  1462. }
  1463.     return 0;
  1464.     }     
  1465. /***************************************************************************
  1466. *
  1467. * fncEndpointAssign - Assigns an endpoint for a specific kind of transfer
  1468. *
  1469. * This function is called when the usbTargLib or the target application
  1470. * wants to create a new pipe.  This function enables the endpoint to handle
  1471. * the type of data transfer indicated by the caller.
  1472. *
  1473. * RETURNS: OK or S_usbTcdLib_xxxx if an error is detected
  1474. */
  1475. LOCAL int fncEndpointAssign
  1476.     (
  1477.     pTRB_ENDPOINT_ASSIGN pTrb,
  1478.     pTARGET pTarget
  1479.     )
  1480.     {
  1481.     pUSB_TARG_ENDPOINT_INFO pEndpoint;
  1482.     /* NOTE: By convention, usbTargLib guarantees that the parameters in the
  1483.      * TRB are valid for this endpoint prior to calling this function.
  1484.      */
  1485.     pEndpoint = &pTarget->pEndpoints [pTrb->endpointId];
  1486.     pEndpoint->endpointNum = pTrb->endpointNum;
  1487.     pEndpoint->configuration = pTrb->configuration;
  1488.     pEndpoint->interface = pTrb->interface;
  1489.     pEndpoint->transferType = pTrb->transferType;
  1490.     pEndpoint->direction = pTrb->direction;
  1491.     /* Determine the maxPacketSize based on the selected type of transfer */
  1492.     switch (pTrb->transferType)
  1493. {
  1494. case USB_XFRTYPE_CONTROL:
  1495.     pEndpoint->maxPacketSize = pEndpoint->ctlMaxPacketSize;
  1496.     break;
  1497. case USB_XFRTYPE_BULK:
  1498.     pEndpoint->maxPacketSize = pickPacketSize (pTrb->direction,
  1499. pEndpoint->bulkInMaxPacketSize, pEndpoint->bulkOutMaxPacketSize,
  1500. pEndpoint->bulkInOutMaxPacketSize);
  1501.     break;
  1502. case USB_XFRTYPE_INTERRUPT:
  1503.     pEndpoint->maxPacketSize = pickPacketSize (pTrb->direction,
  1504. pEndpoint->intInMaxPacketSize, pEndpoint->intOutMaxPacketSize,
  1505. pEndpoint->intInOutMaxPacketSize);
  1506.     break;
  1507. case USB_XFRTYPE_ISOCH:
  1508.     pEndpoint->maxPacketSize = pickPacketSize (pTrb->direction,
  1509. pEndpoint->isochInMaxPacketSize, pEndpoint->isochOutMaxPacketSize,
  1510. pEndpoint->isochInOutMaxPacketSize);
  1511.     break;
  1512. }
  1513.     /* Enable the endpoint as necessary. */
  1514.     d12SetEndpointStatus (pTarget, pTrb->endpointId, 0);    /* reset to DATA0 */
  1515.     switch (pTrb->endpointId)
  1516. {
  1517. case D12_ENDPOINT_CONTROL_OUT:
  1518. case D12_ENDPOINT_CONTROL_IN:
  1519.     break;  /* no additional processing required */
  1520. case D12_ENDPOINT_2_OUT:
  1521. case D12_ENDPOINT_2_IN:
  1522.     /* These comprise the D12's "main" endpoint.  When these endpoints
  1523.      * are enabled, we need to change the endpoint configuration mode
  1524.      * according to the type of transfer.
  1525.      */
  1526.     if (++pTarget->epMainCount == 1 &&
  1527. pTrb->transferType == USB_XFRTYPE_ISOCH)
  1528. {
  1529. pTarget->configByte &= ~D12_CMD_SM_CFG_MODE_MASK;
  1530. switch (pTrb->direction)
  1531.     {
  1532.     case USB_DIR_OUT:
  1533. pTarget->configByte |= D12_CMD_SM_CFG_MODE1_ISO_OUT;
  1534. break;
  1535.     case USB_DIR_IN:
  1536. pTarget->configByte |= D12_CMD_SM_CFG_MODE2_ISO_IN;
  1537. break;
  1538.     case USB_DIR_INOUT:
  1539. pTarget->configByte |= D12_CMD_SM_CFG_MODE3_ISO_IO;
  1540. break;
  1541.     }
  1542. d12SetMode (pTarget);
  1543. }
  1544.     /* NOTE: Code falls through into case below intentionally. */
  1545. case D12_ENDPOINT_1_OUT:
  1546. case D12_ENDPOINT_1_IN:
  1547.     /* Whenever the D12's endpoint #1 or #2 is enabled, we need to
  1548.      * issue a Set Endpoint Enable command.
  1549.      */
  1550.     if (++pTarget->epOneAndTwoCount == 1)
  1551. d12SetEndpointEnable (pTarget, ENABLE);
  1552.     break;
  1553. }
  1554.     /* Mark the endpoint as "in use" */
  1555.     pEndpoint->flags |= TCD_ENDPOINT_IN_USE;
  1556.     return OK;
  1557.     }
  1558. /***************************************************************************
  1559. *
  1560. * fncEndpointRelease - Releases an endpoint
  1561. *
  1562. * This function is used to release an endpoint which was previously enabled
  1563. * for data transfer by calling fncEndpointAssign().
  1564. *
  1565. * RETURNS: OK or S_usbTcdLib_xxxx if an error is detected
  1566. */
  1567. LOCAL int fncEndpointRelease
  1568.     (
  1569.     pTRB_ENDPOINT_RELEASE pTrb,
  1570.     pTARGET pTarget
  1571.     )
  1572.     {
  1573.     pUSB_TARG_ENDPOINT_INFO pEndpoint;
  1574.     /* mark endpoint as no longer "in use" */
  1575.     pEndpoint = &pTarget->pEndpoints [pTrb->endpointId];
  1576.     pEndpoint->flags &= ~TCD_ENDPOINT_IN_USE;
  1577.     pEndpoint->endpointNum = 0;
  1578.     pEndpoint->configuration = 0;
  1579.     pEndpoint->interface = 0;
  1580.     pEndpoint->transferType = 0;
  1581.     pEndpoint->direction = 0;
  1582.     pEndpoint->maxPacketSize = 0;
  1583.     /* We may need to disable certain d12 functions. */
  1584.     switch (pEndpoint->endpointId)
  1585. {
  1586. case D12_ENDPOINT_CONTROL_OUT:
  1587. case D12_ENDPOINT_CONTROL_IN:
  1588.     break;  /* no additional processing required */
  1589. case D12_ENDPOINT_2_OUT:
  1590. case D12_ENDPOINT_2_IN:
  1591.     /* These comprise the D12's "main" endpoint.  When these endpoints
  1592.      * are disabled, we may need to change the endpoint configuration.
  1593.      */
  1594.     if (--pTarget->epMainCount == 0)
  1595. {
  1596. pTarget->configByte &= ~D12_CMD_SM_CFG_MODE_MASK;
  1597. pTarget->configByte |= D12_CMD_SM_CFG_MODE0_NON_ISO;
  1598. d12SetMode (pTarget);
  1599. }
  1600.     /* NOTE: Code falls through into case below intentionally. */
  1601. case D12_ENDPOINT_1_OUT:
  1602. case D12_ENDPOINT_1_IN:
  1603.     /* Whenever the D12's endpoint #1 or #2 is disabled, we may need to
  1604.      * issue a Set Endpoint Enable command.
  1605.      */
  1606.     if (--pTarget->epOneAndTwoCount == 0)
  1607. d12SetEndpointEnable (pTarget, DISABLE);
  1608.     break;
  1609. }
  1610.     
  1611.     return OK;
  1612.     }
  1613. /***************************************************************************
  1614. *
  1615. * fncSignalResume - Drives RESUME signalling on USB
  1616. *
  1617. * If the USB is in the SUSPEND state, the host may wish to drive RESUME
  1618. * signalling in order to try to "wake up" the host.
  1619. *
  1620. * RETURNS: OK or S_usbTcdLib_xxxx if an error is detected
  1621. */
  1622. LOCAL int fncSignalResume
  1623.     (
  1624.     pTRB_SIGNAL_RESUME pTrb,
  1625.     pTARGET pTarget
  1626.     )
  1627.     {
  1628.     d12SendResume (pTarget);
  1629.     return OK;
  1630.     }
  1631. /***************************************************************************
  1632. *
  1633. * fncEndpointStateSet - Sets endpoint as stalled/unstalled or resets data toggle
  1634. *
  1635. * In response to an error condition, the usbTargLib or an application may
  1636. * wish to set one or more endpoints to the "stalled" state.  Using this
  1637. * function, the caller can specify whether an endpoint should be "stalled"
  1638. * or "unstalled".
  1639. *
  1640. * Independently, an endpoint's data toggle may be reset to DATA0.  This is 
  1641. * necessary when a "configuration event" is detected for the endpoint.
  1642. *
  1643. * RETURNS: OK, or S_usbTcdLib_xxx if an error is detected.
  1644. */
  1645. LOCAL int fncEndpointStateSet
  1646.     (
  1647.     pTRB_ENDPOINT_STATE_SET pTrb,
  1648.     pTARGET pTarget
  1649.     )
  1650.     {
  1651.     if ((pTrb->state & TCD_ENDPOINT_STALL) != 0)
  1652. {
  1653. stallEndpoint (pTarget, pTrb->endpointId);
  1654. }
  1655.     if ((pTrb->state & TCD_ENDPOINT_UNSTALL) != 0 ||
  1656. (pTrb->state & TCD_ENDPOINT_DATA0) != 0)
  1657. {
  1658. d12SetEndpointStatus (pTarget, pTrb->endpointId, 0);
  1659. }
  1660.     return OK;
  1661.     }
  1662. /***************************************************************************
  1663. *
  1664. * fncCurrentFrameGet - Returns current USB frame number
  1665. *
  1666. * Certain applications, particularly those using isochronous data transfers,
  1667. * need to know the current USB frame number.  This function returns the
  1668. * most recently decoded USB frame number (as encoded in the USB SOF packet).
  1669. *
  1670. * RETURNS: OK or S_usbTcdLib_xxxx if an error is detected
  1671. */
  1672. LOCAL int fncCurrentFrameGet
  1673.     (
  1674.     pTRB_CURRENT_FRAME_GET pTrb,
  1675.     pTARGET pTarget
  1676.     )
  1677.     {
  1678.     pTrb->frameNo = d12ReadCurrentFrameNumber (pTarget);
  1679.     return OK;
  1680.     }
  1681. /***************************************************************************
  1682. *
  1683. * fncErpSubmit - Submits an ERP for subsequent data transfer
  1684. *
  1685. * All data transfers across the USB are managed through ERPs (Endpoint
  1686. * Request Packets).  These ERPs are analogous to the IRPs used by the host
  1687. * to manage data transfers.
  1688. *
  1689. * RETURNS: OK or S_usbTcdLib_xxxx if an error is detected
  1690. */
  1691. LOCAL int fncErpSubmit
  1692.     (
  1693.     pTRB_ERP_SUBMIT pTrb,
  1694.     pTARGET pTarget
  1695.     )
  1696.     {
  1697.     pUSB_ERP pErp = pTrb->pErp;
  1698.     /* Enqueue the ERP for the corresponding endpoint. */
  1699.     usbListLink (&pTarget->erps [pErp->endpointId], pErp, &pErp->tcdLink,
  1700. LINK_TAIL);
  1701.     pTarget->endpointNeedsService [pErp->endpointId] = TRUE;
  1702.     OSS_SEM_GIVE (pTarget->intPending);
  1703.     return OK;
  1704.     }
  1705. /***************************************************************************
  1706. *
  1707. * fncErpCancel - Cancels an ERP 
  1708. *
  1709. * This function allows the caller to cancel an ERP which was previously
  1710. * submitted for execution by calling fncErpSubmit().  It may or may not
  1711. * be possible to cancel the ERP (depending on whether or not the ERP has
  1712. * already completed processing).
  1713. *
  1714. * RETURNS: OK or S_usbTcdLib_xxxx if an error is detected
  1715. */
  1716. LOCAL int fncErpCancel
  1717.     (
  1718.     pTRB_ERP_CANCEL pTrb,
  1719.     pTARGET pTarget
  1720.     )
  1721.     {
  1722.     return cancelErp (pTarget, pTrb->pErp);
  1723.     }
  1724. /***************************************************************************
  1725. *
  1726. * usbTcdPdiusbd12EvalExec - USB_TCD_EXEC_FUNC entry point for PDIUSBD12 TCD
  1727. *
  1728. * This is the primary entry point for the Philips PDIUSBD12 (ISA eval version)
  1729. * USB TCD (Target Controller Driver).  The function qualifies the TRB passed
  1730. * by the caller and fans out to the appropriate TCD function handler.
  1731. *
  1732. * RETURNS: OK or ERROR if failed to execute TRB passed by caller
  1733. *
  1734. * ERRNO:
  1735. *   S_usbTcdLib_BAD_PARAM
  1736. *   S_usbTcdLib_BAD_HANDLE
  1737. *   S_usbTcdLib_SHUTDOWN
  1738. */
  1739. STATUS usbTcdPdiusbd12EvalExec
  1740.     (
  1741.     pVOID pTrb     /* TRB to be executed */
  1742.     )
  1743.     {
  1744.     pTRB_HEADER pHeader = (pTRB_HEADER) pTrb;
  1745.     pTARGET pTarget = NULL;
  1746.     int status;
  1747.     
  1748.     /* Validate parameters */
  1749.     if (pHeader == NULL || pHeader->trbLength < sizeof (TRB_HEADER))
  1750. return ossStatus (S_usbTcdLib_BAD_PARAM);
  1751.     if (pHeader->function != TCD_FNC_ATTACH)
  1752. {
  1753. if ((pTarget = (pTARGET) pHeader->handle) == NULL)
  1754.     return ossStatus (S_usbTcdLib_BAD_HANDLE);
  1755. if (pTarget->shutdown)
  1756.     return ossStatus (S_usbTcdLib_SHUTDOWN);
  1757. }
  1758.     /* Guard against other tasks */
  1759.     if (pHeader->function != TCD_FNC_ATTACH && 
  1760. pHeader->function != TCD_FNC_DETACH)
  1761. {
  1762. OSS_MUTEX_TAKE (pTarget->tcdMutex, OSS_BLOCK);
  1763. }
  1764.     /* Fan-out to appropriate function processor */
  1765.     switch (pHeader->function)
  1766. {
  1767. case TCD_FNC_ATTACH:
  1768.     status = fncAttach ((pTRB_ATTACH) pHeader);
  1769.     break;
  1770. case TCD_FNC_DETACH:
  1771.     status = fncDetach ((pTRB_DETACH) pHeader, pTarget);
  1772.     break;
  1773. case TCD_FNC_ENABLE:
  1774.     status = fncEnable ((pTRB_ENABLE_DISABLE) pHeader, pTarget);
  1775.     break;
  1776. case TCD_FNC_DISABLE:
  1777.     status = fncDisable ((pTRB_ENABLE_DISABLE) pHeader, pTarget);
  1778.     break;
  1779. case TCD_FNC_ADDRESS_SET:
  1780.     status = fncAddressSet ((pTRB_ADDRESS_SET) pHeader, pTarget);
  1781.     break;
  1782. case TCD_FNC_ENDPOINT_ASSIGN:
  1783.     status = fncEndpointAssign ((pTRB_ENDPOINT_ASSIGN) pHeader, pTarget);
  1784.     break;
  1785. case TCD_FNC_ENDPOINT_RELEASE:
  1786.     status = fncEndpointRelease ((pTRB_ENDPOINT_RELEASE) pHeader, pTarget);
  1787.     break;
  1788. case TCD_FNC_SIGNAL_RESUME:
  1789.     status = fncSignalResume ((pTRB_SIGNAL_RESUME) pHeader, pTarget);
  1790.     break;
  1791. case TCD_FNC_ENDPOINT_STATE_SET:
  1792.     status = fncEndpointStateSet ((pTRB_ENDPOINT_STATE_SET) pHeader, pTarget);
  1793.     break;
  1794. case TCD_FNC_CURRENT_FRAME_GET:
  1795.     status = fncCurrentFrameGet ((pTRB_CURRENT_FRAME_GET) pHeader, pTarget);
  1796.     break;
  1797. case TCD_FNC_ERP_SUBMIT:
  1798.     status = fncErpSubmit ((pTRB_ERP_SUBMIT) pHeader, pTarget);
  1799.     break;
  1800. case TCD_FNC_ERP_CANCEL:
  1801.     status = fncErpCancel ((pTRB_ERP_CANCEL) pHeader, pTarget);
  1802.     break;
  1803. default:
  1804.     status = S_usbTcdLib_BAD_PARAM;
  1805.     break;
  1806. }
  1807.     /* Release guard mutex */
  1808.     if (pHeader->function != TCD_FNC_ATTACH && 
  1809. pHeader->function != TCD_FNC_DETACH)
  1810. {
  1811. OSS_MUTEX_RELEASE (pTarget->tcdMutex);
  1812. }
  1813.     /* Return status */
  1814.     return ossStatus (status);
  1815.     }
  1816. /* End of file. */