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

📄 a2dp_sd_interface_usb.c

📁 CSR蓝牙MP3播放USB DONGLE源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
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 + -