📄 usbspeakerlib.c
字号:
* Unlinks the indicated USB_SPKR_SEQ_DEV structure and de-allocates* resources associated with the device.** RETURNS: N/A*/LOCAL VOID destroySeqDev ( pUSB_SPKR_SEQ_DEV pSeqDev ) { /* Unlink the structure. */ usbListUnlink (&pSeqDev->devLink); /* Release audio stream-related info */ destroyAudioStream (pSeqDev, TRUE); /* Release per-channel data */ if (pSeqDev->pCaps != NULL) OSS_FREE (pSeqDev->pCaps); /* Release audio format data */ if (pSeqDev->pFmt != NULL) OSS_FREE (pSeqDev->pFmt); /* Release structure. */ OSS_FREE (pSeqDev); }/***************************************************************************** createSeqDev - creates a new USB_SPKR_SEQ_DEV structure** Creates a new USB_SPKR_SEQ_DEV structure for the indicated <nodeId>.* If successful, the new structure is linked into the devList upon * return.** <configuration> and <interface> identify the configuration/interface* that first reported itself as an audio device.** RETURNS: pointer to newly created structure, or NULL if failure*/LOCAL pUSB_SPKR_SEQ_DEV createSeqDev ( USBD_NODE_ID nodeId, UINT16 configuration, UINT16 interface ) { pUSB_SPKR_SEQ_DEV pSeqDev; /* Try to allocate space for a new speaker struct */ if ((pSeqDev = OSS_CALLOC (sizeof (*pSeqDev))) == NULL) return NULL; pSeqDev->seqDev.sd_seqRd = usbSpkrSeqRd; pSeqDev->seqDev.sd_seqWrt = usbSpkrSeqWrt; pSeqDev->seqDev.sd_ioctl = usbSpkrIoctl; pSeqDev->seqDev.sd_seqWrtFileMarks = usbSpkrSeqWrtFileMarks; pSeqDev->seqDev.sd_rewind = usbSpkrRewind; pSeqDev->seqDev.sd_reserve = usbSpkrReserve; pSeqDev->seqDev.sd_release = usbSpkrRelease; pSeqDev->seqDev.sd_readBlkLim = usbSpkrReadBlkLim; pSeqDev->seqDev.sd_load = usbSpkrLoad; pSeqDev->seqDev.sd_space = usbSpkrSpace; pSeqDev->seqDev.sd_erase = usbSpkrErase; pSeqDev->seqDev.sd_reset = NULL; pSeqDev->seqDev.sd_statusChk = NULL; pSeqDev->seqDev.sd_blkSize = 0; pSeqDev->seqDev.sd_mode = O_WRONLY; pSeqDev->seqDev.sd_readyChanged = TRUE; pSeqDev->seqDev.sd_maxVarBlockLimit = A_REALLY_BIG_INTEGER; pSeqDev->seqDev.sd_density = 0; pSeqDev->nodeId = nodeId; pSeqDev->configuration = configuration; pSeqDev->connected = TRUE; /* Try to configure the speaker. */ if (configureSeqDev (pSeqDev) != OK) { destroySeqDev (pSeqDev); return NULL; } /* Link the newly created structure. */ usbListLink (&devList, pSeqDev, &pSeqDev->devLink, LINK_TAIL); return pSeqDev; }/***************************************************************************** findSeqDev - Searches for a USB_SPKR_SEQ_DEV for indicated node ID** RETURNS: pointer to matching USB_SPKR_SEQ_DEV or NULL if not found*/LOCAL pUSB_SPKR_SEQ_DEV findSeqDev ( USBD_NODE_ID nodeId ) { pUSB_SPKR_SEQ_DEV pSeqDev = usbListFirst (&devList); while (pSeqDev != NULL) { if (pSeqDev->nodeId == nodeId) break; pSeqDev = usbListNext (&pSeqDev->devLink); } return pSeqDev; }/***************************************************************************** notifyAttach - Notifies registered callers of attachment/removal** RETURNS: N/A*/LOCAL VOID notifyAttach ( pUSB_SPKR_SEQ_DEV pSeqDev, UINT16 attachCode ) { pATTACH_REQUEST pRequest = usbListFirst (&reqList); while (pRequest != NULL) { (*pRequest->callback) (pRequest->callbackArg, (SEQ_DEV *) pSeqDev, attachCode); pRequest = usbListNext (&pRequest->reqLink); } }/***************************************************************************** usbSpeakerAttachCallback - called by USBD when speaker attached/removed** The USBD will invoke this callback when a USB audio device 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.* Audio devices report their class information at the interface level, so * <configuration> and <interface> will indicate the configuratin/interface that * reports itself as an audio device. Finally, <deviceClass>, <deviceSubClass>,* and <deviceProtocol> will identify the type of audio device (eg. a speaker).** NOTE: The USBD will invoke this function once for each configuration/* interface which reports itself as an audio device. 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. We also ignore* audio devices that are not speakers (eg., we ignore microphones and other* input audio devices).** RETURNS: N/A*/LOCAL VOID usbSpeakerAttachCallback ( USBD_NODE_ID nodeId, UINT16 attachAction, UINT16 configuration, UINT16 interface, UINT16 deviceClass, UINT16 deviceSubClass, UINT16 deviceProtocol ) { pUSB_SPKR_SEQ_DEV pSeqDev; OSS_MUTEX_TAKE (speakerMutex, OSS_BLOCK); /* Depending on the attach code, add a new speaker or disabled 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 (findSeqDev (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 ((pSeqDev = createSeqDev (nodeId, configuration, interface)) == NULL) break; /* Notify registered callers that a new speaker has been * added and a new channel created. */ notifyAttach (pSeqDev, USB_SPKR_ATTACH); break; case USBD_DYNA_REMOVE: /* A device is being detached. Check if we have any * structures to manage this device. */ if ((pSeqDev = findSeqDev (nodeId)) == NULL) break; /* The device has been disconnected. */ pSeqDev->connected = FALSE; /* Notify registered callers that the speaker has been * removed and the channel disabled. * * NOTE: We temporarily increment the channel's lock count * to prevent usbSpeakerSeqDevUnlock() from destroying the * structure while we're still using it. */ pSeqDev->lockCount++; notifyAttach (pSeqDev, USB_SPKR_REMOVE); pSeqDev->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 usbSpeakerUnlock(). */ if (pSeqDev->lockCount == 0) destroySeqDev (pSeqDev); break; } OSS_MUTEX_RELEASE (speakerMutex); }/***************************************************************************** doShutdown - shuts down USB speaker SIO driver** <errCode> should be OK or S_usbSpeakerLib_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_SPKR_SEQ_DEV pSeqDev; /* Dispose of any outstanding notification requests */ while ((pRequest = usbListFirst (&reqList)) != NULL) destroyAttachRequest (pRequest); /* Dispose of any open speaker connections. */ while ((pSeqDev = usbListFirst (&devList)) != NULL) destroySeqDev (pSeqDev); /* 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 (speakerMutex != NULL) { OSS_MUTEX_DESTROY (speakerMutex); speakerMutex = NULL; } return ossStatus (errCode); }/***************************************************************************** usbSpeakerDevInit - initialize USB speaker SIO driver** Initializes the USB speaker SIO driver. The USB speaker SIO driver* maintains an initialization count, so calls to this function may be* nested.** RETURNS: OK, or ERROR if unable to initialize.** ERRNO:** S_usbSpeakerLib_OUT_OF_RESOURCES* S_usbSpeakerLib_USBD_FAULT*/STATUS usbSpeakerDevInit (void) { /* If not already initialized, then initialize internal structures * and connection to USBD. */ if (initCount == 0) { /* Initialize lists, structures, resources. */ memset (&devList, 0, sizeof (devList)); memset (&reqList, 0, sizeof (reqList)); speakerMutex = NULL; usbdHandle = NULL; if (OSS_MUTEX_CREATE (&speakerMutex) != OK) return doShutdown (S_usbSpeakerLib_OUT_OF_RESOURCES); /* Establish connection to USBD */ if (usbdClientRegister (SPKR_CLIENT_NAME, &usbdHandle) != OK || usbdDynamicAttachRegister (usbdHandle, USB_CLASS_AUDIO, USBD_NOTIFY_ALL, USBD_NOTIFY_ALL, usbSpeakerAttachCallback) != OK) { return doShutdown (S_usbSpeakerLib_USBD_FAULT); } } initCount++; return OK; }/***************************************************************************** usbSpeakerDevShutdown - shuts down speaker SIO driver** RETURNS: OK, or ERROR if unable to shutdown.** ERRNO:* S_usbSpeakerLib_NOT_INITIALIZED*/STATUS usbSpeakerDevShutdown (void) { /* Shut down the USB speaker SIO driver if the initCount goes to 0. */ if (initCount == 0) return ossStatus (S_usbSpeakerLib_NOT_INITIALIZED); if (--initCount == 0) return doShutdown (OK); return OK; }/***************************************************************************** usbSpeakerDynamicAttachRegister - Register speaker attach callback** <callback> is a caller-supplied function of the form:** .CS* typedef (*USB_SPKR_ATTACH_CALLBACK) * (* pVOID arg,* SEQ_DEV *pSeqDev,* UINT16 attachCode* );* .CE** usbSpeakerLib will invoke <callback> each time a USB speaker* 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 * SEQ_DEV structure for the channel being created/destroyed and* an attach code of USB_SPKR_ATTACH or USB_SPKR_REMOVE.** RETURNS: OK, or ERROR if unable to register callback** ERRNO:* S_usbSpeakerLib_BAD_PARAM* S_usbSpeakerLib_OUT_OF_MEMORY*/STATUS usbSpeakerDynamicAttachRegister ( USB_SPKR_ATTACH_CALLBACK callback, /* new callback to be registered */ pVOID arg /* user-defined arg to callback */ ) { pATTACH_REQUEST pRequest; pUSB_SPKR_SEQ_DEV pSeqDev; int status = OK; /* Validate parameters */ if (callback == NULL) return ossStatus (S_usbSpeakerLib_BAD_PARAM); OSS_MUTEX_TAKE (speakerMutex, OSS_BLOCK); /* Create a new request structure to track this callback request. */ if ((pRequest = OSS_CALLOC (sizeof (*pRequest))) == NULL) status = S_usbSpeakerLib_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 * speaker devices. */ pSeqDev = usbListFirst (&devList); while (pSeqDev != NULL) { if (pSeqDev->connected) (*callback) (arg, (SEQ_DEV *) pSeqDev, USB_SPKR_ATTACH); pSeqDev = usbListNext (&pSeqDev->devLink); } } OSS_MUTEX_RELEASE (speakerMutex); return ossStatus (status); }/***************************************************************************** usbSpeakerDynamicAttachUnregister - Unregisters speaker attach callback** This function cancels a previous request to be dynamically notified for* speaker attachment and removal. The <callback> and <arg> paramters must* exactly match those passed in a previous call to * usbSpeakerDynamicAttachRegister().** RETURNS: OK, or ERROR if unable to unregister callback** ERRNO:* S_usbSpeakerLib_NOT_REGISTERED*/STATUS usbSpeakerDynamicAttachUnRegister ( USB_SPKR_ATTACH_CALLBACK callback, /* callback to be unregistered */ pVOID arg /* user-defined arg to callback */ ) { pATTACH_REQUEST pRequest; int status = S_usbSpeakerLib_NOT_REGISTERED; OSS_MUTEX_TAKE (speakerMutex, OSS_BLOCK); pRequest = usbListFirst (&reqList); while (pRequest != NULL) { if (callback == pRequest->callback && arg == pReq
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -