📄 usbloopbacklib.c
字号:
* notifyAttach - Notifies registered callers of attachment/removal** RETURNS: N/A*/LOCAL VOID notifyAttach ( pUSB_LOOPBACK_DEVICE pLoopbackDev, UINT16 attachCode ) { pATTACH_REQUEST pRequest = usbListFirst (&reqList); while (pRequest != NULL) { (*pRequest->callback) (pRequest->callbackArg, (USB_LOOPBACK_CHAN *) pLoopbackDev, attachCode); pRequest = usbListNext (&pRequest->reqLink); } }/***************************************************************************** usbLoopbackAttachCallback - called by USBD when Loopback attached/removed** The USBD will invoke this callback when a USB Loopback 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.* Our loopback device reports class information device level,* <deviceClass> and <deviceSubClass> will match the class/subclass for * which we registered.** RETURNS: N/A*/LOCAL VOID usbLoopbackAttachCallback ( USBD_NODE_ID nodeId, UINT16 attachAction, UINT16 configuration, UINT16 interface, UINT16 deviceClass, UINT16 deviceSubClass, UINT16 deviceProtocol ) { pUSB_LOOPBACK_DEVICE pLoopbackDev; OSS_MUTEX_TAKE (loopbackMutex, OSS_BLOCK); /* Depending on the attach code, add a new Loopback or disable 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 (findLoopbackDevice (nodeId) != NULL) break; /* 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 ((pLoopbackDev = createLoopbackDevice (nodeId, configuration, interface, deviceProtocol)) == NULL) break; /* Notify registered callers that a new Loopback has been * added and a new channel created. */ notifyAttach (pLoopbackDev, USB_LOOPBACK_ATTACH); break; case USBD_DYNA_REMOVE: /* A device is being detached. Check if we have any * structures to manage this device. */ if ((pLoopbackDev = findLoopbackDevice (nodeId)) == NULL) break; /* The device has been disconnected. */ pLoopbackDev->connected = FALSE; /* Notify registered callers that the Loopback has been * removed and the channel disabled. * * NOTE: We temporarily increment the channel's lock count * to prevent usbLoopbackChanUnlock() from destroying the * structure while we're still using it. */ pLoopbackDev->lockCount++; notifyAttach (pLoopbackDev, USB_LOOPBACK_REMOVE); pLoopbackDev->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 usbLoopbackUnlock(). */ if (pLoopbackDev->lockCount == 0) destroyLoopbackDevice (pLoopbackDev); break; } OSS_MUTEX_RELEASE (loopbackMutex); }/***************************************************************************** doShutdown - shuts down USB Loopback driver** <errCode> should be OK or S_usbLoopbackLib_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; pUSB_LOOPBACK_DEVICE pLoopbackDev; /* Dispose of any outstanding notification requests */ while ((pRequest = usbListFirst (&reqList)) != NULL) destroyAttachRequest (pRequest); /* Dispose of any open Loopback connections. */ while ((pLoopbackDev = usbListFirst (&loopbackList)) != NULL) destroyLoopbackDevice (pLoopbackDev); /* 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 (loopbackMutex != NULL) { OSS_MUTEX_DESTROY (loopbackMutex); loopbackMutex = NULL; } return ossStatus (errCode); }/***************************************************************************** usbLoopbackIoctl - special device control** usbLoopbackLib supports the following IOCTLs:** TODO: Stuff the function as required* RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed* request.*/LOCAL int usbLoopbackIoctl ( USB_LOOPBACK_CHAN *pChan, /* device to control */ int request, /* request code */ void *someArg /* some argument */ ){ pUSB_LOOPBACK_DEVICE pLoopbackDev = (pUSB_LOOPBACK_DEVICE) pChan; int arg = (int) someArg; switch (request) { case USB_LOOPBACK_STAT_GET: if (arg == 0) return EIO; /* Return modes supported by driver. */ memcpy( (UINT8 *)arg,(UINT8 *)&(pLoopbackDev->deviceStat),sizeof(pLoopbackDev->deviceStat)); return OK; case USB_LOOPBACK_PROTOCOL_GET: if (arg == 0) return EIO; /* Return loopback stats of the device */ *((int *) arg) = pLoopbackDev->protocol; return OK; default: /* unknown/unsupported command. */ return ENOSYS; }}/***************************************************************************** usbLoopbackDevInit - initialize USB Loopback driver** Initializes the USB Loopback driver. The USB Loopback driver* maintains an initialization count, so calls to this function may be* nested.** RETURNS: OK, or ERROR if unable to initialize.** ERRNO:** S_usbLoopbackLib_OUT_OF_RESOURCES* S_usbLoopbackLib_USBD_FAULT*/STATUS usbLoopbackDevInit (void) { /* If not already initialized, then initialize internal structures * and connection to USBD. */ if (initCount == 0) { /* Initialize lists, structures, resources. */ memset (&loopbackList, 0, sizeof (loopbackList)); memset (&reqList, 0, sizeof (reqList)); loopbackMutex = NULL; usbdHandle = NULL; if (OSS_MUTEX_CREATE (&loopbackMutex) != OK) return doShutdown (S_usbLoopbackLib_OUT_OF_RESOURCES); /* Establish connection to USBD */ if (usbdClientRegister (USB_LOOPBACK_CLIENT_NAME, &usbdHandle) != OK || usbdDynamicAttachRegister (usbdHandle, USB_CLASS_LOOPBACK, USB_SUBCLASS_LOOPBACK, USBD_NOTIFY_ALL, usbLoopbackAttachCallback) != OK) { return doShutdown (S_usbLoopbackLib_USBD_FAULT); } } initCount++; return OK; }/***************************************************************************** usbLoopbackDevShutdown - shuts down Loopback driver** RETURNS: OK, or ERROR if unable to shutdown.** ERRNO:* S_usbLoopbackLib_NOT_INITIALIZED*/STATUS usbLoopbackDevShutdown (void) { /* Shut down the USB Loopback driver if the initCount goes to 0. */ if (initCount == 0) return ossStatus (S_usbLoopbackLib_NOT_INITIALIZED); if (--initCount == 0) return doShutdown (OK); return OK; }/***************************************************************************** usbLoopbackDynamicAttachRegister - Register Loopback attach callback** <callback> is a caller-supplied function of the form:** .CS* typedef (*USB_LOOPBACK_ATTACH_CALLBACK)* (* pVOID arg,* USB_LOOPBACK_CHAN *pChan,* UINT16 attachCode* );* .CE** usbLoopbackLib will invoke <callback> each time a USB Loopback* is attached to or removed from the system. <arg> is a caller-defined* parameter which will be passed to the <callback> each time it is* invoked. The <callback> will also be passed a pointer to the* USB_LOOPBACK_CHAN structure for the channel being created/destroyed and* an attach code of USB_PRN_ATTACH or USB_PRN_REMOVE.** RETURNS: OK, or ERROR if unable to register callback** ERRNO:* S_usbLoopbackLib_BAD_PARAM* S_usbLoopbackLib_OUT_OF_MEMORY*/STATUS usbLoopbackDynamicAttachRegister ( USB_LOOPBACK_ATTACH_CALLBACK callback, /* new callback to be registered */ pVOID arg /* user-defined arg to callback */ ) { pATTACH_REQUEST pRequest; pUSB_LOOPBACK_DEVICE pLoopbackDev; int status = OK; /* Validate parameters */ if (callback == NULL) return ossStatus (S_usbLoopbackLib_BAD_PARAM); OSS_MUTEX_TAKE (loopbackMutex, OSS_BLOCK); /* Create a new request structure to track this callback request. */ if ((pRequest = OSS_CALLOC (sizeof (*pRequest))) == NULL) status = S_usbLoopbackLib_OUT_OF_MEMORY; else { pRequest->callback = callback; pRequest->callbackArg = arg; usbListLink (&reqList, pRequest, &pRequest->reqLink, LINK_TAIL); /* Perform an initial notification of all currrently attached * Loopback devices. */ pLoopbackDev = usbListFirst (&loopbackList); while (pLoopbackDev != NULL) { if (pLoopbackDev->connected) (*callback) (arg, (USB_LOOPBACK_CHAN *) pLoopbackDev, USB_LOOPBACK_ATTACH); pLoopbackDev = usbListNext (&pLoopbackDev->loopbackLink); } } OSS_MUTEX_RELEASE (loopbackMutex); return ossStatus (status); }/***************************************************************************** usbLoopbackDynamicAttachUnregister - Unregisters Loopback attach callback** This function cancels a previous request to be dynamically notified for* Loopback attachment and removal. The <callback> and <arg> paramters must* exactly match those passed in a previous call to* usbLoopbackDynamicAttachRegister().** RETURNS: OK, or ERROR if unable to unregister callback** ERRNO:* S_usbLoopbackLib_NOT_REGISTERED*/STATUS usbLoopbackDynamicAttachUnRegister ( USB_LOOPBACK_ATTACH_CALLBACK callback, /* callback to be unregistered */ pVOID arg /* user-defined arg to callback */ ) { pATTACH_REQUEST pRequest; int status = S_usbLoopbackLib_NOT_REGISTERED; OSS_MUTEX_TAKE (loopbackMutex, OSS_BLOCK); pRequest = usbListFirst (&reqList); while (pRequest != NULL) { if (callback == pRequest->callback && arg == pRequest->callbackArg) { /* We found a matching notification request. */ destroyAttachRequest (pRequest); status = OK; break; } pRequest = usbListNext (&pRequest->reqLink); } OSS_MUTEX_RELEASE (loopbackMutex); return ossStatus (status); }/***************************************************************************** usbLoopbackChanLock - Marks USB_LOOPBACK_CHAN structure as in use** A caller uses usbLoopbackChanLock() to notify usbLoopbackLib that* it is using the indicated USB_LOOPBACK_CHAN structure. usbLoopbackLib maintains* a count of callers using a particular USB_LOOPBACK_CHAN structure so that it* knows when it is safe to dispose of a structure when the underlying* USB Loopback is removed from the system. So long as the "lock count"* is greater than zero, usbLoopbackLib will not dispose of an USB_LOOPBACK_CHAN* structure.** RETURNS: OK, or ERROR if unable to mark USB_LOOPBACK_CHAN structure in use.*/STATUS usbLoopbackChanLock ( USB_LOOPBACK_CHAN *pChan /* USB_LOOPBACK_CHAN to be marked as in use */ ) { pUSB_LOOPBACK_DEVICE pLoopbackDev = (pUSB_LOOPBACK_DEVICE) pChan; pLoopbackDev->lockCount++; return OK; }/***************************************************************************** usbLoopbackChanUnlock - Marks USB_LOOPBACK_CHAN structure as unused** This function releases a lock placed on an USB_LOOPBACK_CHAN structure. When a* caller no longer needs an USB_LOOPBACK_CHAN structure for which it has previously* called usbLoopbackChanLock(), then it should call this function to* release the lock.** NOTE: If the underlying USB Loopback device has already been removed* from the system, then this function will automatically dispose of the* USB_LOOPBACK_CHAN structure if this call removes the last lock on the structure.* Therefore, a caller must not reference the USB_LOOPBACK_CHAN again structure after* making this call.** RETURNS: OK, or ERROR if unable to mark USB_LOOPBACK_CHAN structure unused** ERRNO:* S_usbLoopbackLib_NOT_LOCKED*/STATUS usbLoopbackChanUnlock ( USB_LOOPBACK_CHAN *pChan /* USB_LOOPBACK_CHAN to be marked as unused */ ) { pUSB_LOOPBACK_DEVICE pLoopbackDev = (pUSB_LOOPBACK_DEVICE) pChan; int status = OK; OSS_MUTEX_TAKE (loopbackMutex, OSS_BLOCK); if (pLoopbackDev->lockCount == 0) status = S_usbLoopbackLib_NOT_LOCKED; else { /* If this is the last lock and the underlying USB Loopback is * no longer connected, then dispose of the Loopback. */ if (--pLoopbackDev->lockCount == 0 && !pLoopbackDev->connected) destroyLoopbackDevice (pLoopbackDev); } OSS_MUTEX_RELEASE (loopbackMutex); return ossStatus (status); }/* end of file. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -