📄 a2dp_sd_interface_usb.c
字号:
/****************************************************************************
Copyright (C) Cambridge Silicon Radio Ltd. 2004-2006
Part of BlueLab 3.5.2-release
FILE NAME
a2dp_sd_interface_usb.c
DESCRIPTION
USB support code
NOTES
*/
/****************************************************************************
Header files
*/
#include "a2dp_sd_private.h"
#include "a2dp_sd_interface.h"
#include <boot.h>
#include <usb.h>
#include <panic.h>
#include <sink.h>
#include <source.h>
#include <string.h>
#include <stdlib.h>
#define USB_TERMINAL_ID (1)
#define OUTPUT_TERMINAL_ID (2)
#define SAMPLE_RATE ((uint32) 48000)
/* HID descriptor */
#define HID_DESCRIPTOR_LENGTH (9)
#define HID_DESCRIPTOR (0x21)
#define HID_REPORT_DESCRIPTOR (0x22)
#define HID_REPORT_DESCRIPTOR_LENGTH (44)
/* USB Audio class defines */
#define SET_CUR (0x01)
#define GET_CUR (0x81)
#define SAMPLING_FREQ_CONTROL (0x01)
static UsbInterface ac, as, hid;
static UsbCodes codes_ac = {0x01, 0x01, 0x00};
static UsbCodes codes_as = {0x01, 0x02, 0x00};
static UsbCodes codes_hid = {0x03, 0x00, 0x00};
static void audio_control_handler(Task task, MessageId id, Message message);
static void audio_streaming_handler(Task task, MessageId id, Message message);
static void handleAudioControlClassRequest(Source req);
static void handleAudioStreamingClassRequest(Source req);
static void handleHIDClassRequest(Source req, const a2dpSourceDongleTaskData *theApp);
/*
USB Audio Descriptors
Our descriptors declare the dongle as a pair of Headphones
that supports 16bit Stereo PCM playback at 48khz.
Terminal Architecture
=====================
USB Streaming -> Headphones
TerminalID 1 TerminalID 2
USB Streaming:
Two channel 16bit PCM input: Left and Right.
Format of PCM stream:
| Left LSB | Left MSB | Right LSB | Right MSB |
Headphones:
Physical representation of the device output.
Does not contain actual functionality.
*/
/* Audio Control Class Descriptor */
static const uint8 ac_class_descriptor[] =
{
0x09, /* bLength */
0x24, /* bDescriptorType */
0x01, /* bDescriptorSubType */
0x00, /* bcdADC */
0x01, /* */
0x09 + 0x0c + 0x09, /* wTotal */
0x00, /* */
0x01, /* bInCollection */
0x01, /* baInterfaceNr(1) */
0x0c, /* bLength */
0x24, /* bDescriptorType = CS_INTERFACE */
0x02, /* bDescriptorSubType = INPUT_TERMINAL */
USB_TERMINAL_ID, /* bTerminalID */
0x01, /* wTerminalType = USB streaming */
0x01, /* */
0x00, /* bAssocTerminal = no */
0x02, /* bNrChannels = 2 */
0x03, /* wChannelConfig = left and right */
0x00, /* */
0x00, /* iChannelName = no string */
0x02, /* iTerminal = same as USB product string */
0x09, /* bLength */
0x24, /* bDescriptorType = CS_INTERFACE */
0x03, /* bDescriptorSubType = OUTPUT_TERMINAL */
OUTPUT_TERMINAL_ID, /* bTerminalID */
0x02, /* wTerminalType = headphones */
0x03, /* */
0x00, /* bAssocTerminal = no */
USB_TERMINAL_ID, /* bSourceID */
0x02, /* iTerminal = same as USB product string */
};
/* Audio Streaming Class Descriptor */
static const uint8 as_class_descriptor[] =
{
/*CS GENERAL STREAM DESCRIPTOR: */
/* BYTE Length: */0x07,
/* BYTE DescriptorType: */0x24,
/* BYTE DescriptorSubType: */0x01,
/* BYTE bTerminalLink: */0x01,
/* BYTE bDelay: */0x00,
/* SHORT wFormatTag: */0x01,
0x00,
/*CS FORMAT TYPE DESCRIPTOR: */
/* BYTE Length: */0x0b,
/* BYTE DescriptorType: */0x24,
/* BYTE DescriptorSubType: */0x02,
/* BYTE bFormatType: */0x01,
/* BYTE bNumberOfChannels: */0x02,
/* BYTE bSubframeSize: */0x02,
/* BYTE bBitsResolution: */0x10,
/* BYTE bSampleFreqType: */0x01,
/* 3BYTE SampleRate */ SAMPLE_RATE & 0xff,
(SAMPLE_RATE >> 8) & 0xff,
(SAMPLE_RATE >> 16) & 0xff, /*lint !e572 !e778 */
/* CS AUDIO ENDPOINT DESCRIPTOR: */
/* BYTE Length: */0x07,
/* BYTE DescriptorType: */0x25,
/* BYTE DescriptorSubType: */0x01,
/* BYTE bmAttributes: MaxPacketsOnly and frequency control */0x81,
/* BYTE bLockDelayUnits: */0x02,
/* SHORT wLockDelay: */0x00,
0x00
};
/*
Streaming Isochronous Endpoint
Maximum packet size 192 (stereo at 48khz)
*/
static const uint8 audio_extended[] =
{
0, /* bRefresh */
0 /* bSyncAddress */
};
static const EndPointInfo epinfo_as_alt0[] =
{
{
audio_extended,
sizeof(audio_extended),
end_point_iso_in,
end_point_attr_iso,
192,
TRUE /* Disable HCI headers */
}
};
/* USB HID class descriptor */
static const uint8 hid_descriptor[HID_DESCRIPTOR_LENGTH] =
{
HID_DESCRIPTOR_LENGTH, /* bLength */
HID_DESCRIPTOR, /* bDescriptorType */
0x11, /* bcdHID */
0x01, /* bcdHID */
0, /* bCountryCode */
1, /* bNumDescriptors */
0x22, /* bDescriptorType */
HID_REPORT_DESCRIPTOR_LENGTH, /* wDescriptorLength */
0, /* wDescriptorLength */
};
/* HID Report Descriptor - Consumer Control Device */
static const uint8 hid_report_descriptor[HID_REPORT_DESCRIPTOR_LENGTH] =
{
0x05,0x0C, /* USAGE_PAGE (Consumer Devices) */
0x09,0x01, /* USAGE (Consumer Control) */
0xa1,0x01, /* COLLECTION (Application) */
0x05,0x0C, /* USAGE_PAGE (Consumer Devices) */
0x15,0x00, /* LOGICAL_MINIMUM (0) */
0x25,0x01, /* LOGICAL_MAXIMUM (1) */
0x09,0xcd, /* USAGE (Play/Pause) */
0x09,0xb5, /* USAGE (Next Track) */
0x09,0xb6, /* USAGE (Previous Track) */
0x09,0xb7, /* USAGE (Stop) */
0x75,0x01, /* REPORT_SIZE (1) */
0x95,0x04, /* REPORT_COUNT (4) */
0x81,0x02, /* INPUT (Data,Var,Abs) */
0x75,0x01, /* REPORT_SIZE (1) */
0x95,0x04, /* REPORT_COUNT (4) */
0x81,0x01, /* INPUT (Const) */
/* Feature report to communicate with AVControl application */
0x06, 0x00, 0xff, /* Usage Page (Vendor 0xFF00) */
0x09, 0x01, /* Usage (Vendor Page 1) */
0x95, 0x01, /* Report Count (1) */
0x75, 0x40, /* Report Size (64) */
0xB1, 0x02, /* Feature (Var) */
0xc0 /* END_COLLECTION */
};
/* USB HID endpoint information */
static const EndPointInfo epinfo_hid_alt0[] =
{
{
NULL,
0,
end_point_int_out,
end_point_attr_int,
16
}
};
/****************************************************************************
NAME
initInterfaceTimeCritical
DESCRIPTION
Time critical USB initialisation.
RETURNS
void
*/
void initInterfaceTimeCritical(void)
{
/* DFU runs in mode zero, so stop */
if (BootGetMode() == 0)
exit(0);
/* Add an Audio Control Interface */
ac = UsbAddInterface(&codes_ac, 0x24, ac_class_descriptor, sizeof(ac_class_descriptor));
if(ac == usb_interface_error) Panic();
/* Add an Audio Streaming Interface */
as = UsbAddInterface(&codes_as, 0x24, as_class_descriptor, sizeof(as_class_descriptor));
if(as == usb_interface_error) Panic();
/* Add the endpoint */
(void) PanicFalse(UsbAddEndPoints(as, 1, epinfo_as_alt0));
/* Add an HID Class Interface */
hid = UsbAddInterface(&codes_hid, HID_DESCRIPTOR, hid_descriptor, HID_DESCRIPTOR_LENGTH);
if(hid == usb_interface_error) Panic();
/* Register HID report rescriptor with the interface */
(void) PanicFalse(UsbAddDescriptor(hid, HID_REPORT_DESCRIPTOR, hid_report_descriptor, HID_REPORT_DESCRIPTOR_LENGTH));
/* Add required endpoints to the interface */
(void) PanicFalse(UsbAddEndPoints(hid, 1, epinfo_hid_alt0));
}
/****************************************************************************
NAME
a2dpSdInitInterface
DESCRIPTION
Initialise USB support in the app.
RETURNS
void
*/
void a2dpSdInitInterface(a2dpSourceDongleTaskData *theApp)
{
/* Store the handler functions for the audio control and audio streaming */
theApp->audio_control.handler = audio_control_handler;
theApp->audio_streaming.handler = audio_streaming_handler;
/* Register our task for the sinks */
(void) MessageSinkTask(StreamUsbClassSink(as), &theApp->audio_streaming);
(void) MessageSinkTask(StreamUsbClassSink(ac), &theApp->audio_control);
(void) MessageSinkTask(StreamUsbClassSink(hid), &theApp->task);
}
/* Handle message more data messages for the audio control interface */
static void audio_control_handler(Task task, MessageId id, Message message)
{
task = task;
message = message;
if (id == MESSAGE_MORE_DATA)
handleAudioControlClassRequest(StreamUsbClassSource(ac));
}
/* Handle message more data messages for the audio streaming interface */
static void audio_streaming_handler(Task task, MessageId id, Message message)
{
task = task;
message = message;
if (id == MESSAGE_MORE_DATA)
handleAudioStreamingClassRequest(StreamUsbClassSource(as));
}
/****************************************************************************
NAME
a2dpSdHandleInterfaceEvent
DESCRIPTION
Process a more data message for the USB source.
RETURNS
void
*/
void a2dpSdHandleInterfaceEvent(const a2dpSourceDongleTaskData *theApp)
{
/*
The other two streams are handled by separate handlers but
this one needs access to app data so handle through main still
*/
handleHIDClassRequest(StreamUsbClassSource(hid), theApp);
}
/*
Process class requests to the Audio Control Interface
*/
static void handleAudioControlClassRequest(Source req)
{
uint16 packet_size;
bool activity = FALSE;
Sink resp = StreamSinkFromSource(req);
/* Check for outstanding Class requests */
while ((packet_size = SourceBoundary(req)) != 0)
{
/*
Build the response. It must contain the original request,
so copy from the source header.
*/
UsbResponse usbresp;
memcpy(&usbresp.original_request, SourceMapHeader(req), sizeof(UsbRequest));
usbresp.data_length = 0;
/* We advertise any commands on this endpoint, so reject */
usbresp.success = FALSE;
/* Sink packets can never be zero-length, so flush a dummy byte */
(void)SinkClaim(resp, 1);
(void)SinkFlushHeader(resp, 1, (void *)&usbresp, sizeof(UsbResponse));
/* Discard the original request */
SourceDrop(req, packet_size);
activity = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -