📄 audioclass.c
字号:
/*----------------------------------------------------------------------------------
*
* COPYRIGHT (c) 2001 by Singing Electrons, Inc. All rights reserved.
*
* Module Name : C:\se\adi\hidclass\Source\HidClass.c
*
* Description : The HID Class implementation - contains routines that implment the HID Class device
*
*
* Revision History : At bottom of the file.
*
*---------------------------------------------------------------------------------*/
/** include files **/
#include <sys/exception.h>
#include <sys/excause.h>
//#include <def21535.h>
#include <defBF535.h>
#include "dtype.h"
#include "usb.h"
#include "usbdriver.h"
#include "audioclass.h"
#include "ac97.h"
#include "dprintf.h"
/** local definitions **/
#define PROVIDE_FEEDBACK 1
/* default settings */
#define CONTROL_PIPE_MAX_TRANSFER_LENGTH 32
#define INTERFACE_FOR_AUDIOCONTROL 0
#define ALTSETTING_FOR_AUDIOCONTROL 0
#define INTERFACE_FOR_AUDIOSTREAMING 1
#define ALTSETTING_FOR_AUDIOSTREAMING_IDLE 0
#define ALTSETTING_FOR_AUDIOSTREAMING_48K 1
#define PLAYBACK_EP 0x01
#define PLAYBACK_FEEDBACK_EP 0x82
#define TERMID_USBOUT 0x01
#define UNITID_OUTVOLUME 0x02
#define TERMID_LINEOUT 0x03
#define PLAYBACK_DELAY 3 //milliseconds
//ToDo: These need to be changed based on the codec used
#define OUTVOLUME_MIN 0xa180 //-94.5dB
#define OUTVOLUME_MAX 0x0000 //0 dB
#define OUTVOLUME_RES 0x0180 //1.5 dB
#define NUM_CHANNELS 2
#define CHANNELCONFIG 0x0003 //left and right
#define SAMPLINGRATE 48000
//To create a 24bit audio device change
//the following two values to 24, and also
//change the code that takes data from the buffer
#define BIT_DEPTH 16
#define CONTAINER_SIZE 16
#if PROVIDE_FEEDBACK
#define FEEDBACK_RANGE 1000 //samples per second
#else
#define FEEDBACK_RANGE 0 //samples per second
#endif
#define MAX_PACKET_SIZE (((SAMPLINGRATE + FEEDBACK_RANGE) * NUM_CHANNELS * (CONTAINER_SIZE / 8)) / 1000)
#define FEEDBACK_PACKET_SIZE 3
//#define NUM_PACKETS_TO_BUFFER 7
//#define MAX_DATA_BUFFER_SIZE (MAX_PACKET_SIZE * NUM_PACKETS_TO_BUFFER)
//0000110000.0000000000 = 48.0 (48 + 0/1024) (bcd 10.10 format)
//000011000000000000000000 = 48.0 (48 + 0/1024) = 0c0000
#define FEEDBACK_FREQUENCY_NORMAL 0x0c0000
//0000110000.1000000000 = 48.5 (48 + 512/1024)
//000011000010000000000000 = 48.5 (48 + 512/1024) = 0c2000
//#define FEEDBACK_FREQUENCY_PLEASE_HURRY 0x0c2000
#define FEEDBACK_FREQUENCY_PLEASE_HURRY 0x0c4000 //49K
//0000101111.1000000000 = 47.5 (47 + 512/1024)
//000010111110000000000000 = 47.5 (47 + 512/1024) = 0be000
//#define FEEDBACK_FREQUENCY_PLEASE_SLOWDOWN 0x0be000
#define FEEDBACK_FREQUENCY_PLEASE_SLOWDOWN 0x0bc000 //47K
#include "descriptors.h"
/** external functions **/
/** external data **/
/** internal functions **/
/** public data **/
bool gIsPlaybackActive;
/** private data **/
static PSUSPENDPROC gpOnSuspend;
static PRESUMEPROC gpOnResume;
static PRESETPROC gpOnReset;
static UCHAR gOutMute;
static USHORT gOutLeftVol;
static USHORT gOutRightVol;
static UINT gFeedbackData;
static USHORT gEnablePlaybackCountdown;
static UINT gRegChangesRequested, gRegChangesImplemented;
static UINT gTimeoutCount;
//static UINT gDataBufferHead;
//static UINT gDataBufferTail;
//static UCHAR gDataBuffer[MAX_DATA_BUFFER_SIZE];
static UINT gDebugNumTransfers;
static UINT gDebugTotalTransferLength;
/** public functions **/
/** private functions **/
bool AudioGetRequest (UCHAR bRequest, UCHAR wIndexHi, USHORT wValue, USHORT wLength, PUINT pNumBytesToTransfer, UCHAR *buffer);
bool AudioSetRequest (UCHAR bRequest, UCHAR wIndexHi, USHORT wValue, USHORT wLength, UCHAR *buffer);
/** callback functions **/
static bool OnSetupRequest (UCHAR endpointNumber, PUSB_SETUP_DATA pSetupData, void *buffer,
PUINT pNumBytesToTransfer);
static bool OnGetDeviceDescriptor (void *buffer, PUINT pNumBytesToTransfer);
static bool OnGetConfigDescriptor (void *buffer, PUINT pNumBytesToTransfer);
static bool OnGetStringDescriptor (UCHAR stringIndex, USHORT langID, void *buffer, PUINT pNumBytesToTransfer);
static void OnInTransferComplete (UCHAR endpointNumber);
static bool OnOutTransferComplete (UCHAR endpointNumber, void *buffer, UINT numBytesReceived, bool wasPCAsserted);
static void OnNAKSent (UCHAR endpointNumber);
static bool OnConfigRequest (UCHAR newConfiguration, UCHAR newInterface, UCHAR newAltSetting);
static void OnSuspend (void);
static void OnResume (void);
static void OnReset (void);
static void OnSOF (void);
/*------------------------------------------------------------
* HIDCLASS_Init
*
* Parameters:
*
* Globals Used:
* gpOnResume, gpOnReset, gUseINEP, gpTheReportDescriptor, gTheReportDescriptorSize
* gTheDeviceDescriptor, gTheConfigDescriptor
*
* Description:
* This is the main initialization routine. The client provides the vendor id, device id,
* revision, and a bunch of pointers to routines to be calleld under various conditions.
*
* Returns:
* true on success, false on failure.
*
*------------------------------------------------------------*/
bool AUDIOCLASS_Init (uint16 vid, uint16 pid, uint16 rel, PSUSPENDPROC pOnSuspendProc,
PRESUMEPROC pOnResumeProc, PRESETPROC pOnResetProc)
{
if (!AC97_Init())
return false;
//Initialize the state variables
gOutMute = 0;
gOutLeftVol = OUTVOLUME_MAX;
gOutRightVol = OUTVOLUME_MAX;
gIsPlaybackActive = false;
gEnablePlaybackCountdown = 0;
//gDataBufferHead = gDataBufferTail = 0;
//memset (&gDataBuffer, 0, sizeof (gDataBuffer));
gDebugNumTransfers = 0;
gDebugTotalTransferLength = 0;
gFeedbackData = FEEDBACK_FREQUENCY_NORMAL;
//Save the callback addresses
gpOnSuspend = pOnSuspendProc;
gpOnResume = pOnResumeProc;
gpOnReset = pOnResetProc;
gRegChangesRequested = gRegChangesImplemented = 0;
//Update the VID and PID
memcpy (&gTheDeviceDescriptor[OFFSET_VENDOR_ID], &vid, sizeof (uint16));
memcpy (&gTheDeviceDescriptor[OFFSET_PRODUCT_ID], &pid, sizeof (uint16));
memcpy (&gTheDeviceDescriptor[OFFSET_RELEASE], &rel, sizeof (uint16));
//Things to do before setting up endpoints
if (!USBDriver_PreInit ())
return false;
USBDriver_SetupEndpoint (EP1, ALTSETTING_FOR_AUDIOSTREAMING_IDLE,
INTERFACE_FOR_AUDIOSTREAMING, EP_CONFIG1, EP_OUT,
EP_ISO, 0);
USBDriver_SetupEndpoint (EP1, ALTSETTING_FOR_AUDIOSTREAMING_48K,
INTERFACE_FOR_AUDIOSTREAMING, EP_CONFIG1, EP_OUT,
EP_ISO, MAX_PACKET_SIZE);
#if PROVIDE_FEEDBACK
USBDriver_SetupEndpoint (EP2, ALTSETTING_FOR_AUDIOSTREAMING_48K,
INTERFACE_FOR_AUDIOSTREAMING, EP_CONFIG1, EP_IN,
EP_ISO, FEEDBACK_PACKET_SIZE);
#endif //PROVIDE_FEEDBACK
return USBDriver_CompleteInit (OnSetupRequest, OnGetDeviceDescriptor,
OnGetConfigDescriptor, OnGetStringDescriptor,
OnInTransferComplete, OnOutTransferComplete, OnNAKSent,
OnSuspend, OnResume, OnReset, OnConfigRequest, OnSOF, CONTROL_PIPE_MAX_TRANSFER_LENGTH);
}
/*------------------------------------------------------------
* AUDIOCLASS_DoForegroundTasks
*
* Parameters: None
*
* Globals Used:
* gRegChangesImplemented, gRegChangesRequested
*
* Description:
* This routine essentially does the time consuming task
* of talking to the AC97 codec when requested for volume
* and mute controls. This way the ISR does not have to
* waste a lot of time.
*
* Returns:
* Nothing
*
*------------------------------------------------------------*/
void AUDIOCLASS_DoForegroundTasks (void)
{
if (gRegChangesRequested != gRegChangesImplemented)
{
AC97_SetVolumeAndMute (gOutLeftVol, gOutRightVol, gOutMute);
gRegChangesImplemented++;
}
}
/*------------------------------------------------------------
* OnSetupRequest
*
* Parameters:
* endpointNumber - the endpoint on which this request was received
* pSetupData - points to a structure cantaining the SETUP DATA(0)
* buffer - points to a buffer where the setup data is available, or should be placed.
* pNumBytesToTransfer - points to a location where the number of bytes
* to be sent back should be stored.
* Globals Used:
* None
*
* Description:
* This routine is called by the USB driver to handle a special setup request,
* that is not a GET DEVICE, GET CONFIG, or GET STRING descriptor
*
* Based on the request type, this routine reads/writes to the buffer
* provided.
*
* Returns:
* true to succeed the request, false to stall the request
*
*------------------------------------------------------------*/
bool OnSetupRequest (UCHAR endpointNumber, PUSB_SETUP_DATA pSetupData, void *buffer,
PUINT pNumBytesToTransfer)
{
bool retVal = false; //stall
bool validRequest = false;
//Need to handle the requests used to change the various controls
if (endpointNumber == EP0)
{
if ((USB_CONTROL_REQUEST_GET_TYPE (pSetupData->bmRequestType) == USB_CONTROL_REQUEST_TYPE_CLASS) &&
(USB_CONTROL_REQUEST_GET_RECIPIENT (pSetupData->bmRequestType) == USB_CONTROL_REQUEST_TYPE_INTERFACE) &&
(LOBYTE (pSetupData->wIndex) == INTERFACE_FOR_AUDIOCONTROL))
{
validRequest = true;
if (USB_CONTROL_REQUEST_GET_DIRECTION(pSetupData->bmRequestType) == USB_CONTROL_REQUEST_TYPE_OUT)
retVal = AudioSetRequest (pSetupData->bRequest, HIBYTE(pSetupData->wIndex), pSetupData->wValue, pSetupData->wLength, buffer);
else
retVal = AudioGetRequest (pSetupData->bRequest, HIBYTE(pSetupData->wIndex), pSetupData->wValue, pSetupData->wLength, pNumBytesToTransfer, buffer);
}
}
if (!validRequest)
{
Dprintf1 ("Unknown setup request: %02x", pSetupData->bmRequestType);
Dprintf3 ("Dir = %02x, Type = %02x, Rec = %02x", USB_CONTROL_REQUEST_GET_DIRECTION (pSetupData->bmRequestType),
USB_CONTROL_REQUEST_GET_TYPE (pSetupData->bmRequestType),
USB_CONTROL_REQUEST_GET_RECIPIENT (pSetupData->bmRequestType));
Dprintf1 ("bRequest = %02x", pSetupData->bRequest);
}
return (retVal);
}
/*------------------------------------------------------------
* AudioGetRequest
*
* Parameters:
* bRequest - the request.
* wIndexHi - the high byte of wIndex
* wValue - as it comes in the setup packet
* wLength - as it comes in the setup packet.
* pNumBytesToTransfer - pointer to a location which receives the number of bytes to be transferred.
* buffer - pointer to a buffer where the result data is to be stored.
*
* Globals Used:
* gOutMute, gOutLeftVol, gOutRightVol
*
* Description:
* This handles the Audio Class Get Requests
*
* Returns:
* true on success, false on failure (to stall the EP).
*
*------------------------------------------------------------*/
bool AudioGetRequest (UCHAR bRequest, UCHAR wIndexHi, USHORT wValue, USHORT wLength, PUINT pNumBytesToTransfer, UCHAR *buffer)
{
bool retVal = false;
switch (bRequest)
{
case GET_CUR:
switch (wIndexHi)
{
case UNITID_OUTVOLUME:
switch (HIBYTE(wValue))
{
case USB_AUDIO_CONTROL_SELECTOR_MUTE_CONTROL:
if (LOBYTE(wValue) == 0)
{
buffer[0] = gOutMute;
*pNumBytesToTransfer = sizeof (UCHAR);
retVal = true;
}
break;
case USB_AUDIO_CONTROL_SELECTOR_VOLUME_CONTROL:
switch (LOBYTE(wValue))
{
case 0:
buffer[0] = LOBYTE ((gOutLeftVol + gOutRightVol) >> 1);
buffer[1] = HIBYTE ((gOutLeftVol + gOutRightVol) >> 1);
*pNumBytesToTransfer = sizeof (USHORT);
retVal = true;
break;
case 1:
buffer[0] = LOBYTE (gOutLeftVol);
buffer[1] = HIBYTE (gOutLeftVol);
*pNumBytesToTransfer = sizeof (USHORT);
retVal = true;
break;
case 2:
buffer[0] = LOBYTE (gOutRightVol);
buffer[1] = HIBYTE (gOutRightVol);
*pNumBytesToTransfer = sizeof (USHORT);
retVal = true;
break;
case 0xff:
buffer[0] = LOBYTE ((gOutLeftVol + gOutRightVol) >> 1);
buffer[1] = HIBYTE ((gOutLeftVol + gOutRightVol) >> 1);
buffer[2] = LOBYTE (gOutLeftVol);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -