📄 usbacmlib.c
字号:
* RETURNS: pointer to newly created structure, or NULL if failure*/LOCAL pUSB_ACM_SIO_CHAN createSioChan ( USBD_NODE_ID nodeId, UINT16 configuration, UINT16 interface, UINT16 deviceProtocol ) { pUSB_ACM_SIO_CHAN pSioChan; /* Try to allocate space for a new modem struct and its buffers */ if ((pSioChan = OSS_CALLOC (sizeof (*pSioChan))) == NULL ) { USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "Out of Memory \n", 0, 0, 0, 0, 0, 0); return NULL; } if((pSioChan->outBfr = OSS_MALLOC (ACM_OUT_BFR_SIZE)) == NULL) { destroySioChan (pSioChan); USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "Out of Memory \n", 0, 0, 0, 0, 0, 0); return NULL; } if ((pSioChan->inBfr = OSS_MALLOC (ACM_IN_BFR_SIZE)) == NULL) { destroySioChan (pSioChan); USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "Out of Memory \n", 0, 0, 0, 0, 0, 0); return NULL; } pSioChan->sioChan.pDrvFuncs = &usbAcmSioDrvFuncs; pSioChan->nodeId = nodeId; pSioChan->mode = SIO_MODE_INT; pSioChan->connected = TRUE; pSioChan->callbackStatus = 0x0; /* No callbacks installed */ /* Configure the Modem. */ if (configureSioChan (pSioChan, configuration, interface) != OK) { destroySioChan (pSioChan); return NULL; } /* Link the newly created structure. */ usbListLink (&sioList, pSioChan, &pSioChan->sioLink, LINK_TAIL); USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "SIOCHAN created \n", 0, 0, 0, 0, 0, 0); return pSioChan; }/***************************************************************************** findSioChan - Searches for a USB_ACM_SIO_CHAN for indicated node ID** RETURNS: pointer to matching USB_ACM_SIO_CHAN or NULL if not found*/LOCAL pUSB_ACM_SIO_CHAN findSioChan ( USBD_NODE_ID nodeId ) { pUSB_ACM_SIO_CHAN pSioChan = usbListFirst (&sioList); while (pSioChan != NULL) { if (pSioChan->nodeId == nodeId) break; pSioChan = usbListNext (&pSioChan->sioLink); } return pSioChan; }/***************************************************************************** usbAcmAttachCallback - called by USBD when a modem is attached/removed** The USBD will invoke this callback when a USB modem is attached to or* removed from the system. <nodeId> is the USBD_NODE_ID of the node being* attached or removed. <attachAction> is USBD_DYNA_ATTACH or USBD_DYNA_REMOVE.* modems report their class information at the interface level,* so <configuration> and <interface> will indicate the configuratin/interface* that reports itself as a modem. <deviceClass> and <deviceSubClass> * will match the class/subclass for which we registered. <deviceProtocol>* shall be USB_COMM_PROTOCOL_COMMONAT.** NOTE: The USBD will invoke this function once for each configuration/* interface which reports itself as a modem. So, it is possible that* a single device insertion/removal may trigger multiple callbacks. We* ignore all callbacks except the first for a given device.** RETURNS: N/A*/LOCAL VOID usbAcmAttachCallback ( USBD_NODE_ID nodeId, UINT16 attachAction, UINT16 configuration, UINT16 interface, UINT16 deviceClass, UINT16 deviceSubClass, UINT16 deviceProtocol ) { pUSB_ACM_SIO_CHAN pSioChan; OSS_MUTEX_TAKE (acmMutex, OSS_BLOCK); /* * Depending on the attach code, add a new modem or remove one * that's already been created. */ switch (attachAction) { case USBD_DYNA_ATTACH: /* * A new device is being attached. Check if we already * have a structure for this device. */ if (findSioChan (nodeId) != NULL) break; USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "New ACM device found \n", 0, 0, 0, 0, 0, 0); /* * Create a new structure to manage this device. If there's * an error, there's nothing we can do about it, so skip the * device and return immediately. */ if ((pSioChan = createSioChan (nodeId, configuration, interface, deviceProtocol)) == NULL) { USB_ACM_LOG (USB_ACM_DEBUG_ATTACH, "Could not create \ SIO_CHAN \n", 0, 0, 0, 0, 0, 0); break; } /* * Notify registered callers that a new modem has been * added and a new channel created. */ notifyAttach (pSioChan, USB_ACM_CALLBACK_ATTACH); usbAcmOpen ((SIO_CHAN *)pSioChan); break; case USBD_DYNA_REMOVE: /* * A device is being detached. Check if we have any * structures to manage this device. */ if ((pSioChan = findSioChan (nodeId)) == NULL) break; /* The device has been disconnected. */ pSioChan->connected = FALSE; /* * Notify registered callers that the modem has been * removed and the channel disabled. * * NOTE: We temporarily increment the channel's lock count * to prevent usbAcmSioChanUnlock() from destroying the * structure while we're still using it. */ pSioChan->lockCount++; notifyAttach (pSioChan, USB_ACM_CALLBACK_DETACH); pSioChan->lockCount--; /* * If no callers have the channel structure locked, destroy * it now. If it is locked, it will be destroyed later during * a call to usbAcmUnlock(). */ if (pSioChan->lockCount == 0) destroySioChan (pSioChan); break; } OSS_MUTEX_RELEASE (acmMutex); }/***************************************************************************** destroyAttachRequest - disposes of an ATTACH_REQUEST structure** RETURNS: N/A* NOMANUAL*/LOCAL VOID destroyAttachRequest ( pATTACH_REQUEST pRequest ) { /* Unlink request */ usbListUnlink (&pRequest->reqLink); /* Dispose of structure */ OSS_FREE (pRequest); }/***************************************************************************** destroySioChan - disposes of a USB_PRN_ACM_CHAN structure** Unlinks the indicated USB_ACM_SIO_CHAN structure and de-allocates* resources associated with the channel.** RETURNS: N/A*/LOCAL VOID destroySioChan ( pUSB_ACM_SIO_CHAN pSioChan ) { if (pSioChan != NULL) { /* Unlink the structure. */ usbListUnlink (&pSioChan->sioLink); /* Release pipes and wait for IRPs to be cancelled if necessary. */ if (pSioChan->outPipeHandle != NULL) usbdPipeDestroy (usbdHandle, pSioChan->outPipeHandle); if (pSioChan->inPipeHandle != NULL) usbdPipeDestroy (usbdHandle, pSioChan->inPipeHandle); if (pSioChan->intrPipeHandle != NULL) usbdPipeDestroy (usbdHandle, pSioChan->intrPipeHandle); while (pSioChan->outIrpInUse || pSioChan->inIrpInUse || pSioChan->intrIrpInUse) { OSS_THREAD_SLEEP (1); } /* release buffers */ if (pSioChan->outBfr != NULL) OSS_FREE (pSioChan->outBfr); if (pSioChan->inBfr != NULL) OSS_FREE (pSioChan->inBfr); /* Release structure. */ OSS_FREE (pSioChan); } } /***************************************************************************** doShutdown - shuts down USB ACM SIO driver** <errCode> should be OK or S_usbAcmLib_xxxx. This value will be* passed to ossStatus() and the return value from ossStatus() is the* return value of this function.** RETURNS: OK, or ERROR per value of <errCode> passed by caller*/LOCAL STATUS doShutdown ( int errCode ) { pATTACH_REQUEST pRequest; USB_ACM_SIO_CHAN * pSioChan; /* Dispose of any outstanding notification requests */ while ((pRequest = usbListFirst (&reqList)) != NULL) destroyAttachRequest (pRequest); /* Dispose of any open connections. */ while ((pSioChan = usbListFirst (&sioList)) != NULL) destroySioChan (pSioChan); /* * Release our connection to the USBD. The USBD automatically * releases any outstanding dynamic attach requests when a client * unregisters. */ if (usbdHandle != NULL) { usbdClientUnregister (usbdHandle); usbdHandle = NULL; } /* Release resources. */ if (acmMutex != NULL) { OSS_MUTEX_DESTROY (acmMutex); acmMutex = NULL; } if (acmIrpSem != NULL) { OSS_SEM_DESTROY (acmIrpSem); acmIrpSem = NULL; } return ossStatus (errCode); }/**************************************************************************** usbAcmLibInit - initialize USB ACM SIO driver.** Initializes the USB ACM SIO driver. The USB acm SIO driver* maintains an initialization count, so calls to this function may be* nested. This function will regsiter the driver as a client for the USBD. It* also registers itself for a notification (by usbd) when a ACM device* is dynamically attached / removed from the USB.** RETURNS: OK, or ERROR if unable to initialize.** ERRNO:** S_usbAcmLib_OUT_OF_RESOURCES* S_usbAcmLib_USBD_FAULT*/STATUS usbAcmLibInit (void) { /* * If not already initialized, then initialize internal structures * and connection to USBD. */ initCount++; if (initCount > 1) return OK; /* Initialize lists, structures, resources. */ memset (&sioList, 0, sizeof (sioList)); memset (&reqList, 0, sizeof (reqList)); acmMutex = NULL; usbdHandle = NULL; acmIrpSem = NULL; if (OSS_MUTEX_CREATE (&acmMutex) != OK) return doShutdown (S_usbAcmLib_OUT_OF_RESOURCES); if (OSS_SEM_CREATE (1, 0 , &acmIrpSem) != OK) return (doShutdown (S_usbAcmLib_OUT_OF_RESOURCES)); /* Establish connection to USBD */ if (usbdClientRegister (ACM_CLIENT_NAME, &usbdHandle) != OK || usbdDynamicAttachRegister (usbdHandle, USB_CLASS_COMMDEVICE, USB_SUBCLASS_ACM, USB_COMM_PROTOCOL_COMMONAT, usbAcmAttachCallback) != OK) { return doShutdown (S_usbAcmLib_USBD_FAULT); } return OK; }/**************************************************************************** usbAcmCallbackRegister - Installs a callback for an event.** This function installs a callback for a <callbackType> event. If the event* occurs, the client will be notified via the installed <callback> function.* <arg> is a client specific argument, used as a parameter to the <callback>* routine.** The macro USB_ACM_CALLBACK defines a callback routine which will be invoked* by usbAcmLib when any of these events happen, provided that the user* registered a callback for such an event. This macro is compatible with the* SIO TxCallback and RxCallback definitions and provides additional * functionality for registering for attachment/removal.* * Note that all these fields are not required for all of the events.* They will be filled with NULL or ZERO (0) when the callback is executed.*** .CS* * typedef STATUS (*USB_ACM_CALLBACK) ( pVOID arg, /@ caller-defined argument @/ SIO_CHAN * pChan, /@ pointer to affected SIO_CHAN @/ UINT16 callbackType, /@ defined as USB_ACM_CALLBACK_xxxx @/ UINT8 * pBuf, /@ pointer to data buffer, if any data @/ /@ transfer is involved. Otherwise NULL @/ UINT16 count /@ No of bytes of data transferred @/ /@ if a data transfer is involved. @/ /@ 0 otherwise. @/ );** .CE** Note that the <pChan> paramter shall be NULL for the Dynamic attachment* notification requests, indicating that the event is not for any particular* device.** Care should be taken not to install multiple callbacks for the same event* for the same <pChan>. How-ever this is not applicable for the dynamic * attachment event notification requests.** Different <callbackType> events suppoted by this driver are** .IP "USB_ACM_CALLBACK_ATTACH"* Used to get notified of dynamic attachment / removal of usb modems. * .IP "USB_ACM_CALLBACK_SIO_TX"* Used for transmitting characters. This is equivalent to SIO_CALLBACK_GET_TX_CHAR.* .IP "USB_ACM_CALLBACK_SIO_RX"* Used for receiving characters. This is equivalent to SIO_CALLBACK_PUT_RCV_CHAR.** RETURNS: OK, or ERROR if unable to install.** ERRNO : S_usbAcmLib_OUT_OF_MEMORY, S_usbAcmLib_BAD_PARAM**/int usbAcmCallbackRegister ( SIO_CHAN * pChan, /* Channel for the callback */ int callbackType, /* Callback type. see above */ FUNCPTR callback, /* the callback routine */ pVOID arg /* User defined argument */ ) { pUSB_ACM_SIO_CHAN pSioChan = (pUSB_ACM_SIO_CHAN)pChan; pATTACH_REQUEST pRequest; int status = OK; if (callback == NULL) { return ossStatus (S_usbAcmLib_BAD_PARAM); } if ((callbackType != USB_ACM_CALLBACK_ATTACH) && (callbackType != USB_ACM_CALLBACK_DETACH)) { if (pSioChan == NULL) { return ossStatus (S_usbAcmLib_BAD_PARAM); } } switch (callbackType) { case USB_ACM_CALLBACK_ATTACH : case USB_ACM_CALLBACK_DETACH : /* Client wants to get notified of attachment/removal of modems */ /* Create a new request structure to track this callback request */ OSS_MUTEX_TAKE (acmMutex, OSS_BLOCK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -