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

VxWorks

开发平台:

C/C++

  1. /* usbAcmLib.c - USB Communications Class - Abstract Control Model Driver */
  2. /* Copyright 2000-2001 Wind River systems, Inc */
  3. /*
  4. modification history
  5. --------------------
  6. 01b,08aug01,dat  Removing warnings
  7. 01a,19sep00,bri  Created
  8. */
  9. /*
  10. DESCRIPTION
  11. This module implements the USB ACM Class Driver for the vxWorks operating
  12. system.  This module presents an interface which is a superset of the vxWorks
  13. SIO (serial IO) driver model.  That is, this driver presents the external APIs
  14. which would be expected of a standard "multi-mode serial (SIO) driver" and
  15. adds certain extensions which are needed to address adequately the requirements
  16. of the hot-plugging USB environment.USB modems are described in the USB
  17. communications class / acm sub class definition.  
  18. The Client (user) interaction with the device is via the VxWorks IO system. 
  19. This device appears as an SIO device and the driver exports the functions 
  20. as required by VxWorks SIO driver Model. 
  21. Unlike most SIO drivers, the number of channels supported by this driver is not
  22. fixed. Rather, USB modems may be added or removed from the system at any
  23. time.  This creates a situation in which the number of modems is dynamic, and
  24. clients of usbAcmLib need to be made aware of the appearance and 
  25. disappearance of channels.  Therefore, this driver adds an additional set of
  26. functions which allows clients to register for notification upon the insertion
  27. and removal of USB modems, and hence the creation and deletion of channels.
  28. This module itself is a client of the Universal Serial Bus Driver (USBD).  All
  29. interaction with the USB buses and devices is handled through the USBD.
  30. INITIALIZATION
  31. This driver must be initialized by calling usbAcmLibInit(). usbAcmLibInit() in
  32. turn initializes its connection to the USBD and other internal resources needed
  33. for operation.
  34. Prior to calling usbAcmLibInit(), the caller must ensure that the USBD
  35. has been properly initialized by calling - at a minimum - usbdInitialize().
  36. It is also the caller's responsibility to ensure that at least one USB HCD
  37. (USB Host Controller Driver) is attached to the USBD - using the USBD function
  38. usbdHcdAttach() - before modem operation can begin.  However, it is not 
  39. necessary for usbdHcdAttach() to be called prior to initializating usbAcmLib.
  40. usbAcmLib uses the USBD dynamic attach services and is capable of 
  41. recognizing USB Modem attachment and removal on the fly.  Therefore, it is 
  42. possible for USB HCDs to be attached to or detached from the USBD at run time
  43. - as may be required, for example, in systems supporting hot swapping of
  44. hardware.
  45. usbAcmLib does not export entry points for transmit, receive, and error
  46. interrupt entry points like traditional SIO drivers.  All "interrupt" driven
  47. behavior is managed by the underlying USBD and USB HCD(s), so there is no
  48. need for a caller (or BSP) to connect interrupts on behalf of usbAcmLib.
  49. For the same reason, there is no post-interrupt-connect initialization code
  50. and usbAcmLib.c therefore also omits the "devInit2" entry point.
  51. OTHER FUNCTIONS
  52. usbAcmLib also supports the SIO ioctl interface. All the set baudrate, 
  53. get baud rate functions will work as per the SIO driver specification. 
  54. Additional ioctl functions have been added to allow the caller to use 
  55. the additional commands specified in the USB ACM class specification. 
  56. However the modem can be treated as any serial modem and can be 
  57. controlled.
  58. Modems work on AT commands. The AT commands can be sent via the standard
  59. way i.e., through the Bulk Out pipe. Here the driver doesn't differentiate 
  60. between AT commands and any other data. 
  61. DATA FLOW
  62. For each USB modem connected to the system, usbAcmLib sets up  USB pipes
  63. to transmit and receive data to the Modem. 
  64. The USB Modem SIO driver supports only the SIO "interrupt" mode of operation
  65. - SIO_MODE_INT. Any attempt to place the driver in the polled mode will return
  66. an error.
  67. INCLUDE FILES:
  68. usbAcmLib.h
  69. */
  70. /* includes */
  71. #include "vxWorks.h"
  72. #include "string.h"
  73. #include "stdio.h"
  74. #include "sioLib.h"
  75. #include "errno.h"
  76. #include "ctype.h"
  77. #include "logLib.h"
  78. #include "usb/usbPlatform.h"
  79. #include "usb/ossLib.h" /* operations system srvcs */
  80. #include "usb/usb.h" /* general USB definitions */
  81. #include "usb/usbListLib.h" /* linked list functions */
  82. #include "usb/usbdLib.h" /* USBD interface */
  83. #include "usb/usbLib.h" /* USB utility functions */
  84. #include "usb/usbCommdevices.h"
  85. #include "drv/usb/usbAcmLib.h" /* our API */
  86. /* defines */
  87. #define ACM_CLIENT_NAME     "usbAcmLib" /* USBD client name */
  88. /* for debugging */
  89. #define USB_ACM_DEBUG
  90. #ifdef USB_ACM_DEBUG
  91. #define USB_ACM_DEBUG_OFF 0x0000
  92. #define USB_ACM_DEBUG_RX 0x0001
  93. #define USB_ACM_DEBUG_TX 0x0002
  94. #define USB_ACM_DEBUG_BLOCK 0x0004
  95. #define USB_ACM_DEBUG_ATTACH 0X0008
  96. #define USB_ACM_DEBUG_INIT 0x0010
  97. #define USB_ACM_DEBUG_OPEN 0x0020
  98. #define USB_ACM_DEBUG_CLOSE 0x0040
  99. #define USB_ACM_DEBUG_IOCTL 0x0080
  100. #define USB_ACM_DEBUG_INT 0x0100
  101. int usbAcmDebug = (0x0);
  102. #define USB_ACM_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)    
  103. if (usbAcmDebug & FLG)                           
  104.             logMsg(X0, X1, X2, X3, X4, X5, X6);
  105. #else /*USB_ACM_DEBUG*/
  106. #define USB_ACM_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)
  107. #endif /*USB_ACM_DEBUG*/
  108. /*
  109.  * ATTACH_REQUEST
  110.  */
  111. typedef struct attach_request
  112.     {
  113.     
  114.     LINK reqLink; /* linked list of requests  */
  115.     USB_ACM_CALLBACK callback; /* client callback routine  */
  116.     pVOID callbackArg; /* client callback argument */
  117.     
  118.     }ATTACH_REQUEST, *pATTACH_REQUEST;
  119. /* forward static declarations */
  120. int  usbAcmTxStartup  (SIO_CHAN * pSioChan);
  121. LOCAL  int usbAcmPollOutput  (SIO_CHAN * pSioChan, char    outChar);
  122. LOCAL  int usbAcmPollInput   (SIO_CHAN * pSioChan, char *thisChar);
  123. int  usbAcmIoctl      (SIO_CHAN * pSioChan, int request, void *arg);
  124. LOCAL VOID usbAcmTxIrpCallback  (pVOID p);
  125. LOCAL VOID usbAcmRxIrpCallback  (pVOID p);
  126. LOCAL VOID destroySioChan  (pUSB_ACM_SIO_CHAN pSioChan);
  127. LOCAL STATUS usbAcmCtrlCmdSend  (pUSB_ACM_SIO_CHAN pSioChan, 
  128.  UINT16 request,             
  129.        UINT8 * pBuf,               
  130.  UINT16  count               
  131.         );
  132. LOCAL STATUS usbAcmOpen (SIO_CHAN * pSioChan);
  133. /* locals */
  134. LOCAL UINT16 initCount = 0;  /* Count of init nesting */
  135. LOCAL MUTEX_HANDLE acmMutex;  /* mutex used to protect internal structs */
  136. LOCAL LIST_HEAD sioList;  /* linked list of USB_ACM_SIO_CHAN */
  137. LOCAL LIST_HEAD reqList;  /* Attach callback request list */
  138. LOCAL USBD_CLIENT_HANDLE usbdHandle; /* our USBD client handle */
  139. LOCAL SEM_HANDLE   acmIrpSem;    /* Semaphore for IRP Synchronisation */
  140. /* Channel function table. */
  141. LOCAL SIO_DRV_FUNCS usbAcmSioDrvFuncs =
  142.     {
  143.     usbAcmIoctl,
  144.     usbAcmTxStartup,
  145.     usbAcmCallbackRegister,
  146.     usbAcmPollInput,
  147.     usbAcmPollOutput
  148.     };
  149. /***************************************************************************
  150. *
  151. * notifyAttach - Notifies registered callers of attachment/removal events
  152. *
  153. * RETURNS: N/A
  154. */
  155. LOCAL VOID notifyAttach
  156.     (
  157.     pUSB_ACM_SIO_CHAN pSioChan,
  158.     UINT16 attachCode
  159.     )
  160.     {
  161.     pATTACH_REQUEST pRequest = usbListFirst (&reqList);
  162.     while (pRequest != NULL)
  163. {
  164.         /* Invoke the Callback registered */
  165.         (*pRequest->callback) (pRequest->callbackArg, 
  166.     (SIO_CHAN *) pSioChan, attachCode, NULL, NULL);
  167.         
  168.         /* Move to the next client */
  169. pRequest = usbListNext (&pRequest->reqLink);
  170. }
  171.     }
  172. /***************************************************************************
  173. *
  174. * findEndpoint - Searches for a <type> endpoint of the <direction> direction.
  175. *
  176. * RETURNS: pointer to matching endpoint descriptor or NULL if not found
  177. */
  178. LOCAL pUSB_ENDPOINT_DESCR findEndpoint
  179.     (
  180.     pUINT8 pBfr,
  181.     UINT16 bfrLen,
  182.     UINT16 direction,
  183.     UINT16 attributes
  184.     )
  185.     {
  186.     pUSB_ENDPOINT_DESCR pEp;
  187.     while ((pEp = usbDescrParseSkip (&pBfr, &bfrLen, USB_DESCR_ENDPOINT)) 
  188.   != NULL)
  189. {
  190. if ((pEp->attributes & USB_ATTR_EPTYPE_MASK) == attributes &&
  191.     (pEp->endpointAddress & USB_ENDPOINT_DIR_MASK) == direction)
  192.     break;
  193. }
  194.     return pEp;
  195.     }
  196. /***************************************************************************
  197. *
  198. * configureSioChan - configure USB Modem for operation.
  199. *
  200. * Selects the configuration/interfaces specified in the <pSioChan>
  201. * structure.  These values come from the USBD dynamic attach callback,
  202. * which in turn are retrieved from the configuration/interface
  203. * descriptors which reported the device to be a modem.
  204. *
  205. * ACM Specification requires that the device supporting two interfaces.
  206. * 1. Communication Interface class
  207. * 2. Data Interface class.
  208. *
  209. * We've registered (with usbd) for getting notified when a ACM device 
  210. * is attached.  While registering, we supplied the Communications Class 
  211. * information and Communications interface class information.  The 
  212. * configuration with the communication interface class also should support 
  213. * the data interface class.  Also the communication interface class shall 
  214. * support the common AT command set protocol.
  215. *
  216. * RETURNS: OK if successful, else ERROR if failed to configure channel
  217. */
  218. LOCAL STATUS configureSioChan
  219.     (
  220.     pUSB_ACM_SIO_CHAN pSioChan,
  221.     UINT16 configuration,
  222.     UINT16 interface
  223.     )
  224.     {
  225.     pUSB_CONFIG_DESCR pCfgDescr;
  226.     pUSB_INTERFACE_DESCR pIfDescr;
  227.     pUSB_ENDPOINT_DESCR pOutEp = NULL;
  228.     pUSB_ENDPOINT_DESCR pInEp = NULL;
  229.     pUSB_ENDPOINT_DESCR pIntrEp = NULL;
  230.     UINT8 bfr [USB_MAX_DESCR_LEN];
  231.     pUINT8 pBfr;
  232.     UINT16 actLen;
  233.     UINT16 ifNo;
  234.     /* 
  235.      * Read the configuration descriptor to get the configuration selection
  236.      * value and to determine the device's power requirements.
  237.      */
  238.     if (usbdDescriptorGet (usbdHandle, 
  239.    pSioChan->nodeId,
  240.    USB_RT_STANDARD | USB_RT_DEVICE, USB_DESCR_CONFIGURATION, 
  241.    (configuration - 1), 
  242.    0, 
  243.    sizeof (bfr), 
  244.    bfr, 
  245.    &actLen) != OK)
  246. return ERROR;
  247.     if ((pCfgDescr = usbDescrParse (bfr, actLen, USB_DESCR_CONFIGURATION)) 
  248. == NULL)
  249. return ERROR;
  250.     pSioChan->configuration = configuration;
  251.     /*
  252.      * Now look for the Data Interface Class  and Communication interface 
  253.      * Class. Then find the Corresponding End points
  254.      */
  255.     
  256.     ifNo = 0;
  257.     pBfr = bfr;
  258.     while ((pIfDescr = usbDescrParseSkip (&pBfr, &actLen, USB_DESCR_INTERFACE)) 
  259.  != NULL)
  260. {
  261.         
  262.         if (pIfDescr->interfaceClass == USB_CLASS_COMMINTERFACE)
  263.             {
  264.             
  265.             if (pIfDescr->interfaceProtocol == USB_COMM_PROTOCOL_COMMONAT)
  266.                 {
  267.                 
  268.                 pSioChan->ifaceCommClass = ifNo;
  269.                 pSioChan->ifaceCommAltSetting = pIfDescr->alternateSetting;
  270.                 pSioChan->protocol = USB_COMM_PROTOCOL_COMMONAT;
  271.                 /* It should have an interrupt end point. Find out */
  272.                 if ((pIntrEp = findEndpoint (pBfr, actLen, 
  273.                                             USB_ENDPOINT_IN, 
  274.                                             USB_ATTR_INTERRUPT)) == NULL)
  275.                     {
  276.                     USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, 
  277.                                 " No Interrupt End point n",0, 0, 0, 0, 0, 0);
  278.                     return ERROR;
  279.                     
  280.                     }
  281.                 usbdInterfaceSet (usbdHandle, pSioChan->nodeId,
  282.                              pSioChan->ifaceCommClass, 
  283.                                 pSioChan->ifaceCommAltSetting);
  284.                 }
  285.             }
  286.         else
  287.             {
  288.             if (pIfDescr->interfaceClass == USB_CLASS_DATAINTERFACE)
  289.                 {
  290.                   pSioChan->ifaceDataClass = ifNo;
  291.                   pSioChan->ifaceDataAltSetting = pIfDescr->alternateSetting;
  292.                   /* It should have a Bulk I/P and a Bulk O/P end points */
  293.                   
  294.                   if ((pInEp = findEndpoint (pBfr, 
  295.      actLen, 
  296.                                              USB_ENDPOINT_IN,
  297.                                              USB_ATTR_BULK)) == NULL)
  298.                       {
  299.                     
  300.                       USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, 
  301.                                    " No Input End point n",0, 0, 0, 0, 0, 0);
  302.                       return ERROR;
  303.                       
  304.                       }
  305.                   
  306.                   if ((pOutEp = findEndpoint (pBfr, actLen, 
  307.                                             USB_ENDPOINT_OUT, 
  308.                                             USB_ATTR_BULK)) == NULL)
  309.                       {
  310.                       
  311.                       USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, 
  312.                                    " No Output End point n",0, 0, 0, 0, 0, 0);
  313.                       return ERROR;
  314.                       
  315.                       }
  316.                   usbdInterfaceSet (usbdHandle, pSioChan->nodeId,
  317.                                  pSioChan->ifaceDataClass, 
  318.                                     pSioChan->ifaceDataAltSetting);
  319.                 }
  320.             }
  321.         ifNo++;
  322.         if (pIntrEp != NULL)
  323.             if (pOutEp != NULL)
  324.                 if (pInEp != NULL)
  325.                     break;
  326.         }
  327.     if (pIfDescr == NULL)
  328.         {
  329.         USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, " No appropriate interface 
  330.             descriptor ",0, 0, 0, 0, 0, 0);
  331. return ERROR;
  332.         }
  333.     if ((pInEp == NULL) || (pOutEp == NULL) || (pIntrEp == NULL))
  334. {
  335. USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, " No End points n",0, 0, 0, 0, 0, 0);
  336. }
  337.     USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "Intr EP : 0x%x :: 
  338.         In EP : 0x%x  :: Out EP : 0x%x n", (UINT16)pIntrEp->endpointAddress, 
  339.                   (UINT16)(pInEp->endpointAddress), 
  340.                   (UINT16)(pOutEp->endpointAddress), 0, 0, 0);
  341.     /* Fill in the maximum packet sizes */
  342.     pSioChan->outBfrLen = pOutEp->maxPacketSize;
  343.     pSioChan->inBfrLen = pInEp->maxPacketSize;
  344.     /* Select the configuration. */
  345.     if (usbdConfigurationSet (usbdHandle, 
  346.       pSioChan->nodeId,
  347.       pCfgDescr->configurationValue, 
  348.       pCfgDescr->maxPower * USB_POWER_MA_PER_UNIT) 
  349.     != OK)
  350. return ERROR;
  351.     /* Create a pipe for output to the modem. */
  352.     if (usbdPipeCreate (usbdHandle, 
  353. pSioChan->nodeId, 
  354. pOutEp->endpointAddress, 
  355. pCfgDescr->configurationValue,
  356. pSioChan->ifaceDataClass, 
  357. USB_XFRTYPE_BULK, 
  358. USB_DIR_OUT,
  359. FROM_LITTLEW (pOutEp->maxPacketSize), 
  360. 0, 
  361. 0, 
  362. &pSioChan->outPipeHandle) 
  363.        != OK)
  364. {
  365. return ERROR;
  366. }
  367.     /* 
  368.      * Create a pipe to listen for input from the device 
  369.      */
  370.     if (usbdPipeCreate (usbdHandle, 
  371. pSioChan->nodeId, 
  372. pInEp->endpointAddress, 
  373. pCfgDescr->configurationValue,
  374. pSioChan->ifaceDataClass, 
  375. USB_XFRTYPE_BULK, 
  376. USB_DIR_IN,
  377. FROM_LITTLEW (pInEp->maxPacketSize), 
  378. 0, 
  379. 0, 
  380. &pSioChan->inPipeHandle) 
  381.       != OK)
  382. {
  383. return ERROR;
  384. }
  385.     /* set the default settings for the modem */
  386.     pSioChan->lineCode.baudRate = 9600;    /* Bits/sec */
  387.     pSioChan->lineCode.noOfStopBits = USB_ACM_STOPBITS_1; /* 1 stop bit */
  388.     pSioChan->lineCode.parityType = USB_ACM_PARITY_NONE; /* No parity */
  389.     pSioChan->lineCode.noOfDataBits = 8;   /* 8 data bits */
  390.     if (usbAcmCtrlCmdSend (pSioChan, 
  391.    USB_ACM_REQ_LINE_CODING_SET, 
  392.    (UINT8 *)(&pSioChan->lineCode), 
  393.    sizeof(pSioChan->lineCode)) 
  394.  == ERROR)
  395. {
  396.         USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "LineCode could not be setn",
  397.     0, 0, 0, 0, 0, 0);
  398. }
  399.     return OK;
  400.     }
  401. /***************************************************************************
  402. *
  403. * createSioChan - creates a new USB_ACM_SIO_CHAN structure
  404. *
  405. * Creates a new USB_ACM_SIO_CHAN structure for the indicated <nodeId>.
  406. * If successful, the new structure is linked into the sioList upon 
  407. * return.
  408. *
  409. * <configuration> and <interface> identify the configuration/interface
  410. * that first reported itself as a modem for this device.
  411. *
  412. * RETURNS: pointer to newly created structure, or NULL if failure
  413. */
  414. LOCAL pUSB_ACM_SIO_CHAN createSioChan
  415.     (
  416.     USBD_NODE_ID nodeId,
  417.     UINT16 configuration,
  418.     UINT16 interface,
  419.     UINT16 deviceProtocol
  420.     )
  421.     {
  422.     pUSB_ACM_SIO_CHAN pSioChan;
  423.     /* Try to allocate space for a new modem struct and its buffers */
  424.     if ((pSioChan = OSS_CALLOC (sizeof (*pSioChan))) == NULL )
  425.         {
  426.         USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "Out of Memory n", 
  427.     0, 0, 0, 0, 0, 0);
  428.         return NULL;
  429.         }
  430.     if((pSioChan->outBfr = OSS_MALLOC (ACM_OUT_BFR_SIZE)) == NULL)
  431. {
  432. destroySioChan (pSioChan);
  433.         USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "Out of Memory n",
  434.             0, 0, 0, 0, 0, 0);
  435.         return NULL;
  436. }
  437.     if ((pSioChan->inBfr = OSS_MALLOC (ACM_IN_BFR_SIZE)) == NULL)
  438.         {
  439. destroySioChan (pSioChan);
  440.         USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "Out of Memory n",
  441.             0, 0, 0, 0, 0, 0);
  442. return NULL;
  443. }
  444.     
  445.     pSioChan->sioChan.pDrvFuncs = &usbAcmSioDrvFuncs;
  446.     pSioChan->nodeId = nodeId;
  447.     pSioChan->mode = SIO_MODE_INT;
  448.     pSioChan->connected = TRUE;
  449.     pSioChan->callbackStatus = 0x0;     /* No callbacks installed */
  450.     
  451.     /* Configure the Modem. */
  452.     if (configureSioChan (pSioChan, configuration, interface) != OK)
  453. {
  454. destroySioChan (pSioChan);
  455. return NULL;
  456. }
  457.     /* Link the newly created structure. */
  458.     usbListLink (&sioList, pSioChan, &pSioChan->sioLink, LINK_TAIL);
  459.     USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "SIOCHAN created n",
  460.             0, 0, 0, 0, 0, 0);
  461.     return pSioChan;
  462.     }
  463. /***************************************************************************
  464. *
  465. * findSioChan - Searches for a USB_ACM_SIO_CHAN for indicated node ID
  466. *
  467. * RETURNS: pointer to matching USB_ACM_SIO_CHAN or NULL if not found
  468. */
  469. LOCAL pUSB_ACM_SIO_CHAN findSioChan
  470.     (
  471.     USBD_NODE_ID nodeId
  472.     )
  473.     {
  474.     pUSB_ACM_SIO_CHAN pSioChan = usbListFirst (&sioList);
  475.     while (pSioChan != NULL)
  476. {
  477. if (pSioChan->nodeId == nodeId)
  478.     break;
  479. pSioChan = usbListNext (&pSioChan->sioLink);
  480. }
  481.     return pSioChan;
  482.     }
  483. /***************************************************************************
  484. *
  485. * usbAcmAttachCallback - called by USBD when a modem is attached/removed
  486. *
  487. * The USBD will invoke this callback when a USB modem is attached to or
  488. * removed from the system.  <nodeId> is the USBD_NODE_ID of the node being
  489. * attached or removed. <attachAction> is USBD_DYNA_ATTACH or USBD_DYNA_REMOVE.
  490. * modems report their class information at the interface level,
  491. * so <configuration> and <interface> will indicate the configuratin/interface
  492. * that reports itself as a modem.  <deviceClass> and <deviceSubClass> 
  493. * will match the class/subclass for which we registered.  <deviceProtocol>
  494. * shall be USB_COMM_PROTOCOL_COMMONAT.
  495. *
  496. * NOTE: The USBD will invoke this function once for each configuration/
  497. * interface which reports itself as a modem.  So, it is possible that
  498. * a single device insertion/removal may trigger multiple callbacks.  We
  499. * ignore all callbacks except the first for a given device.
  500. *
  501. * RETURNS: N/A
  502. */
  503. LOCAL VOID usbAcmAttachCallback
  504.     (
  505.     USBD_NODE_ID nodeId, 
  506.     UINT16 attachAction, 
  507.     UINT16 configuration,
  508.     UINT16 interface,
  509.     UINT16 deviceClass, 
  510.     UINT16 deviceSubClass, 
  511.     UINT16 deviceProtocol
  512.     )
  513.     {
  514.     pUSB_ACM_SIO_CHAN pSioChan;
  515.     OSS_MUTEX_TAKE (acmMutex, OSS_BLOCK);
  516.     /* 
  517.      * Depending on the attach code, add a new modem or remove one
  518.      * that's already been created.
  519.      */
  520.     switch (attachAction)
  521. {
  522. case USBD_DYNA_ATTACH:
  523.     /* 
  524.              * A new device is being attached. Check if we already 
  525.      * have a structure for this device.
  526.      */
  527.     if (findSioChan (nodeId) != NULL)
  528. break;
  529.             USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "New ACM device found n",
  530.                 0, 0, 0, 0, 0, 0);
  531.             /* 
  532.              * Create a new structure to manage this device.  If there's
  533.      * an error, there's nothing we can do about it, so skip the
  534.      * device and return immediately. 
  535.      */
  536.     if ((pSioChan = createSioChan (nodeId, configuration, interface,
  537. deviceProtocol)) == NULL)
  538.                 {
  539.                 USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "Could not create 
  540.                     SIO_CHAN n", 0, 0, 0, 0, 0, 0);
  541. break;
  542.                 }
  543.     /* 
  544.              * Notify registered callers that a new modem has been
  545.      * added and a new channel created.
  546.      */
  547.     notifyAttach (pSioChan, USB_ACM_CALLBACK_ATTACH);
  548.             usbAcmOpen ((SIO_CHAN *)pSioChan);
  549.     break;
  550. case USBD_DYNA_REMOVE:
  551.     /* 
  552.              * A device is being detached.  Check if we have any
  553.      * structures to manage this device.
  554.      */
  555.     if ((pSioChan = findSioChan (nodeId)) == NULL)
  556. break;
  557.     /* The device has been disconnected. */
  558.     pSioChan->connected = FALSE;
  559.     /* 
  560.              * Notify registered callers that the modem has been
  561.      * removed and the channel disabled. 
  562.      *
  563.      * NOTE: We temporarily increment the channel's lock count
  564.      * to prevent usbAcmSioChanUnlock() from destroying the
  565.      * structure while we're still using it.
  566.      */
  567.     pSioChan->lockCount++;
  568.     notifyAttach (pSioChan, USB_ACM_CALLBACK_DETACH);
  569.     pSioChan->lockCount--;
  570.     /* 
  571.              * If no callers have the channel structure locked, destroy
  572.      * it now. If it is locked, it will be destroyed later during
  573.      * a call to usbAcmUnlock().
  574.      */
  575.     if (pSioChan->lockCount == 0)
  576. destroySioChan (pSioChan);
  577.     break;
  578. }
  579.     OSS_MUTEX_RELEASE (acmMutex);
  580.     }
  581. /***************************************************************************
  582. *
  583. * destroyAttachRequest - disposes of an ATTACH_REQUEST structure
  584. *
  585. * RETURNS: N/A
  586. * NOMANUAL
  587. */
  588. LOCAL VOID destroyAttachRequest
  589.     (
  590.     pATTACH_REQUEST pRequest
  591.     )
  592.     {
  593.     /* Unlink request */
  594.     usbListUnlink (&pRequest->reqLink);
  595.     /* Dispose of structure */
  596.     OSS_FREE (pRequest);
  597.     }
  598. /***************************************************************************
  599. *
  600. * destroySioChan - disposes of a USB_PRN_ACM_CHAN structure
  601. *
  602. * Unlinks the indicated USB_ACM_SIO_CHAN structure and de-allocates
  603. * resources associated with the channel.
  604. *
  605. * RETURNS: N/A
  606. */
  607. LOCAL VOID destroySioChan
  608.     (
  609.     pUSB_ACM_SIO_CHAN pSioChan
  610.     )
  611.     {
  612.     if (pSioChan != NULL)
  613. {
  614. /* Unlink the structure. */
  615. usbListUnlink (&pSioChan->sioLink);
  616. /* Release pipes and wait for IRPs to be cancelled if necessary. */
  617. if (pSioChan->outPipeHandle != NULL)
  618.     usbdPipeDestroy (usbdHandle, pSioChan->outPipeHandle);
  619. if (pSioChan->inPipeHandle != NULL)
  620.     usbdPipeDestroy (usbdHandle, pSioChan->inPipeHandle);
  621. if (pSioChan->intrPipeHandle != NULL)
  622.     usbdPipeDestroy (usbdHandle, pSioChan->intrPipeHandle);
  623. while (pSioChan->outIrpInUse || pSioChan->inIrpInUse 
  624.                 || pSioChan->intrIrpInUse)
  625.             {
  626.     OSS_THREAD_SLEEP (1);
  627.             }
  628. /* release buffers */
  629. if (pSioChan->outBfr != NULL)
  630.     OSS_FREE (pSioChan->outBfr);
  631. if (pSioChan->inBfr != NULL)
  632.     OSS_FREE (pSioChan->inBfr);
  633. /* Release structure. */
  634. OSS_FREE (pSioChan);
  635. }
  636.     }
  637.     
  638. /***************************************************************************
  639. *
  640. * doShutdown - shuts down USB ACM SIO driver
  641. *
  642. * <errCode> should be OK or S_usbAcmLib_xxxx.  This value will be
  643. * passed to ossStatus() and the return value from ossStatus() is the
  644. * return value of this function.
  645. *
  646. * RETURNS: OK, or ERROR per value of <errCode> passed by caller
  647. */
  648. LOCAL STATUS doShutdown
  649.     (
  650.     int errCode
  651.     )
  652.     {
  653.     pATTACH_REQUEST pRequest;
  654.     USB_ACM_SIO_CHAN * pSioChan;
  655.     /* Dispose of any outstanding notification requests */
  656.     while ((pRequest = usbListFirst (&reqList)) != NULL)
  657. destroyAttachRequest (pRequest);
  658.     /* Dispose of any open connections. */
  659.     while ((pSioChan = usbListFirst (&sioList)) != NULL)
  660. destroySioChan (pSioChan);
  661.     /* 
  662.      * Release our connection to the USBD.  The USBD automatically 
  663.      * releases any outstanding dynamic attach requests when a client
  664.      * unregisters.
  665.      */
  666.     if (usbdHandle != NULL)
  667. {
  668. usbdClientUnregister (usbdHandle);
  669. usbdHandle = NULL;
  670. }
  671.     /* Release resources. */
  672.     if (acmMutex != NULL)
  673. {
  674. OSS_MUTEX_DESTROY (acmMutex);
  675. acmMutex = NULL;
  676. }
  677.     if (acmIrpSem != NULL)
  678.         {
  679.         OSS_SEM_DESTROY (acmIrpSem);
  680.         acmIrpSem = NULL;
  681.         }
  682.     return ossStatus (errCode);
  683.     }
  684. /**************************************************************************
  685. *
  686. * usbAcmLibInit - initialize USB ACM SIO driver.
  687. *
  688. * Initializes the USB ACM SIO driver.  The USB acm SIO driver
  689. * maintains an initialization count, so calls to this function may be
  690. * nested. This function will regsiter the driver as a client for the USBD. It
  691. * also registers itself for a notification (by usbd) when a ACM device
  692. * is dynamically attached / removed from the USB.
  693. *
  694. * RETURNS: OK, or ERROR if unable to initialize.
  695. *
  696. * ERRNO:
  697. *
  698. *   S_usbAcmLib_OUT_OF_RESOURCES
  699. *   S_usbAcmLib_USBD_FAULT
  700. */
  701. STATUS usbAcmLibInit (void)
  702.     {
  703.     /* 
  704.      * If not already initialized, then initialize internal structures
  705.      * and connection to USBD.
  706.      */
  707.     initCount++;
  708.     if (initCount > 1)
  709.         return OK;
  710.            
  711.     /* Initialize lists, structures, resources. */
  712.     memset (&sioList, 0, sizeof (sioList));
  713.     memset (&reqList, 0, sizeof (reqList));
  714.     acmMutex = NULL;
  715.     usbdHandle = NULL;
  716.     acmIrpSem = NULL;
  717.     if (OSS_MUTEX_CREATE (&acmMutex) != OK)
  718.         return doShutdown (S_usbAcmLib_OUT_OF_RESOURCES);
  719.     if (OSS_SEM_CREATE (1, 0 , &acmIrpSem) != OK)
  720.         return (doShutdown (S_usbAcmLib_OUT_OF_RESOURCES));
  721.     /* Establish connection to USBD */
  722.     if (usbdClientRegister (ACM_CLIENT_NAME, &usbdHandle) != OK 
  723. ||
  724.         usbdDynamicAttachRegister (usbdHandle, 
  725.    USB_CLASS_COMMDEVICE,
  726.    USB_SUBCLASS_ACM, 
  727.    USB_COMM_PROTOCOL_COMMONAT,
  728.    usbAcmAttachCallback) 
  729.   != OK)
  730.             {
  731.     return doShutdown (S_usbAcmLib_USBD_FAULT);
  732.     }
  733.     
  734.     return OK;
  735.     }
  736. /**************************************************************************
  737. *
  738. * usbAcmCallbackRegister - Installs a callback for an event.
  739. *
  740. * This function installs a callback for a <callbackType> event. If the event
  741. * occurs, the client will be notified via the installed <callback> function.
  742. * <arg> is a client specific argument, used as a parameter to the <callback>
  743. * routine.
  744. *
  745. * The macro USB_ACM_CALLBACK defines a callback routine which will be invoked
  746. * by usbAcmLib when any of these events happen, provided that the user
  747. * registered a callback for such an event. This macro is compatible with the
  748. * SIO TxCallback and RxCallback definitions and provides additional 
  749. * functionality for registering for attachment/removal.
  750. * Note that all these fields are not required for all of the events.
  751. * They will be filled with NULL or ZERO (0) when the callback is executed.
  752. *
  753. *
  754. * .CS
  755. * typedef STATUS (*USB_ACM_CALLBACK)
  756.     (
  757.     pVOID       arg,             /@ caller-defined argument @/
  758.     SIO_CHAN * pChan,     /@ pointer to affected SIO_CHAN @/
  759.     UINT16 callbackType,     /@ defined as USB_ACM_CALLBACK_xxxx @/
  760.     UINT8 * pBuf,                   /@ pointer to data buffer, if any data @/
  761.                                     /@ transfer is involved. Otherwise NULL @/
  762.     UINT16 count                    /@ No of bytes of data transferred @/
  763.                                     /@ if a data transfer is involved. @/
  764.                                     /@ 0 otherwise. @/
  765.     );
  766. *
  767. * .CE
  768. *
  769. * Note that the <pChan> paramter shall be NULL for the Dynamic attachment
  770. * notification requests, indicating that the event is not for any particular
  771. * device.
  772. *
  773. * Care should be taken not to install multiple callbacks for the same event
  774. * for the same <pChan>. How-ever this is not applicable for the dynamic 
  775. * attachment event notification requests.
  776. *
  777. * Different <callbackType> events suppoted by this driver are
  778. *
  779. * .IP "USB_ACM_CALLBACK_ATTACH"
  780. *  Used to get notified of dynamic attachment / removal of usb modems. 
  781. * .IP "USB_ACM_CALLBACK_SIO_TX"
  782. *  Used for transmitting characters. This is equivalent to SIO_CALLBACK_GET_TX_CHAR.
  783. * .IP "USB_ACM_CALLBACK_SIO_RX"
  784. *  Used for receiving characters. This is equivalent to SIO_CALLBACK_PUT_RCV_CHAR.
  785. *
  786. * RETURNS: OK, or ERROR if unable to install.
  787. *
  788. * ERRNO : S_usbAcmLib_OUT_OF_MEMORY,  S_usbAcmLib_BAD_PARAM
  789. *
  790. */
  791. int usbAcmCallbackRegister 
  792.     (
  793.     SIO_CHAN * pChan,               /* Channel for the callback */
  794.     int      callbackType,          /* Callback type. see above */
  795.     FUNCPTR  callback,           /* the callback routine */
  796.     pVOID   arg                     /* User defined argument */
  797.     )
  798.     {
  799.     pUSB_ACM_SIO_CHAN pSioChan = (pUSB_ACM_SIO_CHAN)pChan;
  800.     pATTACH_REQUEST pRequest;
  801.     int status = OK;
  802.     
  803.     if (callback == NULL)
  804. {
  805.         return ossStatus (S_usbAcmLib_BAD_PARAM);
  806. }
  807.     if ((callbackType != USB_ACM_CALLBACK_ATTACH) && 
  808.         (callbackType != USB_ACM_CALLBACK_DETACH))
  809.         {
  810.         if (pSioChan == NULL)
  811.     {
  812.     return ossStatus (S_usbAcmLib_BAD_PARAM);
  813.     }
  814.         }
  815.     switch (callbackType)
  816.         {
  817.         case USB_ACM_CALLBACK_ATTACH :
  818.         case USB_ACM_CALLBACK_DETACH :
  819.             /* Client wants to get notified of attachment/removal of modems */
  820.             /* Create a new request structure to track this callback request */
  821.             OSS_MUTEX_TAKE (acmMutex, OSS_BLOCK);
  822.             if ((pRequest = OSS_CALLOC (sizeof (*pRequest))) == NULL)
  823. {
  824.         status = S_usbAcmLib_OUT_OF_MEMORY;
  825. }
  826.             else
  827.         {
  828.         pRequest->callback = (USB_ACM_CALLBACK)callback;
  829.         pRequest->callbackArg = arg;
  830.         usbListLink (&reqList, pRequest, &pRequest->reqLink, LINK_TAIL);
  831.                 /*
  832.                  * Perform an initial notification of all currrently 
  833.                  * attached modems.
  834.                  */
  835.   pSioChan = usbListFirst (&sioList);
  836.         while (pSioChan != NULL)
  837.             {
  838.             if (pSioChan->connected)
  839. (*callback) (arg, 
  840.      (SIO_CHAN *) pSioChan, 
  841.      USB_ACM_CALLBACK_ATTACH, 
  842.      NULL, 
  843.      0);
  844.             pSioChan = usbListNext (&pSioChan->sioLink);
  845.             }
  846.         }
  847.             OSS_MUTEX_RELEASE (acmMutex);
  848.             return ossStatus (status);
  849.         case USB_ACM_CALLBACK_SIO_TX    :
  850.         case SIO_CALLBACK_GET_TX_CHAR   :
  851.             /* Callback for getting Tx Chars : Normal VxWorks SIO Model */
  852.       USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "Tx callback installed n",
  853.                 0, 0, 0, 0, 0, 0);
  854.             pSioChan->callbackStatus |= USB_ACM_CALLBACK_SIO_TX;
  855.             pSioChan->getTxCharCallback = (FUNCPTR)callback;
  856.     pSioChan->getTxCharArg = arg;
  857.     return OK;
  858.         
  859.         case USB_ACM_CALLBACK_SIO_RX    :
  860.         case SIO_CALLBACK_PUT_RCV_CHAR  :
  861.             /* Callback for returning rx Chars : Normal VxWorks SIO Model */
  862.       USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "Rx callback installed n",
  863.                 0, 0, 0, 0, 0, 0);
  864.             pSioChan->callbackStatus |= USB_ACM_CALLBACK_SIO_RX;
  865.             pSioChan->putRxCharCallback = (FUNCPTR)callback;
  866.     pSioChan->putRxCharArg = arg;
  867.     return OK;
  868.         default :
  869.             return ossStatus (S_usbAcmLib_BAD_PARAM);
  870.         }
  871.     return OK;
  872.     }
  873. /**************************************************************************
  874. *
  875. * usbAcmCallbackRemove - De-Registers a callback for an event.
  876. *
  877. * This function removess a (previously installed) <callback> callback routine 
  878. * for a <callbackType> event. 
  879. *
  880. * Though this function provides a way to remove the callbacks even for the
  881. * transmit and receive functionality, it is adviced that these callbacks be
  882. * not removed. Note that the <pChan> paramter shall be NULL for the Dynamic 
  883. * attachment notification requests, indicating that the event is not for any 
  884. * particular device. Similary, <callback> can be NULL for all the other 
  885. * events other than the dynamic attachment / removal events.
  886. *
  887. * Different <callbackType> events suppoted by this driver are mentioned in 
  888. * usbAcmCallbackRegister. Please refer to the corresponding entry.
  889. *
  890. * RETURNS: OK, or ERROR if unable to remove a callback.
  891. *
  892. * ERRNO : 
  893. *  S_usbAcmLib_BAD_PARAM
  894. *  S_usbAcmLib_NOT_REGISTERED
  895. *
  896. */
  897. STATUS usbAcmCallbackRemove
  898.     (
  899.     SIO_CHAN * pChan,           /* Channel for de-registering callbacks */
  900.     UINT callbackType,          /* Event the call back is to be removed */
  901.     USB_ACM_CALLBACK callback /* callback to be unregistered */
  902.     )
  903.     {
  904.     
  905.     pUSB_ACM_SIO_CHAN pSioChan = (pUSB_ACM_SIO_CHAN)pChan;
  906.     pATTACH_REQUEST pRequest;
  907.     int status = OK;
  908.     /* Check for the validity of the input paramaters */
  909.     
  910.     if ((callbackType != USB_ACM_CALLBACK_ATTACH) && 
  911.         (callbackType != USB_ACM_CALLBACK_DETACH))
  912.         {
  913.         /* 
  914.          * Except for attachment/removal requests, pChan should never 
  915.          * be Null 
  916.          */
  917.         if (pSioChan == NULL)
  918.             return ossStatus (S_usbAcmLib_BAD_PARAM);
  919.         
  920.         /* Check if there is a callback for this event. */
  921.         
  922.         if ((pSioChan->callbackStatus & callbackType) == 0)
  923.             return ossStatus (S_usbAcmLib_NOT_REGISTERED);
  924.         
  925.         /* De-Register the callback.*/
  926.         pSioChan->callbackStatus &= ~callbackType;
  927.         /* Thats all required , return now.*/
  928.         return OK;
  929.         }
  930.     if (callback == NULL)
  931.         return ossStatus (S_usbAcmLib_BAD_PARAM);
  932.     status = S_usbAcmLib_NOT_REGISTERED;
  933.     OSS_MUTEX_TAKE (acmMutex, OSS_BLOCK);
  934.     pRequest = usbListFirst (&reqList);
  935.     while (pRequest != NULL)
  936.         {
  937. if (callback == pRequest->callback)
  938.             {
  939.     
  940.             /* We found a matching notification request. */
  941.             destroyAttachRequest (pRequest);
  942.     status = OK;
  943.     break;
  944.             }
  945.         
  946.     pRequest = usbListNext (&pRequest->reqLink);
  947.         }
  948.     OSS_MUTEX_RELEASE (acmMutex);
  949.     return ossStatus (status);
  950.         
  951.     }
  952. /***************************************************************************
  953. *
  954. * usbAcmSioChanLock - Marks SIO_CHAN structure as in use
  955. *
  956. * A caller uses usbAcmSioChanLock() to notify usbAcmLib that
  957. * it is using the indicated SIO_CHAN structure.  usbAcmLib maintains
  958. * a count of users using a particular SIO_CHAN structure so that it 
  959. * knows when it is safe to dispose of a structure when the underlying
  960. * USB Modem is removed from the system.  As long as the "lock count"
  961. * is greater than zero, usbAcmLib will not dispose of an SIO_CHAN
  962. * structure.
  963. *
  964. * RETURNS: OK, or ERROR if unable to mark SIO_CHAN structure in use.
  965. */
  966. STATUS usbAcmSioChanLock
  967.     (
  968.     SIO_CHAN *pChan /* SIO_CHAN to be marked as in use */
  969.     )
  970.     {
  971.     pUSB_ACM_SIO_CHAN pSioChan = (pUSB_ACM_SIO_CHAN) pChan;
  972.     
  973.     pSioChan->lockCount++;
  974.     return OK;
  975.     }
  976. /***************************************************************************
  977. *
  978. * usbAcmSioChanUnlock - Marks SIO_CHAN structure as unused
  979. *
  980. * This function releases a lock placed on an SIO_CHAN structure.  When a
  981. * caller no longer needs an SIO_CHAN structure for which it has previously
  982. * called usbAcmSioChanLock(), then it should call this function to
  983. * release the lock.
  984. *
  985. * NOTE: If the underlying USB Modem device has already been removed
  986. * from the system, then this function will automatically dispose of the
  987. * SIO_CHAN structure if this call removes the last lock on the structure.
  988. * Therefore, a caller must not reference the SIO_CHAN again structure after
  989. * making this call.
  990. *
  991. * RETURNS: OK, or ERROR if unable to mark SIO_CHAN structure unused
  992. *
  993. * ERRNO:  S_usbAcmLib_NOT_LOCKED
  994. *
  995. */
  996. STATUS usbAcmSioChanUnlock
  997.     (
  998.     SIO_CHAN *pChan /* SIO_CHAN to be marked as unused */
  999.     )
  1000.     {
  1001.     pUSB_ACM_SIO_CHAN pSioChan = (pUSB_ACM_SIO_CHAN) pChan;
  1002.     int status = OK;
  1003.     OSS_MUTEX_TAKE (acmMutex, OSS_BLOCK);
  1004.     if (pSioChan->lockCount == 0)
  1005. status = S_usbAcmLib_NOT_LOCKED;
  1006.     else
  1007. {
  1008.         /* 
  1009.          * If this is the last lock and the underlying USB modem is
  1010.  * no longer connected, then dispose of the acm struct.
  1011.  */
  1012. if (--pSioChan->lockCount == 0 && !pSioChan->connected)
  1013.     destroySioChan (pSioChan);
  1014. }
  1015.     OSS_MUTEX_RELEASE (acmMutex);
  1016.     return ossStatus (status);
  1017.     }
  1018. /***************************************************************************
  1019. *
  1020. * initiateOutput - initiates SIO model data transmission to modem.
  1021. *
  1022. * If the output IRP is not already in use, this function fills the output
  1023. * buffer by invoking the "tx char callback".  If at least one character is
  1024. * available for output, the function then initiates the output IRP.
  1025. *
  1026. * RETURNS: OK, or ERROR if unable to initiate transmission
  1027. *
  1028. * NOMANUAL
  1029. */
  1030. STATUS initiateOutput
  1031.     (
  1032.     pUSB_ACM_SIO_CHAN pSioChan
  1033.     )
  1034.     {
  1035.     pUSB_IRP pIrp = &pSioChan->outIrp;
  1036.     UINT16 count;
  1037.     /* Return immediately if the output IRP is already in use. */
  1038.     if (pSioChan->outIrpInUse)
  1039. {
  1040. logMsg(" OutIrp in Use..n",0,0,0,0,0,0);
  1041. return ERROR; 
  1042. }
  1043.     /* If there is no tx callback, return an error */
  1044.     if (pSioChan->getTxCharCallback == NULL)
  1045. {
  1046. logMsg("No TxCallback n",0,0,0,0,0,0);
  1047. return ERROR;
  1048. }
  1049.     /* 
  1050.      * Fill the output buffer until it is full or until the tx callback
  1051.      * has no more data.  Return if there is no data available.
  1052.      */
  1053.     count = 0;
  1054.     USB_ACM_LOG(USB_ACM_DEBUG_TX," Preparing data n",0,0,0,0,0,0);
  1055.     while (count < pSioChan->outBfrLen &&
  1056. (*pSioChan->getTxCharCallback) (pSioChan->getTxCharArg, 
  1057. &pSioChan->outBfr [count]) 
  1058.       == OK)
  1059. {
  1060. count++;
  1061. }
  1062.     if (count == 0)
  1063. return OK;
  1064.     /* Initialize IRP */
  1065.     memset (pIrp, 0, sizeof (*pIrp));
  1066.     pIrp->userPtr = pSioChan;
  1067.     pIrp->irpLen = sizeof (*pIrp);
  1068.     pIrp->userCallback = usbAcmTxIrpCallback;
  1069.     pIrp->timeout = 2000;
  1070.     pIrp->transferLen = count;
  1071.     pIrp->bfrCount = 1;
  1072.     pIrp->bfrList [0].pid = USB_PID_OUT;
  1073.     pIrp->bfrList [0].pBfr = pSioChan->outBfr;
  1074.     pIrp->bfrList [0].bfrLen = count;
  1075.     USB_ACM_LOG(USB_ACM_DEBUG_TX," Irp framed %d bytesn",count,0,0,0,0,0);
  1076.     pSioChan->outIrpInUse = TRUE;   /* This is a MUST */
  1077.  
  1078.     /* Submit IRP */
  1079.     if (usbdTransfer (usbdHandle, pSioChan->outPipeHandle, pIrp) != OK)
  1080. return ERROR;
  1081.     USB_ACM_LOG(USB_ACM_DEBUG_TX," Data.submitted for tx n",0,0,0,0,0,0);
  1082.     /* Wait for IRP to complete or cancel by timeout */
  1083.     if ( OSS_SEM_TAKE (acmIrpSem, 2000 + 1000) == ERROR )
  1084.         {
  1085.         printf ("ACM:initiateOutput: Fatal Error n");
  1086.         }
  1087.     USB_ACM_LOG(USB_ACM_DEBUG_TX," returning n",0,0,0,0,0,0);
  1088.     return OK;
  1089.     }
  1090. /***************************************************************************
  1091. *
  1092. * listenForInput - Initialize IRP to listen for input from Modem
  1093. *
  1094. * RETURNS: OK, or ERROR if unable to submit IRP to listen for input
  1095. */
  1096. LOCAL STATUS listenForInput
  1097.     (
  1098.     pUSB_ACM_SIO_CHAN pSioChan
  1099.     )
  1100.     {
  1101.     pUSB_IRP pIrp = &pSioChan->inIrp;
  1102.     /* Initialize IRP */
  1103.     memset (pIrp, 0, sizeof (*pIrp));
  1104.     pIrp->userPtr = pSioChan;
  1105.     pIrp->irpLen = sizeof (*pIrp);
  1106.     pIrp->userCallback = usbAcmRxIrpCallback;
  1107.     pIrp->timeout = USB_TIMEOUT_NONE;
  1108.     pIrp->transferLen = pSioChan->inBfrLen;
  1109.     pIrp->bfrCount = 1;
  1110.     pIrp->bfrList [0].pid = USB_PID_IN;
  1111.     pIrp->bfrList [0].pBfr = (pUINT8) &pSioChan->inBfr;
  1112.     pIrp->bfrList [0].bfrLen = pSioChan->inBfrLen;
  1113.     pSioChan->inIrpInUse = TRUE;
  1114.     /* Submit IRP */
  1115.     if (usbdTransfer (usbdHandle, pSioChan->inPipeHandle, pIrp) != OK)
  1116. return ERROR;
  1117.     return OK;
  1118.     }
  1119. /***************************************************************************
  1120. *
  1121. * usbAcmTxIrpCallback - Invoked upon IRP completion/cancellation
  1122. *
  1123. * Examines the cause of the IRP completion and re-submits the IRP.
  1124. *
  1125. * RETURNS: N/A
  1126. */
  1127. LOCAL VOID usbAcmTxIrpCallback
  1128.     (
  1129.     pVOID p /* completed IRP */
  1130.     )
  1131.     {
  1132.     pUSB_IRP pIrp = (pUSB_IRP) p;
  1133.     pUSB_ACM_SIO_CHAN pSioChan = pIrp->userPtr;
  1134.     pSioChan->outIrpInUse = FALSE;
  1135.     if (pIrp->result != OK)
  1136.         pSioChan->outErrors++;
  1137.     /*
  1138.      * If a Block transmission occured, we just return. Otherwise
  1139.      * we'll see if some more data is to be transmitted.
  1140.      */
  1141.     if (pSioChan->callbackStatus | USB_ACM_CALLBACK_BLK_TX)
  1142.         {
  1143.         pSioChan->callbackStatus &= ~USB_ACM_CALLBACK_BLK_TX;
  1144.         }
  1145.     OSS_SEM_GIVE (acmIrpSem);
  1146.     }
  1147. /***************************************************************************
  1148. *
  1149. * usbAcmRxIrpCallback - Invoked upon IRP completion/cancellation
  1150. *
  1151. * Examines the cause of the IRP completion and re-submits the IRP.
  1152. *
  1153. * RETURNS: N/A
  1154. */
  1155. LOCAL VOID usbAcmRxIrpCallback
  1156.     (
  1157.     pVOID p /* completed IRP */
  1158.     )
  1159.     {
  1160.     pUSB_IRP pIrp = (pUSB_IRP) p;
  1161.     pUSB_ACM_SIO_CHAN pSioChan = pIrp->userPtr;
  1162.     UINT16 count;
  1163.     USB_ACM_LOG(USB_ACM_DEBUG_RX," RxCallBack n",0,0,0,0,0,0);
  1164.     /* Input IRP completed */
  1165.     pSioChan->inIrpInUse = FALSE;
  1166.     if (pIrp->result != OK)
  1167.         pSioChan->inErrors++;
  1168.     /*
  1169.      * If the IRP was successful then pass the data back to the client.
  1170.      */
  1171.     if (pIrp->result == OK)
  1172.         {
  1173.         
  1174.         /* 
  1175.          * How to pass the data to clients? If a BlockRxCallback is installed,
  1176.          * then that callback shall be used to send back the data. Otherwise
  1177.          * it shall be the Vxworks SIO model callback 
  1178.          */
  1179.             /* Its the normal VxWorks SIO model now */
  1180.           
  1181. USB_ACM_LOG(USB_ACM_DEBUG_RX," Passing data up n",0,0,0,0,0,0);
  1182.         
  1183.         if (pSioChan->putRxCharCallback == NULL)
  1184.     {
  1185.     logMsg("ACM: Rx Callback Null!!!n",0,0,0,0,0,0);
  1186.             ossStatus (S_usbAcmLib_NOT_REGISTERED);
  1187.             return;
  1188.             }
  1189.         for (count = 0; count < pIrp->bfrList [0].actLen; count++)
  1190.     {
  1191.     (*pSioChan->putRxCharCallback) (pSioChan->putRxCharArg,
  1192. pIrp->bfrList [0].pBfr [count]);
  1193.     }
  1194. }
  1195. /* 
  1196.          * Unless the IRP was cancelled - implying the channel is being
  1197.  * shutdown, re-initiate the "in" IRP to listen for more data from
  1198.  * the modem.
  1199.  */
  1200.         USB_ACM_LOG(USB_ACM_DEBUG_RX," Passing data up ..done n",0,0,0,0,0,0);
  1201. if (pIrp->result != S_usbHcdLib_IRP_CANCELED)
  1202.     listenForInput (pSioChan);
  1203.    }
  1204.  
  1205. /***************************************************************************
  1206. *
  1207. * usbAcmCtrlCmdSend - Sends a Control command to the Modem.
  1208. *
  1209. * This function sends an AT command to the modem. The response to the command
  1210. * will be passed to the client via a previously installed callback for the
  1211. * Modem response.
  1212. *
  1213. * RETURNS: OK or ERROR if the command could not be sent.
  1214. *
  1215. */
  1216. LOCAL STATUS usbAcmCtrlCmdSend
  1217.     (
  1218.     pUSB_ACM_SIO_CHAN pSioChan, /* Modem reference */
  1219.     UINT16 request,             /* Command to send */
  1220.     UINT8 * pBuf,               /* Modem command buffer */
  1221.     UINT16  count               /* no of bytes in command */
  1222.     )
  1223.     {
  1224.     UINT16 actLen;
  1225.     if (pSioChan == NULL)
  1226.         return ERROR;
  1227.     if (usbdVendorSpecific (usbdHandle, 
  1228. pSioChan->nodeId,
  1229. USB_RT_HOST_TO_DEV | USB_RT_CLASS | USB_RT_INTERFACE,
  1230. request, 
  1231. pSioChan->configuration,
  1232. (pSioChan->ifaceCommClass << 8 | pSioChan->ifaceCommAltSetting),
  1233. count, 
  1234. pBuf, 
  1235. &actLen) 
  1236.       != OK)
  1237. {
  1238. return ERROR;
  1239. }
  1240.     return OK;
  1241.     }
  1242. /***************************************************************************
  1243. *
  1244. * usbAcmHwOptsSet - set hardware options
  1245. *
  1246. * This routine sets up the modem according to the specified option
  1247. * argument.  If the hardware cannot support a particular option value, then
  1248. * it should ignore that portion of the request.
  1249. *
  1250. * USB modems supports more features than what are provided by the SIO model.
  1251. * It is suggested that to take full advantage of these features, user shall
  1252. * make use of the additional ioctl requests provided.
  1253. *
  1254. * RETURNS: OK upon success, or EIO for invalid arguments.
  1255. */
  1256. LOCAL int usbAcmHwOptsSet
  1257.     (
  1258.     USB_ACM_SIO_CHAN * pChan, /* channel */
  1259.     uint_t     newOpts           /* new options */
  1260.     )
  1261.     {
  1262.     BOOL hdweFlowCtrl= TRUE;
  1263.     BOOL rcvrEnable = TRUE;
  1264.     LINE_CODE oldLineCode;
  1265.     if (pChan == NULL || newOpts & 0xffffff00)
  1266. return EIO;
  1267.     /* do nothing if options already set */
  1268.     if ((uint_t)pChan->options == newOpts)
  1269. return OK;
  1270.     oldLineCode = pChan->lineCode;
  1271.     /* decode individual request elements */
  1272.     switch (newOpts & CSIZE)
  1273. {
  1274. case CS5:
  1275.     pChan->lineCode.noOfDataBits = 5; 
  1276.     break;
  1277. case CS6:
  1278.     pChan->lineCode.noOfDataBits = 6; 
  1279.     break;
  1280. case CS7:
  1281.     pChan->lineCode.noOfDataBits = 7; 
  1282.     break;
  1283. default:
  1284. case CS8:
  1285.     pChan->lineCode.noOfDataBits = 8; 
  1286.     break;
  1287. }
  1288.     if (newOpts & STOPB)
  1289. pChan->lineCode.noOfStopBits = USB_ACM_STOPBITS_2;
  1290.     else
  1291. pChan->lineCode.noOfStopBits = USB_ACM_STOPBITS_1;
  1292.     switch (newOpts & (PARENB|PARODD))
  1293. {
  1294. case PARENB|PARODD:
  1295.     pChan->lineCode.parityType = USB_ACM_PARITY_ODD;
  1296.     break;
  1297. case PARENB:
  1298.     pChan->lineCode.parityType = USB_ACM_PARITY_EVEN;
  1299.     break;
  1300. case PARODD:
  1301.     /* invalid mode, not normally used. */
  1302.     break;
  1303. default:
  1304. case 0:
  1305.     pChan->lineCode.parityType = USB_ACM_PARITY_NONE;
  1306.             break;
  1307. }
  1308.     /* TODO : set the H/W Flow control some how */
  1309.     if (newOpts & CLOCAL)
  1310. {
  1311.         /* clocal disables hardware flow control */
  1312.         hdweFlowCtrl = FALSE;
  1313. }
  1314.     if ((newOpts & CREAD) == 0)
  1315. rcvrEnable = FALSE;
  1316.     USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, "Setting HW options n", 
  1317.         0, 0, 0, 0, 0, 0);
  1318.     
  1319.     if (usbAcmCtrlCmdSend (pChan, 
  1320.    USB_ACM_REQ_LINE_CODING_SET,
  1321.    (UINT8 *)(&pChan->lineCode), 
  1322.    sizeof(pChan->lineCode)) 
  1323.   == ERROR)
  1324.         {
  1325.         pChan->lineCode = oldLineCode;
  1326.         return ERROR;
  1327.         }
  1328.     pChan->options = newOpts;
  1329.     return (OK);
  1330.     }
  1331. /***************************************************************************
  1332. *
  1333. * usbAcmIoctl - special device control
  1334. *
  1335. * This routine handles the IOCTL messages from the user. It supports commands 
  1336. * to get/set baud rate, mode( only INT mode), hardware options(parity, 
  1337. * number of data bits). 
  1338. *
  1339. * This driver works only in the interrupt mode. Attempts to place the driver
  1340. * in polled mode result in ERROR.
  1341. *
  1342. * SIO_HUP is not implemented. Instead, user can issue a "ATH" AT command
  1343. * to the modem to hangup the line.
  1344. *
  1345. * RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed
  1346. * request.
  1347. */
  1348. int usbAcmIoctl
  1349.     (
  1350.     SIO_CHAN * pChan,       /* Channel to control */
  1351.     int     request,        /* IOCTL request */
  1352.     void *  pArg            /* pointer to an argument  */
  1353.     )
  1354.     {
  1355.     pUSB_ACM_SIO_CHAN pSioChan = (pUSB_ACM_SIO_CHAN)pChan;
  1356.     int arg = (int)pArg;
  1357.     UINT16 tempValue = 0;
  1358.     if (pSioChan == NULL)
  1359.         return ERROR;
  1360.     USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, "Ioctl : 0x%0x request n",
  1361.         request, 0, 0, 0, 0, 0);
  1362.     switch (request)
  1363. {
  1364.         case USB_ACM_SIO_MODE_SET:
  1365.     /* 
  1366.      * Set driver operating mode: interrupt or polled.
  1367.      * NOTE: This driver supports only SIO_MODE_INT.
  1368.      */
  1369.     USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, 
  1370.                          "Ioctl : MODE_SET request for %s mode n",
  1371.                   (UINT)((arg == SIO_MODE_INT)?"Interrupt":"Polled"), 
  1372.                          0, 0, 0, 0, 0);
  1373.     if (arg != SIO_MODE_INT)
  1374. return EIO;
  1375.     pSioChan->mode = arg;
  1376.     return OK;
  1377. case USB_ACM_SIO_MODE_GET:
  1378.     /* Return current driver operating mode for channel */
  1379.     USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, "Ioctl : MODE_GET request n",
  1380.          0, 0, 0, 0, 0, 0);
  1381.     *((int *) arg) = pSioChan->mode;
  1382.     return OK;
  1383. case USB_ACM_SIO_AVAIL_MODES_GET:
  1384.     /* Return modes supported by driver. */
  1385.     USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, 
  1386.                          "Ioctl : GET_ALL_MODES request n",
  1387.                   0, 0, 0, 0, 0, 0);
  1388.     *((int *) arg) = SIO_MODE_INT;
  1389.     return OK;
  1390. case USB_ACM_SIO_OPEN:
  1391.     /* Channel is always open. */
  1392.     USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, "Ioctl : OPEN request n",
  1393.          0, 0, 0, 0, 0, 0);
  1394.     return OK;
  1395.         case USB_ACM_SIO_BAUD_SET:
  1396.             /*
  1397.      * like unix, a baud request for 0 is really a request to
  1398.      * hangup. In usb modems, hangup is achieved by sending an
  1399.              * AT command "ATH" than this way. We return ERROR here.
  1400.      */
  1401.     USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, 
  1402.                          "Ioctl : SET_BAUD of %d  request n",
  1403.                   arg, 0, 0, 0, 0, 0);
  1404.     if (arg == 0)
  1405. /*return usbAcmHup (pSioChan);*/
  1406.                 return EIO;
  1407.     /*
  1408.      * Set the baud rate. Return EIO for an invalid baud rate, or
  1409.      * OK on success.
  1410.      */
  1411.     if (arg < USB_ACM_BAUD_MIN || arg > USB_ACM_BAUD_MAX)
  1412.         {
  1413.           USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, 
  1414.                              "Ioctl : %dbaud exceeds range n",
  1415.                       arg, 0, 0, 0, 0, 0);
  1416. return (EIO);
  1417.         }
  1418.             tempValue = pSioChan->lineCode.baudRate;
  1419.             pSioChan->lineCode.baudRate = arg;
  1420.             if (usbAcmCtrlCmdSend (pSioChan, 
  1421.    USB_ACM_REQ_LINE_CODING_SET, 
  1422.    (UINT8 *)(&pSioChan->lineCode), 
  1423.    sizeof(pSioChan->lineCode)) 
  1424.  == ERROR)
  1425.                 {
  1426.                 pSioChan->lineCode.baudRate = tempValue;
  1427.           USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, 
  1428.                              "Ioctl : SET_BAUD of %d  request failed n",
  1429.                       arg, 0, 0, 0, 0, 0);
  1430.                 return EIO;
  1431.                 }
  1432.             return OK;
  1433.         case USB_ACM_SIO_BAUD_GET:
  1434.     USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, 
  1435.                          "Ioctl : GET_BAUD of %d  request n",
  1436.                   0, 0, 0, 0, 0, 0);
  1437.             *(UINT *)arg = pSioChan->lineCode.baudRate;
  1438.             return OK;
  1439.         case USB_ACM_SIO_HW_OPTIONS_SET:
  1440.             /*
  1441.      * Optional command to set the hardware options (as defined
  1442.      * in sioLib.h).
  1443.      * Return OK, or ENOSYS if this command is not implemented.
  1444.      * Note: several hardware options are specified at once.
  1445.      * This routine should set as many as it can and then return
  1446.      * OK. The SIO_HW_OPTS_GET is used to find out which options
  1447.      * were actually set.
  1448.      */
  1449.     USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, "Ioctl : SET_HW_OPTS request n",
  1450.          0, 0, 0, 0, 0, 0);
  1451.             return  usbAcmHwOptsSet (pSioChan, arg);
  1452.         case USB_ACM_SIO_HW_OPTIONS_GET:
  1453.             
  1454.             /*
  1455.      * Optional command to get the hardware options (as defined
  1456.      * in sioLib.h). Return OK or ENOSYS if this command is not
  1457.      * implemented.  Note: if this command is unimplemented, it
  1458.      * will be assumed that the driver options are CREAD | CS8
  1459.      * (e.g., eight data bits, one stop bit, no parity, ints enabled).
  1460.      */
  1461.     USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, "Ioctl : GET_HW_OPTS request n",
  1462.          0, 0, 0, 0, 0, 0);
  1463.             *(UINT *) arg = pSioChan->options;
  1464.             return OK;
  1465.         case USB_ACM_SIO_HUP:
  1466.             /* 
  1467.              * As mentioned before, hang-up is achieved by sending an AT 
  1468.              * command. 
  1469.              */
  1470.     USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, "Ioctl : hangUp request n",
  1471.          0, 0, 0, 0, 0, 0);
  1472.             return ENOSYS;
  1473.         case USB_ACM_SIO_FEATURE_SET:
  1474. return ENOSYS;
  1475.         case USB_ACM_SIO_FEATURE_GET:
  1476. return ENOSYS;
  1477.         case USB_ACM_SIO_FEATURE_CLEAR:
  1478. return ENOSYS;
  1479.         case USB_ACM_SIO_LINE_CODING_SET:
  1480.             /*
  1481.              * The USB way of setting line parameters 
  1482.              */
  1483.             if (usbAcmCtrlCmdSend (pSioChan, 
  1484.    USB_ACM_REQ_LINE_CODING_SET, 
  1485.    (UINT8 *)(arg), 
  1486.    sizeof(pSioChan->lineCode)) 
  1487.   == ERROR)
  1488.                 {
  1489.                 return ERROR;
  1490.                 }
  1491.             pSioChan->lineCode =  *(LINE_CODE *)arg;
  1492.             return OK;
  1493.         case USB_ACM_SIO_LINE_CODING_GET:
  1494.             /*
  1495.              * USB way of retreving parameters 
  1496.              */
  1497.             memcpy ((UINT8 *)arg, 
  1498.     (UINT8 *) &pSioChan->lineCode, 
  1499.     sizeof (pSioChan->lineCode));
  1500.         case USB_ACM_SIO_CTRL_LINE_STATE_SET:   
  1501. return ENOSYS;
  1502.         case USB_ACM_SIO_SEND_BREAK:   
  1503. return ENOSYS;
  1504.         case USB_ACM_SIO_MAX_BUF_SIZE_GET:
  1505.             *(UINT *)arg = pSioChan->outBfrLen;
  1506.             return OK;
  1507.         default:
  1508.     USB_ACM_LOG (USB_ACM_DEBUG_IOCTL, 
  1509.                          "Ioctl : 0x%0x UnKnown request n",
  1510.                   request, 0, 0, 0, 0, 0);
  1511.             return ENOSYS;
  1512.         }
  1513.         return OK;
  1514.     }
  1515. /***************************************************************************
  1516. *
  1517. * usbAcmOpen - Start the Modem communications.
  1518. *
  1519. * RETURNS: OK on success, or ERROR if listening fails
  1520. */
  1521. LOCAL STATUS usbAcmOpen
  1522.     (
  1523.     SIO_CHAN * pChan  /* pointer to channel */
  1524.     )
  1525.     {
  1526.     
  1527.     pUSB_ACM_SIO_CHAN pSioChan = (pUSB_ACM_SIO_CHAN)pChan;
  1528.     if (pSioChan == NULL)
  1529.         return ERROR;
  1530.     /* Start listening for normal data */
  1531.     if (listenForInput(pSioChan) == ERROR)
  1532.         {
  1533.         USB_ACM_LOG (USB_ACM_DEBUG_OPEN, "listenForInput() Failed....",
  1534.             0, 0, 0, 0, 0, 0);
  1535.         return ERROR;
  1536.         }
  1537.     return OK;
  1538.     }
  1539. /***************************************************************************
  1540. *
  1541. * usbAcmTxStartup - start the transmition.
  1542. *
  1543. * This function uses the initiateOutput for the transmission.
  1544. *
  1545. * RETURNS: OK on success, or EIO if output initiation fails
  1546. *
  1547. * NOMANUAL
  1548. */
  1549. int usbAcmTxStartup
  1550.     (
  1551.     SIO_CHAN * pChan                 /* channel to start */
  1552.     )
  1553.     {
  1554.     pUSB_ACM_SIO_CHAN pSioChan = (pUSB_ACM_SIO_CHAN)pChan;
  1555.     int status = OK;
  1556.     if (initiateOutput (pSioChan) != OK)
  1557. {
  1558. logMsg("InitiateOutput failed n",0,0,0,0,0,0);
  1559. status = EIO;
  1560. }
  1561.     return status;
  1562.     }
  1563. /***************************************************************************
  1564. *
  1565. * usbAcmPollOutput - output a character in polled mode
  1566. *
  1567. * The USB modem driver supports only interrupt-mode operation.  Therefore,
  1568. * this function always returns the error ENOSYS.
  1569. *
  1570. * RETURNS: ENOSYS
  1571. */
  1572. LOCAL int usbAcmPollOutput
  1573.     (
  1574.     SIO_CHAN *pChan,
  1575.     char outChar
  1576.     )
  1577.     {
  1578.     return ENOSYS;
  1579.     }
  1580. /***************************************************************************
  1581. *
  1582. * usbAcmPollInput - poll the device for input
  1583. *
  1584. * The USB modem driver supports only interrupt-mode operation.  Therefore,
  1585. * this function always returns the error ENOSYS.
  1586. *
  1587. * RETURNS: ENOSYS
  1588. */
  1589. LOCAL int usbAcmPollInput
  1590.     (
  1591.     SIO_CHAN *pChan,
  1592.     char *thisChar
  1593.     )
  1594.     {
  1595.     return ENOSYS;
  1596.     }