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

VxWorks

开发平台:

C/C++

  1. /* usbMouseLib.c - USB mouse class drive with vxWorks SIO interface */
  2. /* Copyright 2000-2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01c,29oct01,wef  Remove automatic buffer creations and repalce with OSS_MALLOC.
  7. 01b,20mar00,rcb  Re-write code to fetch maxPacketSize from endpoint descriptor
  8.    on machines which don't support non-aligned word access.
  9.    Allocate "report" structure separately from SIO_CHAN in order
  10.    to avoid cache problems on MIPS platform.
  11. 01a,07oct99,rcb  written.
  12. */
  13. /*
  14. DESCRIPTION
  15. This module implements the USB mouse class driver for the vxWorks operating
  16. system.  This module presents an interface which is a superset of the vxWorks
  17. SIO (serial IO) driver model.  That is, this driver presents the external APIs
  18. which would be expected of a standard "multi-mode serial (SIO) driver" and
  19. adds certain extensions which are needed to address adequately the requirements
  20. of the hot-plugging USB environment.
  21. USB mice are described as part of the USB "human interface device" class
  22. specification and related documents.  This driver concerns itself only with USB
  23. devices which claim to be mouses as set forth in the USB HID specification
  24. and ignores other types of human interface devices (i.e., keyboard).  USB
  25. mice can operate according to either a "boot protocol" or to a "report
  26. protocol".  This driver enables mouses for operation using the boot
  27. protocol.
  28. Unlike most SIO drivers, the number of channels supported by this driver is not
  29. fixed. Rather, USB mice may be added or removed from the system at any
  30. time.  This creates a situation in which the number of channels is dynamic, and
  31. clients of usbMouseLib.c need to be made aware of the appearance and 
  32. disappearance of channels.  Therefore, this driver adds an additional set of
  33. functions which allows clients to register for notification upon the insertion
  34. and removal of USB mice, and hence the creation and deletion of channels.
  35. This module itself is a client of the Universal Serial Bus Driver (USBD).  All
  36. interaction with the USB buses and devices is handled through the USBD.
  37. INITIALIZATION
  38. As with standard SIO drivers, this driver must be initialized by calling
  39. usbMouseDevInit().  usbMouseDevInit() in turn initializes its 
  40. connection to the USBD and other internal resources needed for operation.  
  41. Unlike some SIO drivers, there are no usbMouseLib.c data structures which need 
  42. to be initialized prior to calling usbMouseDevInit().
  43. Prior to calling usbMouseDevInit(), the caller must ensure that the USBD
  44. has been properly initialized by calling - at a minimum - usbdInitialize().
  45. It is also the caller's responsibility to ensure that at least one USB HCD
  46. (USB Host Controller Driver) is attached to the USBD - using the USBD function
  47. usbdHcdAttach() - before mouse operation can begin.  However, it is not 
  48. necessary for usbdHcdAttach() to be alled prior to initializating usbMouseLib.c.
  49. usbMouseLib.c uses the USBD dynamic attach services and is capable of 
  50. recognizing USB keboard attachment and removal on the fly.  Therefore, it is 
  51. possible for USB HCDs to be attached to or detached from the USBD at run time
  52. - as may be required, for example, in systems supporting hot swapping of
  53. hardware.
  54. usbMouseLib.c does not export entry points for transmit, receive, and error
  55. interrupt entry points like traditional SIO drivers.  All "interrupt" driven
  56. behavior is managed by the underlying USBD and USB HCD(s), so there is no
  57. need for a caller (or BSP) to connect interrupts on behalf of usbMouseLib.c.
  58. For the same reason, there is no post-interrupt-connect initialization code
  59. and usbKeboardLib.c therefore also omits the "devInit2" entry point.
  60. OTHER FUNCTIONS
  61. usbMouseLib.c also supports the SIO ioctl interface.  However, attempts to
  62. set parameters like baud rates and start/stop bits have no meaning in the USB
  63. environment and will be treated as no-ops.  
  64. DATA FLOW
  65. For each USB mouse connected to the system, usbMouseLib.c sets up a
  66. USB pipe to monitor input from the mouse.  usbMouseLib.c supports only the
  67. SIO "interrupt" mode of operation.  In this mode, the application must install 
  68. a "report callback" through the driver's callbackInstall() function.  This
  69. callback is of the form:
  70. .CS
  71. typedef STATUS (*REPORT_CALLBACK) 
  72.     (
  73.     void *arg, 
  74.     pHID_MSE_BOOT_REPORT pReport
  75.     );
  76. .CE
  77. usbMouseLib.c will invoke this callback for each report received.  The STATUS
  78. returned by the callback is ignored by usbMouseLib.c.  If the application is
  79. unable to accept a report, the report is discarded.  The report structure is
  80. defined in usbHid.h, which is included automatically by usbMouseLib.h.
  81. usbMouseLib.c does not support output to the mouse.  Therefore, calls to
  82. the txStartup() and pollOutput() functions will fail.  
  83. INCLUDE FILES:
  84. sioLib.h usbMouseLib.h
  85. */
  86. /* includes */
  87. #include "vxWorks.h"
  88. #include "string.h"
  89. #include "sioLib.h"
  90. #include "errno.h"
  91. #include "ctype.h"
  92. #include "usb/usbPlatform.h"
  93. #include "usb/ossLib.h"  /* operations system srvcs */
  94. #include "usb/usb.h" /* general USB definitions */
  95. #include "usb/usbListLib.h" /* linked list functions */
  96. #include "usb/usbdLib.h" /* USBD interface */
  97. #include "usb/usbLib.h"  /* USB utility functions */
  98. #include "usb/usbHid.h"  /* USB HID definitions */
  99. #include "drv/usb/usbMouseLib.h"    /* our API */
  100. /* defines */
  101. #define MSE_CLIENT_NAME "usbMouseLib"     /* our USBD client name */
  102. /* If your hardware platform has problems sharing cache lines, then define
  103.  * CACHE_LINE_SIZE below so that critical buffers can be allocated within
  104.  * their own cache lines.
  105.  */
  106. #define CACHE_LINE_SIZE     16
  107. /* typedefs */
  108. /*
  109.  * ATTACH_REQUEST
  110.  */
  111. typedef struct attach_request
  112.     {
  113.     LINK reqLink;     /* linked list of requests */
  114.     USB_MSE_ATTACH_CALLBACK callback; /* client callback routine */
  115.     pVOID callbackArg; /* client callback argument */
  116.     } ATTACH_REQUEST, *pATTACH_REQUEST;
  117. /* USB_MSE_SIO_CHAN is the internal data structure we use to track each USB
  118.  * mouse.
  119.  */
  120. typedef struct usb_mse_sio_chan
  121.     {
  122.     SIO_CHAN sioChan; /* must be first field */
  123.     LINK sioLink;     /* linked list of mouse structs */
  124.     UINT16 lockCount; /* Count of times structure locked */
  125.     USBD_NODE_ID nodeId; /* mouse node Id */
  126.     UINT16 configuration; /* configuration/interface reported as */
  127.     UINT16 interface; /* a mouse by this device */
  128.     BOOL connected;     /* TRUE if mouse currently connected */
  129.     UINT16 intMaxPacketSize;     /* max pkt size for interrupt pipe */
  130.     USBD_PIPE_HANDLE pipeHandle;    /* USBD pipe handle for interrupt pipe */
  131.     USB_IRP irp;     /* IRP to monitor interrupt pipe */
  132.     BOOL irpInUse;     /* TRUE while IRP is outstanding */
  133.     pUINT8 pIrpBfr;     /* bfr for boot report */
  134.     pHID_MSE_BOOT_REPORT pReport;   /* points to pIrpBfr */
  135.     int mode;     /* SIO_MODE_INT or SIO_MODE_POLL */
  136.     STATUS (*getTxCharCallback) (); /* tx callback */
  137.     void *getTxCharArg;  /* tx callback argument */
  138.     STATUS (*putRxCharCallback) (); /* rx callback */
  139.     void *putRxCharArg;  /* rx callback argument */
  140.     STATUS (*putReportCallback) (); /* report callback */
  141.     void *putReportArg;  /* report callback argument */
  142.     } USB_MSE_SIO_CHAN, *pUSB_MSE_SIO_CHAN;
  143. /* forward static declarations */
  144. LOCAL int usbMouseTxStartup (SIO_CHAN * pSioChan);
  145. LOCAL int usbMouseCallbackInstall (SIO_CHAN *pSioChan, int callbackType,
  146.     STATUS (*callback)(), void *callbackArg);
  147. LOCAL int usbMousePollOutput (SIO_CHAN *pSioChan, char outChar);
  148. LOCAL int usbMousePollInput (SIO_CHAN *pSioChan, char *thisChar);
  149. LOCAL int usbMouseIoctl (SIO_CHAN *pSioChan, int request, void *arg);
  150. LOCAL VOID usbMouseIrpCallback (pVOID p);
  151. /* locals */
  152. LOCAL UINT16 initCount = 0; /* Count of init nesting */
  153. LOCAL MUTEX_HANDLE mseMutex;     /* mutex used to protect internal structs */
  154. LOCAL LIST_HEAD sioList; /* linked list of USB_MSE_SIO_CHAN */
  155. LOCAL LIST_HEAD reqList; /* Attach callback request list */
  156. LOCAL USBD_CLIENT_HANDLE usbdHandle; /* our USBD client handle */
  157. /* Channel function table. */
  158. LOCAL SIO_DRV_FUNCS usbMouseSioDrvFuncs =
  159.     {
  160.     usbMouseIoctl,
  161.     usbMouseTxStartup,
  162.     usbMouseCallbackInstall,
  163.     usbMousePollInput,
  164.     usbMousePollOutput
  165.     };
  166. /***************************************************************************
  167. *
  168. * interpMseReport - interprets USB mouse BOOT report
  169. *
  170. * Interprets a mouse boot report and updates channel state as
  171. * appropriate.
  172. *
  173. * RETURNS: N/A
  174. */
  175. LOCAL VOID interpMseReport
  176.     (
  177.     pUSB_MSE_SIO_CHAN pSioChan
  178.     )
  179.     {
  180.     pHID_MSE_BOOT_REPORT pReport = pSioChan->pReport;
  181.     /* Validate report */
  182.     if (pSioChan->irp.bfrList [0].actLen >= sizeof (HID_MSE_BOOT_REPORT))
  183.     {
  184.     /* invoke receive callback */
  185.     if (pSioChan->putReportCallback != NULL)
  186. {
  187. (*pSioChan->putReportCallback) (pSioChan->putReportArg, pReport);
  188. }
  189.     }
  190.     }
  191. /***************************************************************************
  192. *
  193. * usbMouseIoctl - special device control
  194. *
  195. * This routine is largely a no-op for the usbMouseLib. The only ioctls
  196. * which are used by this module are the SIO_AVAIL_MODES_GET and SIO_MODE_SET.
  197. *
  198. * RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed
  199. * request.
  200. */
  201. LOCAL int usbMouseIoctl
  202.     (
  203.     SIO_CHAN *pChan,     /* device to control */
  204.     int request, /* request code */
  205.     void *someArg /* some argument */
  206.     )
  207.     {
  208.     pUSB_MSE_SIO_CHAN pSioChan = (pUSB_MSE_SIO_CHAN) pChan;
  209.     int arg = (int) someArg;
  210.     switch (request)
  211.     {
  212.     case SIO_MODE_SET:
  213. /* Set driver operating mode: must be interrupt */
  214. if (arg != SIO_MODE_INT)
  215. return EIO;
  216. pSioChan->mode = arg;
  217. return OK;
  218.     case SIO_MODE_GET:
  219. /* Return current driver operating mode for channel */
  220. *((int *) arg) = pSioChan->mode;
  221. return OK;
  222.     case SIO_AVAIL_MODES_GET:
  223. /* Return modes supported by driver. */
  224. *((int *) arg) = SIO_MODE_INT;
  225. return OK;
  226.     case SIO_OPEN:
  227. /* Channel is always open. */
  228. return OK;
  229.     case SIO_BAUD_SET:
  230.     case SIO_BAUD_GET:
  231.     case SIO_HW_OPTS_SET:   /* optional, not supported */
  232.     case SIO_HW_OPTS_GET:   /* optional, not supported */
  233.     case SIO_HUP: /* hang up is not supported */
  234.     default:     /* unknown/unsupported command. */
  235. return ENOSYS;
  236.     }
  237.     }
  238. /***************************************************************************
  239. *
  240. * usbMouseTxStartup - start the interrupt transmitter
  241. *
  242. * The USB mouse SIO driver does not support output to the mouse.
  243. *
  244. * RETURNS: EIO
  245. */
  246. LOCAL int usbMouseTxStartup
  247.     (
  248.     SIO_CHAN *pChan /* channel to start */
  249.     )
  250.     {
  251.     return EIO;
  252.     }
  253. /***************************************************************************
  254. *
  255. * usbMouseCallbackInstall - install ISR callbacks to get/put chars
  256. *
  257. * This driver allows interrupt callbacks for transmitting characters
  258. * and receiving characters.=
  259. *
  260. * RETURNS: OK on success, or ENOSYS for an unsupported callback type.
  261. */ 
  262. LOCAL int usbMouseCallbackInstall
  263.     (
  264.     SIO_CHAN *pChan,     /* channel */
  265.     int callbackType,     /* type of callback */
  266.     STATUS (*callback) (),  /* callback */
  267.     void *callbackArg     /* parameter to callback */
  268.     )
  269.     {
  270.     pUSB_MSE_SIO_CHAN pSioChan = (pUSB_MSE_SIO_CHAN) pChan;
  271.     switch (callbackType)
  272.     {
  273.     case SIO_CALLBACK_GET_TX_CHAR:
  274. pSioChan->getTxCharCallback = callback;
  275. pSioChan->getTxCharArg = callbackArg;
  276. return OK;
  277.     case SIO_CALLBACK_PUT_RCV_CHAR:
  278. pSioChan->putRxCharCallback = callback;
  279. pSioChan->putRxCharArg = callbackArg;
  280. return OK;
  281.     case SIO_CALLBACK_PUT_MOUSE_REPORT:
  282. pSioChan->putReportCallback = callback;
  283. pSioChan->putReportArg = callbackArg;
  284. return OK;
  285.     default:
  286. return ENOSYS;
  287.     }
  288.     }
  289. /***************************************************************************
  290. *
  291. * usbMousePollOutput - output a character in polled mode
  292. *
  293. * The USB mouse SIO driver does not support output to the mouse.
  294. *
  295. * RETURNS: EIO
  296. */
  297. LOCAL int usbMousePollOutput
  298.     (
  299.     SIO_CHAN *pChan,
  300.     char outChar
  301.     )
  302.     {
  303.     return EIO;
  304.     }
  305. /***************************************************************************
  306. *
  307. * usbMousePollInput - poll the device for input
  308. *
  309. * RETURNS: ENOSYS
  310. */
  311. LOCAL int usbMousePollInput
  312.     (
  313.     SIO_CHAN *pChan,
  314.     char *thisChar
  315.     )
  316.     {
  317.     return ENOSYS;
  318.     }
  319. /***************************************************************************
  320. *
  321. * initMseIrp - Initialize IRP to listen for input on interrupt pipe
  322. *
  323. * RETURNS: TRUE if able to submit IRP successfully, else FALSE
  324. */
  325. LOCAL BOOL initMseIrp
  326.     (
  327.     pUSB_MSE_SIO_CHAN pSioChan
  328.     )
  329.     {
  330.     pUSB_IRP pIrp = &pSioChan->irp;
  331.     /* Initialize IRP */
  332.     memset (pIrp, 0, sizeof (*pIrp));
  333.     pIrp->userPtr = pSioChan;
  334.     pIrp->irpLen = sizeof (*pIrp);
  335.     pIrp->userCallback = usbMouseIrpCallback;
  336.     pIrp->timeout = USB_TIMEOUT_NONE;
  337.     pIrp->transferLen = sizeof (HID_MSE_BOOT_REPORT);
  338.     pIrp->bfrCount = 1;
  339.     pIrp->bfrList [0].pid = USB_PID_IN;
  340.     pIrp->bfrList [0].pBfr = pSioChan->pIrpBfr;
  341.     pIrp->bfrList [0].bfrLen = 
  342.     min (pSioChan->intMaxPacketSize, HID_BOOT_REPORT_MAX_LEN);
  343.     /* Submit IRP */
  344.     if (usbdTransfer (usbdHandle, pSioChan->pipeHandle, pIrp) != OK)
  345.     return FALSE;
  346.     pSioChan->irpInUse = TRUE;
  347.     return TRUE;
  348.     }
  349. /***************************************************************************
  350. *
  351. * usbMouseIrpCallback - Invoked upon IRP completion/cancellation
  352. *
  353. * Examines the cause of the IRP completion.  If completion was successful,
  354. * interprets the USB mouse's boot report and re-submits the IRP.
  355. *
  356. * RETURNS: N/A
  357. */
  358. LOCAL VOID usbMouseIrpCallback
  359.     (
  360.     pVOID p     /* completed IRP */
  361.     )
  362.     {
  363.     pUSB_IRP pIrp = (pUSB_IRP) p;
  364.     pUSB_MSE_SIO_CHAN pSioChan = pIrp->userPtr;
  365.     OSS_MUTEX_TAKE (mseMutex, OSS_BLOCK);
  366.     /* Was the IRP successful? */
  367.     if (pIrp->result == OK)
  368.     {
  369.     /* Interpret the mouse report */
  370.     interpMseReport (pSioChan);
  371.     }
  372.     /* Re-submit the IRP unless it was canceled - which would happen only
  373.      * during pipe shutdown (e.g., the disappearance of the device).
  374.      */
  375.     pSioChan->irpInUse = FALSE;
  376.     if (pIrp->result != S_usbHcdLib_IRP_CANCELED)
  377.     initMseIrp (pSioChan);
  378.     OSS_MUTEX_RELEASE (mseMutex);
  379.     }
  380. /***************************************************************************
  381. *
  382. * configureSioChan - configure USB mouse for operation
  383. *
  384. * Selects the configuration/interface specified in the <pSioChan>
  385. * structure.  These values come from the USBD dynamic attach callback,
  386. * which in turn retrieved them from the configuration/interface
  387. * descriptors which reported the device to be a mouse.
  388. *
  389. * RETURNS: TRUE if successful, else FALSE if failed to configure channel
  390. */
  391. LOCAL BOOL configureSioChan
  392.     (
  393.     pUSB_MSE_SIO_CHAN pSioChan
  394.     )
  395.     {
  396.     pUSB_CONFIG_DESCR pCfgDescr;
  397.     pUSB_INTERFACE_DESCR pIfDescr;
  398.     pUSB_ENDPOINT_DESCR pEpDescr;
  399.     UINT8 * pBfr;
  400.     UINT8 * pScratchBfr;
  401.     UINT16 actLen;
  402.     UINT16 ifNo;
  403.     if ((pBfr = OSS_MALLOC (USB_MAX_DESCR_LEN)) == NULL)
  404. return FALSE;
  405.     /* Read the configuration descriptor to get the configuration selection
  406.      * value and to determine the device's power requirements.
  407.      */
  408.     if (usbdDescriptorGet (usbdHandle, 
  409.    pSioChan->nodeId, 
  410.    USB_RT_STANDARD | USB_RT_DEVICE, 
  411.    USB_DESCR_CONFIGURATION, 
  412.    0, 
  413.    0, 
  414.    USB_MAX_DESCR_LEN,
  415.    pBfr, 
  416.    &actLen) 
  417. != OK)
  418. {
  419. OSS_FREE (pBfr);
  420.      return FALSE;
  421. }
  422.     if ((pCfgDescr = usbDescrParse (pBfr, 
  423.     actLen, 
  424.     USB_DESCR_CONFIGURATION)) 
  425.      == NULL)
  426.         {
  427.         OSS_FREE (pBfr);
  428.         return FALSE;
  429.         }
  430.     /* Look for the interface indicated in the pSioChan structure. */
  431.     ifNo = 0;
  432.     /* 
  433.      * usbDescrParseSkip() modifies the value of the pointer it recieves
  434.      * so we pass it a copy of our buffer pointer
  435.      */
  436.     pScratchBfr = pBfr;
  437.     while ((pIfDescr = usbDescrParseSkip (&pScratchBfr, 
  438.   &actLen, 
  439.   USB_DESCR_INTERFACE)) 
  440.      != NULL)
  441.      {
  442.      if (ifNo == pSioChan->interface)
  443.     break;
  444.      ifNo++;
  445.      }
  446.     if (pIfDescr == NULL)
  447.         {
  448.         OSS_FREE (pBfr);
  449.         return FALSE;
  450.         }
  451.     /* Retrieve the endpoint descriptor following the identified interface
  452.      * descriptor.
  453.      */
  454.     if ((pEpDescr = usbDescrParseSkip (&pScratchBfr, 
  455.        &actLen, 
  456.        USB_DESCR_ENDPOINT))
  457.      == NULL)
  458.         {
  459.         OSS_FREE (pBfr);
  460.         return FALSE;
  461.         }
  462.     /* Select the configuration. */
  463.     if (usbdConfigurationSet (usbdHandle, 
  464.       pSioChan->nodeId, 
  465.       pCfgDescr->configurationValue, 
  466.       pCfgDescr->maxPower * USB_POWER_MA_PER_UNIT) 
  467.    != OK)
  468.         {
  469.         OSS_FREE (pBfr);
  470.         return FALSE;
  471.         }
  472.     /* Select interface 
  473.      * 
  474.      * NOTE: Some devices may reject this command, and this does not represent
  475.      * a fatal error.  Therefore, we ignore the return status.
  476.      */
  477.     usbdInterfaceSet (usbdHandle, 
  478.       pSioChan->nodeId, 
  479.       pSioChan->interface, 
  480.       pIfDescr->alternateSetting);
  481.     /* Select the mouse boot protocol. */
  482.     if (usbHidProtocolSet (usbdHandle, 
  483.    pSioChan->nodeId, 
  484.    pSioChan->interface, 
  485.    USB_HID_PROTOCOL_BOOT) 
  486. != OK)
  487.         {
  488.         OSS_FREE (pBfr);
  489.         return FALSE;
  490.         }
  491.     /* Set the mouse idle time to infinite. */
  492.     if (usbHidIdleSet (usbdHandle, 
  493.        pSioChan->nodeId, 
  494.        pSioChan->interface, 
  495.        0 /* no report ID */, 
  496.        0 /* infinite */) 
  497.     != OK)
  498.         {
  499.         OSS_FREE (pBfr);
  500.         return FALSE;
  501.         }
  502.     /* Create a pipe to monitor input reports from the mouse. */
  503.     pSioChan->intMaxPacketSize = *((pUINT8) &pEpDescr->maxPacketSize) |
  504.      (*(((pUINT8) &pEpDescr->maxPacketSize) + 1) << 8);
  505.     if (usbdPipeCreate (usbdHandle, 
  506. pSioChan->nodeId, 
  507. pEpDescr->endpointAddress, 
  508. pCfgDescr->configurationValue, 
  509. pSioChan->interface, 
  510. USB_XFRTYPE_INTERRUPT, 
  511. USB_DIR_IN, 
  512. pSioChan->intMaxPacketSize, 
  513. sizeof (HID_MSE_BOOT_REPORT), 
  514. pEpDescr->interval, 
  515. &pSioChan->pipeHandle) 
  516.     != OK)
  517.         {
  518.         OSS_FREE (pBfr);
  519.         return FALSE;
  520.         }
  521.     /* Initiate IRP to listen for input on interrupt pipe */
  522.     if (!initMseIrp (pSioChan))
  523.         {
  524.         OSS_FREE (pBfr);
  525.         return FALSE;
  526.         }
  527.     OSS_FREE (pBfr);
  528.     return TRUE;
  529.     }
  530. /***************************************************************************
  531. *
  532. * destroyAttachRequest - disposes of an ATTACH_REQUEST structure
  533. *
  534. * RETURNS: N/A
  535. */
  536. LOCAL VOID destroyAttachRequest
  537.     (
  538.     pATTACH_REQUEST pRequest
  539.     )
  540.     {
  541.     /* Unlink request */
  542.     usbListUnlink (&pRequest->reqLink);
  543.     /* Dispose of structure */
  544.     OSS_FREE (pRequest);
  545.     }
  546. /***************************************************************************
  547. *
  548. * destroySioChan - disposes of a USB_MSE_SIO_CHAN structure
  549. *
  550. * Unlinks the indicated USB_MSE_SIO_CHAN structure and de-allocates
  551. * resources associated with the channel.
  552. *
  553. * RETURNS: N/A
  554. */
  555. LOCAL VOID destroySioChan
  556.     (
  557.     pUSB_MSE_SIO_CHAN pSioChan
  558.     )
  559.     {
  560.     /* Unlink the structure. */
  561.     usbListUnlink (&pSioChan->sioLink);
  562.     /* Release pipe if one has been allocated. Wait for the IRP to be
  563.      * cancelled if necessary.
  564.      */
  565.     if (pSioChan->pipeHandle != NULL)
  566.     usbdPipeDestroy (usbdHandle, pSioChan->pipeHandle);
  567.     while (pSioChan->irpInUse)
  568.     OSS_THREAD_SLEEP (1);
  569.     /* Release structure. */
  570.     if (pSioChan->pIrpBfr != NULL)
  571.     OSS_FREE (pSioChan->pIrpBfr);
  572.     OSS_FREE (pSioChan);
  573.     }
  574. /***************************************************************************
  575. *
  576. * createSioChan - creates a new USB_MSE_SIO_CHAN structure
  577. *
  578. * Creates a new USB_MSE_SIO_CHAN structure for the indicated <nodeId>.
  579. * If successful, the new structure is linked into the sioList upon 
  580. * return.
  581. *
  582. * <configuration> and <interface> identify the configuration/interface
  583. * that first reported itself as a mouse for this device.
  584. *
  585. * RETURNS: pointer to newly created structure, or NULL if failure
  586. */
  587. LOCAL pUSB_MSE_SIO_CHAN createSioChan
  588.     (
  589.     USBD_NODE_ID nodeId,
  590.     UINT16 configuration,
  591.     UINT16 interface
  592.     )
  593.     {
  594.     pUSB_MSE_SIO_CHAN pSioChan;
  595.     /* Try to allocate space for a new mouse struct */
  596.     if ((pSioChan = OSS_CALLOC (sizeof (*pSioChan))) == NULL)
  597.     return NULL;
  598.     if ((pSioChan->pIrpBfr = OSS_MALLOC (HID_BOOT_REPORT_MAX_LEN)) == NULL)
  599.      {
  600.      OSS_FREE (pSioChan);
  601.      return NULL;
  602.         }
  603.     pSioChan->sioChan.pDrvFuncs = &usbMouseSioDrvFuncs;
  604.     pSioChan->nodeId = nodeId;
  605.     pSioChan->connected = TRUE;
  606.     pSioChan->mode = SIO_MODE_INT;
  607.     pSioChan->configuration = configuration;
  608.     pSioChan->interface = interface;
  609.     pSioChan->pReport = (pHID_MSE_BOOT_REPORT) pSioChan->pIrpBfr;
  610.     /* Try to configure the mouse. */
  611.     if (!configureSioChan (pSioChan))
  612.     {
  613.     destroySioChan (pSioChan);
  614.     return NULL;
  615.     }
  616.     /* Link the newly created structure. */
  617.     usbListLink (&sioList, pSioChan, &pSioChan->sioLink, LINK_TAIL);
  618.     return pSioChan;
  619.     }
  620. /***************************************************************************
  621. *
  622. * findSioChan - Searches for a USB_MSE_SIO_CHAN for indicated node ID
  623. *
  624. * RETURNS: pointer to matching USB_MSE_SIO_CHAN or NULL if not found
  625. */
  626. LOCAL pUSB_MSE_SIO_CHAN findSioChan
  627.     (
  628.     USBD_NODE_ID nodeId
  629.     )
  630.     {
  631.     pUSB_MSE_SIO_CHAN pSioChan = usbListFirst (&sioList);
  632.     while (pSioChan != NULL)
  633.     {
  634.     if (pSioChan->nodeId == nodeId)
  635. break;
  636.     pSioChan = usbListNext (&pSioChan->sioLink);
  637.     }
  638.     return pSioChan;
  639.     }
  640. /***************************************************************************
  641. *
  642. * notifyAttach - Notifies registered callers of attachment/removal
  643. *
  644. * RETURNS: N/A
  645. */
  646. LOCAL VOID notifyAttach
  647.     (
  648.     pUSB_MSE_SIO_CHAN pSioChan,
  649.     UINT16 attachCode
  650.     )
  651.     {
  652.     pATTACH_REQUEST pRequest = usbListFirst (&reqList);
  653.     while (pRequest != NULL)
  654.     {
  655.     (*pRequest->callback) (pRequest->callbackArg, 
  656. (SIO_CHAN *) pSioChan, attachCode);
  657.     pRequest = usbListNext (&pRequest->reqLink);
  658.     }
  659.     }
  660. /***************************************************************************
  661. *
  662. * usbMouseAttachCallback - called by USBD when mouse attached/removed
  663. *
  664. * The USBD will invoke this callback when a USB mouse is attached to or
  665. * removed from the system.  <nodeId> is the USBD_NODE_ID of the node being
  666. * attached or removed. <attachAction> is USBD_DYNA_ATTACH or USBD_DYNA_REMOVE.
  667. * Mice generally report their class information at the interface level,
  668. * so <configuration> and <interface> will indicate the configuratin/interface
  669. * that reports itself as a mouse.  Finally, <deviceClass>, <deviceSubClass>,
  670. * and <deviceProtocol> will identify a HID/BOOT/KEYBOARD device.
  671. *
  672. * NOTE: The USBD will invoke this function once for each configuration/
  673. * interface which reports itself as a mouse.  So, it is possible that
  674. * a single device insertion/removal may trigger multiple callbacks.  We
  675. * ignore all callbacks except the first for a given device.
  676. *
  677. * RETURNS: N/A
  678. */
  679. LOCAL VOID usbMouseAttachCallback
  680.     (
  681.     USBD_NODE_ID nodeId, 
  682.     UINT16 attachAction, 
  683.     UINT16 configuration,
  684.     UINT16 interface,
  685.     UINT16 deviceClass, 
  686.     UINT16 deviceSubClass, 
  687.     UINT16 deviceProtocol
  688.     )
  689.     {
  690.     pUSB_MSE_SIO_CHAN pSioChan;
  691.     OSS_MUTEX_TAKE (mseMutex, OSS_BLOCK);
  692.     /* Depending on the attach code, add a new mouse or disabled one
  693.      * that's already been created.
  694.      */
  695.     switch (attachAction)
  696.     {
  697.     case USBD_DYNA_ATTACH:
  698. /* A new device is being attached.  Check if we already 
  699.  * have a structure for this device.
  700.  */
  701. if (findSioChan (nodeId) != NULL)
  702. break;
  703. /* Create a new structure to manage this device.  If there's
  704.  * an error, there's nothing we can do about it, so skip the
  705.  * device and return immediately. 
  706.  */
  707. if ((pSioChan = createSioChan (nodeId, configuration, interface)) 
  708. == NULL)
  709. break;
  710. /* Notify registered callers that a new mouse has been
  711.  * added and a new channel created.
  712.  */
  713. notifyAttach (pSioChan, USB_MSE_ATTACH);
  714. break;
  715.     case USBD_DYNA_REMOVE:
  716. /* A device is being detached. Check if we have any
  717.  * structures to manage this device.
  718.  */
  719. if ((pSioChan = findSioChan (nodeId)) == NULL)
  720. break;
  721. /* The device has been disconnected. */
  722. pSioChan->connected = FALSE;
  723. /* Notify registered callers that the mouse has been
  724.  * removed and the channel disabled. 
  725.  *
  726.  * NOTE: We temporarily increment the channel's lock count
  727.  * to prevent usbMouseSioChanUnlock() from destroying the
  728.  * structure while we're still using it.
  729.  */
  730. pSioChan->lockCount++;
  731. notifyAttach (pSioChan, USB_MSE_REMOVE);
  732. pSioChan->lockCount--;
  733. /* If no callers have the channel structure locked, destroy
  734.  * it now.  If it is locked, it will be destroyed later during
  735.  * a call to usbMouseUnlock().
  736.  */
  737. if (pSioChan->lockCount == 0)
  738. destroySioChan (pSioChan);
  739. break;
  740.     }
  741.     OSS_MUTEX_RELEASE (mseMutex);
  742.     }
  743. /***************************************************************************
  744. *
  745. * doShutdown - shuts down USB mouse SIO driver
  746. *
  747. * <errCode> should be OK or S_usbMouseLib_xxxx.  This value will be
  748. * passed to ossStatus() and the return value from ossStatus() is the
  749. * return value of this function.
  750. *
  751. * RETURNS: OK, or ERROR per value of <errCode> passed by caller
  752. */
  753. LOCAL STATUS doShutdown
  754.     (
  755.     int errCode
  756.     )
  757.     {
  758.     pATTACH_REQUEST pRequest;
  759.     pUSB_MSE_SIO_CHAN pSioChan;
  760.     /* Dispose of any outstanding notification requests */
  761.     while ((pRequest = usbListFirst (&reqList)) != NULL)
  762.     destroyAttachRequest (pRequest);
  763.     /* Dispose of any open mouse connections. */
  764.     while ((pSioChan = usbListFirst (&sioList)) != NULL)
  765.     destroySioChan (pSioChan);
  766.     
  767.     /* Release our connection to the USBD.  The USBD automatically 
  768.      * releases any outstanding dynamic attach requests when a client
  769.      * unregisters.
  770.      */
  771.     if (usbdHandle != NULL)
  772.     {
  773.     usbdClientUnregister (usbdHandle);
  774.     usbdHandle = NULL;
  775.     }
  776.     /* Release resources. */
  777.     if (mseMutex != NULL)
  778.     {
  779.     OSS_MUTEX_DESTROY (mseMutex);
  780.     mseMutex = NULL;
  781.     }
  782.     return ossStatus (errCode);
  783.     }
  784. /***************************************************************************
  785. *
  786. * usbMouseDevInit - initialize USB mouse SIO driver
  787. *
  788. * Initializes the USB mouse SIO driver.  The USB mouse SIO driver
  789. * maintains an initialization count, so calls to this function may be
  790. * nested.
  791. *
  792. * RETURNS: OK, or ERROR if unable to initialize.
  793. *
  794. * ERRNO:
  795. *
  796. *   S_usbMouseLib_OUT_OF_RESOURCES
  797. *   S_usbMouseLib_USBD_FAULT
  798. */
  799. STATUS usbMouseDevInit (void)
  800.     {
  801.     /* If not already initialized, then initialize internal structures
  802.      * and connection to USBD.
  803.      */
  804.     if (initCount == 0)
  805.     {
  806.     /* Initialize lists, structures, resources. */
  807.     memset (&sioList, 0, sizeof (sioList));
  808.     memset (&reqList, 0, sizeof (reqList));
  809.     mseMutex = NULL;
  810.     usbdHandle = NULL;
  811.     if (OSS_MUTEX_CREATE (&mseMutex) != OK)
  812. return doShutdown (S_usbMouseLib_OUT_OF_RESOURCES);
  813.     /* Establish connection to USBD */
  814.     if (usbdClientRegister (MSE_CLIENT_NAME, &usbdHandle) != OK ||
  815. usbdDynamicAttachRegister (usbdHandle, USB_CLASS_HID,
  816. USB_SUBCLASS_HID_BOOT, USB_PROTOCOL_HID_BOOT_MOUSE,
  817. usbMouseAttachCallback) != OK)
  818. {
  819. return doShutdown (S_usbMouseLib_USBD_FAULT);
  820. }
  821.     }
  822.     initCount++;
  823.     return OK;
  824.     }
  825. /***************************************************************************
  826. *
  827. * usbMouseDevShutdown - shuts down mouse SIO driver
  828. *
  829. * RETURNS: OK, or ERROR if unable to shutdown.
  830. *
  831. * ERRNO:
  832. *   S_usbMouseLib_NOT_INITIALIZED
  833. */
  834. STATUS usbMouseDevShutdown (void)
  835.     {
  836.     /* Shut down the USB mouse SIO driver if the initCount goes to 0. */
  837.     if (initCount == 0)
  838.     return ossStatus (S_usbMouseLib_NOT_INITIALIZED);
  839.     if (--initCount == 0)
  840.     return doShutdown (OK);
  841.     return OK;
  842.     }
  843. /***************************************************************************
  844. *
  845. * usbMouseDynamicAttachRegister - Register mouse attach callback
  846. *
  847. * <callback> is a caller-supplied function of the form:
  848. *
  849. * .CS
  850. * typedef (*USB_MSE_ATTACH_CALLBACK) 
  851. *     (
  852. *     pVOID arg,
  853. *     SIO_CHAN *pSioChan,
  854. *     UINT16 attachCode
  855. *     );
  856. * .CE
  857. *
  858. * usbMouseLib will invoke <callback> each time a USB mouse
  859. * is attached to or removed from the system.  <arg> is a caller-defined
  860. * parameter which will be passed to the <callback> each time it is
  861. * invoked.  The <callback> will also be passed a pointer to the 
  862. * SIO_CHAN structure for the channel being created/destroyed and
  863. * an attach code of USB_MSE_ATTACH or USB_MSE_REMOVE.
  864. *
  865. * RETURNS: OK, or ERROR if unable to register callback
  866. *
  867. * ERRNO:
  868. *   S_usbMouseLib_BAD_PARAM
  869. *   S_usbMouseLib_OUT_OF_MEMORY
  870. */
  871. STATUS usbMouseDynamicAttachRegister
  872.     (
  873.     USB_MSE_ATTACH_CALLBACK callback, /* new callback to be registered */
  874.     pVOID arg     /* user-defined arg to callback */
  875.     )
  876.     {
  877.     pATTACH_REQUEST pRequest;
  878.     pUSB_MSE_SIO_CHAN pSioChan;
  879.     int status = OK;
  880.     /* Validate parameters */
  881.     if (callback == NULL)
  882.     return ossStatus (S_usbMouseLib_BAD_PARAM);
  883.     OSS_MUTEX_TAKE (mseMutex, OSS_BLOCK);
  884.     /* Create a new request structure to track this callback request. */
  885.     if ((pRequest = OSS_CALLOC (sizeof (*pRequest))) == NULL)
  886.     status = S_usbMouseLib_OUT_OF_MEMORY;
  887.     else
  888.     {
  889.     pRequest->callback = callback;
  890.     pRequest->callbackArg = arg;
  891.     usbListLink (&reqList, pRequest, &pRequest->reqLink, LINK_TAIL);
  892.     
  893.     /* Perform an initial notification of all currrently attached
  894.      * mouse devices.
  895.      */
  896.     pSioChan = usbListFirst (&sioList);
  897.     while (pSioChan != NULL)
  898. {
  899. if (pSioChan->connected)
  900. (*callback) (arg, (SIO_CHAN *) pSioChan, USB_MSE_ATTACH);
  901. pSioChan = usbListNext (&pSioChan->sioLink);
  902. }
  903.     }
  904.     OSS_MUTEX_RELEASE (mseMutex);
  905.     return ossStatus (status);
  906.     }
  907. /***************************************************************************
  908. *
  909. * usbMouseDynamicAttachUnregister - Unregisters mouse attach callback
  910. *
  911. * This function cancels a previous request to be dynamically notified for
  912. * mouse attachment and removal.  The <callback> and <arg> paramters must
  913. * exactly match those passed in a previous call to 
  914. * usbMouseDynamicAttachRegister().
  915. *
  916. * RETURNS: OK, or ERROR if unable to unregister callback
  917. *
  918. * ERRNO:
  919. *   S_usbMouseLib_NOT_REGISTERED
  920. */
  921. STATUS usbMouseDynamicAttachUnRegister
  922.     (
  923.     USB_MSE_ATTACH_CALLBACK callback, /* callback to be unregistered */
  924.     pVOID arg     /* user-defined arg to callback */
  925.     )
  926.     {
  927.     pATTACH_REQUEST pRequest;
  928.     int status = S_usbMouseLib_NOT_REGISTERED;
  929.     OSS_MUTEX_TAKE (mseMutex, OSS_BLOCK);
  930.     pRequest = usbListFirst (&reqList);
  931.     while (pRequest != NULL)
  932.     {
  933.     if (callback == pRequest->callback && arg == pRequest->callbackArg)
  934. {
  935. /* We found a matching notification request. */
  936. destroyAttachRequest (pRequest);
  937. status = OK;
  938. break;
  939. }
  940.     pRequest = usbListNext (&pRequest->reqLink);
  941.     }
  942.     OSS_MUTEX_RELEASE (mseMutex);
  943.     return ossStatus (status);
  944.     }
  945. /***************************************************************************
  946. *
  947. * usbMouseSioChanLock - Marks SIO_CHAN structure as in use
  948. *
  949. * A caller uses usbMouseSioChanLock() to notify usbMouseLib that
  950. * it is using the indicated SIO_CHAN structure.  usbMouseLib maintains
  951. * a count of callers using a particular SIO_CHAN structure so that it 
  952. * knows when it is safe to dispose of a structure when the underlying
  953. * USB mouse is removed from the system.  So long as the "lock count"
  954. * is greater than zero, usbMouseLib will not dispose of an SIO_CHAN
  955. * structure.
  956. *
  957. * RETURNS: OK, or ERROR if unable to mark SIO_CHAN structure in use.
  958. */
  959. STATUS usbMouseSioChanLock
  960.     (
  961.     SIO_CHAN *pChan /* SIO_CHAN to be marked as in use */
  962.     )
  963.     {
  964.     pUSB_MSE_SIO_CHAN pSioChan = (pUSB_MSE_SIO_CHAN) pChan;
  965.     pSioChan->lockCount++;
  966.     return OK;
  967.     }
  968. /***************************************************************************
  969. *
  970. * usbMouseSioChanUnlock - Marks SIO_CHAN structure as unused
  971. *
  972. * This function releases a lock placed on an SIO_CHAN structure.  When a
  973. * caller no longer needs an SIO_CHAN structure for which it has previously
  974. * called usbMouseSioChanLock(), then it should call this function to
  975. * release the lock.
  976. *
  977. * NOTE: If the underlying USB mouse device has already been removed
  978. * from the system, then this function will automatically dispose of the
  979. * SIO_CHAN structure if this call removes the last lock on the structure.
  980. * Therefore, a caller must not reference the SIO_CHAN again structure after
  981. * making this call.
  982. *
  983. * RETURNS: OK, or ERROR if unable to mark SIO_CHAN structure unused
  984. *
  985. * ERRNO:
  986. *   S_usbMouseLib_NOT_LOCKED
  987. */
  988. STATUS usbMouseSioChanUnlock
  989.     (
  990.     SIO_CHAN *pChan /* SIO_CHAN to be marked as unused */
  991.     )
  992.     {
  993.     pUSB_MSE_SIO_CHAN pSioChan = (pUSB_MSE_SIO_CHAN) pChan;
  994.     int status = OK;
  995.     OSS_MUTEX_TAKE (mseMutex, OSS_BLOCK);
  996.     if (pSioChan->lockCount == 0)
  997.     status = S_usbMouseLib_NOT_LOCKED;
  998.     else
  999.     {
  1000.     /* If this is the last lock and the underlying USB mouse is
  1001.      * no longer connected, then dispose of the mouse.
  1002.      */
  1003.     if (--pSioChan->lockCount == 0 && !pSioChan->connected)
  1004. destroySioChan (pSioChan);
  1005.     }
  1006.     OSS_MUTEX_RELEASE (mseMutex);
  1007.     return ossStatus (status);
  1008.     }
  1009. /* end of file. */