⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbspeakerlib.c

📁 T2.0 USB driver.rar T2.0 USB driver.rar
💻 C
📖 第 1 页 / 共 5 页
字号:
/* usbSpeakerLib.c - USB speaker class drive with vxWorks SEQ_DEV interface *//* Copyright 2000-2001 Wind River Systems, Inc. *//*modification history--------------------01e,08aug01,dat  Removing warnings01d,31jan01,wef  Fixed tab stops01c,12apr00,wef  Fixed uninitialized variable warning: controlSelector and		 settingWidth in setChannelControl()01b,20mar00,rcb  Re-write code which de-references potentiall non-aligned word 		 fields to prevent faults on certain processors (e.g., MIPS).01a,12jan00,rcb  written.*//*DESCRIPTIONThis module implements the class driver for USB speaker devices.  USB speakersare a subset of the USB audio class, and this module handles only those partsof the USB audio class definition which are relevant to the operation of USBspeakers.  This module presents a modified VxWorks SEQ_DEV interface to its callers.  TheSEQ_DEV interface was chosen because, of the existing VxWorks driver models, itbest supports the streaming data transfer model required by isochronous devicessuch as USB speakers.  As with other VxWorks USB class drivers, the standarddriver interface has been expanded to support features unique to the USB and tospeakers in general.  Functions have been added to allow callers to recognizethe dynamic attachment and removal of speaker devices.	IOCTL functions have been added to retrieve and control additional settings related to speakeroperation.INITIALIZATIONAs with standard SEQ_DEV drivers, this driver must be initialized by callingusbSpeakerDevInit().  usbSpeakerDevInit() in turn initializes its connection to the USBD and other internal resources needed for operation.	Unlike some SEQ_DEV drivers, there are no usbSpeakerLib.c data structures which need to be initialized prior to calling usbSpeakerDevInit().Prior to calling usbSpeakerDevInit(), the caller must ensure that the USBDhas been properly initialized by calling - at a minimum - usbdInitialize().It is also the caller's responsibility to ensure that at least one USB HCD(USB Host Controller Driver) is attached to the USBD - using the USBD functionusbdHcdAttach() - before speaker operation can begin.  However, it is not necessary for usbdHcdAttach() to be alled prior to initializating usbSpeakerLib.usbSpeakerLib.c uses the USBD dynamic attach services and is capable of recognizing USB speaker attachment and removal on the fly.  Therefore, it is possible for USB HCDs to be attached to or detached from the USBD at run time- as may be required, for example, in systems supporting hot swapping ofhardware.RECOGNIZING & HANDLING USB SPEAKERSAs noted earlier, the operation of USB speakers is defined in the USB Audio ClassSpecification.	Speakers, loosely defined, are those USB audio devices whichprovide an "Output Terminal".  For each USB audio device, usbSpeakerLib examinesthe descriptors which enumerate the "units" and "terminals" contained within thedevice.  These descriptors define both which kinds of units/terminals are presentand how they are connected.  If an "Output Terminal" is found, usbSpeakerLib traces the device's internalconnections to determine which "Input Terminal" ultiminately provides the audiostream for the "Output Terminal" and which, if any, Feature Unit is responsiblefor controlling audio stream attributes like volume.  Once having built such aninternal "map" of the device, usbSpeakerLib configures the device and waits fora caller to provide a stream of audio data.  If no "Output Terminal" is found,usbSpeakerLib ignores the audio device.After determining that the audio device contains an Output Terminal, usbSpeakerLib builds a list of the audio formats supported by the device. usbSpeakerLib supports only AudioStreaming interfaces (no MidiStreaming is supported).  For each USB speaker attached to the system and properly recognized by usbSpeakerLib, usbSpeakerLib creates a SEQ_DEV structure to control the speaker.Each speaker is uniquely identified by the pointer to its corresponding SEQ_DEVstructure.DYNAMIC ATTACHMENT & REMOVAL OF SPEAKERSAs with other USB devices, USB speakers may be attached to or detached from thesystem dynamically.  usbSpeakerLib uses the USBD's dynamic attach services in order to recognize these events.  Callers of usbSpeakerLib may, in turn, registerwith usbSpeakerLib for notification when USB speakers are attached or removedusing the usbSpeakerDynamicAttachRegister() function.  When a USB speaker isattached or removed, usbSpeakerLib invokes the attach notification callbacks for all registered callers.  The callback is passed the pointer to the affectedSEQ_DEV structure and a code indicated whether the speaker is being attached orremoved.usbSpeakerLib maintains a usage count for each SEQ_DEV structure.  Callers can increment the usage count by calling usbSpeakSeqDevLock() and can decrement the usage count by calling usbSpeakerSeqDevUnlock().  When a USB speaker is removedfrom the system and its usage count is 0, usbSpeakerLib automatically removes all data structures, including the SEQ_DEV structure itself, allocated on behalfof the device.	Sometimes, however, callers rely on these data structures and must properly recognize the removal of the device before it is safe to destroy the underlying data structures.  The lock/unlock functions provide a mechanismfor callers to protect these data structures as needed.DATA FLOWBefore sending audio data to a speaker device, the caller must specify the dataformat (e.g., PCM, MPEG) using an IOCTL (see below).  The USB speaker itselfmust support the indicated (or a similar) data format.USB speakers rely on an uninterrupted, time-critical stream of audio data.  Thedata is sent to the speaker through an isochronous pipe.  In order for the dataflow to continue uninterrupted, usbSpeakerLib internally uses a double-bufferingscheme.  When data is presented to usbSpeakerLib's sd_seqWrt() function by the caller, usbSpeakerLib copies the data into an internal buffer and immediately releases the caller's buffer.  The caller should immediately try to pass the next buffer to usbSpeakerLib.  When usbSpeakerLib's internal buffer is filled, it will block the caller until such time as it can accept the new data.  In this manner,the caller and usbSpeakerLib work together to ensure that an adequate supply ofaudio data will always be available to continue isochronous transmission uninterrupted.Audio play begins after usbSpeakerLib has accepted half a second of audio dataor when the caller closes the audio stream, whichever happens first.  The callermust use the IOCTLs to "open" and "close" each audio stream.  usbSpeakerLibrelies on these IOCTLs to manage its internal buffers correctly.IOCTLsusbSpeakerLib implements a number of IOCTLs unique to the handling of audiodata and devices.  usbSpeakerLib provides IOCTLs to set the following controls:mute, volume, bass, mid-range, and treble.  usbSpeakerLib also provides IOCTLsto be used by callers to interrogate a speaker's audio format capabilities or to specify the audio format for a subsequent data stream.INCLUDE FILES:seqIo.h usbAudio.h usbSpeakerLib.h*//* includes */#include "vxWorks.h"#include "string.h"#include "ioLib.h"#include "seqIo.h"#include "errno.h"#include "usb/usbPlatform.h"#include "usb/ossLib.h" 	/* operations system srvcs */#include "usb/usb.h"		/* general USB definitions */#include "usb/usbListLib.h"	/* linked list functions */#include "usb/usbdLib.h"	/* USBD interface */#include "usb/usbLib.h" 	/* USB utility functions */#include "usb/usbAudio.h"	/* USB audio class definitions */#include "drv/usb/usbSpeakerLib.h"  /* our API *//* defines */#define SPKR_CLIENT_NAME	"usbSpeakerLib" /* our USBD client name */#define A_REALLY_BIG_INTEGER	0x7fffffff  /* large positive integer */#define MSEC_PER_SEC		1000L	/* number of msec per second */#define FRAME_SKIP		20	/* frames to skip before play */					/* (makes sure h/w doesn't run 					 * ahead of us) 					 */#define IRP_COUNT	2		/* number of IRPs for transmit *//* typedefs *//* ATTACH_REQUEST */typedef struct attach_request    {    LINK reqLink;			/* linked list of requests */    USB_SPKR_ATTACH_CALLBACK callback;	/* client callback routine */    pVOID callbackArg;			/* client callback argument */    } ATTACH_REQUEST, *pATTACH_REQUEST;/* USB_SPKR_SEQ_DEV is the internal data structure we use to track each USB * speaker. */typedef struct usb_spkr_seq_dev    {    SEQ_DEV seqDev;		/* must be first field */    BOOL reserved;		/* TRUE if device reserved */    LINK devLink;		/* linked list of structs */    UINT16 lockCount;		/* Count of times structure locked */    USBD_NODE_ID nodeId;	/* speaker node Id */    UINT16 configuration;	/* configuration/interface reported as */    BOOL connected;		/* TRUE if speaker currently connected */    UINT8 outputTerminalId;	/* ID of output terminal */    UINT8 inputTerminalId;	/* ID of input terminal */    UINT8 featureUnitId;	/* ID of feature unit (optional) */    UINT8 channels;		/* count of channels */    UINT16 channelConfig;	/* channel configuration */    UINT16 capsLen;		/* size of following array */    pUSB_SPKR_CHANNEL_CAPS pCaps;   /* Indicates feature support on each				     * channel...channel 0 is the "master"				     * and is global to all 				     */    UINT16 fmtCount;		/* count of audio formats */    pUSB_SPKR_AUDIO_FORMAT pFmt;    /* indicates nature of each format */    pUSB_SPKR_AUDIO_FORMAT pSelFmt; /* pointer to selected format */    UINT32 sampleFrequency;	/* playback frequency */    UINT32 sampleSize;		/* data always sent in blocks which are 				 * multiples of this value 				 */    UINT32 bytesPerSec; 	/* playback bytes per second */    BOOL open;			/* TRUE when audio stream is open */    BOOL streamFault;		/* TRUE if stream fault detected */    pUINT8 pAudioBfr;		/* bfr for audio data */    UINT32 audioBfrLen; 	/* size of audio buffer */    UINT32 audioBfrHalf;	/* one half the length of the buffer */    UINT32 audioBfrCount;	/* count of data available */    UINT32 audioBfrIn;		/* next location to receive data */    UINT32 audioBfrOut; 	/* next location to transmit */    UINT32 audioBfrPending;	/* nbr of bytes being transmitted */    UINT32 audioBfrTotal;	/* total data passed through bfr */    BOOL foregroundWaiting;	/* TRUE if foreground waiting for bfr */    SEM_HANDLE bfrNotFullSem;	/* signalled when bfr goes from 				 * full->not full 				 */    USBD_PIPE_HANDLE isochPipeHandle; /* USBD handle for isoch data pipe */    UINT32 frameWindow; 	/* size of host controller frame ctr */    UINT32 nextStartFrame;	/* next frame for isoch transfer */    UINT32 blocksSent;		/* blocks sent for this stream */    USB_IRP irp [IRP_COUNT];	/* IRPs to be used for transmit */    UINT16 nextIrp;		/* index of next IRP to use */    UINT16 nextDoneIrp; 	/* index of next IRP to complete */    UINT16 irpsInUse;		/* count of IRPs in use */    } USB_SPKR_SEQ_DEV, *pUSB_SPKR_SEQ_DEV;/* forward function declarations */LOCAL VOID usbSpkrIrpCallback     (    pVOID p    );/* locals */LOCAL UINT16 initCount = 0;	/* Count of init nesting */LOCAL MUTEX_HANDLE speakerMutex;	/* mutex used to protect 					 * internal structs 					 */LOCAL LIST_HEAD devList;	/* linked list of USB_SPKR_SEQ_DEV */LOCAL LIST_HEAD reqList;	/* Attach callback request list */LOCAL USBD_CLIENT_HANDLE usbdHandle;	/* our USBD client handle *//***************************************************************************** audioIfGetRequest - executes an audio-class-specific request** Executes a request to an AudioControl or AudioStreaming interface.* The actual length of data transferred must be equal to the <length> passed* by the caller or an ERROR is returned.** RETURNS: OK, else ERROR if not successful*/LOCAL STATUS audioIfRequest    (    pUSB_SPKR_SEQ_DEV pSeqDev,    UINT8 requestType,    UINT8 request,    UINT8 entityId,    UINT16 value,    UINT16 length,    pVOID pBfr    )        {    UINT16 actLen;    if (usbdVendorSpecific (usbdHandle, 			    pSeqDev->nodeId, 			    requestType,			    request, 			    value, 			    entityId << 8, 			    length, 			    (pUINT8) pBfr, 			    &actLen) 			  != OK 	|| actLen != length)	{	return ERROR;	}    return OK;    }/***************************************************************************** findAudioByUnit - seaches a buffer for the indicated audio descriptor** RETURNS: ptr to a matching descriptor or NULL if not found*/LOCAL pVOID findAudioDescrByUnit    (    pUINT8 pBfr,    UINT16 bfrLen,    UINT8 unitId    )    {    pUSB_AUDIO_AC_COMMON pHdr;    /* The remaining buffer length must be at least three bytes to accommodate     * the USB_AUDIO_AC_COMMON structure.      */    while (bfrLen >= sizeof (*pHdr))	{	pHdr = (pUSB_AUDIO_AC_COMMON) pBfr;	if (pHdr->length == 0)	    return NULL;	/* must be invalid */	pBfr += min (pHdr->length, bfrLen);	bfrLen -= min (pHdr->length, bfrLen);	if (pHdr->descriptorType == USB_DESCR_AUDIO_INTERFACE &&				    pHdr->unitId == unitId)	    return (pVOID) pHdr;	}    return NULL;    }/***************************************************************************** findAudioDescrSkip - seaches a buffer for the indicated audio descriptor** Upon return, <ppBfr> points to the descriptor following the last searhed* descriptor and <pBfrLen> is updated with the number of bytes remaining in * the bfr.** RETURNS: ptr to a matching descriptor or NULL if not found*/LOCAL pVOID findAudioDescrSkip    (    pUINT8 *ppBfr,    pUINT16 pBfrLen,    UINT8 descriptorType,    UINT8 descriptorSubType    )    {    pUSB_DESCR_HDR_SUBHDR pHdr;    /* The remaining buffer length must be at least three bytes to accommodate     * the descriptor length, descriptorType, and descriptorSubType fields.      */    while (*pBfrLen >= sizeof (*pHdr))	{	pHdr = (pUSB_DESCR_HDR_SUBHDR) *ppBfr;	if (pHdr->length == 0)	    return NULL;	/* must be invalid */	*ppBfr += min (pHdr->length, *pBfrLen);	*pBfrLen -= min (pHdr->length, *pBfrLen);	if (pHdr->descriptorType == descriptorType &&	    pHdr->descriptorSubType == descriptorSubType)	    return (pVOID) pHdr;	}    return NULL;    }/***************************************************************************** findAudioDescr - seaches a buffer for the indicated audio descriptor** RETURNS: ptr to a matching descriptor or NULL if not found*/LOCAL pVOID findAudioDescr    (    pUINT8 pBfr,    UINT16 bfrLen,    UINT8 descriptorType,    UINT8 descriptorSubType    )    {    return findAudioDescrSkip (&pBfr, 			       &bfrLen, 			       descriptorType, 			       descriptorSubType);    }/***************************************************************************** setChannelControl - Sets the specified channel control** <funcCode> is the IOCTL code specifying the control to set.  <channel>* is the channel number (channel 0 = master channel).  <value> is the* new setting value.** RETURNS: OK if successful, ENOSYS if not supported, else EIO if failure*/LOCAL STATUS setChannelControl    (    pUSB_SPKR_SEQ_DEV pSeqDev,    int funcCode,    UINT16 channel,    UINT16 value    )    {    pUSB_SPKR_CHANNEL_CAPS pChannelCaps;    pUSB_SPKR_CTL_CAPS pCtlCaps = NULL;    UINT8 controlSelector = NULL;    UINT8 settingWidth = NULL;    UINT16 setting;    /* validate channel number.  0 = master channel.  1..n = other channels. */    if (channel > pSeqDev->channels)	return EIO;    pChannelCaps = &pSeqDev->pCaps [channel];    /* Check the capabilities of the control */    switch (funcCode)	{	case USB_SPKR_IOCTL_SET_MUTE:   	    pCtlCaps = NULL;	    controlSelector = USB_AUDIO_FCS_VOLUME;	    settingWidth = USB_AUDIO_MUTE_ATTR_WIDTH;	    break;	case USB_SPKR_IOCTL_SET_VOLUME: 	    pCtlCaps = &pChannelCaps->volume;	    controlSelector = USB_AUDIO_FCS_VOLUME;	    settingWidth = USB_AUDIO_VOLUME_ATTR_WIDTH;	    break;	case USB_SPKR_IOCTL_SET_BASS:	    pCtlCaps = &pChannelCaps->bass;	    controlSelector = USB_AUDIO_FCS_BASS;	    settingWidth = USB_AUDIO_BASS_ATTR_WIDTH;	    break;	case USB_SPKR_IOCTL_SET_MID:	    pCtlCaps = &pChannelCaps->mid;	    controlSelector = USB_AUDIO_FCS_MID;	    settingWidth = USB_AUDIO_MID_ATTR_WIDTH;	    break;	case USB_SPKR_IOCTL_SET_TREBLE: 	    	    pCtlCaps = &pChannelCaps->treble;	    controlSelector = USB_AUDIO_FCS_TREBLE;	    settingWidth = USB_AUDIO_TREBLE_ATTR_WIDTH;	    break;	}    if (pCtlCaps != NULL)	{	if (!pCtlCaps->supported)	    return ENOSYS;	if (((INT16) value) < pCtlCaps->min || ((INT16) value) > pCtlCaps->max)	    return EIO;	}    /* Set the control */    setting = TO_LITTLEW (value);    if (audioIfRequest (pSeqDev,			USB_RT_HOST_TO_DEV | USB_RT_CLASS | USB_RT_INTERFACE,			USB_REQ_AUDIO_SET_CUR, 			pSeqDev->featureUnitId, 			controlSelector << 8 | channel, 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -