usbdCoreLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:93k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* usbdCoreLib.c - USBD core logic */
  2. /* Copyright 2000-2002 Wind River Systems, Inc. */
  3. /*
  4. Modification history
  5. --------------------
  6. 01l,08nov01,wef  USBD_NODE struture element changed from hubStatus to 
  7.  pHubStatus, reflect this change
  8. 01k,25oct01,wef  repalce automatic buffer creations with calls to OSS_MALLOC
  9.  in places where the buffer is passed to the hardware (related 
  10.  to SPR 70492).
  11. 01j,18sep01,wef  merge from wrs.tor2_0.usb1_1-f for veloce
  12. 01i,08aug01,dat  Removing warnings
  13. 01h,12aug00,bri  Modify interrogateDeviceClass() to 
  14.  1. Allow multifunction devices that belong to same USB class
  15.     but have interfaces belonging to different subclasses.
  16.  2. Store the configuration Value as mentioned in the 
  17.     configuration descriptor in the nodeClass.
  18.  3. Ensure nodeclasses are created for all devices.
  19. 01g,20mar00,rcb  Add USB_DEVICE_DESCR field to USBD_NODE.
  20. 01f,17jan00,rcb  Modify interrogateDeviceClass() to use usbConfigDescrGet()...
  21.  ensures that all descriptors associated with a configuration
  22.  descriptor will be read, even if the total length is very long.
  23. 01e,20dec99,rcb  Fix benign bug in fncConfigSet() regarding pRoot.
  24.  Fix benign bug in HCD detach logic which detached the HCD
  25.  before deleting all pipes.
  26. 01d,23nov99,rcb  Replace HCD bandwidth alloc/release with pipe create/destroy
  27.  in order to generalize approach for OHCI HCD.
  28. 01c,24sep99,rcb  Change packet count calculation in transferIrpCallback()
  29.  to handle case where a single 0-length packet is transferred.
  30. 01b,07sep99,rcb  Add support for management callbacks and set-bus-state API.
  31. 01a,08jun99,rcb  First.
  32. */
  33. /*
  34. DESCRIPTION
  35. This module contains the primary USBD entry point, usbdUrbExec() and the
  36. individual USBD function execution routines.  usbdUrbExec() is responsible for 
  37. interpreting each URB's function code and then fanning-out to the individual 
  38. function processor.  
  39. IMPLEMENTATION NOTES
  40. When the USBD is first initialized it creates an internal "client" which is 
  41. used by the USBD when performing control pipe transfers to each hub/device.  This
  42. "client" remains active until the USBD is shut down.
  43. For each client registered with the USBD, including the internal client, the USBD
  44. allocates an individual task, and that task inherits the priority of the client
  45. task which invokes the usbdClientRegister() function.  This task is normally 
  46. inactive, and only wakes up when a client callback is to be executed.  Therefore, 
  47. each client's callbacks are invoked on a task which is unique to that client.
  48. Other USBD tasks (see below) are therefore shielded from the behavoir of an
  49. individual client's callback routine.
  50. For each USB which is attached to the USBD through the usbdHcdAttach() function,
  51. the USBD also creates a unique "bus monitor" task.  This task is responsible
  52. for configuring and monitoring each hub on a given USB.  Whenever a hub or device
  53. is attached/removed from the USB, the bus monitor thread is responsible for
  54. updating internal data structures, configuring/re-configuring hubs, and for
  55. triggering "dynamic attach/removal" callbacks - which themselves are performed by
  56. each individual client's callback task.
  57. All USBD internal data structures, e.g., client lists, HCD lists and releated
  58. node structures, are protected by a single mutex, structMutex. All threads which
  59. rely on the stability of internal data structures or which can modify internal
  60. data structures take this mutex.  usbdCoreEntry() is the single entry point
  61. responsible for taking this mutex when clients invoke the USBD.  Each "bus
  62. monitor" thread also takes this mutex each time it may update bus structures.  
  63. IRP callback, however, do not take the mutex.  While certain IRP "userPtr" fields
  64. may point to other USBD structures, the organization of the code guarantees that
  65. IRPs will be completed or canceled prior to dismantling the USBD structures with
  66. which they are associated.
  67. */
  68. /* defines */
  69. #define USBD_VERSION 0x0001     /* USBD version in BCD */
  70. #define USBD_MFG "Wind River Systems, Inc."  /* USBD Mfg */
  71. #define INTERNAL_CLIENT_NAME "usbd"
  72. /* includes */
  73. #include "usb/usbPlatform.h"
  74. #include "string.h"
  75. #include "usb/ossLib.h"
  76. #include "usb/usbQueueLib.h"
  77. #include "usb/usbLib.h"  /* USB utility functions */
  78. #include "usb/usbdCoreLib.h" /* our API */
  79. #include "drv/usb/usbHcd.h" /* HCD interface */
  80. #include "usb/usbHcdLib.h" /* HCD function library */
  81. #include "usb/usbdStructures.h" /* usbdCoreLib data structures */
  82. /* defines */
  83. #define PENDING  1
  84. #define CALLBACK_Q_DEPTH 128 /* Needs to be fairly deep to handle */
  85. /* a potentially large number of */
  86. /* notification callbacks */
  87. #define BUS_Q_DEPTH 32 /* Outstanding bus service requests */
  88. /* clientThread request codes...stored in msg field of OSS_MESSAGE. */
  89. #define CALLBACK_FNC_TERMINATE     0 /* Terminate the callback thread */
  90. #define CALLBACK_FNC_IRP_COMPLETE   1 /* issue an IRP completion callback */
  91. #define CALLBACK_FNC_NOTIFY_ATTACH  2 /* issue an attach callback */
  92. #define CALLBACK_FNC_MNGMT_EVENT    3 /* management event callback */
  93. #define CALLBACK_TIMEOUT 5000 /* Wait 5 seconds for callback to */
  94. /* exit in response to terminate fnc */
  95. /* busThread request codes...stored in msg field of OSS_MESSAGE. */
  96. #define BUS_FNC_TERMINATE 0 /* Terminate the bus monitor thread */
  97. #define BUS_FNC_UPDATE_HUB 1 /* update a hub */
  98. #define BUS_TIMEOUT 5000 /* Wait 5 seconds for bus monitor */
  99. /* thread to terminate */
  100. /* general timeout */
  101. #define IO_TIMEOUT 5000 /* 5 seconds */
  102. #define EXCLUSION_TIMEOUT 10000 /* 10 seconds */
  103. /* HUB_STATUS_LEN() returns length of status structure for indicated hub node */
  104. #define HUB_STATUS_LEN(pNode)
  105.     min ((pNode->numPorts + 1 + 7) / 8, (int) MAX_HUB_STATUS_LEN)
  106. /* Constants used by resetDataToggle(). */
  107. #define ANY_CONFIGURATION 0xffff
  108. #define ANY_INTERFACE 0xffff
  109. #define ANY_ENDPOINT 0xffff
  110. /* typedefs */
  111. /* NOTIFICATION
  112.  * 
  113.  * Created by notifyIfMatch() and consumed by client's callback thread.
  114.  */
  115. typedef struct notification
  116.     {
  117.     USBD_ATTACH_CALLBACK callback; /* client's callback routine */
  118.     USBD_NODE_ID nodeId; /* node being attached/removed */
  119.     UINT16 attachCode; /* attach code */
  120.     UINT16 configuration; /* config matching notify request */
  121.     UINT16 interface; /* interface matching notify request */
  122.     UINT16 deviceClass;  /* device/interface class */
  123.     UINT16 deviceSubClass; /* device/interface sub class */
  124.     UINT16 deviceProtocol; /* device/interface protcol */
  125.     } NOTIFICATION, *pNOTIFICATION;
  126. /* locals */
  127. LOCAL int initCount = 0;
  128. LOCAL MUTEX_HANDLE structMutex = NULL; /* guards USBD structures */
  129. LOCAL LIST_HEAD hcdList = {0}; /* List of attached HCDs */
  130. LOCAL LIST_HEAD clientList = {0}; /* list of registered clients */
  131. LOCAL USBD_CLIENT_HANDLE internalClient = NULL; /* internal client */
  132. /* forward declarations */
  133. LOCAL BOOL initHubIrp
  134.     (
  135.     pUSBD_NODE pNode
  136.     );
  137. LOCAL pUSBD_NODE createNode 
  138.     (
  139.     pUSBD_BUS pBus,     /* node's parent bus */
  140.     USBD_NODE_ID rootId,     /* root id */
  141.     USBD_NODE_ID parentHubId,     /* parent hub id */
  142.     UINT16 parentHubPort,     /* parent hub port no */
  143.     UINT16 nodeSpeed,     /* node speed */
  144.     UINT16 topologyDepth     /* this node's depth in topology */
  145.     );
  146. /* functions */
  147. /***************************************************************************
  148. *
  149. * validateClient - Determines if a client handle is valid
  150. *
  151. * RETURNS: TRUE if client valid, else FALSE
  152. */
  153. LOCAL BOOL validateClient
  154.     (
  155.     USBD_CLIENT_HANDLE clientHandle, /* client to be validated */
  156.     pUSBD_CLIENT *ppClient /* ptr to USBD_CLIENT if valid */
  157.     )
  158.     {
  159.     if (usbHandleValidate (clientHandle, USBD_CLIENT_SIG, (pVOID *) ppClient) 
  160. != OK)
  161. return FALSE;
  162.     return TRUE;
  163.     }
  164. /***************************************************************************
  165. *
  166. * validateNode - Determines if a node handle is valid
  167. *
  168. * RETURNS: TRUE if node valid, else FALSE
  169. */
  170. LOCAL BOOL validateNode
  171.     (
  172.     USBD_NODE_ID nodeId,     /* Node to be validated */
  173.     pUSBD_NODE *ppNode     /* ptr to USBD_NODE if valid */
  174.     )
  175.     {
  176.     if (usbHandleValidate (nodeId, USBD_NODE_SIG, (pVOID *) ppNode) != OK ||
  177. (*ppNode)->nodeDeletePending)
  178. return FALSE;
  179.     return TRUE;
  180.     }
  181. /***************************************************************************
  182. *
  183. * validatePipe - Determines if a pipe is valid
  184. *
  185. * RETURNS: TRUE if pipe valid, else FALSE
  186. */
  187. LOCAL BOOL validatePipe
  188.     (
  189.     USBD_PIPE_HANDLE pipeHandle,    /* pipe to be validated */
  190.     pUSBD_PIPE *ppPipe     /* ptr to USBD_PIPE if valid */
  191.     )
  192.     {
  193.     if (usbHandleValidate (pipeHandle, USBD_PIPE_SIG, (pVOID *) ppPipe) != OK ||
  194. (*ppPipe)->pipeDeletePending || (*ppPipe)->pNode->nodeDeletePending)
  195. return FALSE;
  196.     return TRUE;
  197.     }
  198. /***************************************************************************
  199. *
  200. * validateUrb - Performs validation checks on URB
  201. *
  202. * Checks the URB length set in the URB_HEADER against the <expectedLen>
  203. * passed by the caller.  If <pClient> is not NULL, also attempts to
  204. * validate the USBD_CLIENT_HANDLE.  If successful, stores the client
  205. * handle in <pClient>
  206. *
  207. * RETURNS: S_usbdLib_xxxx
  208. */
  209. LOCAL int validateUrb
  210.     (
  211.     pVOID pUrb,
  212.     UINT16 expectedLen,
  213.     pUSBD_CLIENT *ppClient
  214.     )
  215.     {
  216.     pURB_HEADER pHeader = (pURB_HEADER) pUrb;
  217.     if (initCount == 0)
  218. return S_usbdLib_NOT_INITIALIZED;
  219.     if (pHeader->urbLength != expectedLen)
  220. return S_usbdLib_BAD_PARAM;
  221.     if (ppClient != NULL)
  222. {
  223. if (!validateClient (pHeader->handle, ppClient))
  224.     {
  225.     return S_usbdLib_BAD_HANDLE;
  226.     }
  227. }
  228.     return OK;
  229.     }
  230. /***************************************************************************
  231. *
  232. * setUrbResult - Sets URB_HEADER.status and .result fields
  233. *
  234. * Based on the <result> parameter passed by the caller, set the 
  235. * status and result fields in the URB_HEADER of <pUrb>. 
  236. *
  237. * RETURNS: Value of <result> parameter
  238. */
  239. LOCAL int setUrbResult
  240.     (
  241.     pURB_HEADER pUrb, /* Completed URB */
  242.     int result /* S_usbdLib_xxxx code */
  243.     )
  244.     {
  245.     if (result != PENDING)
  246. {
  247. pUrb->result = result;
  248. if (pUrb->callback != NULL)
  249.     (*pUrb->callback) (pUrb);
  250. }
  251.     return result;
  252.     }
  253. /***************************************************************************
  254. *
  255. * doShutdown - Shut down USBD core lib
  256. *
  257. * RETURNS: N/A
  258. */
  259. LOCAL VOID doShutdown (void)
  260.     {
  261.     /* unregister any clients which may still be registered */
  262.     pUSBD_CLIENT pClient;
  263.     pUSBD_HCD pHcd;
  264.     while ((pClient = usbListFirst (&clientList)) != NULL)
  265. usbdClientUnregister (pClient->handle);
  266.     /* detach any HCDs which may still be attached */
  267.     while ((pHcd = usbListFirst (&hcdList)) != NULL)
  268. usbdHcdDetach (pHcd->attachToken);
  269.     /* release the structure guard mutex */
  270.     if (structMutex != NULL)
  271. {
  272. OSS_MUTEX_DESTROY (structMutex);
  273. structMutex = NULL;
  274. }
  275.     /* Shut down libraries */
  276.     usbHandleShutdown ();
  277.     ossShutdown ();
  278.     }
  279. /***************************************************************************
  280. *
  281. * fncInitialize - Initialize USBD
  282. *
  283. * RETURNS: S_usbdLib_xxxx
  284. */
  285. LOCAL int fncInitialize
  286.     (
  287.     pURB_HEADER pUrb
  288.     )
  289.     {
  290.     int s = OK;
  291.     if (initCount == 0)
  292. {
  293. /* Initialize the osServices library */
  294. if (ossInitialize () != OK)
  295.     return S_usbdLib_GENERAL_FAULT;
  296. if (usbHandleInitialize (0 /* use default */) != OK)
  297.     {
  298.     ossShutdown ();
  299.     return S_usbdLib_GENERAL_FAULT;
  300.     }
  301.     
  302. ++initCount;
  303. /* Initialize the lists of HCDs and clients */
  304. if (OSS_MUTEX_CREATE (&structMutex) != OK)
  305.     s = S_usbdLib_OUT_OF_RESOURCES;
  306. memset (&hcdList, 0, sizeof (hcdList));
  307. memset (&clientList, 0, sizeof (clientList));
  308. }
  309.     if (s == OK)
  310. {
  311. /* Register an internal client for hub I/O, etc. */
  312. internalClient = NULL;
  313. if (usbdClientRegister (INTERNAL_CLIENT_NAME, &internalClient) != OK)
  314.     s = S_usbdLib_GENERAL_FAULT;
  315. }
  316.     if (s != OK)
  317. {
  318. doShutdown ();
  319. initCount = 0;
  320. }
  321.     return s;
  322.     }
  323. /***************************************************************************
  324. *
  325. * fncShutdown - Shuts down USBD
  326. *
  327. * RETURNS: S_usbdLib_xxxx
  328. */
  329. LOCAL int fncShutdown
  330.     (
  331.     pURB_HEADER pUrb
  332.     )
  333.     {
  334.     int s;
  335.     /* validate URB */
  336.     if ((s = validateUrb (pUrb, sizeof (*pUrb), NULL)) != OK)
  337. return s;
  338.     if (initCount == 1)
  339. doShutdown ();
  340.     --initCount;
  341.     return s;
  342.     }
  343. /***************************************************************************
  344. *
  345. * clientThread - client callback thread
  346. *
  347. * A separate clientThread() thread is spawned for each registered
  348. * client.  This thread is responsible for invoking client callback
  349. * routines.  Using a separate callback thread for each client helps to
  350. * ensure that one client's behavior (such as blocking) won't affect the
  351. * throughput of other client requests.
  352. *
  353. * By convention, the <param> is a pointer to the USBD_CLIENT structure
  354. * for the associated client.  This thread waits on the callback queue
  355. * in the client structure.  At the time this thread is first created,
  356. * the USBD_CLIENT structure is only guaranteed to have an initialized
  357. * queue...other fields may not yet be initialized.
  358. *
  359. * NOTE: This thread does not need to take the structMutex.  The mainline
  360. * code ensures that the clientThread() for a given USBD_CLIENT is
  361. * terminated prior to dismantling the USBD_CLIENT structure.
  362. *
  363. * RETURNS: N/A
  364. */
  365. LOCAL VOID clientThread
  366.     (
  367.     pVOID param      /* thread parameter */
  368.     )
  369.     {
  370.     pUSBD_CLIENT pClient = (pUSBD_CLIENT) param;
  371.     USB_MESSAGE msg;
  372.     pUSB_IRP pIrp;
  373.     pNOTIFICATION pNotification;
  374.     
  375.     /* Execute messages from the callbackQueue until a CLIENT_FNC_TERMINATE
  376.     message is received. */
  377.     do
  378. {
  379. if (usbQueueGet (pClient->callbackQueue, &msg, OSS_BLOCK) != OK)
  380.     break;
  381. switch (msg.msg)
  382.     {
  383.     case CALLBACK_FNC_IRP_COMPLETE:
  384. /* invoke a client's IRP callback routine.  The msg.lParam
  385.  * is a pointer to the completed USB_IRP.
  386.  */
  387. pIrp = (pUSB_IRP) msg.lParam;
  388. if (pIrp->userCallback != NULL)
  389.     (*pIrp->userCallback) (pIrp);
  390. break;
  391.     case CALLBACK_FNC_NOTIFY_ATTACH:
  392. /* invoke a client's dynamic attach routine.  The msg.lParam
  393.  * is a pointer to a NOTIFICATION structure.  
  394.  *
  395.  * NOTE: We dispose of the NOTIFICATION request after
  396.  * consuming it.
  397.  */
  398. pNotification = (pNOTIFICATION) msg.lParam;
  399. (*pNotification->callback) (pNotification->nodeId, 
  400.     pNotification->attachCode, pNotification->configuration, 
  401.     pNotification->interface, pNotification->deviceClass, 
  402.     pNotification->deviceSubClass, 
  403.     pNotification->deviceProtocol);
  404. OSS_FREE (pNotification);
  405. break;
  406.     
  407.     case CALLBACK_FNC_MNGMT_EVENT:
  408. /* invoke a client's managment callback routine.  The 
  409.  * msg.wParam is the management code and the msg.lParam is
  410.  * the USBD_NODE_ID of the root for the affected bus.
  411.  */
  412. if (pClient->mngmtCallback != NULL)
  413.     (*pClient->mngmtCallback) (pClient->mngmtCallbackParam,
  414. (USBD_NODE_ID) msg.lParam, msg.wParam);
  415. break;
  416.     }
  417. }
  418.     while (msg.msg != CALLBACK_FNC_TERMINATE);
  419.     /* Mark the callback routine as having terminated. */
  420.     OSS_SEM_GIVE (pClient->callbackExit);
  421.     }
  422. /***************************************************************************
  423. *
  424. * doTransferAbort - Cancel an outstanding IRP
  425. *
  426. * Directs the HCD to cancel the IRP and waits for the IRP callback to
  427. * be invoked signalling that the IRP has been unlinked successfully.
  428. *
  429. * RETURNS: S_usbdLib_xxxx
  430. */
  431. LOCAL int doTransferAbort
  432.     (
  433.     pUSBD_PIPE pPipe,     /* Pipe owning transfer */
  434.     pUSB_IRP pIrp     /* IRP to be cancelled */
  435.     )
  436.     {
  437.     /* The callback which indicates that an IRP has been deleted is
  438.      * asynchronous.  However, when deleting an IRP (such as when
  439.      * destroying a pipe) we generally need to know when the IRP
  440.      * callback has actually been invoked - and hence the IRP unlinked
  441.      * from the list of outstanding IRPs on the pipe.
  442.      */
  443.     pPipe->irpBeingDeleted = pIrp;
  444.     pPipe->irpDeleted = FALSE;
  445.     /* Instruct the HCD to cancel the IRP */
  446.     if (usbHcdIrpCancel (&pPipe->pNode->pBus->pHcd->nexus, pIrp) != OK)
  447. return S_usbdLib_CANNOT_CANCEL;
  448.     /* Wait for the IRP callback to be invoked. */
  449.     while (!pPipe->irpDeleted)
  450. OSS_THREAD_SLEEP (1);
  451.     return OK;
  452.     }
  453. /***************************************************************************
  454. *
  455. * destroyNotify - de-allocates a USBD_NOTIFY_REQ
  456. *
  457. * RETURNS: N/A
  458. */
  459. LOCAL VOID destroyNotify
  460.     (
  461.     pUSBD_NOTIFY_REQ pNotify
  462.     )
  463.     {
  464.     usbListUnlink (&pNotify->reqLink);
  465.     OSS_FREE (pNotify);
  466.     }
  467. /***************************************************************************
  468. *
  469. * destroyPipe - de-allocates a USBD_PIPE and its resources
  470. *
  471. * RETURNS: N/A
  472. */
  473. LOCAL VOID destroyPipe
  474.     (
  475.     pUSBD_PIPE pPipe
  476.     )
  477.     {
  478.     pUSB_IRP pIrp;
  479.     pUSBD_BUS pBus;
  480.     if (pPipe != NULL)
  481. {
  482. pPipe->pipeDeletePending = TRUE;
  483. /* Cancel all IRPs outstanding on this pipe.
  484.  *
  485.  * NOTE: Since the IRP completion callbacks are on a different thread,
  486.  * we need to wait until all callbacks have been completed.  This
  487.  * functionality is built into doTransferAbort().
  488.  */
  489. while ((pIrp = usbListFirst (&pPipe->irps)) != NULL)
  490.     doTransferAbort (pPipe, pIrp);
  491. /* Release bandwidth and notify HCD that the pipe is going away. */
  492. pBus = pPipe->pNode->pBus;
  493. pBus->nanoseconds -= pPipe->nanoseconds;
  494. usbHcdPipeDestroy (&pBus->pHcd->nexus, pPipe->hcdHandle);
  495. /* Unlink pipe from owning client's list of pipes */
  496. if (pPipe->pClient != NULL)
  497.     usbListUnlink (&pPipe->clientPipeLink);
  498. /* Unlink pipe from owning node's list of pipes */
  499. if (pPipe->pNode != NULL)
  500.     usbListUnlink (&pPipe->nodePipeLink);
  501. /* Release pipe handle */
  502. if (pPipe->handle != NULL)
  503.     usbHandleDestroy (pPipe->handle);
  504. OSS_FREE (pPipe);
  505. }
  506.     }
  507. /***************************************************************************
  508. *
  509. * destroyClient - tears down a USBD_CLIENT structure
  510. *
  511. * RETURNS: N/A
  512. */
  513. LOCAL VOID destroyClient
  514.     (
  515.     pUSBD_CLIENT pClient
  516.     )
  517.     {
  518.     pUSBD_NOTIFY_REQ pNotify;
  519.     pUSBD_PIPE pPipe;
  520.     pUSBD_HCD pHcd;
  521.     UINT16 busNo;
  522.     
  523.     /* unlink client from list of clients.
  524.      *
  525.      * NOTE: usbListUnlink is smart and only unlinks the structure if it is
  526.      * actually linked.
  527.      */
  528.     usbListUnlink (&pClient->clientLink);
  529.     /* destroy all notification requests outstanding for the client */
  530.     while ((pNotify = usbListFirst (&pClient->notifyReqs)) != NULL)
  531. destroyNotify (pNotify);
  532.     /* destroy all pipes owned by this client */
  533.     while ((pPipe = usbListFirst (&pClient->pipes)) != NULL)
  534. destroyPipe (pPipe);
  535.     /* If this client is the current SOF master for any USBs, then release
  536.      * the SOF master status.
  537.      */
  538.     pHcd = usbListFirst (&hcdList);
  539.     while (pHcd != NULL)
  540. {
  541. for (busNo = 0; busNo < pHcd->busCount; busNo++)
  542.     if (pHcd->pBuses [busNo].pSofMasterClient == pClient)
  543. pHcd->pBuses [busNo].pSofMasterClient = NULL;
  544. pHcd = usbListNext (&pHcd->hcdLink);
  545. }
  546.     /* Note: callbackQueue is always created after callbackExit and
  547.      * before callbackThread
  548.      */
  549.     if (pClient->callbackThread != NULL)
  550. {
  551. /* Terminate the client callback thread */
  552. usbQueuePut (pClient->callbackQueue, CALLBACK_FNC_TERMINATE,
  553.     0, 0, CALLBACK_TIMEOUT);
  554. OSS_SEM_TAKE (pClient->callbackExit, CALLBACK_TIMEOUT);
  555. OSS_THREAD_DESTROY (pClient->callbackThread);
  556. }
  557.     if (pClient->callbackQueue != NULL)
  558. usbQueueDestroy (pClient->callbackQueue);
  559.     if (pClient->callbackExit != NULL)
  560. OSS_SEM_DESTROY (pClient->callbackExit);
  561.     if (pClient->handle != NULL)
  562. usbHandleDestroy (pClient->handle);
  563.     OSS_FREE (pClient);
  564.     }
  565. /***************************************************************************
  566. *
  567. * fncClientReg - Register a new USBD client
  568. *
  569. * RETURNS: S_usbdLib_xxxx
  570. */
  571. LOCAL int fncClientReg
  572.     (
  573.     pURB_CLIENT_REG pUrb
  574.     )
  575.     {
  576.     pUSBD_CLIENT pClient;
  577.     int s;
  578.     /* validate URB */
  579.     if ((s = validateUrb (pUrb, sizeof (*pUrb), NULL)) != OK)
  580. return s;
  581.     /* Create structures/resources/etc., required by new client */
  582.     if ((pClient = OSS_CALLOC (sizeof (*pClient))) == NULL)
  583. return S_usbdLib_OUT_OF_MEMORY;
  584.     memcpy (pClient->clientName, pUrb->clientName, USBD_NAME_LEN);
  585.     if (usbHandleCreate (USBD_CLIENT_SIG, pClient, &pClient->handle) != OK ||
  586. OSS_SEM_CREATE (1, 0, &pClient->callbackExit) != OK ||
  587. usbQueueCreate (CALLBACK_Q_DEPTH, &pClient->callbackQueue) != OK ||
  588. OSS_THREAD_CREATE (clientThread, pClient, OSS_PRIORITY_INHERIT, 
  589.     "tUsbdClnt", &pClient->callbackThread) != OK)
  590.     s = S_usbdLib_OUT_OF_RESOURCES;
  591.     else
  592. {
  593. /* The client was initialized successfully. Add it to the list */
  594. usbListLink (&clientList, pClient, &pClient->clientLink, LINK_TAIL);
  595. /* return the client's USBD_CLIENT_HANDLE */
  596. pUrb->header.handle = pClient->handle;
  597. }
  598.     if (s != OK)
  599. {
  600. destroyClient (pClient);
  601. }
  602.     return s;
  603.     }
  604. /***************************************************************************
  605. *
  606. * fncClientUnreg - Unregister a USBD client
  607. *
  608. * RETURNS: S_usbdLib_xxxx
  609. */
  610. LOCAL int fncClientUnreg
  611.     (
  612.     pURB_CLIENT_UNREG pUrb
  613.     )
  614.     {
  615.     pUSBD_CLIENT pClient;
  616.     int s;
  617.     /* validate Urb */
  618.     if ((s = validateUrb (pUrb, sizeof (*pUrb), &pClient)) != OK)
  619. return s;
  620.     /* destroy client */
  621.     destroyClient (pClient);
  622.     return s;
  623.     }
  624. /***************************************************************************
  625. *
  626. * fncMngmtCallbackSet - sets management callback for a client
  627. *
  628. * RETURNS: S_usbdLib_xxxx
  629. */
  630. LOCAL int fncMngmtCallbackSet
  631.     (
  632.     pURB_MNGMT_CALLBACK_SET pUrb
  633.     )
  634.     {
  635.     pUSBD_CLIENT pClient;
  636.     int s;
  637.     /* validate URB */
  638.     if ((s = validateUrb (pUrb, sizeof (*pUrb), &pClient)) != OK)
  639. return s;
  640.     /* Set the management callback */
  641.     pClient->mngmtCallback = pUrb->mngmtCallback;
  642.     pClient->mngmtCallbackParam = pUrb->mngmtCallbackParam;
  643.     return s;
  644.     }
  645. /***************************************************************************
  646. *
  647. * fncVersionGet - Return USBD version
  648. *
  649. * RETURNS: S_usbdLib_xxxx
  650. */
  651. LOCAL int fncVersionGet
  652.     (
  653.     pURB_VERSION_GET pUrb
  654.     )
  655.     {
  656.     int s;
  657.     /* validate urb */
  658.     if ((s = validateUrb (pUrb, sizeof (*pUrb), NULL)) != OK)
  659. return s;
  660.     /* return version information */
  661.     pUrb->version = USBD_VERSION;
  662.     strncpy ((char *)pUrb->mfg, USBD_MFG, USBD_NAME_LEN);
  663.     return s;
  664.     }
  665. /***************************************************************************
  666. *
  667. * releaseAddress - release a USB device address
  668. *
  669. * RETURNS: N/A
  670. */
  671. LOCAL VOID releaseAddress
  672.     (
  673.     pUSBD_NODE pNode
  674.     )
  675.     {
  676.     pUSBD_BUS pBus = pNode->pBus;
  677.     pBus->adrsVec [pNode->busAddress / 8] &= ~(0x1 << (pNode->busAddress % 8));
  678.     }
  679. /***************************************************************************
  680. *
  681. * assignAddress - assigns a unique USB address to a node
  682. *
  683. * RETURNS: TRUE if successful, else FALSE
  684. */
  685. LOCAL BOOL assignAddress
  686.     (
  687.     pUSBD_NODE pNode
  688.     )
  689.     {
  690.     pUSBD_BUS pBus = pNode->pBus;
  691.     UINT16 i;
  692.     /* Find an available address */
  693.     for (i = 1; i < USB_MAX_DEVICES; i++)
  694. {
  695. if ((pBus->adrsVec [i / 8] & (0x1 << (i % 8))) == 0)
  696.     {
  697.     /* i is the value of an unused address.  Set the device adrs. */
  698.     if (usbdAddressSet (internalClient, pNode->nodeHandle, i) == OK)
  699. {
  700. pNode->busAddress = i;
  701. pBus->adrsVec [i / 8] |= 0x1 << (i % 8);
  702. return TRUE;
  703. }
  704.     else
  705. {
  706. return FALSE;
  707. }
  708.     }
  709. }
  710.     return FALSE;
  711.     }
  712. /***************************************************************************
  713. *
  714. * notifyIfMatch - Invoke attach callback if appropriate.
  715. *
  716. * Compares the device class/subclass/protocol for <pClassType> and <pNotify>.
  717. * If the two match, then invokes the callback in <pNotify> with an attach
  718. * code of <attachCode>.
  719. *
  720. * RETURNS: N/A
  721. */
  722. LOCAL VOID notifyIfMatch
  723.     (
  724.     pUSBD_NODE pNode,
  725.     pUSBD_NODE_CLASS pClassType,
  726.     pUSBD_CLIENT pClient,
  727.     pUSBD_NOTIFY_REQ pNotify,
  728.     UINT16 attachCode
  729.     )
  730.     {
  731.     pNOTIFICATION pNotification;
  732.     /* Do the pClassType and pNotify structures contain matching class
  733.      * descriptions?
  734.      */
  735.     if (pNotify->deviceClass == USBD_NOTIFY_ALL ||
  736. pClassType->deviceClass == pNotify->deviceClass)
  737. {
  738. if (pNotify->deviceSubClass == USBD_NOTIFY_ALL ||
  739.     pClassType->deviceSubClass == pNotify->deviceSubClass)
  740.     {
  741.     if (pNotify->deviceProtocol == USBD_NOTIFY_ALL ||
  742. pClassType->deviceProtocol == pNotify->deviceProtocol)
  743. {
  744. /* We have a match.  Schedule the client attach callback. 
  745.  *
  746.  * NOTE: The pNotification structure is created here and
  747.  * released when consumed in the client callback thread.
  748.  *
  749.  * NOTE: In a very large USB topology (at least several
  750.  * dozen nodes) there is a chance that we could overrun
  751.  * a client's callback queue depending on the type of 
  752.  * notification requests the client has made.  If this happens,
  753.  * the following call to usbQueuePut() may block.  If *that*
  754.  * happens, there is a chance of a deadlock if the client's
  755.  * callback code - invoked from the clientThread() reenters
  756.  * the USBD.  A simple solution, if that situation is observed,
  757.  * is to increase the depth of the callback queue.
  758.  */
  759. if ((pNotification = OSS_CALLOC (sizeof (*pNotification))) 
  760.     != NULL)
  761.     {
  762.     pNotification->callback = pNotify->callback;
  763.     pNotification->nodeId = pNode->nodeHandle;
  764.     pNotification->attachCode = attachCode;
  765.     pNotification->configuration = pClassType->configuration;
  766.     pNotification->interface = pClassType->interface;
  767.     pNotification->deviceClass = pClassType->deviceClass;
  768.     pNotification->deviceSubClass = pClassType->deviceSubClass;
  769.     pNotification->deviceProtocol = pClassType->deviceProtocol;
  770.     usbQueuePut (pClient->callbackQueue, 
  771. CALLBACK_FNC_NOTIFY_ATTACH, 0, (UINT32) pNotification, 
  772. OSS_BLOCK);
  773.     }
  774. }
  775.     }
  776. }
  777.     }
  778. /***************************************************************************
  779. *
  780. * notifyClients - notify clients of a dynamic attach/removal
  781. *
  782. * Scans the clientList looking for clients who have requested dynamic
  783. * attach/removal notification for a class matching <pNode>.  If any
  784. * are found, their dynamic attach callback routines will be invoked
  785. * with an attach code of <attachCode>.
  786. *
  787. * RETURNS: N/A
  788. */
  789. LOCAL VOID notifyClients
  790.     (
  791.     pUSBD_NODE pNode,
  792.     UINT16 attachCode
  793.     )
  794.     {
  795.     pUSBD_CLIENT pClient;
  796.     pUSBD_NOTIFY_REQ pNotify;
  797.     pUSBD_NODE_CLASS pClassType;
  798.     /* Scan for clients which have requested dynamic attach notification. */
  799.     pClient = usbListFirst (&clientList);
  800.     while (pClient != NULL)
  801. {
  802. /* Walk through the list of notification requests for this client */
  803. pNotify = usbListFirst (&pClient->notifyReqs);
  804. while (pNotify != NULL)
  805.     {
  806.     /* Walk through the class types for this node, looking for one
  807.      * which matches the current client notification request.
  808.      */
  809.     pClassType = usbListFirst (&pNode->classTypes);
  810.     while (pClassType != NULL)
  811. {
  812. notifyIfMatch (pNode, pClassType, pClient, pNotify, attachCode);
  813. pClassType = usbListNext (&pClassType->classLink);
  814. }
  815.     pNotify = usbListNext (&pNotify->reqLink);
  816.     }
  817. pClient = usbListNext (&pClient->clientLink);
  818. }
  819.     }
  820. /***************************************************************************
  821. *
  822. * createNodeClass - Creates a USBD_NODE_CLASS structure
  823. *
  824. * Creates a USBD_NODE_CLASS structure, initializes it with the passed
  825. * parameters, and attaches it to the <pNode>.
  826. *
  827. * RETURNS: TRUE if successful, else FALSE if out of memory.
  828. */
  829. LOCAL BOOL createNodeClass
  830.     (
  831.     pUSBD_NODE pNode,
  832.     UINT16 configuration,
  833.     UINT16 interface,
  834.     UINT16 deviceClass,
  835.     UINT16 deviceSubClass,
  836.     UINT16 deviceProtocol
  837.     )
  838.     {
  839.     pUSBD_NODE_CLASS pClassType;
  840.     if ((pClassType = OSS_CALLOC (sizeof (*pClassType))) == NULL)
  841. return FALSE;
  842.     pClassType->configuration = configuration;
  843.     pClassType->interface = interface;
  844.     pClassType->deviceClass = deviceClass;
  845.     pClassType->deviceSubClass = deviceSubClass;
  846.     pClassType->deviceProtocol = deviceProtocol;
  847.     usbListLink (&pNode->classTypes, pClassType, &pClassType->classLink,
  848. LINK_TAIL);
  849.     return TRUE;
  850.     }
  851. /***************************************************************************
  852. *
  853. * interrogateDeviceClass - Retrieve's device class information
  854. *
  855. * Interrogate the device class and construct one or more USBD_NODE_CLASS 
  856. * structures and attach them to <pNode>.  <deviceClass>, <deviceSubClass>,
  857. * and <deviceProtocol> are the device-level fields for this device.  If
  858. * <deviceClass> is 0, then this routine will automatically interrogate
  859. * the interface-level class information. If the information is provided
  860. * at the device level then the interfaces are not probed. 
  861. *
  862. * RETURNS: TRUE if successful, else FALSE if error.
  863. */
  864. LOCAL BOOL interrogateDeviceClass
  865.     (
  866.     pUSBD_NODE pNode,
  867.     UINT16 deviceClass,
  868.     UINT16 deviceSubClass,
  869.     UINT16 deviceProtocol
  870.     )
  871.     {
  872.     pUSB_CONFIG_DESCR pCfgDescr;
  873.     pUSB_INTERFACE_DESCR pIfDescr;
  874.     pUINT8 pCfgBfr;
  875.     pUINT8 pRemBfr;
  876.     UINT16 cfgLen;
  877.     UINT16 remLen;
  878.     UINT16 numConfig;
  879.     UINT8 configIndex;
  880.     BOOL retcode = TRUE;
  881.     UINT8 configValue = 1;
  882.     
  883.     /* If class information has been specified at the device level, then
  884.      * record it and return.
  885.      */
  886.     if ((deviceClass != 0) && (deviceSubClass != 0) && (deviceProtocol != 0))
  887. return createNodeClass (pNode, 0, 0, deviceClass, deviceSubClass,
  888.     deviceProtocol); 
  889.     /* Read the device descriptor to determine the number of configurations. */
  890.     if (usbConfigCountGet (internalClient, pNode->nodeHandle, &numConfig) != OK)
  891. return FALSE;
  892.   
  893.     /* Read and process each configuration. */
  894.     for (configIndex = 0; configIndex < numConfig && retcode; configIndex++)
  895. {
  896. /* Read the next configuration descriptor. */
  897. if (usbConfigDescrGet (internalClient, pNode->nodeHandle, configIndex,
  898.     &cfgLen, &pCfgBfr) != OK)
  899.     {
  900.     retcode = FALSE;
  901.     }
  902. else
  903.     {
  904.     if ((pCfgDescr = usbDescrParse (pCfgBfr, cfgLen, 
  905. USB_DESCR_CONFIGURATION)) != NULL)
  906. {
  907. /* Scan each interface descriptor. 
  908.  *
  909.  * NOTE: If we can't find an interface descriptor, we just keep
  910.  * going. 
  911.  */
  912. pRemBfr = pCfgBfr;
  913. remLen = cfgLen;
  914. configValue = pCfgDescr->configurationValue;
  915. while ((pIfDescr = usbDescrParseSkip (&pRemBfr, &remLen, 
  916.     USB_DESCR_INTERFACE)) != NULL && retcode)
  917.     {
  918.     if (!createNodeClass (pNode, configValue,
  919. pIfDescr->interfaceNumber, pIfDescr->interfaceClass, 
  920. pIfDescr->interfaceSubClass, pIfDescr->interfaceProtocol))
  921. {
  922. retcode = FALSE;
  923. }
  924.     }
  925. }
  926.     /* Release bfr allocated by usbConfigDescrGet(). */
  927.     
  928.     OSS_FREE (pCfgBfr);
  929.     }
  930. }
  931.     return retcode;
  932.     }
  933. /***************************************************************************
  934. *
  935. * destroyNode - deletes node structure
  936. *
  937. * RETURNS: N/A
  938. */
  939. LOCAL VOID destroyNode
  940.     (
  941.     pUSBD_NODE pNode
  942.     )
  943.     {
  944.     pUSBD_NODE_CLASS pClassType;
  945.     pUSBD_PIPE pPipe;
  946.     /* Mark node as "going down" */
  947.     pNode->nodeDeletePending = TRUE;
  948.     /* Cancel any other pipes associated with this node...This has the
  949.      * effect of cancelling any IRPs outstanding on this node. */
  950.     while ((pPipe = usbListFirst (&pNode->pipes)) != NULL)
  951. destroyPipe (pPipe);
  952.     /* Notify an interested clients that this node is going away. */
  953.     notifyClients (pNode, USBD_DYNA_REMOVE);
  954.     /* Delete any class type structures associated with this node. */
  955.     while ((pClassType = usbListFirst (&pNode->classTypes)) != NULL)
  956. {
  957. usbListUnlink (&pClassType->classLink);
  958. OSS_FREE (pClassType);
  959. }
  960.     /* release bus address associated with node */
  961.     releaseAddress (pNode);
  962.     /* Release node resources/memory. */
  963.     if (pNode->controlSem != NULL)
  964. OSS_SEM_DESTROY (pNode->controlSem);
  965.     if (pNode->nodeHandle != NULL)
  966. usbHandleDestroy (pNode->nodeHandle);
  967.     OSS_FREE (pNode->pHubStatus);
  968.     OSS_FREE (pNode);
  969.     }
  970. /***************************************************************************
  971. *
  972. * destroyAllNodes - destroys all nodes in a tree of nodes
  973. *
  974. * Recursively destroys all nodes from <pNode> and down.  If <pNode> is
  975. * NULL, returns immediately.
  976. *
  977. * RETURNS: N/A
  978. */
  979. LOCAL VOID destroyAllNodes
  980.     (
  981.     pUSBD_NODE pNode
  982.     )
  983.     {
  984.     int i;
  985.     if (pNode != NULL)
  986. {
  987. if (pNode->nodeInfo.nodeType == USB_NODETYPE_HUB &&
  988.     pNode->pPorts != NULL)
  989.     {
  990.     /* destroy all children of this node */
  991.     for (i = 0; i < pNode->numPorts; i++)
  992. destroyAllNodes (pNode->pPorts [i].pNode);
  993.     }
  994. destroyNode (pNode);
  995. }
  996.     }
  997. /***************************************************************************
  998. *
  999. * updateHubPort - Determine if a device has been attached/removed
  1000. *
  1001. * Note: The <port> parameter to this function is 0-based (0 = first port,
  1002. * 1 = second port, etc.)  However, on the USB interface itself, the index
  1003. * passed in a Setup packet to identify a port is 1-based.
  1004. *
  1005. * RETURNS: N/A
  1006. */
  1007. LOCAL VOID updateHubPort
  1008.     (
  1009.     pUSBD_NODE pNode,
  1010.     UINT16 port
  1011.     )
  1012.     {
  1013.     USB_HUB_STATUS * pStatus;
  1014.     UINT16 actLen;
  1015.     UINT16 nodeSpeed;
  1016.     pStatus = OSS_MALLOC (sizeof (USB_HUB_STATUS));
  1017.     /* retrieve status for the indicated hub port. */
  1018.     if (usbdStatusGet (internalClient, 
  1019.        pNode->nodeHandle, 
  1020.        USB_RT_CLASS | USB_RT_OTHER, 
  1021.        port + 1, 
  1022.        sizeof (USB_HUB_STATUS), 
  1023.        (UINT8 *) pStatus, 
  1024.        &actLen) != OK ||
  1025. actLen < sizeof (USB_HUB_STATUS))
  1026. {
  1027. OSS_FREE (pStatus);
  1028. return;
  1029. }
  1030.     /* correct the status byte order */
  1031.     pStatus->status = FROM_LITTLEW (pStatus->status);
  1032.     pStatus->change = FROM_LITTLEW (pStatus->change);
  1033.     /* Process the change indicated by status.change */
  1034.     /* NOTE: To see if a port's connection status has changed we also see
  1035.      * whether our internal understanding of the port's connection status
  1036.      * matches the hubs's current connection status.  If the two do not
  1037.      * agree, then we also assume a connection change, whether the hub is
  1038.      * indicating one or not. This covers the case at power on where the
  1039.      * hub does not report a connection change (i.e., the device is already
  1040.      * plugged in), but we need to initialize the port for the first time.
  1041.      */
  1042.     if ((pStatus->change & USB_HUB_C_PORT_CONNECTION) != 0 ||
  1043. ((pNode->pPorts [port].pNode == NULL) != 
  1044.     ((pStatus->status & USB_HUB_STS_PORT_CONNECTION) == 0)))
  1045. {
  1046. /* Given that there has been a change on this port, it stands to
  1047.  * reason that all nodes connected to this port must be invalidated -
  1048.  * even if a node currently appears to be connected to the port.
  1049.  */
  1050. destroyAllNodes (pNode->pPorts [port].pNode);
  1051. pNode->pPorts [port].pNode = NULL;
  1052. /* If a node appears to be connected to the port, reset the port. */
  1053. if ((pStatus->status & USB_HUB_STS_PORT_CONNECTION) != 0)
  1054.     {
  1055.     /* Wait 100 msec after detecting a connection to allow power to
  1056.      * stabilize.  Then enable the port and issue a reset.
  1057.      */
  1058.     OSS_THREAD_SLEEP (USB_TIME_POWER_ON);
  1059.     usbdFeatureSet (internalClient, pNode->nodeHandle,
  1060. USB_RT_CLASS | USB_RT_OTHER, USB_HUB_FSEL_PORT_RESET, port + 1);
  1061.     /* 
  1062.      * Acoording to the USB spec (refer to section 7.1.7.3) we should
  1063.        * wait 50 msec for reset signaling + an additional 10 msec reset 
  1064.      * recovery time.  We double this time for safety's sake since 
  1065.      * we have seen a few devices that do not respond to the suggested 
  1066.      * time of 60 msec.
  1067.      */ 
  1068.     OSS_THREAD_SLEEP (2*USB_TIME_RESET + USB_TIME_RESET_RECOVERY);
  1069.     }
  1070. /* Clear the port connection change indicator - whether or not it
  1071.  * appears that a device is currently connected. */
  1072. usbdFeatureClear (internalClient, pNode->nodeHandle, 
  1073.     USB_RT_CLASS | USB_RT_OTHER, USB_HUB_FSEL_C_PORT_CONNECTION, port + 1);
  1074. /* If a node appears to be connected, create a new node structure for 
  1075.  * it and attach it to this hub. */
  1076. if ((pStatus->status & USB_HUB_STS_PORT_CONNECTION) != 0)
  1077.     {
  1078.     /* If the following call to createNode() fails, it returns NULL.
  1079.      * That's fine, as the corresponding USBD_PORT structure will be
  1080.      * initialized correctly either way.
  1081.      */
  1082.     nodeSpeed = ((pStatus->status & USB_HUB_STS_PORT_LOW_SPEED) != 0) ?
  1083. USB_SPEED_LOW : USB_SPEED_FULL;
  1084.     if ((pNode->pPorts [port].pNode = createNode (pNode->pBus,
  1085. pNode->pBus->pRoot->nodeHandle, pNode->nodeHandle, port,
  1086. nodeSpeed, pNode->topologyDepth + 1)) == NULL)
  1087. {
  1088. /* Attempt to initialize the port failed.  Disable the port */
  1089. usbdFeatureClear (internalClient, pNode->nodeHandle,
  1090.     USB_RT_CLASS | USB_RT_OTHER, USB_HUB_FSEL_PORT_ENABLE, 
  1091. port + 1);
  1092. }
  1093.     }
  1094. }
  1095.     if ((pStatus->change & USB_HUB_C_PORT_ENABLE) != 0)
  1096. {
  1097. /* Clear the port enable change indicator */
  1098. usbdFeatureClear (internalClient, pNode->nodeHandle, 
  1099.     USB_RT_CLASS | USB_RT_OTHER, USB_HUB_FSEL_C_PORT_ENABLE, port + 1);
  1100. }
  1101.     if ((pStatus->change & USB_HUB_C_PORT_SUSPEND) != 0)
  1102. {
  1103. /* Clear the suspend change indicator */
  1104. usbdFeatureClear (internalClient, pNode->nodeHandle, 
  1105.     USB_RT_CLASS | USB_RT_OTHER, USB_HUB_FSEL_C_PORT_SUSPEND, port + 1);
  1106. }
  1107.     if ((pStatus->change & USB_HUB_C_PORT_OVER_CURRENT) != 0)
  1108. {
  1109. /* Clear the over current change indicator */
  1110. usbdFeatureClear (internalClient, pNode->nodeHandle,
  1111.     USB_RT_CLASS | USB_RT_OTHER, USB_HUB_FSEL_C_PORT_OVER_CURRENT, 
  1112.     port + 1);
  1113. }
  1114.     if ((pStatus->change & USB_HUB_C_PORT_RESET) != 0)
  1115. {
  1116. /* Clear the reset change indicator */
  1117. usbdFeatureClear (internalClient, pNode->nodeHandle, 
  1118.     USB_RT_CLASS | USB_RT_OTHER, USB_HUB_FSEL_C_PORT_RESET, port + 1);
  1119. }
  1120.     }
  1121. /***************************************************************************
  1122. *
  1123. * hubIrpCallback - called when hub status IRP completes
  1124. *
  1125. * By convention, the USB_IRP.userPtr field is a pointer to the USBD_NODE
  1126. * for this transfer.
  1127. *
  1128. * RETURNS: N/A
  1129. */
  1130. LOCAL VOID hubIrpCallback
  1131.     (
  1132.     pVOID p /* completed IRP */
  1133.     )
  1134.     {
  1135.     pUSB_IRP pIrp = (pUSB_IRP) p;
  1136.     pUSBD_NODE pNode = (pUSBD_NODE) pIrp->userPtr;
  1137.     /* If the IRP was canceled, it means that the hub node is being torn
  1138.      * down, so don't queue a request for the bus thread.
  1139.      */
  1140.     if (pIrp->result != S_usbHcdLib_IRP_CANCELED)
  1141. {
  1142. /* Let the bus thread update the port and re-queue the hub IRP. */
  1143. usbQueuePut (pNode->pBus->busQueue, BUS_FNC_UPDATE_HUB,
  1144.     0, (UINT32) pNode->nodeHandle, OSS_BLOCK);
  1145. }
  1146.     }
  1147. /***************************************************************************
  1148. *
  1149. * initHubIrp - initialize IRP used to listen for hub status
  1150. *
  1151. * RETURNS: TRUE if successful, else FALSE
  1152. */
  1153. LOCAL BOOL initHubIrp
  1154.     (
  1155.     pUSBD_NODE pNode
  1156.     )
  1157.     {
  1158.     pUSB_IRP pIrp = &pNode->hubIrp;
  1159.     
  1160.     /* initialize IRP */
  1161.     memset (pIrp, 0, sizeof (*pIrp));
  1162.     pIrp->userPtr = pNode;
  1163.     pIrp->irpLen = sizeof (USB_IRP);
  1164.     pIrp->userCallback = hubIrpCallback;
  1165.     pIrp->flags = USB_FLAG_SHORT_OK;
  1166.     pIrp->timeout = USB_TIMEOUT_NONE;
  1167.     pIrp->transferLen = HUB_STATUS_LEN (pNode);
  1168.     pIrp->bfrCount = 1;
  1169.     pIrp->bfrList [0].pid = USB_PID_IN;
  1170.     pIrp->bfrList [0].pBfr = (pUINT8) pNode->pHubStatus;
  1171.     pIrp->bfrList [0].bfrLen = pIrp->transferLen;
  1172.     memset (pNode->pHubStatus, 0, MAX_HUB_STATUS_LEN);
  1173.     /* submit the IRP. */
  1174.     if (usbdTransfer (internalClient, pNode->hubStatusPipe, pIrp) != OK)
  1175. return FALSE;
  1176.     return TRUE;
  1177.     }
  1178. /***************************************************************************
  1179. *
  1180. * initHubNode - initialize a hub
  1181. *
  1182. * RETURNS: TRUE if successful, else FALSE
  1183. */
  1184. LOCAL BOOL initHubNode
  1185.     (
  1186.     pUSBD_NODE pNode
  1187.     )
  1188.     {
  1189.     pUSB_CONFIG_DESCR pCfgDescr;
  1190.     pUSB_INTERFACE_DESCR pIfDescr;
  1191.     pUSB_ENDPOINT_DESCR pEpDescr;
  1192.     pUSB_HUB_DESCR pHubDescrBuf;
  1193.     UINT8 * pConfDescrBfr;
  1194.     UINT16 actLen;
  1195.     UINT16 port;
  1196.     pConfDescrBfr = OSS_MALLOC (USB_MAX_DESCR_LEN);
  1197.     pHubDescrBuf = OSS_MALLOC (sizeof (USB_HUB_DESCR));
  1198.     /* Read the hub's descriptors. */
  1199.     if (usbdDescriptorGet (internalClient, 
  1200.    pNode->nodeHandle, 
  1201.    USB_RT_STANDARD | USB_RT_DEVICE, 
  1202.    USB_DESCR_CONFIGURATION, 
  1203.    0, 
  1204.    0, 
  1205.    USB_MAX_DESCR_LEN, 
  1206.    pConfDescrBfr, 
  1207.    &actLen) 
  1208.  != OK)
  1209. {
  1210. OSS_FREE (pConfDescrBfr);
  1211. OSS_FREE (pHubDescrBuf);
  1212. return FALSE;
  1213. }
  1214.     if ((pCfgDescr = usbDescrParse (pConfDescrBfr, 
  1215.     actLen, 
  1216.     USB_DESCR_CONFIGURATION)) 
  1217. == NULL ||
  1218. (pIfDescr = usbDescrParse (pConfDescrBfr, 
  1219.    actLen, 
  1220.    USB_DESCR_INTERFACE))
  1221.    == NULL ||
  1222. (pEpDescr = usbDescrParse (pConfDescrBfr, 
  1223.    actLen, 
  1224.    USB_DESCR_ENDPOINT))
  1225. == NULL)
  1226. {
  1227.         OSS_FREE (pConfDescrBfr);
  1228.         OSS_FREE (pHubDescrBuf);
  1229. return FALSE;
  1230. }
  1231.     if (usbdDescriptorGet (internalClient, 
  1232.    pNode->nodeHandle, 
  1233.    USB_RT_CLASS | USB_RT_DEVICE, 
  1234.    USB_DESCR_HUB, 
  1235.    0, 
  1236.    0, 
  1237.    sizeof (USB_HUB_DESCR), 
  1238.    (UINT8 *) pHubDescrBuf, 
  1239.    &actLen) 
  1240. != OK ||
  1241. actLen < USB_HUB_DESCR_LEN)
  1242. {
  1243.         OSS_FREE (pConfDescrBfr);
  1244.         OSS_FREE (pHubDescrBuf);
  1245. return FALSE;
  1246. }
  1247.     /* We now have all important descriptors for this hub.  Pick out
  1248.      * important information and configure hub.
  1249.      */
  1250.     /* Record hub power capability */
  1251.     pNode->pwrGoodDelay = pHubDescrBuf->pwrOn2PwrGood * 2; /* 2 msec per unit */
  1252.     pNode->hubContrCurrent = pHubDescrBuf->hubContrCurrent;
  1253.     if ((pCfgDescr->attributes & USB_ATTR_SELF_POWERED) != 0)
  1254. {
  1255. pNode->selfPowered = TRUE;
  1256. pNode->maxPowerPerPort = USB_POWER_SELF_POWERED;
  1257. }
  1258.     else
  1259. {
  1260. pNode->selfPowered = FALSE;
  1261. pNode->maxPowerPerPort = USB_POWER_BUS_POWERED;
  1262. }
  1263.     pNode->numPorts = pHubDescrBuf->nbrPorts;
  1264.     /* If this hub is not already at the maximum USB topology depth, then
  1265.      * create a pipe to monitor it's status and enable each of its ports.
  1266.      */
  1267.     if (pNode->topologyDepth < USB_MAX_TOPOLOGY_DEPTH)
  1268. {
  1269. /* Set the hub's configuration. */
  1270. if (usbdConfigurationSet (internalClient, 
  1271.   pNode->nodeHandle, 
  1272.   pCfgDescr->configurationValue, 
  1273.   pNode->hubContrCurrent) 
  1274.   != OK)
  1275.     {
  1276.             OSS_FREE (pConfDescrBfr);
  1277.             OSS_FREE (pHubDescrBuf);
  1278.     return FALSE;
  1279.     }
  1280. /* Create a pipe for interrupt transfers from this device. */
  1281. if (usbdPipeCreate (internalClient, 
  1282.     pNode->nodeHandle, 
  1283.     pEpDescr->endpointAddress, 
  1284.     pCfgDescr->configurationValue, 
  1285.     0, 
  1286.     USB_XFRTYPE_INTERRUPT, 
  1287.     USB_DIR_IN, 
  1288.     FROM_LITTLEW (pEpDescr->maxPacketSize), 
  1289.     HUB_STATUS_LEN (pNode), 
  1290.     pEpDescr->interval, 
  1291.     &pNode->hubStatusPipe) 
  1292.   != OK)
  1293.     {
  1294.             OSS_FREE (pConfDescrBfr);
  1295.             OSS_FREE (pHubDescrBuf);
  1296.     return FALSE;
  1297.     }
  1298. /* Allocate structures for downstream nodes. */
  1299. if ((pNode->pPorts = OSS_CALLOC (pNode->numPorts * sizeof (USBD_PORT))) 
  1300.     == NULL)
  1301.     {
  1302.             OSS_FREE (pConfDescrBfr);
  1303.             OSS_FREE (pHubDescrBuf);
  1304.     return FALSE;
  1305.     }
  1306. /* Initialize each hub port */
  1307. for (port = 0; port < pNode->numPorts; port++)
  1308.     {
  1309.     /* Enable power to the port */
  1310.     usbdFeatureSet (internalClient, pNode->nodeHandle, 
  1311. USB_RT_CLASS | USB_RT_OTHER, USB_HUB_FSEL_PORT_POWER, port + 1);
  1312.     }
  1313. OSS_THREAD_SLEEP (pNode->pwrGoodDelay); /* let power stabilize */
  1314. /* Initialize an IRP to listen for status changes on the hub */
  1315.     if (!initHubIrp (pNode))
  1316.     {
  1317.             OSS_FREE (pConfDescrBfr);
  1318.             OSS_FREE (pHubDescrBuf);
  1319.     return FALSE;
  1320.     }
  1321. }
  1322.     
  1323.     OSS_FREE (pConfDescrBfr);
  1324.     OSS_FREE (pHubDescrBuf);
  1325.  
  1326.     return TRUE;
  1327.     }
  1328. /***************************************************************************
  1329. *
  1330. * createNode - Creates and initializes new USBD_NODE
  1331. *
  1332. * If the node is a hub, then automatically initializes hub.
  1333. *
  1334. * RETURNS: pointer to newly created USBD_NODE, or
  1335. *    NULL if not successful
  1336. */
  1337. LOCAL pUSBD_NODE createNode 
  1338.     (
  1339.     pUSBD_BUS pBus,     /* node's parent bus */
  1340.     USBD_NODE_ID rootId,     /* root id */
  1341.     USBD_NODE_ID parentHubId,     /* parent hub id */
  1342.     UINT16 parentHubPort,     /* parent hub port no */
  1343.     UINT16 nodeSpeed,     /* node speed */
  1344.     UINT16 topologyDepth     /* this node's depth in topology */
  1345.     )
  1346.     {
  1347.     pUSBD_NODE pNode;
  1348.     pUSBD_PIPE pPipe;
  1349.     UINT16 actLen;
  1350.     /* Allocate/initialize USBD_NODE */
  1351.     if ((pNode = OSS_CALLOC (sizeof (*pNode))) == NULL)
  1352. return NULL;
  1353.     /* 
  1354.      * The hub status buffer gets touched by hardware.  Ensure that 
  1355.      * it does not span a cache line
  1356.      */
  1357.     if ((pNode->pHubStatus = OSS_CALLOC (MAX_HUB_STATUS_LEN)) == NULL)
  1358. {
  1359. OSS_FREE (pNode);
  1360. return NULL;
  1361. }
  1362.     if (usbHandleCreate (USBD_NODE_SIG, pNode, &pNode->nodeHandle) != OK ||
  1363. OSS_SEM_CREATE (1, 1, &pNode->controlSem) != OK)
  1364. {
  1365. destroyNode (pNode);
  1366. return NULL;
  1367. }
  1368.     pNode->pBus = pBus;
  1369.     pNode->nodeInfo.nodeSpeed = nodeSpeed;
  1370.     pNode->nodeInfo.parentHubId = parentHubId;
  1371.     pNode->nodeInfo.parentHubPort = parentHubPort;
  1372.     pNode->nodeInfo.rootId = (rootId == 0) ? pNode->nodeHandle : rootId;
  1373.     pNode->topologyDepth = topologyDepth;
  1374.     /* Create a pipe for control transfers to this device. */
  1375.     if (usbdPipeCreate (internalClient, pNode->nodeHandle, USB_ENDPOINT_CONTROL,
  1376. 0, 0, USB_XFRTYPE_CONTROL, USB_DIR_INOUT, USB_MIN_CTRL_PACKET_SIZE, 0, 0, 
  1377. &pNode->controlPipe) != OK)
  1378. {
  1379. destroyNode (pNode);
  1380. return NULL;
  1381. }
  1382.     /* Read the device descriptor to get the maximum payload size and to
  1383.      * determine if this is a hub or not.
  1384.      *
  1385.      * NOTE: We read only the first 8 bytes of the device descriptor (which
  1386.      * takes us through the maxPacketSize field) as suggested by the USB
  1387.      * spec.
  1388.      */
  1389.     if (usbdDescriptorGet (internalClient, pNode->nodeHandle,
  1390. USB_RT_STANDARD | USB_RT_DEVICE, USB_DESCR_DEVICE, 0, 0,
  1391. USB_MIN_CTRL_PACKET_SIZE, (pUINT8) &pNode->devDescr, &actLen) != OK ||
  1392. actLen < USB_MIN_CTRL_PACKET_SIZE)
  1393. {
  1394. destroyNode (pNode);
  1395. return NULL;
  1396. }
  1397.     /* Now that we've read the device descriptor, we know the actual
  1398.      * packet size supported by the control pipe.  Update the pipe
  1399.      * accordingly.
  1400.      */
  1401.     validatePipe (pNode->controlPipe, &pPipe);
  1402.     pPipe->maxPacketSize = pNode->devDescr.maxPacketSize0;  /* field is byte wide */
  1403.     /* Set a unique address for this device. */
  1404.     if (!assignAddress (pNode))
  1405. {
  1406. destroyNode (pNode);
  1407. return NULL;
  1408. }
  1409.     /* Notify the HCD of the change in device address and max packet size */
  1410.     usbHcdPipeModify (&pBus->pHcd->nexus, pPipe->hcdHandle, 
  1411. pNode->busAddress, pPipe->maxPacketSize);
  1412.     /* If this is a hub node, it requires additional initialization.  Otherwise,
  1413.      * we're done unless and until a client performs additional I/O to this
  1414.      * device.
  1415.      */
  1416.     if (pNode->devDescr.deviceClass == USB_CLASS_HUB)
  1417. {
  1418. pNode->nodeInfo.nodeType = USB_NODETYPE_HUB;
  1419. if (!initHubNode (pNode))
  1420.     {
  1421.     destroyNode (pNode);
  1422.     return NULL;
  1423.     }
  1424. }
  1425.     else
  1426. {
  1427. pNode->nodeInfo.nodeType = USB_NODETYPE_DEVICE;
  1428. }
  1429.     /* Read the device class type(s) from the device and notify interested
  1430.      * clients of the device's insertion.
  1431.      */
  1432.     interrogateDeviceClass (pNode, pNode->devDescr.deviceClass,
  1433. pNode->devDescr.deviceSubClass, pNode->devDescr.deviceProtocol);
  1434.     notifyClients (pNode, USBD_DYNA_ATTACH);
  1435.     return pNode;
  1436.     }
  1437. /***************************************************************************
  1438. *
  1439. * checkHubStatus - checks hub status and updates hub as necessary
  1440. *
  1441. * Note: We take a Node ID as our parameter (instead of, say, a pointer
  1442. * to a USBD_NODE structure) so that we can validate the node upon entry.
  1443. * There are cases where this routine may be called when the underlying
  1444. * node has already disappeared.
  1445. *
  1446. * RETURNS: N/A
  1447. */
  1448. LOCAL VOID checkHubStatus
  1449.     (
  1450.     USBD_NODE_ID nodeId
  1451.     )
  1452.     {
  1453.     pUSBD_NODE pNode;
  1454.     pUSB_IRP pIrp;
  1455.     UINT16 port;
  1456.     UINT8 portMask;
  1457.     UINT8 statusIndex;
  1458.     /* Is the node still valid? */
  1459.     if (!validateNode (nodeId, &pNode))
  1460. return;
  1461.     pIrp = &pNode->hubIrp;
  1462.     /* Determine what status is available.
  1463.      *
  1464.      * The hubStatus vector contains one bit for the hub itself and 
  1465.      * then one bit for each port.
  1466.      */
  1467.     if (pIrp->result == OK)
  1468. {
  1469. port = 0;
  1470. statusIndex = 0;
  1471. portMask = USB_HUB_ENDPOINT_STS_PORT0;
  1472. while (port < pNode->numPorts && statusIndex < pIrp->bfrList [0].actLen)
  1473.     {
  1474.     if ((*(pNode->pHubStatus + statusIndex) & portMask) != 0)
  1475. {
  1476. /* This port appears to have status to report */
  1477. updateHubPort (pNode, port);
  1478. }
  1479.     port++;
  1480.     portMask <<= 1;
  1481.     if (portMask == 0)
  1482. {
  1483. portMask = 0x01;    /* next byte starts with bit 0 */
  1484. statusIndex++;
  1485. }
  1486.     }
  1487. }
  1488.     /* resubmit the IRP */
  1489.     if (pIrp->result != S_usbHcdLib_IRP_CANCELED)
  1490. initHubIrp (pNode);
  1491.     }
  1492. /***************************************************************************
  1493. *
  1494. * busThread - bus monitor thread
  1495. *
  1496. * A separate busThread() thread is spawned for each bus currently
  1497. * attached to the USBD.  This thread is responsible for monitoring and
  1498. * responding to bus events, like the attachment and removal of devices.
  1499. * Using a separate thread for each bus helps to ensure that one bus's 
  1500. * behavior won't affect the throughput of other buses.
  1501. *
  1502. * By convention, the <param> is a pointer to the USBD_BUS structure
  1503. * for the associated bus.  This thread waits on the bus queue
  1504. * in the bus structure.  At the time this thread is first created,
  1505. * the USBD_BUS structure is only guaranteed to have an initialized
  1506. * queue...other fields may not yet be initialized.
  1507. *
  1508. * RETURNS: N/A
  1509. */
  1510. LOCAL VOID busThread
  1511.     (
  1512.     pVOID param      /* thread parameter */
  1513.     )
  1514.     {
  1515.     pUSBD_BUS pBus = (pUSBD_BUS) param;
  1516.     USB_MESSAGE msg;
  1517.     /* Execute messages from the busQueue until a BUS_FNC_TERMINATE
  1518.     message is received. */
  1519.     do
  1520. {
  1521. if (usbQueueGet (pBus->busQueue, &msg, OSS_BLOCK) != OK)
  1522.     break;
  1523. switch (msg.msg)
  1524.     {
  1525.     case BUS_FNC_UPDATE_HUB:
  1526. OSS_MUTEX_TAKE (structMutex, OSS_BLOCK);
  1527. checkHubStatus ((USBD_NODE_ID) msg.lParam);
  1528. OSS_MUTEX_RELEASE (structMutex);
  1529. break;
  1530.     }
  1531. }
  1532.     while (msg.msg != BUS_FNC_TERMINATE);
  1533.     /* Mark the callback routine as having terminated. */
  1534.     OSS_SEM_GIVE (pBus->busExit);
  1535.     }
  1536. /***************************************************************************
  1537. *
  1538. * hcdMngmtCallback - invoked when HCD detects managment event
  1539. *
  1540. * RETURNS: N/A
  1541. */
  1542. LOCAL VOID hcdMngmtCallback
  1543.     (
  1544.     pVOID mngmtCallbackParam,     /* caller-defined param */
  1545.     HCD_CLIENT_HANDLE handle,     /* handle to host controller */
  1546.     UINT16 busNo,     /* bus number */
  1547.     UINT16 mngmtCode     /* management code */
  1548.     )
  1549.     {
  1550.     pUSBD_HCD pHcd = (pUSBD_HCD) mngmtCallbackParam;
  1551.     pUSBD_BUS pBus;
  1552.     pUSBD_CLIENT pClient;
  1553.     /* In an unusual case, this routine could be invoked by the HCD
  1554.      * before we have completely initialized our structures.  In that
  1555.      * case, just ignore the event.
  1556.      */
  1557.     if (pHcd->pBuses == NULL)
  1558. return;
  1559.     pBus = &pHcd->pBuses [busNo];
  1560.     if (pBus->busThread == NULL || pBus->busQueue == NULL ||
  1561. pBus->pRoot == NULL || pBus->pRoot->nodeHandle == NULL)
  1562. return;
  1563.     /* Reflect the management event to interested clients */
  1564.     OSS_MUTEX_TAKE (structMutex, OSS_BLOCK);
  1565.     pClient = usbListFirst (&clientList);
  1566.     while (pClient != NULL)
  1567. {
  1568. if (pClient->mngmtCallback != NULL)
  1569.     usbQueuePut (pClient->callbackQueue, CALLBACK_FNC_MNGMT_EVENT, 
  1570. mngmtCode, (UINT32) pBus->pRoot->nodeHandle, OSS_BLOCK);
  1571. pClient = usbListNext (&pClient->clientLink);
  1572. }
  1573.     OSS_MUTEX_RELEASE (structMutex);
  1574.     }
  1575. /***************************************************************************
  1576. *
  1577. * initHcdBus - Initialize USBD_BUS element of USBD_HCD structure
  1578. *
  1579. * <pHcd> points to the USBD_HCD being initialized.  <busNo> is the index
  1580. * of the HCD bus to be initialized.
  1581. *
  1582. * RETURNS: S_usbdLib_xxxx
  1583. */
  1584. LOCAL int initHcdBus
  1585.     (
  1586.     pUSBD_HCD pHcd,     /* USBD_HCD being initialized */
  1587.     UINT16 busNo     /* Bus number to initialize */
  1588.     )
  1589.     {
  1590.     pUSBD_BUS pBus = &pHcd->pBuses [busNo];
  1591.     int s = OK;
  1592.     /* Allocate resources for this bus. */
  1593.     pBus->pHcd = pHcd;
  1594.     pBus->busNo = busNo;
  1595.     if (OSS_SEM_CREATE (1, 0, &pBus->busExit) != OK ||
  1596. usbQueueCreate (BUS_Q_DEPTH, &pBus->busQueue) != OK ||
  1597. OSS_THREAD_CREATE (busThread, pBus, OSS_PRIORITY_HIGH, "tUsbdBus", 
  1598.     &pBus->busThread) != OK ||
  1599. (pBus->pRoot = createNode (pBus, 0, 0, 0, USB_SPEED_FULL, 0)) == NULL)
  1600. {
  1601. /* NOTE: If we fail here, destroyHcd() will clean up partially
  1602.  * allocate structures/resources/etc.
  1603.  */
  1604. return S_usbdLib_OUT_OF_RESOURCES;
  1605. }
  1606.     return s;
  1607.     }
  1608. /***************************************************************************
  1609. *
  1610. * destroyHcd - tears down a USBD_HCD structure
  1611. *
  1612. * Detaches the indicated HCD and tears down the HCD structures.
  1613. *
  1614. * RETURNS: N/A
  1615. */
  1616. LOCAL VOID destroyHcd
  1617.     (
  1618.     pUSBD_HCD pHcd
  1619.     )
  1620.     {
  1621.     pUSBD_BUS pBus;
  1622.     UINT16 busNo;
  1623.     /* Unlink the HCD */
  1624.     usbListUnlink (&pHcd->hcdLink);
  1625.     /* Begin by de-allocating resources related to each bus */
  1626.     for (busNo = 0; pHcd->pBuses != NULL && busNo < pHcd->busCount; busNo++)
  1627. {
  1628. pBus = &pHcd->pBuses [busNo];
  1629. /* Destroy all nodes associated with this bus */
  1630. destroyAllNodes (pBus->pRoot);
  1631. /* NOTE: The busQueue is always allocated before the busThread. */
  1632. if (pBus->busThread != NULL)
  1633.     {
  1634.     /* Issue a terminate request to the bus thread */
  1635.     usbQueuePut (pBus->busQueue, BUS_FNC_TERMINATE, 0, 0, BUS_TIMEOUT);
  1636.     OSS_SEM_TAKE (pBus->busExit, BUS_TIMEOUT);
  1637.     OSS_THREAD_DESTROY (pBus->busThread);
  1638.     }
  1639. if (pBus->busQueue != NULL)
  1640.     usbQueueDestroy (pBus->busQueue);
  1641. if (pBus->busExit != NULL)
  1642.     OSS_SEM_DESTROY (pBus->busQueue);
  1643. }
  1644.     /* Detach the HCD */
  1645.     if (pHcd->nexus.hcdExecFunc != NULL && pHcd->nexus.handle != NULL)
  1646. usbHcdDetach (&pHcd->nexus);
  1647.     /* Release USBD_HCD resources */
  1648.     if (pHcd->attachToken != NULL)
  1649. usbHandleDestroy (pHcd->attachToken);
  1650.     OSS_FREE (pHcd);
  1651.     }
  1652. /***************************************************************************
  1653. *
  1654. * fncHcdAttach - Attach an HCD to the USBD
  1655. *
  1656. * RETURNS: S_usbdLib_xxxx
  1657. */
  1658. LOCAL int fncHcdAttach
  1659.     (
  1660.     pURB_HCD_ATTACH pUrb
  1661.     )
  1662.     {
  1663.     pUSBD_HCD pHcd = NULL;
  1664.     UINT16 busNo;
  1665.     int s;
  1666.     /* validate URB */
  1667.     if ((s = validateUrb (pUrb, sizeof (*pUrb), NULL)) != OK)
  1668. return s;
  1669.     /* Allocate structure for this host controller */
  1670.     if ((pHcd = OSS_CALLOC (sizeof (*pHcd))) == NULL)
  1671. return S_usbdLib_OUT_OF_MEMORY;
  1672.     /* Issue an attach request to the HCD.  If it succeeds, determine the
  1673.      * number of buses managed by the HCD.
  1674.      */
  1675.     if (usbHcdAttach (pUrb->hcdExecFunc, pUrb->param, hcdMngmtCallback,
  1676. pHcd, &pHcd->nexus, &pHcd->busCount) != OK)
  1677. {
  1678. OSS_FREE (pHcd);
  1679. return S_usbdLib_GENERAL_FAULT;
  1680. }
  1681.     if ((pHcd->pBuses = OSS_CALLOC (sizeof (USBD_BUS) * pHcd->busCount)) == NULL)
  1682. {
  1683. destroyHcd (pHcd);
  1684. return S_usbdLib_OUT_OF_MEMORY;
  1685. }
  1686.     /* Initialize the USBD_HCD */
  1687.     if (usbHandleCreate (USBD_HCD_SIG, pHcd, &pHcd->attachToken) != OK)
  1688. {
  1689. s = S_usbdLib_OUT_OF_RESOURCES;
  1690. }
  1691.     else
  1692. {
  1693. /* Fetch information about each bus from the HCD. */
  1694. for (busNo = 0; busNo < pHcd->busCount; busNo++)
  1695.     {
  1696.     if ((s = initHcdBus (pHcd, busNo)) != OK)
  1697. break;
  1698.     }
  1699. }
  1700.     /* If we succeeded in initializing each bus, then the USBD_HCD
  1701.      * is fully initialized...link it into the list of HCDs
  1702.      */
  1703.     if (s == OK)
  1704. {
  1705. usbListLink (&hcdList, pHcd, &pHcd->hcdLink, LINK_TAIL);
  1706. /* Return attachToken to caller */
  1707. pUrb->attachToken = pHcd->attachToken;
  1708. }
  1709.     else
  1710. {
  1711. /* Failed to attach...release allocated structs, etc. */
  1712. destroyHcd (pHcd);
  1713. }
  1714.     return s;
  1715.     }
  1716. /***************************************************************************
  1717. *
  1718. * fncHcdDetach - Detach an HCD from the USBD
  1719. *
  1720. * RETURNS: S_usbdLib_xxxx
  1721. */
  1722. LOCAL int fncHcdDetach
  1723.     (
  1724.     pURB_HCD_DETACH pUrb
  1725.     )
  1726.     {
  1727.     pUSBD_HCD pHcd;
  1728.     int s;
  1729.     /* Validate URB */
  1730.     
  1731.     if ((s = validateUrb (pUrb, sizeof (*pUrb), NULL)) != OK)
  1732. return s;
  1733.     /* Validate attachToken */
  1734.     if (usbHandleValidate (pUrb->attachToken, USBD_HCD_SIG, (pVOID *) &pHcd) 
  1735. != OK)
  1736. return S_usbdLib_BAD_HANDLE;
  1737.     
  1738.     /* Detach the HCD and release HCD structures, etc. */
  1739.     destroyHcd (pHcd);
  1740.     return s;
  1741.     }
  1742. /***************************************************************************
  1743. *
  1744. * fncStatisticsGet - Return USBD operating statistics
  1745. *
  1746. * RETURNS: S_usbdLib_xxxx
  1747. */
  1748. LOCAL int fncStatisticsGet
  1749.     (
  1750.     pURB_STATISTICS_GET pUrb
  1751.     )
  1752.     {
  1753.     pUSBD_NODE pNode;
  1754.     /* Validate root */
  1755.     if (!validateNode (pUrb->nodeId, &pNode))
  1756. return S_usbdLib_BAD_HANDLE;
  1757.     /* Validate other parameters */
  1758.     if (pUrb->pStatistics == NULL)
  1759. return S_usbdLib_BAD_PARAM;
  1760.     /* Copy statistics to callers buffer */
  1761.     memcpy (pUrb->pStatistics, &pNode->pBus->stats,
  1762. min (pUrb->statLen, sizeof (pNode->pBus->stats)));
  1763.     return OK;
  1764.     }
  1765. /***************************************************************************
  1766. *
  1767. * fncBusCountGet - Returns number of USB buses in system
  1768. *
  1769. * RETURNS: S_usbdLib_xxxx
  1770. */
  1771. LOCAL int fncBusCountGet
  1772.     (
  1773.     pURB_BUS_COUNT_GET pUrb
  1774.     )
  1775.     {
  1776.     pUSBD_HCD pHcd;
  1777.     UINT16 busCount;
  1778.     busCount = 0;
  1779.     pHcd = usbListFirst (&hcdList);
  1780.     while (pHcd != NULL)
  1781. {
  1782. busCount += pHcd->busCount;
  1783. pHcd = usbListNext (&pHcd->hcdLink);
  1784. }
  1785.     pUrb->busCount = busCount;
  1786.     return OK;
  1787.     }
  1788. /***************************************************************************
  1789. *
  1790. * fncRootIdGet - Returns root node id for a USB
  1791. *
  1792. * RETURNS: S_usbdLib_xxxx
  1793. */
  1794. LOCAL int fncRootIdGet
  1795.     (
  1796.     pURB_ROOT_ID_GET pUrb
  1797.     )
  1798.     {
  1799.     pUSBD_HCD pHcd;
  1800.     UINT16 i;
  1801.     int s = OK;
  1802.     /* Find the HCD/bus corresponding to the index pUrb->busCount */
  1803.     i = pUrb->busIndex;
  1804.     pHcd = usbListFirst (&hcdList);
  1805.     while (pHcd != NULL)
  1806. {
  1807. if (i < pHcd->busCount)
  1808.     {
  1809.     if (pHcd->pBuses [i].pRoot != NULL)
  1810. pUrb->rootId = pHcd->pBuses [i].pRoot->nodeHandle;
  1811.     else
  1812. s = S_usbdLib_INTERNAL_FAULT;
  1813.     break;
  1814.     }
  1815. else
  1816.     {
  1817.     i -= pHcd->busCount;
  1818.     pHcd = usbListNext (&pHcd->hcdLink);
  1819.     }
  1820. }
  1821.     if (pHcd == NULL)
  1822. s = S_usbdLib_BAD_PARAM;
  1823.     return s;
  1824.     }
  1825. /***************************************************************************
  1826. *
  1827. * fncHubPortCountGet - Returns number of hubs on a port
  1828. *
  1829. * RETURNS: S_usbdLib_xxxx
  1830. */
  1831. LOCAL int fncHubPortCountGet
  1832.     (
  1833.     pURB_HUB_PORT_COUNT_GET pUrb
  1834.     )
  1835.     {
  1836.     pUSBD_NODE pNode;
  1837.     /* validate node handle */
  1838.     if (!validateNode (pUrb->hubId, &pNode))
  1839. return S_usbdLib_BAD_HANDLE;
  1840.     if (pNode->nodeInfo.nodeType != USB_NODETYPE_HUB)
  1841. return S_usbdLib_NOT_HUB;
  1842.     
  1843.     /* return number of ports on this hub */
  1844.     pUrb->portCount = pNode->numPorts;
  1845.     return OK;
  1846.     }
  1847. /***************************************************************************
  1848. *
  1849. * fncNodeIdGet - Returns id of node attached to a hub port
  1850. *
  1851. * RETURNS: S_usbdLib_xxxx
  1852. */
  1853. LOCAL int fncNodeIdGet
  1854.     (
  1855.     pURB_NODE_ID_GET pUrb
  1856.     )
  1857.     {
  1858.     pUSBD_NODE pNode;
  1859.     /* validate node handle */
  1860.     if (!validateNode (pUrb->hubId, &pNode))
  1861. return S_usbdLib_BAD_HANDLE;
  1862.     if (pNode->nodeInfo.nodeType != USB_NODETYPE_HUB)
  1863. return S_usbdLib_NOT_HUB;
  1864.     /* If the port index is valid, return the node id, if any, attached
  1865.      * to this port.
  1866.      */
  1867.     if (pUrb->portIndex >= pNode->numPorts)
  1868. return S_usbdLib_BAD_PARAM;
  1869.     pUrb->nodeType = USB_NODETYPE_NONE;
  1870.     if (pNode->pPorts != NULL &&
  1871. pNode->pPorts [pUrb->portIndex].pNode != NULL) 
  1872. {
  1873. pUrb->nodeType = pNode->pPorts [pUrb->portIndex].pNode->nodeInfo.nodeType;
  1874. pUrb->nodeId = pNode->pPorts [pUrb->portIndex].pNode->nodeHandle;
  1875. }
  1876.     return OK;
  1877.     }
  1878. /***************************************************************************
  1879. *
  1880. * scanClassTypes - Scans nodes for matching class types
  1881. *
  1882. * Scan <pNode> and all child nodes to see if they have exposed one or more
  1883. * class types matching that described in <pNotify>.  If we find match(es),
  1884. * then invoke the corresponding notification callbacks.
  1885. *
  1886. * RETURNS: N/A
  1887. */
  1888. LOCAL VOID scanClassTypes
  1889.     (
  1890.     pUSBD_NODE pNode,
  1891.     pUSBD_CLIENT pClient,
  1892.     pUSBD_NOTIFY_REQ pNotify
  1893.     )
  1894.     {
  1895.     pUSBD_NODE_CLASS pClassType;
  1896.     UINT16 portNo;
  1897.     if (pNode != NULL)
  1898. {
  1899. /* Scan all class types exposed for this node. */
  1900. pClassType = usbListFirst (&pNode->classTypes);
  1901. while (pClassType != NULL)
  1902.     {
  1903.     notifyIfMatch (pNode, pClassType, pClient, pNotify, USBD_DYNA_ATTACH);
  1904.     pClassType = usbListNext (&pClassType->classLink);
  1905.     }
  1906.     
  1907. /* If this node is a hub, then recursively scan child nodes. */
  1908. if (pNode->nodeInfo.nodeType == USB_NODETYPE_HUB &&
  1909.     pNode->pPorts != NULL)
  1910.     {
  1911.     for (portNo = 0; portNo < pNode->numPorts; portNo++)
  1912. scanClassTypes (pNode->pPorts [portNo].pNode, pClient, pNotify);
  1913.     }
  1914. }
  1915.     }
  1916. /***************************************************************************
  1917. *
  1918. * fncDynaAttachReg - Register a client for dynamic attach notification
  1919. *
  1920. * RETURNS: S_usbdLib_xxxx
  1921. */
  1922. LOCAL int fncDynaAttachReg
  1923.     (
  1924.     pURB_DYNA_ATTACH_REG_UNREG pUrb
  1925.     )
  1926.     {
  1927.     pUSBD_CLIENT pClient;
  1928.     pUSBD_NOTIFY_REQ pNotify;
  1929.     pUSBD_HCD pHcd;
  1930.     UINT16 busNo;
  1931.     int s;
  1932.     /* Validate parameters. */
  1933.     if ((s = validateUrb (pUrb, sizeof (*pUrb), &pClient)) != OK)
  1934. return s;
  1935.     if (pUrb->attachCallback == NULL)
  1936. return S_usbdLib_BAD_PARAM;
  1937.     /* Create a new dynamic notification request structure */
  1938.     if ((pNotify = OSS_CALLOC (sizeof (*pNotify))) == NULL)
  1939. return S_usbdLib_OUT_OF_MEMORY;
  1940.     pNotify->deviceClass = pUrb->deviceClass;
  1941.     pNotify->deviceSubClass = pUrb->deviceSubClass;
  1942.     pNotify->deviceProtocol = pUrb->deviceProtocol;
  1943.     pNotify->callback = pUrb->attachCallback;
  1944.     /* Link this to the list of notification requests for the client */
  1945.     usbListLink (&pClient->notifyReqs, pNotify, &pNotify->reqLink, LINK_TAIL);
  1946.     /* At the time of the initial notification registration (now), it is
  1947.      * necessary to scan the list of devices already attached to the USB(s)
  1948.      * in order to see if any match the request.  Devices attached/removed
  1949.      * later will be handled by the busThread.
  1950.      */
  1951.     pHcd = usbListFirst (&hcdList);
  1952.     while (pHcd != NULL)
  1953. {
  1954. for (busNo = 0; busNo < pHcd->busCount; busNo++)
  1955.     scanClassTypes (pHcd->pBuses [busNo].pRoot, pClient, pNotify);
  1956. pHcd = usbListNext (&pHcd->hcdLink);
  1957. }
  1958.     return OK;
  1959.     }
  1960. /***************************************************************************
  1961. *
  1962. * fncDynaAttachUnreg - Unregister a client for dynamic attach notification
  1963. *
  1964. * RETURNS: S_usbdLib_xxxx
  1965. */
  1966. LOCAL int fncDynaAttachUnreg
  1967.     (
  1968.     pURB_DYNA_ATTACH_REG_UNREG pUrb
  1969.     )
  1970.     {
  1971.     pUSBD_CLIENT pClient;
  1972.     pUSBD_NOTIFY_REQ pNotify;
  1973.     int s;
  1974.     /* Validate parameters. */
  1975.     if ((s = validateUrb (pUrb, sizeof (*pUrb), &pClient)) != OK)
  1976. return s;
  1977.     /* Search the client's list of notification requests for one which
  1978.      * matches exactly the parameters in the URB.
  1979.      */
  1980.     pNotify = usbListFirst (&pClient->notifyReqs);
  1981.     while (pNotify != NULL)
  1982. {
  1983. if (pNotify->deviceClass == pUrb->deviceClass &&
  1984.     pNotify->deviceSubClass == pUrb->deviceSubClass &&
  1985.     pNotify->deviceProtocol == pUrb->deviceProtocol &&
  1986.     pNotify->callback == pUrb->attachCallback)
  1987.     {
  1988.     /* We found a matching notification request.  Destroy it. */
  1989.     destroyNotify (pNotify);
  1990.     return OK;
  1991.     }
  1992. pNotify = usbListNext (&pNotify->reqLink);
  1993. }
  1994.     /* If we get this far, no matching request was found.  Declare an error */
  1995.     return S_usbdLib_GENERAL_FAULT;
  1996.     }
  1997. /***************************************************************************
  1998. *
  1999. * controlIrpCallback - called when control pipe Irp completes
  2000. *
  2001. * By convention, the USB_IRP.userPtr field is a pointer to the USBD_NODE
  2002. * for this transfer.
  2003. *
  2004. * RETURNS: N/A
  2005. */
  2006. LOCAL VOID controlIrpCallback
  2007.     (
  2008.     pVOID p /* completed IRP */
  2009.     )
  2010.     {
  2011.     pUSB_IRP pIrp = (pUSB_IRP) p;
  2012.     pUSBD_NODE pNode = pIrp->userPtr;
  2013.     pURB_HEADER pUrb = pNode->pUrb;
  2014.     /* Store the actual length transferred */
  2015.     if (pNode->pActLen != NULL)
  2016. *pNode->pActLen = pIrp->bfrList [1].actLen;
  2017.     /* Store the completion result in the URB */
  2018.     setUrbResult (pUrb, (pIrp->result == OK) ? OK : S_usbdLib_IO_FAULT);
  2019.     /* We're done with the control pipe structures for this node. */
  2020.     OSS_SEM_GIVE (pNode->controlSem);
  2021.     }
  2022. /***************************************************************************
  2023. *
  2024. * controlRequest - Formats and submits a control transfer request
  2025. *
  2026. * This is an internal utility function which formats a USB Setup packet
  2027. * and sends it to the control pipe of a node.
  2028. *
  2029. * RETURNS: S_usbdLib_xxxx
  2030. */
  2031. LOCAL int controlRequest
  2032.     (
  2033.     pURB_HEADER pUrb,     /* URB header */
  2034.     USBD_NODE_ID nodeId,     /* node id */
  2035.     UINT8 requestType,     /* bmRequestType */
  2036.     UINT8 request,     /* bRequest */
  2037.     UINT16 value,     /* wValue */
  2038.     UINT16 index,     /* wIndex */
  2039.     UINT16 length,     /* wLength */
  2040.     pVOID pBfr,      /* data */
  2041.     pUINT16 pActLen     /* actual len for IN data */
  2042.     )
  2043.     {
  2044.     pUSBD_CLIENT pClient;
  2045.     pUSBD_NODE pNode;
  2046.     pUSB_SETUP pSetup;
  2047.     pUSB_IRP pIrp;
  2048.     /* validate the client handle for this request */
  2049.     if (!validateClient (pUrb->handle, &pClient))
  2050. return S_usbdLib_BAD_HANDLE;
  2051.     /* validate the node to which this request is directed */
  2052.     if (!validateNode (nodeId, &pNode))
  2053. return S_usbdLib_BAD_HANDLE;
  2054.     /* Only one control request can be outstanding at a time. */
  2055.     if (OSS_SEM_TAKE (pNode->controlSem, EXCLUSION_TIMEOUT) != OK)
  2056. return S_usbdLib_TIMEOUT;
  2057.     /* we now own the control mutex for this node.  format and issue the
  2058.      * control request to this node.
  2059.      */
  2060.     pSetup = &pNode->setup;
  2061.     pIrp = &pNode->irp;
  2062.     
  2063.     /* format the setup packet */
  2064.     pSetup->requestType = requestType;
  2065.     pSetup->request = request;
  2066.     pSetup->value = TO_LITTLEW (value);
  2067.     pSetup->index = TO_LITTLEW (index);
  2068.     pSetup->length = TO_LITTLEW (length);
  2069.     /* format an IRP to execute this control transfer */
  2070.     memset (pIrp, 0, sizeof (USB_IRP) + sizeof (USB_BFR_LIST));
  2071.     pIrp->userPtr = pNode;
  2072.     pIrp->irpLen = sizeof (USB_IRP) + sizeof (USB_BFR_LIST);
  2073.     pIrp->userCallback = controlIrpCallback;
  2074.     pIrp->flags = USB_FLAG_SHORT_OK;
  2075.     pIrp->timeout = USB_TIMEOUT_DEFAULT;
  2076.     pIrp->transferLen = sizeof (USB_SETUP) + length;
  2077.     /* format bfrList [] entry for Setup packet */
  2078.     pIrp->bfrCount = 0;
  2079.     pIrp->bfrList [pIrp->bfrCount].pid = USB_PID_SETUP;
  2080.     pIrp->bfrList [pIrp->bfrCount].pBfr = (pUINT8) pSetup;
  2081.     pIrp->bfrList [pIrp->bfrCount].bfrLen = sizeof (USB_SETUP);
  2082.     pIrp->bfrCount++;
  2083.     /* format bfrList [] entry for data stage, if any. */
  2084.     if (length > 0)
  2085. {
  2086. pIrp->bfrList [pIrp->bfrCount].pid = 
  2087.     ((requestType & USB_RT_DEV_TO_HOST) != 0) ? USB_PID_IN : USB_PID_OUT;
  2088. pIrp->bfrList [pIrp->bfrCount].pBfr = pBfr;
  2089. pIrp->bfrList [pIrp->bfrCount].bfrLen = length;
  2090. pIrp->bfrCount++;
  2091. }
  2092.     /* All control transfers are followed by a "status" packet for which
  2093.      * the direction is the opposite of that for the data stage and the
  2094.      * length of the transfer is 0. */
  2095.     pIrp->bfrList [pIrp->bfrCount].pid = 
  2096. ((requestType & USB_RT_DEV_TO_HOST) != 0) ? USB_PID_OUT : USB_PID_IN;
  2097.     pIrp->bfrList [pIrp->bfrCount].pBfr = NULL;
  2098.     pIrp->bfrList [pIrp->bfrCount].bfrLen = 0;
  2099.     pIrp->bfrCount++;
  2100.     /* Store info about pending control IRP in node struct */
  2101.     pNode->pClient = pClient;
  2102.     pNode->pUrb = pUrb;
  2103.     pNode->pActLen = pActLen;
  2104.     /* submit the control transfer IRP.
  2105.      *
  2106.      * NOTE: If usbHcdIrpSubmit fails, it will still invoke the IRP callback
  2107.      * which will in turn release the controlSem taken above.  The
  2108.      * callback will also set the URB completion status.
  2109.      */
  2110.     if (usbdTransfer (internalClient, pNode->controlPipe, pIrp) != OK)
  2111. return S_usbdLib_GENERAL_FAULT;
  2112.     return PENDING;
  2113.     }
  2114. /***************************************************************************
  2115. *
  2116. * resetDataToggle - reset data toggle on affected pipes
  2117. *
  2118. * This function is called when a "configuration event" is detected
  2119. * for a given node.  This function searches all pipes associated with
  2120. * the node for any that might be affected by the configuration event
  2121. * and resets their data toggles to DATA0.
  2122. *
  2123. * RETURNS: N/A
  2124. */
  2125. LOCAL VOID resetDataToggle
  2126.     (
  2127.     USBD_NODE_ID nodeId,
  2128.     UINT16 configuration,
  2129.     UINT16 interface,
  2130.     UINT16 endpoint
  2131.     )
  2132.     {
  2133.     pUSBD_NODE pNode;
  2134.     pUSBD_PIPE pPipe;
  2135.     if (!validateNode (nodeId, &pNode))
  2136. return;
  2137.     pPipe = usbListFirst (&pNode->pipes);
  2138.     while (pPipe != NULL)
  2139. {
  2140. if (configuration == ANY_CONFIGURATION ||
  2141.     configuration == pPipe->configuration)
  2142.     {
  2143.     if (interface == ANY_INTERFACE ||
  2144. interface == pPipe->interface)
  2145. {
  2146. if (endpoint == ANY_ENDPOINT ||
  2147.     endpoint == pPipe->endpoint)
  2148.     {
  2149.     pPipe->dataToggle = USB_DATA0;
  2150.     }
  2151. }
  2152.     }
  2153. pPipe = usbListNext (&pPipe->nodePipeLink);
  2154. }
  2155.     }
  2156. /***************************************************************************
  2157. *
  2158. * fncFeatureClear - Clear a USB feature
  2159. *
  2160. * RETURNS: S_usbdLib_xxxx
  2161. */
  2162. LOCAL int fncFeatureClear
  2163.     (
  2164.     pURB_FEATURE_CLEAR_SET pUrb
  2165.     )
  2166.     {
  2167.     /* Check if this constitutes a configuration event.  So, reset the 
  2168.      * data toggle for any affected pipes.
  2169.      */
  2170.     if (pUrb->requestType == (USB_RT_STANDARD | USB_RT_ENDPOINT) &&
  2171. pUrb->feature == USB_FSEL_DEV_ENDPOINT_HALT)
  2172. {
  2173. resetDataToggle (pUrb->nodeId, ANY_CONFIGURATION, ANY_INTERFACE, 
  2174.     pUrb->index);
  2175. }
  2176.     return controlRequest (&pUrb->header, pUrb->nodeId, 
  2177. USB_RT_HOST_TO_DEV | pUrb->requestType, USB_REQ_CLEAR_FEATURE, 
  2178. pUrb->feature, pUrb->index, 0, NULL, NULL);
  2179.     }
  2180. /***************************************************************************
  2181. *
  2182. * fncFeatureSet - Set a USB feature
  2183. *
  2184. * RETURNS: S_usbdLib_xxxx
  2185. */
  2186. LOCAL int fncFeatureSet
  2187.     (
  2188.     pURB_FEATURE_CLEAR_SET pUrb
  2189.     )
  2190.     {
  2191.     return controlRequest (&pUrb->header, pUrb->nodeId, 
  2192. USB_RT_HOST_TO_DEV | pUrb->requestType, USB_REQ_SET_FEATURE, 
  2193. pUrb->feature, pUrb->index, 0, NULL, NULL);
  2194.     }
  2195. /***************************************************************************
  2196. *
  2197. * fncConfigGet - Get a device's configuration
  2198. *
  2199. * RETURNS: S_usbdLib_xxxx
  2200. */
  2201. LOCAL int fncConfigGet
  2202.     (
  2203.     pURB_CONFIG_GET_SET pUrb
  2204.     )
  2205.     {
  2206.     pUrb->configuration = 0;
  2207.     return controlRequest (&pUrb->header, pUrb->nodeId, 
  2208. USB_RT_DEV_TO_HOST | USB_RT_STANDARD | USB_RT_DEVICE,
  2209. USB_REQ_GET_CONFIGURATION, 0, 0, 1, &pUrb->configuration, NULL);
  2210.     }
  2211. /***************************************************************************
  2212. *
  2213. * fncConfigSet - Set a device's configuration
  2214. *
  2215. * RETURNS: S_usbdLib_xxxx
  2216. */
  2217. LOCAL int fncConfigSet
  2218.     (
  2219.     pURB_CONFIG_GET_SET pUrb
  2220.     )
  2221.     {
  2222.     pUSBD_NODE pNode;
  2223.     pUSBD_NODE pParentNode;
  2224.     /* Validate parameters */
  2225.     if (!validateNode (pUrb->nodeId, &pNode))
  2226. return S_usbdLib_BAD_HANDLE;
  2227.     /* Verify that the port to which this device is connected is capable of
  2228.      * providing the current needed by this device.
  2229.      */
  2230.     if (pNode != pNode->pBus->pRoot && pNode->pBus->pRoot != NULL)
  2231. {
  2232. /* Retrieve the pointer to the parent hub for this node */
  2233. validateNode (pNode->nodeInfo.parentHubId, &pParentNode);
  2234. /* Check the power required against the parent's capability */
  2235. if (pUrb->maxPower > pParentNode->maxPowerPerPort)
  2236.     return S_usbdLib_POWER_FAULT;
  2237. }
  2238.     /* This constitutes a configuration event. So, reset the data toggle
  2239.      * for any affected pipes.
  2240.      */
  2241.     resetDataToggle (pUrb->nodeId, pUrb->configuration, ANY_INTERFACE, 
  2242. ANY_ENDPOINT);
  2243.     /* Set the device's configuration */
  2244.     return controlRequest (&pUrb->header, pUrb->nodeId, 
  2245. USB_RT_HOST_TO_DEV | USB_RT_STANDARD | USB_RT_DEVICE,
  2246. USB_REQ_SET_CONFIGURATION, pUrb->configuration, 0, 0, NULL, NULL);
  2247.     }
  2248. /***************************************************************************
  2249. *
  2250. * fncDescriptorGet - Retrieve a USB descriptor
  2251. *
  2252. * RETURNS: S_usbdLib_xxxx
  2253. */
  2254. LOCAL int fncDescriptorGet
  2255.     (
  2256.     pURB_DESCRIPTOR_GET_SET pUrb
  2257.     )
  2258.     {
  2259.     return controlRequest (&pUrb->header, pUrb->nodeId,
  2260. USB_RT_DEV_TO_HOST | pUrb->requestType, USB_REQ_GET_DESCRIPTOR,
  2261. pUrb->descriptorType << 8 | pUrb->descriptorIndex,
  2262. pUrb->languageId, pUrb->bfrLen, pUrb->pBfr, &pUrb->actLen);
  2263.     }
  2264. /***************************************************************************
  2265. *
  2266. * fncDescriptorSet - Sets a USB descriptor
  2267. *
  2268. * RETURNS: S_usbdLib_xxxx
  2269. */
  2270. LOCAL int fncDescriptorSet
  2271.     (
  2272.     pURB_DESCRIPTOR_GET_SET pUrb
  2273.     )
  2274.     {
  2275.     return controlRequest (&pUrb->header, pUrb->nodeId,
  2276. USB_RT_HOST_TO_DEV | pUrb->requestType, USB_REQ_SET_DESCRIPTOR,
  2277. pUrb->descriptorType << 8 | pUrb->descriptorIndex,
  2278. pUrb->languageId, pUrb->bfrLen, pUrb->pBfr, NULL);
  2279.     }
  2280. /***************************************************************************
  2281. *
  2282. * fncInterfaceGet - Returns a device's interface setting
  2283. *
  2284. * RETURNS: S_usbdLib_xxxx
  2285. */
  2286. LOCAL int fncInterfaceGet
  2287.     (
  2288.     pURB_INTERFACE_GET_SET pUrb
  2289.     )
  2290.     {
  2291.     pUrb->alternateSetting = 0;
  2292.     return controlRequest (&pUrb->header, pUrb->nodeId,
  2293. USB_RT_DEV_TO_HOST | USB_RT_STANDARD | USB_RT_INTERFACE,
  2294. USB_REQ_GET_INTERFACE, 0, pUrb->interfaceIndex, 1, 
  2295. &pUrb->alternateSetting, NULL);
  2296.     }
  2297. /***************************************************************************
  2298. *
  2299. * fncInterfaceSet - Sets a device's interface setting
  2300. *
  2301. * RETURNS: S_usbdLib_xxxx
  2302. */
  2303. LOCAL int fncInterfaceSet
  2304.     (
  2305.     pURB_INTERFACE_GET_SET pUrb
  2306.     )
  2307.     {
  2308.     /* This constitutes a configuration event. So, reset the data toggle
  2309.      * for any affected pipes.
  2310.      */
  2311.     resetDataToggle (pUrb->nodeId, ANY_CONFIGURATION, pUrb->interfaceIndex,
  2312. ANY_ENDPOINT);
  2313.     return controlRequest (&pUrb->header, pUrb->nodeId,
  2314. USB_RT_HOST_TO_DEV | USB_RT_STANDARD | USB_RT_INTERFACE,
  2315. USB_REQ_SET_INTERFACE, pUrb->alternateSetting, pUrb->interfaceIndex,
  2316. 0, NULL, NULL);
  2317.     }
  2318. /***************************************************************************
  2319. *
  2320. * fncStatusGet - Returns a device/interface/endpoint status word
  2321. *
  2322. * RETURNS: S_usbdLib_xxxx
  2323. */
  2324. LOCAL int fncStatusGet
  2325.     (
  2326.     pURB_STATUS_GET pUrb
  2327.     )
  2328.     {
  2329.     return controlRequest (&pUrb->header, pUrb->nodeId,
  2330. USB_RT_DEV_TO_HOST | pUrb->requestType, USB_REQ_GET_STATUS, 
  2331. 0, pUrb->index, pUrb->bfrLen, pUrb->pBfr, &pUrb->actLen);
  2332.     }
  2333. /***************************************************************************
  2334. *
  2335. * fncAddressGet - Returns a node's USB address
  2336. *
  2337. * RETURNS: S_usbdLib_xxxx
  2338. */
  2339. LOCAL int fncAddressGet
  2340.     (
  2341.     pURB_ADDRESS_GET_SET pUrb
  2342.     )
  2343.     {
  2344.     pUSBD_NODE pNode;
  2345.     /* validate node handle */
  2346.     if (!validateNode (pUrb->nodeId, &pNode))
  2347. return S_usbdLib_BAD_HANDLE;
  2348.     /* return current USB address for node */
  2349.     pUrb->deviceAddress = pNode->busAddress;
  2350.     return OK;
  2351.     }
  2352. /***************************************************************************
  2353. *
  2354. * fncAddressSet - Sets a node's USB address
  2355. *
  2356. * RETURNS: S_usbdLib_xxxx
  2357. */
  2358. LOCAL int fncAddressSet
  2359.     (
  2360.     pURB_ADDRESS_GET_SET pUrb
  2361.     )
  2362.     {
  2363.     int s;
  2364.     s = controlRequest (&pUrb->header, pUrb->nodeId, 
  2365. USB_RT_HOST_TO_DEV | USB_RT_STANDARD | USB_RT_DEVICE,
  2366. USB_REQ_SET_ADDRESS, pUrb->deviceAddress, 0, 0, NULL, NULL);
  2367.     OSS_THREAD_SLEEP (USB_TIME_SET_ADDRESS);
  2368.     return s;
  2369.     }
  2370. /***************************************************************************
  2371. *
  2372. * fncNodeInfoGet - Returns information about a node
  2373. *
  2374. * RETURNS: S_usbdLib_xxxx
  2375. */
  2376. LOCAL int fncNodeInfoGet
  2377.     (
  2378.     pURB_NODE_INFO_GET pUrb
  2379.     )
  2380.     {
  2381.     pUSBD_NODE pNode;
  2382.     /* Validate root */
  2383.     if (!validateNode (pUrb->nodeId, &pNode))
  2384. return S_usbdLib_BAD_HANDLE;
  2385.     /* Validate other parameters */
  2386.     if (pUrb->pNodeInfo == NULL)
  2387. return S_usbdLib_BAD_PARAM;
  2388.     /* Copy node info to caller's buffer */
  2389.     memcpy (pUrb->pNodeInfo, &pNode->nodeInfo,
  2390. min (pUrb->infoLen, sizeof (pNode->nodeInfo)));
  2391.     return OK;
  2392.     }
  2393. /***************************************************************************
  2394. *
  2395. * fncVendorSpecific - Executes a vendor-specific USB request
  2396. *
  2397. * RETURNS: S_usbdLib_xxxx
  2398. */
  2399. LOCAL int fncVendorSpecific
  2400.     (
  2401.     pURB_VENDOR_SPECIFIC pUrb
  2402.     )
  2403.     {
  2404.     return controlRequest (&pUrb->header, pUrb->nodeId,
  2405. pUrb->requestType, pUrb->request, pUrb->value, pUrb->index,
  2406. pUrb->length, pUrb->pBfr, &pUrb->actLen);
  2407.     }
  2408. /***************************************************************************
  2409. *
  2410. * fncPipeCreate - Create a new transfer pipe
  2411. *
  2412. * RETURNS: S_usbdLib_xxxx
  2413. */
  2414. LOCAL int fncPipeCreate
  2415.     (
  2416.     pURB_PIPE_CREATE pUrb
  2417.     )
  2418.     {
  2419.     pUSBD_CLIENT pClient;
  2420.     pUSBD_NODE pNode;
  2421.     pUSBD_PIPE pPipe;
  2422.     pUSBD_BUS pBus;
  2423.     UINT32 nanoseconds = 0;
  2424.     HCD_PIPE_HANDLE hcdPipeHandle;
  2425.     /* validate the client handle for this request */
  2426.     if (!validateClient (pUrb->header.handle, &pClient))
  2427. return S_usbdLib_BAD_HANDLE;
  2428.     /* validate the node to which this request is directed */
  2429.     if (!validateNode (pUrb->nodeId, &pNode))
  2430. return S_usbdLib_BAD_HANDLE;
  2431.     /* Validate other parameters */
  2432.     if ((pUrb->transferType == USB_XFRTYPE_ISOCH ||
  2433. pUrb->transferType == USB_XFRTYPE_INTERRUPT) &&
  2434. pUrb->bandwidth == 0)
  2435. return S_usbdLib_BAD_PARAM;
  2436.     if (pUrb->transferType == USB_XFRTYPE_INTERRUPT &&
  2437. pUrb->serviceInterval == 0)
  2438. return S_usbdLib_BAD_PARAM;
  2439.     /* Make sure a default packet size is specified */
  2440.     if (pUrb->maxPayload == 0)
  2441. pUrb->maxPayload = USB_MIN_CTRL_PACKET_SIZE;
  2442.     /* Notify HCD of new pipe and make sure enough bandwidth is available to 
  2443.      * create the pipe. 
  2444.      */
  2445.     pBus = pNode->pBus;
  2446.     if (usbHcdPipeCreate (&pBus->pHcd->nexus, pBus->busNo, 
  2447. pNode->busAddress, pUrb->endpoint, 
  2448. pUrb->transferType, pUrb->direction, pNode->nodeInfo.nodeSpeed, 
  2449. pUrb->maxPayload, pUrb->bandwidth, pUrb->serviceInterval, 
  2450. &nanoseconds, &hcdPipeHandle) != OK)
  2451. {
  2452. return S_usbdLib_BANDWIDTH_FAULT;
  2453. }
  2454.     /* Try to create a new pipe structure */
  2455.     if ((pPipe = OSS_CALLOC (sizeof (*pPipe))) == NULL ||
  2456. usbHandleCreate (USBD_PIPE_SIG, pPipe, &pPipe->handle) != OK)
  2457. {
  2458. destroyPipe (pPipe);
  2459. return S_usbdLib_OUT_OF_MEMORY;
  2460. }
  2461.     pPipe->hcdHandle = hcdPipeHandle;
  2462.     pPipe->pClient = pClient;
  2463.     pPipe->pNode = pNode;
  2464.     pPipe->endpoint = pUrb->endpoint;
  2465.     pPipe->configuration = pUrb->configuration;
  2466.     pPipe->interface = pUrb->interface;
  2467.     pPipe->transferType = pUrb->transferType;
  2468.     pPipe->direction = pUrb->direction;
  2469.     pPipe->maxPacketSize = pUrb->maxPayload;
  2470.     pPipe->bandwidth = pUrb->bandwidth;
  2471.     pPipe->interval = pUrb->serviceInterval;
  2472.     pPipe->dataToggle = USB_DATA0;
  2473.     pPipe->nanoseconds = nanoseconds;
  2474.     pBus->nanoseconds += nanoseconds;
  2475.     /* Link pipe to list of pipes owned by this client */
  2476.     usbListLink (&pClient->pipes, pPipe, &pPipe->clientPipeLink, LINK_HEAD);
  2477.     /* Link pipe to list of pipes addressed to this node */
  2478.     usbListLink (&pNode->pipes, pPipe, &pPipe->nodePipeLink, LINK_HEAD);
  2479.     /* Return pipe handle */
  2480.     pUrb->pipeHandle = pPipe->handle;
  2481.     return OK;
  2482.     }
  2483. /***************************************************************************
  2484. *
  2485. * fncPipeDestroy - Destroy a transfer pipe
  2486. *
  2487. * RETURNS: S_usbdLib_xxxx
  2488. */
  2489. LOCAL int fncPipeDestroy
  2490.     (
  2491.     pURB_PIPE_DESTROY pUrb
  2492.     )
  2493.     {
  2494.     pUSBD_PIPE pPipe;
  2495.     /* validate the pipe handle */
  2496.     if (!validatePipe (pUrb->pipeHandle, &pPipe))
  2497. return S_usbdLib_BAD_HANDLE;
  2498.     /* Destroy the pipe */
  2499.     destroyPipe (pPipe);
  2500.     return OK;
  2501.     }
  2502. /***************************************************************************
  2503. *
  2504. * transferIrpCallback - invoked when a client's IRP completes
  2505. *
  2506. * Removes the IRP from the list of IRPs being tracked by the USBD and
  2507. * triggers the invocation of the client's IRP callback routine.
  2508. *
  2509. * NOTE: By convention, the USB_IRP.usbdPtr field points to the USBD_PIPE
  2510. * on which this transfer is being performed.
  2511. *
  2512. * RETURNS: N/A
  2513. */
  2514. LOCAL VOID transferIrpCallback
  2515.     (
  2516.     pVOID p /* pointer to completed IRP */
  2517.     )
  2518.     {
  2519.     pUSB_IRP pIrp = (pUSB_IRP) p;
  2520.     pUSBD_PIPE pPipe = (pUSBD_PIPE) pIrp->usbdPtr;
  2521.     UINT16 packets;
  2522.     UINT16 i;
  2523.     /* Unlink the IRP from the list of IRPs on this pipe. */
  2524.     usbListUnlink (&pIrp->usbdLink);
  2525.     /* Check if this IRP is being deleted.  If so, let the foreground
  2526.      * thread know the callback has been invoked.
  2527.      */
  2528.     if (pIrp == pPipe->irpBeingDeleted)
  2529. pPipe->irpDeleted = TRUE;
  2530.     /* Update bus statistics */
  2531.     if (pIrp->result != OK)
  2532. {
  2533. if (pIrp->bfrList [0].pid == USB_PID_IN)
  2534.     pPipe->pNode->pBus->stats.totalReceiveErrors++;
  2535. else 
  2536.     pPipe->pNode->pBus->stats.totalTransmitErrors++;
  2537. }
  2538.     /* Update data toggle for pipe.  Control and isochronous transfers
  2539.      * always begin with DATA0, which is set at pipe initialization -
  2540.      * so we don't change it here.  Bulk and interrupt pipes alternate
  2541.      * between DATA0 and DATA1, and we need to keep a running track of
  2542.      * the state across IRPs.
  2543.      */
  2544.     if (pPipe->transferType == USB_XFRTYPE_INTERRUPT ||
  2545. pPipe->transferType == USB_XFRTYPE_BULK)
  2546. {
  2547. /* Calculate the number of packets exchanged to determine the
  2548.  * next data toggle value.  If the count of packets is odd, then
  2549.  * the data toggle needs to switch.
  2550.  *
  2551.  * NOTE: If the IRP is successful, then at least one packet MUST
  2552.  * have been transferred.  However, it may have been a 0-length
  2553.  * packet.  This case is handled after the following "for" loop.
  2554.  */
  2555. packets = 0;
  2556. for (i = 0; i < pIrp->bfrCount; i++)
  2557.     {
  2558.     packets += (pIrp->bfrList [i].actLen + pPipe->maxPacketSize - 1) /
  2559. pPipe->maxPacketSize;
  2560.     }
  2561. if (pIrp->result == OK)
  2562.     packets = max (packets, 1);
  2563. if ((packets & 1) != 0)
  2564.     pPipe->dataToggle = (pPipe->dataToggle == USB_DATA0) ?
  2565. USB_DATA1 : USB_DATA0;
  2566. }
  2567.     /* Invoke the user's callback routine */
  2568.     if (pIrp->userCallback != NULL)
  2569. {
  2570. /* If the userCallback routine is internal to the USBD, then
  2571.  * invoke it directly as its behavior is known.  This
  2572.  * streamlines processing of internally generated IRPs.
  2573.  * Moreover, this eliminates a deadlock condition which can
  2574.  * occur if a client's code invoked on the clientThread()
  2575.  * reenters the USBD.  That thread might block waiting for
  2576.  * the execution of a clientThread() callback - which would
  2577.  * never execute.
  2578.  */
  2579. if (pIrp->userCallback == hubIrpCallback)
  2580.     hubIrpCallback (pIrp);
  2581. else if (pIrp->userCallback == controlIrpCallback)
  2582.     controlIrpCallback (pIrp);
  2583. else
  2584.     usbQueuePut (pPipe->pClient->callbackQueue, 
  2585. CALLBACK_FNC_IRP_COMPLETE, 0, (UINT32) pIrp, OSS_BLOCK);
  2586. }
  2587.     }
  2588. /***************************************************************************
  2589. *
  2590. * fncTransfer - Initiates a transfer through a pipe
  2591. *
  2592. * RETURNS: S_usbdLib_xxxx
  2593. */
  2594. LOCAL int fncTransfer
  2595.     (
  2596.     pURB_TRANSFER pUrb
  2597.     )
  2598.     {
  2599.     pUSBD_PIPE pPipe;
  2600.     pUSB_IRP pIrp;
  2601.     /* validate the pipe handle */
  2602.     if (!validatePipe (pUrb->pipeHandle, &pPipe))
  2603. return S_usbdLib_BAD_HANDLE;
  2604.     /* validate the IRP */
  2605.     if ((pIrp = pUrb->pIrp) == NULL || pIrp->userCallback == NULL)
  2606. return S_usbdLib_BAD_PARAM;
  2607.     /* Fill in IRP fields */
  2608.     pIrp->usbdPtr = pPipe;
  2609.     pIrp->usbdCallback = transferIrpCallback;
  2610.     pIrp->dataToggle = pPipe->dataToggle;
  2611.     /* Set an appropriate timeout value */
  2612.     if (pPipe->transferType == USB_XFRTYPE_CONTROL ||
  2613. pPipe->transferType == USB_XFRTYPE_BULK)
  2614. {
  2615. if (pIrp->timeout == 0)
  2616.     pIrp->timeout = USB_TIMEOUT_DEFAULT;
  2617. }
  2618.     /* Update bus statistics */
  2619.     if (pIrp->bfrList [0].pid == USB_PID_IN)
  2620. pPipe->pNode->pBus->stats.totalTransfersIn++;
  2621.     else 
  2622. pPipe->pNode->pBus->stats.totalTransfersOut++;
  2623.     /* Link the IRP to the list of IRPs we're tracking on this pipe. */
  2624.     usbListLink (&pPipe->irps, pIrp, &pIrp->usbdLink, LINK_TAIL);
  2625.     /* Deliver the IRP to the HCD */
  2626.     if (usbHcdIrpSubmit (&pPipe->pNode->pBus->pHcd->nexus, 
  2627. pPipe->hcdHandle, pIrp) != OK)
  2628. {
  2629. usbListUnlink (&pIrp->usbdLink);
  2630. return S_usbdLib_HCD_FAULT;
  2631. }
  2632.     return OK;
  2633.     }
  2634. /***************************************************************************
  2635. *
  2636. * fncTransferAbort - Abort a transfer request
  2637. *
  2638. * RETURNS: S_usbdLib_xxxx
  2639. */
  2640. LOCAL int fncTransferAbort
  2641.     (
  2642.     pURB_TRANSFER pUrb
  2643.     )
  2644.     {
  2645.     pUSBD_PIPE pPipe;
  2646.     pUSB_IRP pIrp;
  2647.     /* validate the pipe handle */
  2648.     if (!validatePipe (pUrb->pipeHandle, &pPipe))
  2649. return S_usbdLib_BAD_HANDLE;
  2650.     /* validate the IRP */
  2651.     if ((pIrp = pUrb->pIrp) == NULL)
  2652. return S_usbdLib_BAD_PARAM;
  2653.     /* Cancel the IRP */
  2654.     return doTransferAbort (pPipe, pIrp);
  2655.     }
  2656. /***************************************************************************
  2657. *
  2658. * fncSynchFrameGet - Returns isochronous synch frame for an endpoint
  2659. *
  2660. * RETURNS: S_usbdLib_xxxx
  2661. */
  2662. LOCAL int fncSynchFrameGet
  2663.     (
  2664.     pURB_SYNCH_FRAME_GET pUrb
  2665.     )
  2666.     {
  2667.     return controlRequest (&pUrb->header, pUrb->nodeId,
  2668. USB_RT_DEV_TO_HOST | USB_RT_STANDARD | USB_RT_ENDPOINT,
  2669. USB_REQ_GET_SYNCH_FRAME, 0, pUrb->endpoint, 2, 
  2670. &pUrb->frameNo, NULL);
  2671.     }
  2672. /***************************************************************************
  2673. *
  2674. * fncCurrentFrameGet - Returns current frame number on a USB
  2675. *
  2676. * RETURNS: S_usbdLib_xxxx
  2677. */
  2678. LOCAL int fncCurrentFrameGet
  2679.     (
  2680.     pURB_CURRENT_FRAME_GET pUrb
  2681.     )
  2682.     {
  2683.     pUSBD_NODE pNode;
  2684.     /* validate node handle */
  2685.     if (!validateNode (pUrb->nodeId, &pNode))
  2686. return S_usbdLib_BAD_HANDLE;
  2687.     /* Retrieve the current frame number and frame window size from the
  2688.      * HCD for this root.
  2689.      */
  2690.     if (usbHcdCurrentFrameGet (&pNode->pBus->pHcd->nexus, pNode->pBus->busNo,
  2691. &pUrb->frameNo, &pUrb->frameWindow) != OK)
  2692. return S_usbdLib_HCD_FAULT;
  2693.     return OK;
  2694.     }
  2695. /***************************************************************************
  2696. *
  2697. * fncSofMasterTake - take SOF master ownership for a bus
  2698. *
  2699. * RETURNS: S_usbdLib_xxxx
  2700. */
  2701. LOCAL int fncSofMasterTake
  2702.     (
  2703.     pURB_SOF_MASTER pUrb
  2704.     )
  2705.     {
  2706.     pUSBD_CLIENT pClient;
  2707.     pUSBD_NODE pNode;
  2708.     int s;
  2709.     /* validate parameters */
  2710.     if ((s = validateUrb (pUrb, sizeof (*pUrb), &pClient)) != OK)
  2711. return s;
  2712.     if (!validateNode (pUrb->nodeId, &pNode))
  2713. return S_usbdLib_BAD_HANDLE;
  2714.     /* Check if another client already is SOF master for the indicated bus */
  2715.     if (pNode->pBus->pSofMasterClient != NULL)
  2716. return S_usbdLib_SOF_MASTER_FAULT;
  2717.     /* Make this client the SOF master. */
  2718.     pNode->pBus->pSofMasterClient = pClient;
  2719.     return OK;
  2720.     }
  2721. /***************************************************************************
  2722. *
  2723. * fncSofMasterRelease - release SOF master ownership for a bus
  2724. *
  2725. * RETURNS: S_usbdLib_xxxx
  2726. */
  2727. LOCAL int fncSofMasterRelease
  2728.     (
  2729.     pURB_SOF_MASTER pUrb
  2730.     )
  2731.     {
  2732.     pUSBD_CLIENT pClient;
  2733.     pUSBD_NODE pNode;
  2734.     int s;
  2735.     /* validate parameters */
  2736.     if ((s = validateUrb (pUrb, sizeof (*pUrb), &pClient)) != OK)
  2737. return s;
  2738.     if (!validateNode (pUrb->nodeId, &pNode))
  2739. return S_usbdLib_BAD_HANDLE;
  2740.     /* Check if this client is the SOF master. */
  2741.     if (pNode->pBus->pSofMasterClient != pClient)
  2742. return S_usbdLib_SOF_MASTER_FAULT;
  2743.     /* Clear the SOF master */
  2744.     pNode->pBus->pSofMasterClient = NULL;
  2745.     return OK;
  2746.     }
  2747. /***************************************************************************
  2748. *
  2749. * fncSofIntervalGet - retrieve SOF interval for a bus
  2750. *
  2751. * RETURNS: S_usbdLib_xxxx
  2752. */
  2753. LOCAL int fncSofIntervalGet
  2754.     (
  2755.     pURB_SOF_INTERVAL_GET_SET pUrb
  2756.     )
  2757.     {
  2758.     pUSBD_CLIENT pClient;
  2759.     pUSBD_NODE pNode;
  2760.     int s;
  2761.     /* validate parameters */
  2762.     if ((s = validateUrb (pUrb, sizeof (*pUrb), &pClient)) != OK)
  2763. return s;
  2764.     if (!validateNode (pUrb->nodeId, &pNode))
  2765. return S_usbdLib_BAD_HANDLE;
  2766.     /* Retrieve the current SOF interval for this bus. */
  2767.     if (usbHcdSofIntervalGet (&pNode->pBus->pHcd->nexus, pNode->pBus->busNo,
  2768. &pUrb->sofInterval) != OK)
  2769. return S_usbdLib_HCD_FAULT;
  2770.     return OK;
  2771.     }
  2772. /***************************************************************************
  2773. *
  2774. * fncSofIntervalSet - set SOF interval for a bus
  2775. *
  2776. * RETURNS: S_usbdLib_xxxx
  2777. */
  2778. LOCAL int fncSofIntervalSet
  2779.     (
  2780.     pURB_SOF_INTERVAL_GET_SET pUrb
  2781.     )
  2782.     {
  2783.     pUSBD_CLIENT pClient;
  2784.     pUSBD_NODE pNode;
  2785.     int s;
  2786.     /* validate parameters */
  2787.     if ((s = validateUrb (pUrb, sizeof (*pUrb), &pClient)) != OK)
  2788. return s;
  2789.     if (!validateNode (pUrb->nodeId, &pNode))
  2790. return S_usbdLib_BAD_HANDLE;
  2791.     /* Check if this client is the SOF master. */
  2792.     if (pNode->pBus->pSofMasterClient != pClient)
  2793. return S_usbdLib_SOF_MASTER_FAULT;
  2794.     /* Set new SOF interval */
  2795.     if (usbHcdSofIntervalSet (&pNode->pBus->pHcd->nexus, pNode->pBus->busNo,
  2796. pUrb->sofInterval) != OK)
  2797. return S_usbdLib_HCD_FAULT;
  2798.     return OK;
  2799.     }
  2800. /***************************************************************************
  2801. *
  2802. * fncBusStateSet - sets bus state (e.g., suspend/resume)
  2803. *
  2804. * RETURNS: S_usbdLib_xxxx
  2805. */
  2806. LOCAL int fncBusStateSet
  2807.     (
  2808.     pURB_BUS_STATE_SET pUrb
  2809.     )
  2810.     {
  2811.     pUSBD_CLIENT pClient;
  2812.     pUSBD_NODE pNode;
  2813.     pUSBD_BUS pBus;
  2814.     int s;
  2815.     /* validate parameters */
  2816.     if ((s = validateUrb (pUrb, sizeof (*pUrb), &pClient)) != OK)
  2817. return s;
  2818.     if (!validateNode (pUrb->nodeId, &pNode))
  2819. return S_usbdLib_BAD_HANDLE;
  2820.     /* Set the indicated bus state */
  2821.     pBus = pNode->pBus;
  2822.     if ((pUrb->busState & USBD_BUS_SUSPEND) != 0)
  2823. {
  2824. /* SUSPEND bus */
  2825. if (!pBus->suspended)
  2826.     {
  2827.     if (usbHcdSetBusState (&pBus->pHcd->nexus, pBus->busNo,
  2828. HCD_BUS_SUSPEND) != OK)
  2829. return S_usbdLib_HCD_FAULT;
  2830.     pBus->suspended = TRUE;
  2831.     }
  2832. }
  2833.     if ((pUrb->busState & USBD_BUS_RESUME) != 0)
  2834. {
  2835. /* RESUME bus */
  2836. if (pBus->suspended)
  2837.     {
  2838.     if (usbHcdSetBusState (&pBus->pHcd->nexus, pBus->busNo,
  2839. HCD_BUS_RESUME) != OK)
  2840. return S_usbdLib_HCD_FAULT;
  2841.     pBus->suspended = FALSE;
  2842.     }
  2843. }
  2844.     return OK;
  2845.     }
  2846. /***************************************************************************
  2847. *
  2848. * usbdCoreEntry - Primary entry point
  2849. *
  2850. * usbdCoreEntry is the primary entry point to the USBD through which callers
  2851. * invoke individual URBs (USB Request Blocks).
  2852. *
  2853. * NOTE: This function is intended exclusively for the use of functions in
  2854. * usbdLib.  Clients should not construct URBs manually and invoke this 
  2855. * function directly.
  2856. *
  2857. * RETURNS: OK or ERROR
  2858. *
  2859. * ERRNO:
  2860. *  S_usbdLib_BAD_PARAM
  2861. */
  2862. STATUS usbdCoreEntry
  2863.     (
  2864.     pURB_HEADER pUrb /* URB to be executed */
  2865.     )
  2866.     {
  2867.     int s;
  2868.     
  2869.     /* Validate parameters */
  2870.     if (pUrb == NULL || pUrb->urbLength < sizeof (URB_HEADER))
  2871. return ossStatus (S_usbdLib_BAD_PARAM);
  2872.     /* Unless this call is for initialization or shutdown, take the
  2873.      * structMutex to prevent other threads from tampering with USBD
  2874.      * data structures.
  2875.      */
  2876.     if (pUrb->function != USBD_FNC_INITIALIZE && 
  2877. pUrb->function != USBD_FNC_SHUTDOWN)
  2878. {
  2879. OSS_MUTEX_TAKE (structMutex, OSS_BLOCK);
  2880. }
  2881.     /* Fan-out to appropriate function processor */
  2882.     switch (pUrb->function)
  2883. {
  2884. case USBD_FNC_INITIALIZE:   
  2885.     s = fncInitialize (pUrb);
  2886.     break;
  2887. case USBD_FNC_SHUTDOWN:
  2888.     s = fncShutdown (pUrb);
  2889.     break;
  2890. case USBD_FNC_CLIENT_REG:
  2891.     s = fncClientReg ((pURB_CLIENT_REG) pUrb);
  2892.     break;
  2893. case USBD_FNC_CLIENT_UNREG:
  2894.     s = fncClientUnreg ((pURB_CLIENT_UNREG) pUrb);
  2895.     break;
  2896. case USBD_FNC_MNGMT_CALLBACK_SET:
  2897.     s = fncMngmtCallbackSet ((pURB_MNGMT_CALLBACK_SET) pUrb);
  2898.     break;
  2899. case USBD_FNC_VERSION_GET:
  2900.     s = fncVersionGet ((pURB_VERSION_GET) pUrb);
  2901.     break;
  2902. case USBD_FNC_HCD_ATTACH:
  2903.     s = fncHcdAttach ((pURB_HCD_ATTACH) pUrb);
  2904.     break;
  2905. case USBD_FNC_HCD_DETACH:
  2906.     s = fncHcdDetach ((pURB_HCD_DETACH) pUrb);
  2907.     break;
  2908. case USBD_FNC_STATISTICS_GET:
  2909.     s = fncStatisticsGet ((pURB_STATISTICS_GET) pUrb);
  2910.     break;
  2911. case USBD_FNC_BUS_COUNT_GET:
  2912.     s = fncBusCountGet ((pURB_BUS_COUNT_GET) pUrb);
  2913.     break;
  2914. case USBD_FNC_ROOT_ID_GET:
  2915.     s = fncRootIdGet ((pURB_ROOT_ID_GET) pUrb);
  2916.     break;
  2917. case USBD_FNC_HUB_PORT_COUNT_GET:
  2918.     s = fncHubPortCountGet ((pURB_HUB_PORT_COUNT_GET) pUrb);
  2919.     break;
  2920. case USBD_FNC_NODE_ID_GET:
  2921.     s = fncNodeIdGet ((pURB_NODE_ID_GET) pUrb);
  2922.     break;
  2923. case USBD_FNC_DYNA_ATTACH_REG:
  2924.     s = fncDynaAttachReg ((pURB_DYNA_ATTACH_REG_UNREG) pUrb);
  2925.     break;
  2926. case USBD_FNC_DYNA_ATTACH_UNREG:
  2927.     s = fncDynaAttachUnreg ((pURB_DYNA_ATTACH_REG_UNREG) pUrb);
  2928.     break;
  2929. case USBD_FNC_FEATURE_CLEAR:
  2930.     s = fncFeatureClear ((pURB_FEATURE_CLEAR_SET) pUrb);
  2931.     break;
  2932. case USBD_FNC_FEATURE_SET:
  2933.     s = fncFeatureSet ((pURB_FEATURE_CLEAR_SET) pUrb);
  2934.     break;
  2935. case USBD_FNC_CONFIG_GET:
  2936.     s = fncConfigGet ((pURB_CONFIG_GET_SET) pUrb);
  2937.     break;
  2938. case USBD_FNC_CONFIG_SET:
  2939.     s = fncConfigSet ((pURB_CONFIG_GET_SET) pUrb);
  2940.     break;
  2941. case USBD_FNC_DESCRIPTOR_GET:
  2942.     s = fncDescriptorGet ((pURB_DESCRIPTOR_GET_SET) pUrb);
  2943.     break;
  2944. case USBD_FNC_DESCRIPTOR_SET:
  2945.     s = fncDescriptorSet ((pURB_DESCRIPTOR_GET_SET) pUrb);
  2946.     break;
  2947. case USBD_FNC_INTERFACE_GET:
  2948.     s = fncInterfaceGet ((pURB_INTERFACE_GET_SET) pUrb);
  2949.     break;
  2950. case USBD_FNC_INTERFACE_SET:
  2951.     s = fncInterfaceSet ((pURB_INTERFACE_GET_SET) pUrb);
  2952.     break;
  2953. case USBD_FNC_STATUS_GET:
  2954.     s = fncStatusGet ((pURB_STATUS_GET) pUrb);
  2955.     break;
  2956. case USBD_FNC_ADDRESS_GET:
  2957.     s = fncAddressGet ((pURB_ADDRESS_GET_SET) pUrb);
  2958.     break;
  2959. case USBD_FNC_ADDRESS_SET:
  2960.     s = fncAddressSet ((pURB_ADDRESS_GET_SET) pUrb);
  2961.     break;
  2962. case USBD_FNC_NODE_INFO_GET:
  2963.     s = fncNodeInfoGet ((pURB_NODE_INFO_GET) pUrb);
  2964.     break;
  2965. case USBD_FNC_VENDOR_SPECIFIC:
  2966.     s = fncVendorSpecific ((pURB_VENDOR_SPECIFIC) pUrb);
  2967.     break;
  2968. case USBD_FNC_PIPE_CREATE:
  2969.     s = fncPipeCreate ((pURB_PIPE_CREATE) pUrb);
  2970.     break;
  2971. case USBD_FNC_PIPE_DESTROY:
  2972.     s = fncPipeDestroy ((pURB_PIPE_DESTROY) pUrb);
  2973.     break;
  2974. case USBD_FNC_TRANSFER:
  2975.     s = fncTransfer ((pURB_TRANSFER) pUrb);
  2976.     break;
  2977. case USBD_FNC_TRANSFER_ABORT:
  2978.     s = fncTransferAbort ((pURB_TRANSFER) pUrb);
  2979.     break;
  2980. case USBD_FNC_SYNCH_FRAME_GET:
  2981.     s = fncSynchFrameGet ((pURB_SYNCH_FRAME_GET) pUrb);
  2982.     break;
  2983. case USBD_FNC_CURRENT_FRAME_GET:
  2984.     s = fncCurrentFrameGet ((pURB_CURRENT_FRAME_GET) pUrb);
  2985.     break;
  2986. case USBD_FNC_SOF_MASTER_TAKE:
  2987.     s = fncSofMasterTake ((pURB_SOF_MASTER) pUrb);
  2988.     break;
  2989. case USBD_FNC_SOF_MASTER_RELEASE:
  2990.     s = fncSofMasterRelease ((pURB_SOF_MASTER) pUrb);
  2991.     break;
  2992. case USBD_FNC_SOF_INTERVAL_GET:
  2993.     s = fncSofIntervalGet ((pURB_SOF_INTERVAL_GET_SET) pUrb);
  2994.     break;
  2995. case USBD_FNC_SOF_INTERVAL_SET:
  2996.     s = fncSofIntervalSet ((pURB_SOF_INTERVAL_GET_SET) pUrb);
  2997.     break;
  2998. case USBD_FNC_BUS_STATE_SET:
  2999.     s = fncBusStateSet ((pURB_BUS_STATE_SET) pUrb);
  3000.     break;
  3001. default:    /* Bad function code */
  3002.     s = S_usbdLib_BAD_PARAM;
  3003.     break;
  3004. }
  3005.     /* Store result. */
  3006.     setUrbResult (pUrb, s);
  3007.     /* release structMutex */
  3008.     if (pUrb->function != USBD_FNC_INITIALIZE && 
  3009. pUrb->function != USBD_FNC_SHUTDOWN)
  3010. {
  3011. OSS_MUTEX_RELEASE (structMutex);
  3012. }
  3013.     /* return status to caller */
  3014.     if (s == OK || s == PENDING)
  3015. return OK;
  3016.     else
  3017. return ossStatus (s);
  3018.     }
  3019. /* End of file. */