--- zzzz-none-000/linux-2.6.32.61/drivers/usb/gadget/f_audio.c 2013-06-10 09:43:48.000000000 +0000 +++ virian-300e-630/linux-2.6.32.61/drivers/usb/gadget/f_audio.c 2011-10-18 07:17:20.000000000 +0000 @@ -12,25 +12,126 @@ #include #include #include +#include +#include +#include +#include #include "u_audio.h" -#define OUT_EP_MAX_PACKET_SIZE 200 -static int req_buf_size = OUT_EP_MAX_PACKET_SIZE; -module_param(req_buf_size, int, S_IRUGO); -MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size"); +#ifdef WLAN_AOW_ENABLED +#include "if_aow.h" /* include the aow_dev interface header file */ +#endif + +#define MAX_AUDIO_CHAN (4) +#define BUF_SIZE_FACTOR 4 +#define OUT_EP_MAX_PACKET_SIZE 192 +#define AUDIO_FRAME_SIZE ((OUT_EP_MAX_PACKET_SIZE)*8) +#define AUDIO_BUF_SIZE (AUDIO_FRAME_SIZE * BUF_SIZE_FACTOR) -static int req_count = 256; -module_param(req_count, int, S_IRUGO); +static unsigned int req_count = 256; +module_param(req_count, uint, S_IRUGO); MODULE_PARM_DESC(req_count, "ISO OUT endpoint request count"); -static int audio_buf_size = 48000; -module_param(audio_buf_size, int, S_IRUGO); -MODULE_PARM_DESC(audio_buf_size, "Audio buffer size"); +static unsigned int req_buf_size = OUT_EP_MAX_PACKET_SIZE; +module_param(req_buf_size, uint, S_IRUGO); +MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size"); static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value); static int generic_get_cmd(struct usb_audio_control *con, u8 cmd); +static unsigned int g_audio_frame_size = AUDIO_FRAME_SIZE; + +static unsigned int g_audio_buf_size = AUDIO_BUF_SIZE; +module_param(g_audio_buf_size, uint, S_IRUGO); +MODULE_PARM_DESC(g_audio_buf_size, "Audio buffer size"); + +/* + * Note: In order to support various sample sizes, we should + * ideally change the design of some parts of this code so + * that it is made generic and a profile structure is used. + * However, for now, we only port the working solution from 2.6.15 - this + * in turn was meant to add to the existing code there with minimum + * potential disruption to other users of the driver. + * In the future, the design change can be carried out by interested + * teams if desired. + */ + +#ifdef USB_24BIT_AUDIO_ENABLED + +/* OUT_EP_MAX_PACKET_SIZE_24BIT is equivalent of + * OUT_EP_MAX_PACKET_SIZE, but for + * 24-bit samples rather than the + * default 16-bit samples. + */ +#define OUT_EP_MAX_PACKET_SIZE_24BIT 288 +#define AUDIO_FRAME_SIZE_24BIT ((OUT_EP_MAX_PACKET_SIZE_24BIT) * 8) +#define AUDIO_BUF_SIZE_24BIT (AUDIO_FRAME_SIZE_24BIT * BUF_SIZE_FACTOR) + +static unsigned int req_buf_size_24bit = OUT_EP_MAX_PACKET_SIZE_24BIT; +module_param(req_buf_size_24bit, uint, S_IRUGO); +MODULE_PARM_DESC(req_buf_size_24bit, "ISO OUT endpoint request buffer size " + "for 24-bit audio"); + +static unsigned int g_audio_frame_size_24bit = AUDIO_FRAME_SIZE_24BIT; + +static unsigned int g_audio_buf_size_24bit = AUDIO_BUF_SIZE_24BIT; +module_param(g_audio_buf_size_24bit, uint, S_IRUGO); +MODULE_PARM_DESC(g_audio_buf_size_24bit, "Audio buffer size for 24-bit audio"); + +static unsigned int max_audio_buf_size = AUDIO_BUF_SIZE_24BIT; +#else +static unsigned int max_audio_buf_size = AUDIO_BUF_SIZE; +#endif /* USB_24BIT_AUDIO_ENABLED */ + +module_param(max_audio_buf_size, uint, S_IRUGO); +MODULE_PARM_DESC(max_audio_buf_size, "Max audio buffer size"); + +#define MIN_FRAME_SIZE_FACTOR (1) +#define MAX_FRAME_SIZE_FACTOR (4) +#define DEFAULT_FRAME_SIZE_FACTOR (4) + +static int list_element_no; + +#ifdef WLAN_AOW_ENABLED + +#define AOWCTRL_QUEUE_LEN 5 +#define DEFAULT_EXPECTED_ALT_SETTING (7) +#define MIN_EXPECTED_ALT_SETTING (1) +#define MAX_EXPECTED_ALT_SETTING (8) + +static unsigned int g_expected_alt_setting = DEFAULT_EXPECTED_ALT_SETTING; +unsigned int g_alt_setting_init_done = 0; + +/* AoW Local Data types */ +aow_dev_t usb_aow_dev; /* USB AoW Audio device instance */ + +typedef struct usb_info { + struct f_audio *dev; +} usb_info_t; + +usb_info_t usbinfo; + +/* AoW Local Prototypes */ +static int is_aow_wlan_calls_registered(void); +static void init_usb_aow_dev(void); +static int set_wlan_audioparams(u8 bBitResolution, u8 tSamFreq[1][3]); + +#endif /* WLAN_AOW_ENABLED */ + +/* Use of I2S_ENABLED with USB_24BIT_AUDIO_ENABLED not (yet) supported */ +#define I2S_ENABLED 1 +#undef I2S_ENABLED + +#ifdef I2S_ENABLED +static int i2s_st; +static int i2s_write_cnt; +extern void ar7240_i2s_clk(unsigned long, unsigned long); +extern int ar7242_i2s_open(void); +extern void ar7242_i2s_close(void); +extern void ar7242_i2s_write(size_t , const char *, int ); +extern void ar7240_i2sound_dma_start(int); +#endif /* * DESCRIPTORS ... most are static, but strings and full * configuration descriptors are built on demand. @@ -42,27 +143,56 @@ */ #define F_AUDIO_AC_INTERFACE 0 #define F_AUDIO_AS_INTERFACE 1 +#if defined(CONFIG_MACH_ATHEROS) +#define F_AUDIO_NUM_INTERFACES 1 + +static off_t count_audio_playback; +#else /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ #define F_AUDIO_NUM_INTERFACES 2 +#endif /*--- #else ---*/ /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ /* B.3.1 Standard AC Interface Descriptor */ static struct usb_interface_descriptor ac_interface_desc __initdata = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, +#if defined(CONFIG_MACH_ATHEROS) + .bInterfaceNumber = 0, + .bAlternateSetting = 0, +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .bNumEndpoints = 0, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, +#if defined(CONFIG_MACH_ATHEROS) + .bInterfaceProtocol = 0x0, + .iInterface = 0x0, +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ }; DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); +#if defined(CONFIG_MACH_ATHEROS) +#define USB_DT_AC_HEADER_LENGTH USB_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) +#define UAC_DT_TOTAL_LENGTH (USB_DT_AC_HEADER_LENGTH + \ + USB_DT_AC_INPUT_TERMINAL_SIZE\ + + USB_DT_AC_OUTPUT_TERMINAL_SIZE) +#else /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ #define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) +#endif /*--- #else ---*/ /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ /* B.3.2 Class-Specific AC Interface Descriptor */ static struct uac_ac_header_descriptor_2 ac_header_desc = { +#if defined(CONFIG_MACH_ATHEROS) + .bLength = USB_DT_AC_HEADER_LENGTH, +#else /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .bLength = UAC_DT_AC_HEADER_LENGTH, +#endif /*--- #else ---*/ /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_HEADER, .bcdADC = __constant_cpu_to_le16(0x0100), +#if defined(CONFIG_MACH_ATHEROS) + .wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH), +#else /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .wTotalLength = __constant_cpu_to_le16(UAC_DT_AC_HEADER_LENGTH), +#endif /*--- #else ---*/ /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .bInCollection = F_AUDIO_NUM_INTERFACES, .baInterfaceNr = { [0] = F_AUDIO_AC_INTERFACE, @@ -71,16 +201,27 @@ }; #define INPUT_TERMINAL_ID 1 +#if defined(CONFIG_MACH_ATHEROS) +#define OUTPUT_TERMINAL_ID 2 +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ static struct uac_input_terminal_descriptor input_terminal_desc = { .bLength = UAC_DT_INPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, .bTerminalID = INPUT_TERMINAL_ID, +#if defined(CONFIG_MACH_ATHEROS) + .wTerminalType = __constant_cpu_to_le16(USB_AC_TERMINAL_STREAMING), + .bAssocTerminal = OUTPUT_TERMINAL_ID, + .bNrChannels = 0x8, + .wChannelConfig = __constant_cpu_to_le16(0x063F), +#else /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .wTerminalType = UAC_TERMINAL_STREAMING, .bAssocTerminal = 0, .wChannelConfig = 0x3, +#endif /*--- #else ---*/ /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ }; +#if defined(FEATURE_UNIT_SUPPORTED) || !defined(CONFIG_MACH_ATHEROS) DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0); #define FEATURE_UNIT_ID 2 @@ -120,36 +261,156 @@ .desc = (struct usb_descriptor_header *)&feature_unit_desc, }; +#endif /*--- #if defined(FEATURE_UNIT_SUPPORTED) || !defined(CONFIG_MACH_ATHEROS) ---*/ +#if !defined(CONFIG_MACH_ATHEROS) #define OUTPUT_TERMINAL_ID 3 +#endif /*--- #if !defined(CONFIG_MACH_ATHEROS) ---*/ static struct uac_output_terminal_descriptor output_terminal_desc = { .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, .bTerminalID = OUTPUT_TERMINAL_ID, .wTerminalType = UAC_OUTPUT_TERMINAL_SPEAKER, +#if defined(CONFIG_MACH_ATHEROS) +#ifdef FEATURE_UNIT_SUPPORTED + .bAssocTerminal = FEATURE_UNIT_ID, + .bSourceID = FEATURE_UNIT_ID, +#else + .bAssocTerminal = INPUT_TERMINAL_ID, + .bSourceID = INPUT_TERMINAL_ID, +#endif +#else /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .bAssocTerminal = FEATURE_UNIT_ID, .bSourceID = FEATURE_UNIT_ID, +#endif /*--- #else ---*/ /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ }; /* B.4.1 Standard AS Interface Descriptor */ static struct usb_interface_descriptor as_interface_alt_0_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, +#if defined(CONFIG_MACH_ATHEROS) + .bInterfaceNumber = 1, +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .bAlternateSetting = 0, .bNumEndpoints = 0, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, +#if defined(CONFIG_MACH_ATHEROS) + .bInterfaceProtocol = 0x0, + .iInterface = 0, +#else /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ }; static struct usb_interface_descriptor as_interface_alt_1_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, +#if defined(CONFIG_MACH_ATHEROS) + .bInterfaceNumber = 1, +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .bAlternateSetting = 1, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, }; +#if defined(CONFIG_MACH_ATHEROS) +static const struct usb_interface_descriptor +as_interface_alt_2_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 2, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, + .bInterfaceProtocol = 0x0, + .iInterface = 0, +}; + + +static const struct usb_interface_descriptor +as_interface_alt_3_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 3, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, + .bInterfaceProtocol = 0x0, + .iInterface = 0, +}; + +static const struct usb_interface_descriptor +as_interface_alt_4_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 4, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, + .bInterfaceProtocol = 0x0, + .iInterface = 0, +}; + +#ifdef USB_24BIT_AUDIO_ENABLED + +static struct usb_interface_descriptor as_interface_alt_5_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 5, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, +}; + +static const struct usb_interface_descriptor +as_interface_alt_6_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 6, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, + .bInterfaceProtocol = 0x0, + .iInterface = 0, +}; + +static const struct usb_interface_descriptor +as_interface_alt_7_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 7, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, + .bInterfaceProtocol = 0x0, + .iInterface = 0, +}; + +static const struct usb_interface_descriptor +as_interface_alt_8_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 8, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, + .bInterfaceProtocol = 0x0, + .iInterface = 0, +}; + +#endif /* USB_24BIT_AUDIO_ENABLED */ + + +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ + /* B.4.2 Class-Specific AS Interface Descriptor */ static struct uac_as_header_descriptor as_header_desc = { .bLength = UAC_DT_AS_HEADER_SIZE, @@ -157,43 +418,398 @@ .bDescriptorSubtype = UAC_AS_GENERAL, .bTerminalLink = INPUT_TERMINAL_ID, .bDelay = 1, +#if defined(CONFIG_MACH_ATHEROS) + .wFormatTag = __constant_cpu_to_le16(USB_AS_AUDIO_FORMAT_TYPE_I_PCM), +#else /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .wFormatTag = UAC_FORMAT_TYPE_I_PCM, +#endif /*--- #else ---*/ /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ }; DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1); +#if defined(CONFIG_MACH_ATHEROS) +static struct usb_as_formate_type_i_discrete_descriptor_1 as_type_i_1_desc = { +#else /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = { +#endif /*--- #else ---*/ /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_FORMAT_TYPE, .bFormatType = UAC_FORMAT_TYPE_I, +#if defined(CONFIG_MACH_ATHEROS) + .bNrChannels = 2, +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .bSubframeSize = 2, .bBitResolution = 16, .bSamFreqType = 1, +#if defined(CONFIG_MACH_ATHEROS) + .tSamFreq = { + [0][0] = 0x80, + [0][1] = 0xBB, + } +}; +static struct usb_as_formate_type_i_discrete_descriptor_1 +as_type_i_2_desc= { + .bLength = USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = FORMAT_TYPE, + + .bFormatType = USB_AS_FORMAT_TYPE_I, + .bNrChannels = 4, + .bSubframeSize = 2, + .bBitResolution = 0x10, + .bSamFreqType = 1, + .tSamFreq = { + [0][0] = 0x80, + [0][1] = 0xBB, + } +}; + +static struct usb_as_formate_type_i_discrete_descriptor_1 +as_type_i_3_desc= { + .bLength = USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = FORMAT_TYPE, + + .bFormatType = USB_AS_FORMAT_TYPE_I, + .bNrChannels = 6, + .bSubframeSize = 2, + .bBitResolution = 0x10, + .bSamFreqType = 1, + .tSamFreq = { + [0][0] = 0x80, + [0][1] = 0xBB, + } +}; + +static struct usb_as_formate_type_i_discrete_descriptor_1 +as_type_i_4_desc= { + .bLength = USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = FORMAT_TYPE, + + .bFormatType = USB_AS_FORMAT_TYPE_I, + .bNrChannels = 8, + .bSubframeSize = 2, + .bBitResolution = 0x10, + .bSamFreqType = 1, + .tSamFreq = { + [0][0] = 0x80, + [0][1] = 0xBB, + } +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ +}; + +#ifdef USB_24BIT_AUDIO_ENABLED + +static struct usb_as_formate_type_i_discrete_descriptor_1 as_type_i_5_desc = { + .bLength = USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = FORMAT_TYPE, + .bFormatType = USB_AS_FORMAT_TYPE_I, + .bNrChannels = 2, + .bSubframeSize = 3, + .bBitResolution = 0x18, + .bSamFreqType = 1, + .tSamFreq = { + [0][0] = 0x80, + [0][1] = 0xBB, + } +}; +static struct usb_as_formate_type_i_discrete_descriptor_1 +as_type_i_6_desc= { + .bLength = USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = FORMAT_TYPE, + + .bFormatType = USB_AS_FORMAT_TYPE_I, + .bNrChannels = 4, + .bSubframeSize = 3, + .bBitResolution = 0x18, + .bSamFreqType = 1, + .tSamFreq = { + [0][0] = 0x80, + [0][1] = 0xBB, + } +}; + +static struct usb_as_formate_type_i_discrete_descriptor_1 +as_type_i_7_desc= { + .bLength = USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = FORMAT_TYPE, + + .bFormatType = USB_AS_FORMAT_TYPE_I, + .bNrChannels = 6, + .bSubframeSize = 3, + .bBitResolution = 0x18, + .bSamFreqType = 1, + .tSamFreq = { + [0][0] = 0x80, + [0][1] = 0xBB, + } +}; + +static struct usb_as_formate_type_i_discrete_descriptor_1 +as_type_i_8_desc= { + .bLength = USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = FORMAT_TYPE, + + .bFormatType = USB_AS_FORMAT_TYPE_I, + .bNrChannels = 8, + .bSubframeSize = 3, + .bBitResolution = 0x18, + .bSamFreqType = 1, + .tSamFreq = { + [0][0] = 0x80, + [0][1] = 0xBB, + } }; +#endif /* USB_24BIT_AUDIO_ENABLED */ + + /* Standard ISO OUT Endpoint Descriptor */ +#if defined(CONFIG_MACH_ATHEROS) +static struct usb_endpoint_descriptor as_out_ep_alt_1_desc __initdata = { +#else /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ static struct usb_endpoint_descriptor as_out_ep_desc __initdata = { +#endif /*--- #else ---*/ /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, .bDescriptorType = USB_DT_ENDPOINT, +#if defined(CONFIG_MACH_ATHEROS) + .bEndpointAddress = 3, +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_SYNC_ADAPTIVE | USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = __constant_cpu_to_le16(OUT_EP_MAX_PACKET_SIZE), .bInterval = 4, +#if defined(CONFIG_MACH_ATHEROS) + .bRefresh = 0, +}; +static struct usb_endpoint_descriptor +as_out_ep_alt_2_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = 3, + .bmAttributes = USB_AS_ENDPOINT_ADAPTIVE | USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = __constant_cpu_to_le16((2*OUT_EP_MAX_PACKET_SIZE)), + .bInterval = 4, + .bRefresh = 0, }; +static struct usb_endpoint_descriptor +as_out_ep_alt_3_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = 3, + .bmAttributes = USB_AS_ENDPOINT_ADAPTIVE | USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = __constant_cpu_to_le16((3*OUT_EP_MAX_PACKET_SIZE)), + .bInterval = 4, + .bRefresh = 0, +}; + +static struct usb_endpoint_descriptor +as_out_ep_alt_4_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = 3, + .bmAttributes = USB_AS_ENDPOINT_ADAPTIVE | USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = __constant_cpu_to_le16((4*OUT_EP_MAX_PACKET_SIZE)), + .bInterval = 4, + .bRefresh = 0, +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ +}; + +#ifdef USB_24BIT_AUDIO_ENABLED + +static struct usb_endpoint_descriptor as_out_ep_alt_5_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 3, + .bmAttributes = USB_AS_ENDPOINT_ADAPTIVE + | USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = __constant_cpu_to_le16(OUT_EP_MAX_PACKET_SIZE_24BIT), + .bInterval = 4, + .bRefresh = 0, +}; + +static struct usb_endpoint_descriptor +as_out_ep_alt_6_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = 3, + .bmAttributes = USB_AS_ENDPOINT_ADAPTIVE | USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = __constant_cpu_to_le16((2 * OUT_EP_MAX_PACKET_SIZE_24BIT)), + .bInterval = 4, + .bRefresh = 0, +}; + +static struct usb_endpoint_descriptor +as_out_ep_alt_7_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = 3, + .bmAttributes = USB_AS_ENDPOINT_ADAPTIVE | USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = __constant_cpu_to_le16((3 * OUT_EP_MAX_PACKET_SIZE_24BIT)), + .bInterval = 4, + .bRefresh = 0, +}; + +static struct usb_endpoint_descriptor +as_out_ep_alt_8_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = 3, + .bmAttributes = USB_AS_ENDPOINT_ADAPTIVE | USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = __constant_cpu_to_le16((4 * OUT_EP_MAX_PACKET_SIZE_24BIT)), + .bInterval = 4, + .bRefresh = 0, +}; + +#endif /* USB_24BIT_AUDIO_ENABLED */ + /* Class-specific AS ISO OUT Endpoint Descriptor */ static struct uac_iso_endpoint_descriptor as_iso_out_desc __initdata = { .bLength = UAC_ISO_ENDPOINT_DESC_SIZE, .bDescriptorType = USB_DT_CS_ENDPOINT, .bDescriptorSubtype = UAC_EP_GENERAL, +#if defined(CONFIG_MACH_ATHEROS) .bmAttributes = 1, .bLockDelayUnits = 1, .wLockDelay = __constant_cpu_to_le16(1), +#else /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ + .bmAttributes = 0, + .bLockDelayUnits = 0, + .wLockDelay = __constant_cpu_to_le16(0), +#endif /*--- #else ---*/ /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ +}; + +#if defined(CONFIG_MACH_ATHEROS) +#ifdef WLAN_AOW_ENABLED + +#define AOWCTRL_IN_EP_INTERVAL 3 +#define AOWCTRL_OUT_EP_INTERVAL 4 +#define AOWCTRL_PROT_BYTECOUNT 512 + +static struct usb_interface_descriptor +vs_aowctrl_intf = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 2, + .bAlternateSetting = 0, + + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_VENDOR_SPEC, + .bInterfaceProtocol = 0x0, + .iInterface = 0x0, }; +static struct usb_endpoint_descriptor +vs_aowctrl_out_ep_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT | 1, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16 (AOWCTRL_PROT_BYTECOUNT), + .bInterval = AOWCTRL_OUT_EP_INTERVAL, +}; + +static struct usb_endpoint_descriptor +vs_aowctrl_in_ep_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN | 1, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16 (AOWCTRL_PROT_BYTECOUNT), + .bInterval = AOWCTRL_IN_EP_INTERVAL, +}; + +#endif /* WLAN_AOW_ENABLED */ + + +#define MULTIPLE_SETTINGS_SUPPORTED +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ + static struct usb_descriptor_header *f_audio_desc[] __initdata = { +#if defined(CONFIG_MACH_ATHEROS) + (struct usb_descriptor_header *)&ac_interface_desc, + (struct usb_descriptor_header *)&ac_header_desc, + + (struct usb_descriptor_header *)&input_terminal_desc, + (struct usb_descriptor_header *)&output_terminal_desc, +#ifdef FEATURE_UNIT_SUPPORTED + (struct usb_descriptor_header *)&feature_unit_desc, +#endif + (struct usb_descriptor_header *) &as_interface_alt_0_desc, + (struct usb_descriptor_header *) &as_interface_alt_1_desc, + (struct usb_descriptor_header *) &as_header_desc, + (struct usb_descriptor_header *) &as_type_i_1_desc, + (struct usb_descriptor_header *) &as_out_ep_alt_1_desc, + (struct usb_descriptor_header *) &as_iso_out_desc, + +#ifdef MULTIPLE_SETTINGS_SUPPORTED + (struct usb_descriptor_header *) &as_interface_alt_2_desc, + (struct usb_descriptor_header *) &as_header_desc, + (struct usb_descriptor_header *) &as_type_i_2_desc, + (struct usb_descriptor_header *) &as_out_ep_alt_2_desc, + (struct usb_descriptor_header *) &as_iso_out_desc, + + (struct usb_descriptor_header *) &as_interface_alt_3_desc, + (struct usb_descriptor_header *) &as_header_desc, + (struct usb_descriptor_header *) &as_type_i_3_desc, + (struct usb_descriptor_header *) &as_out_ep_alt_3_desc, + (struct usb_descriptor_header *) &as_iso_out_desc, + + (struct usb_descriptor_header *) &as_interface_alt_4_desc, + (struct usb_descriptor_header *) &as_header_desc, + (struct usb_descriptor_header *) &as_type_i_4_desc, + (struct usb_descriptor_header *) &as_out_ep_alt_4_desc, + (struct usb_descriptor_header *) &as_iso_out_desc, + +#ifdef USB_24BIT_AUDIO_ENABLED + (struct usb_descriptor_header *) &as_interface_alt_5_desc, + (struct usb_descriptor_header *) &as_header_desc, + (struct usb_descriptor_header *) &as_type_i_5_desc, + (struct usb_descriptor_header *) &as_out_ep_alt_5_desc, + (struct usb_descriptor_header *) &as_iso_out_desc, + + (struct usb_descriptor_header *) &as_interface_alt_6_desc, + (struct usb_descriptor_header *) &as_header_desc, + (struct usb_descriptor_header *) &as_type_i_6_desc, + (struct usb_descriptor_header *) &as_out_ep_alt_6_desc, + (struct usb_descriptor_header *) &as_iso_out_desc, + + (struct usb_descriptor_header *) &as_interface_alt_7_desc, + (struct usb_descriptor_header *) &as_header_desc, + (struct usb_descriptor_header *) &as_type_i_7_desc, + (struct usb_descriptor_header *) &as_out_ep_alt_7_desc, + (struct usb_descriptor_header *) &as_iso_out_desc, + + (struct usb_descriptor_header *) &as_interface_alt_8_desc, + (struct usb_descriptor_header *) &as_header_desc, + (struct usb_descriptor_header *) &as_type_i_8_desc, + (struct usb_descriptor_header *) &as_out_ep_alt_8_desc, + (struct usb_descriptor_header *) &as_iso_out_desc, +#endif /* USB_24BIT_AUDIO_ENABLED */ +#endif /* MULTIPLE_SETTINGS_SUPPORTED */ +#ifdef WLAN_AOW_ENABLED + (struct usb_descriptor_header *) &vs_aowctrl_intf, + (struct usb_descriptor_header *) &vs_aowctrl_out_ep_desc, + (struct usb_descriptor_header *) &vs_aowctrl_in_ep_desc, +#endif +#else /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ (struct usb_descriptor_header *)&ac_interface_desc, (struct usb_descriptor_header *)&ac_header_desc, @@ -209,6 +825,7 @@ (struct usb_descriptor_header *)&as_out_ep_desc, (struct usb_descriptor_header *)&as_iso_out_desc, +#endif /*--- #else ---*/ /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ NULL, }; @@ -243,9 +860,18 @@ struct f_audio_buf { u8 *buf; int actual; + u_int64_t tsf; struct list_head list; }; +#ifdef WLAN_AOW_ENABLED +struct aowctrl_buf { + u8 *buf; + int actual; + struct list_head list; +}; +#endif + static struct f_audio_buf *f_audio_buffer_alloc(int buf_size) { struct f_audio_buf *copy_buf; @@ -268,6 +894,29 @@ kfree(audio_buf->buf); kfree(audio_buf); } + +#ifdef WLAN_AOW_ENABLED +static struct aowctrl_buf* aowctrl_buffer_alloc(int buf_size) +{ + struct aowctrl_buf *outbuf; + + outbuf = kzalloc(sizeof(struct aowctrl_buf), GFP_ATOMIC); + if (NULL == outbuf) { + return NULL; + } + + outbuf->buf = kzalloc(buf_size, GFP_ATOMIC); + if (NULL == outbuf->buf) { + kfree(outbuf); + return NULL; + } + + return outbuf; +} + +#endif /* WLAN_AOW_ENABLED */ + + /*-------------------------------------------------------------------------*/ struct f_audio { @@ -282,10 +931,28 @@ struct work_struct playback_work; struct list_head play_queue; + /*Queue for maintaining request buffers.*/ + struct list_head req_queue; /* Control Set command */ struct list_head cs; u8 set_cmd; + u8 interface; + u8 altSetting; + u8 curAltSetting; + unsigned urb_created; struct usb_audio_control *set_con; + +#ifdef WLAN_AOW_ENABLED + spinlock_t aowctrl_lock; + struct usb_request *aowctrl_out_req, *aowctrl_in_req; + struct usb_ep *aowctrl_out_ep, *aowctrl_in_ep; + struct usb_endpoint_descriptor *aowctrl_out_desc, *aowctrl_in_desc; + struct list_head aowctrl_queue; + struct list_head aowctrl_free_queue; + + struct work_struct aowctrl_work; + +#endif }; static inline struct f_audio *func_to_audio(struct usb_function *f) @@ -293,6 +960,191 @@ return container_of(f, struct f_audio, card.func); } + +#ifdef USB_24BIT_AUDIO_ENABLED +u16 dst_for24bit[MAX_AUDIO_CHAN][AUDIO_FRAME_SIZE_24BIT/sizeof(u16)]; +#endif /* USB_24BIT_AUDIO_ENABLED */ +static u32 dst[MAX_AUDIO_CHAN][AUDIO_FRAME_SIZE/sizeof(u32)]; + +/* Note: 24-bit audio not tested with BUFDUMP_ENABLED_WQ*/ +//#define BUFDUMP_ENABLED_WQ 1 +//__attribute_used__ noinline static int audio_playback(struct audio_dev *audio, void *buf, int count) +static int audio_playback(struct f_audio *audio, void *buf, int count, u_int64_t time_stamp) +{ + int i, offset; + int altSetting; + int num_chan_pairs = 0; + u32 *src; +#ifdef USB_24BIT_AUDIO_ENABLED + u16 *src_for24bit; +#endif /* USB_24BIT_AUDIO_ENABLED */ + int reqd_audio_buf_size = 0; + int reqd_audio_frame_size = 0; + int cnt, loop_count, extra; + +#ifdef WLAN_AOW_ENABLED + +#ifdef WLAN_AOW_TXSCHED_ENABLED + int send_data_called = 0; +#endif + + /* return if the wlan calls are not registered */ + if (!is_aow_wlan_calls_registered()) + return 0; +#endif /* WLAN_AOW_ENABLED */ + + altSetting = (int)(audio->altSetting); + +#ifdef USB_24BIT_AUDIO_ENABLED + if((altSetting > 8) || (altSetting < 1)) { +#else + if((altSetting >4) || (altSetting < 1)) { +#endif /* USB_24BIT_AUDIO_ENABLED */ + return 0; + } + +#ifdef USB_24BIT_AUDIO_ENABLED + if (altSetting > 4) { + src_for24bit = buf; + num_chan_pairs = altSetting - 4; + reqd_audio_buf_size = g_audio_buf_size_24bit; + reqd_audio_frame_size = g_audio_frame_size_24bit; + } else { +#endif /* USB_24BIT_AUDIO_ENABLED */ + src = buf; + num_chan_pairs = altSetting; + reqd_audio_buf_size = g_audio_buf_size; + reqd_audio_frame_size = g_audio_frame_size; +#ifdef USB_24BIT_AUDIO_ENABLED + } +#endif /* USB_24BIT_AUDIO_ENABLED */ + + if(count < reqd_audio_buf_size) { + cnt = count / (reqd_audio_frame_size * num_chan_pairs); + extra = count % reqd_audio_frame_size; + } else + { + cnt = BUF_SIZE_FACTOR / num_chan_pairs; + extra = 0; + } + count_audio_playback++; + +#ifdef USB_24BIT_AUDIO_ENABLED + if (altSetting > 4) { + + while (cnt--) { + for (offset = 0; offset < (reqd_audio_frame_size / 2); offset += 3) { + for (i = 0; i < num_chan_pairs; i++) { + dst_for24bit[i][offset] = *src_for24bit++; + dst_for24bit[i][offset + 1] = *src_for24bit++; + dst_for24bit[i][offset + 2] = *src_for24bit++; + } + } + + #ifdef WLAN_AOW_ENABLED + //usb_aow_dev.tx.get_tsf(&tsf); + for (i = 0; i < num_chan_pairs; i++) { + usb_aow_dev.tx.send_data((char *)&(dst_for24bit[i][0]), reqd_audio_frame_size, i, time_stamp); + #ifdef WLAN_AOW_TXSCHED_ENABLED + send_data_called = 1; + #endif + } + #endif + } + + if(extra != 0) { + cnt = extra/num_chan_pairs; + loop_count = cnt / 2; + + for (offset = 0; offset < loop_count; offset += 3) { + for (i = 0; i < num_chan_pairs; i++) { + dst_for24bit[i][offset] = *src_for24bit++; + dst_for24bit[i][offset + 1] = *src_for24bit++; + dst_for24bit[i][offset + 2] = *src_for24bit++; + } + } + + #ifdef WLAN_AOW_ENABLED + for (i = 0; i < num_chan_pairs; i++) { + usb_aow_dev.tx.send_data((char *)&(dst_for24bit[i][0]), cnt, i, time_stamp); + #ifdef WLAN_AOW_TXSCHED_ENABLED + send_data_called = 1; + #endif + } + #endif + } + + #ifdef WLAN_AOW_ENABLED + #ifdef WLAN_AOW_TXSCHED_ENABLED + if (send_data_called) { + usb_aow_dev.tx.dispatch_data(); + } + #endif + #endif + + } else { +#endif /* USB_24BIT_AUDIO_ENABLED */ + + /* The below code will not be under an else when USB_24BIT_AUDIO_ENABLED + is disabled. */ + + while (cnt--) { + for (offset = 0; offset < (reqd_audio_frame_size / 4); offset++) { + for (i = 0; i < num_chan_pairs; i++) + dst[i][offset] = *src++; + } + +#ifdef WLAN_AOW_ENABLED + //usb_aow_dev.tx.get_tsf(&tsf); + + for (i = 0; i < num_chan_pairs; i++) { + usb_aow_dev.tx.send_data((char *)&(dst[i][0]), reqd_audio_frame_size, i, time_stamp); + #ifdef WLAN_AOW_TXSCHED_ENABLED + send_data_called = 1; + #endif + } +#endif + +#ifdef I2S_ENABLED + ar7242_i2s_write(AUDIO_FRAME_SIZE, (char *)&(dst[0][0]), 1); +#endif + } + + if(extra != 0) { + cnt = extra/num_chan_pairs; + loop_count = cnt/4; + for (offset = 0; offset < loop_count; offset++) { + for (i = 0; i < num_chan_pairs; i++) { + dst[i][offset] = *src++; + } + } + +#ifdef WLAN_AOW_ENABLED + for (i = 0; i < num_chan_pairs; i++) { + usb_aow_dev.tx.send_data((char *)&(dst[i][0]), cnt, i, time_stamp); + #ifdef WLAN_AOW_TXSCHED_ENABLED + send_data_called = 1; + #endif + } + #endif + } + +#ifdef WLAN_AOW_ENABLED + #ifdef WLAN_AOW_TXSCHED_ENABLED + if (send_data_called) { + usb_aow_dev.tx.dispatch_data(); + } + #endif +#endif + +#ifdef USB_24BIT_AUDIO_ENABLED + } +#endif /* USB_24BIT_AUDIO_ENABLED */ + + return 0; +} + + /*-------------------------------------------------------------------------*/ static void f_audio_playback_work(struct work_struct *data) @@ -306,38 +1158,163 @@ spin_unlock_irq(&audio->lock); return; } - play_buf = list_first_entry(&audio->play_queue, - struct f_audio_buf, list); + + do { + spin_lock_irq(&audio->lock); + play_buf = list_first_entry(&(audio->play_queue), struct f_audio_buf, list); + list_element_no--; list_del(&play_buf->list); spin_unlock_irq(&audio->lock); - + + audio_playback(audio, play_buf->buf, play_buf->actual, play_buf->tsf); +#if 0 u_audio_playback(&audio->card, play_buf->buf, play_buf->actual); +#endif f_audio_buffer_free(play_buf); + } while (list_element_no); return; } +#ifdef WLAN_AOW_ENABLED +static void aowctrl_work(struct work_struct *data) +{ + unsigned long long tsf = 0; + struct aowctrl_buf *outbuf; + struct f_audio *audio = container_of(data, + struct f_audio, + aowctrl_work); + unsigned long irqflags; + + spin_lock_irqsave(&audio->aowctrl_lock, irqflags); + if (list_empty(&audio->aowctrl_queue)) { + spin_unlock_irqrestore(&audio->aowctrl_lock, irqflags); + return; + } + + outbuf = list_first_entry(&(audio->aowctrl_queue), struct aowctrl_buf, list); + list_del(&outbuf->list); + spin_unlock_irqrestore(&audio->aowctrl_lock, irqflags); + + //usb_aow_dev.tx.get_tsf(&tsf); + usb_aow_dev.tx.send_ctrl((char *)outbuf->buf, outbuf->actual, tsf); + + spin_lock_irqsave(&audio->aowctrl_lock, irqflags); + list_add_tail(&outbuf->list, &audio->aowctrl_free_queue); + spin_unlock_irqrestore(&audio->aowctrl_lock, irqflags); + + return; +} + +static void destroy_aowctrl_queues(struct f_audio *dev) +{ + struct aowctrl_buf *outbuf = NULL; + + spin_lock(&dev->aowctrl_lock); + + while (!list_empty(&dev->aowctrl_queue)) { + outbuf = list_first_entry(&(dev->aowctrl_queue), struct aowctrl_buf, list); + list_del(&outbuf->list); + + if (NULL == outbuf) { + continue; + } + + if (outbuf->buf) { + kfree(outbuf->buf); + } + + kfree(outbuf); + } + + while (!list_empty(&dev->aowctrl_free_queue)) { + outbuf = list_first_entry(&(dev->aowctrl_free_queue), struct aowctrl_buf, list); + list_del(&outbuf->list); + + if (NULL == outbuf) { + continue; + } + + if (outbuf->buf) { + kfree(outbuf->buf); + } + + kfree(outbuf); + } + + spin_unlock(&dev->aowctrl_lock); + + return; +} +#endif /* WLAN_AOW_ENABLED */ + static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req) { struct f_audio *audio = req->context; struct usb_composite_dev *cdev = audio->card.func.config->cdev; struct f_audio_buf *copy_buf = audio->copy_buf; int err; + unsigned int reqd_audio_buf_size; + int num_chan_pairs = 0; if (!copy_buf) return -EINVAL; - /* Copy buffer is full, add it to the play_queue */ - if (audio_buf_size - copy_buf->actual < req->actual) { + /* WAR for audio problems when num_chan_pairs < 4 + We schedule playback_work once we have + (g_audio_frame_size * num_chan_pairs) bytes or + (g_audio_frame_size_24bit * num_chan_pairs) bytes. + Ideally, we should be changing the value of g_audio_buf_size + to correspond to the current altSetting, so that space is + conserved. However, this will involve critical code changes + which we don't want to jump into in one stroke. + Besides, the most common use case is with num_chan_pairs == 4, + so the space requirements with the current value of g_audio_buf_size + are bound to hold in most cases, anyway */ + +#ifdef USB_24BIT_AUDIO_ENABLED + if (audio->altSetting > 4) { + num_chan_pairs = audio->altSetting - 4; + reqd_audio_buf_size = g_audio_frame_size_24bit * num_chan_pairs; + } else { +#endif /* USB_24BIT_AUDIO_ENABLED */ + num_chan_pairs = audio->altSetting; + reqd_audio_buf_size = g_audio_frame_size * num_chan_pairs; +#ifdef USB_24BIT_AUDIO_ENABLED + } +#endif /* USB_24BIT_AUDIO_ENABLED */ + + + /* Copy buffer is full, or has requisite no. of bytes, + so add it to the play_queue */ + { + u_int16_t cpyLength = reqd_audio_buf_size - copy_buf->actual; + if (cpyLength > req->actual) { + cpyLength = req->actual; + } + req->actual -= cpyLength; + memcpy(copy_buf->buf + copy_buf->actual, + req->buf, + cpyLength); + copy_buf->actual += cpyLength; + if (copy_buf->actual == reqd_audio_buf_size) { +#ifdef WLAN_AOW_ENABLED + usb_aow_dev.tx.get_tsf(©_buf->tsf); +#endif + list_element_no++; list_add_tail(©_buf->list, &audio->play_queue); schedule_work(&audio->playback_work); - copy_buf = f_audio_buffer_alloc(audio_buf_size); - if (copy_buf < 0) + copy_buf = f_audio_buffer_alloc(max_audio_buf_size); + if (copy_buf < 0 ) { + audio->copy_buf = NULL; return -ENOMEM; + } } - - memcpy(copy_buf->buf + copy_buf->actual, req->buf, req->actual); + } + if (req->actual) { + memcpy(copy_buf->buf, req->buf, req->actual); copy_buf->actual += req->actual; + } audio->copy_buf = copy_buf; err = usb_ep_queue(ep, req, GFP_ATOMIC); @@ -348,18 +1325,98 @@ } +#ifdef WLAN_AOW_ENABLED +static int f_audio_aowctrl_out_ep_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_audio *audio = req->context; + struct usb_composite_dev *cdev = audio->card.func.config->cdev; + int err; + struct aowctrl_buf *outbuf = NULL; + + if (req->status != 0) { + ERROR(cdev, "%s queue req status: %d\n", ep->name, req->status); + /* But we don't give up. */ + goto requeue; + } + + if (list_empty(&audio->aowctrl_free_queue)) { + ERROR(cdev, "%s queue - Out of buffers for Control packets\n", ep->name); + /* But we don't give up. */ + goto requeue; + } + + /* Remove from free queue */ + outbuf = list_first_entry(&(audio->aowctrl_free_queue), struct aowctrl_buf, list); + list_del(&outbuf->list); + + if (NULL == outbuf) { + ERROR(cdev, "%s queue - Could not get valid buffer for Control packet\n", ep->name); + /* But we don't give up. */ + goto requeue; + } + + memcpy(outbuf->buf, req->buf, req->actual); + outbuf->actual = req->actual; + list_add_tail(&outbuf->list, &audio->aowctrl_queue); + schedule_work(&audio->aowctrl_work); + +requeue: + err = usb_ep_queue(ep, req, GFP_ATOMIC); + + if (err) { + ERROR(cdev, "%s queueing error: %d\n", ep->name, err); + return err; + } + + return 0; +} + +static int f_audio_aowctrl_in_ep_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_audio *audio = req->context; + struct usb_composite_dev *cdev = audio->card.func.config->cdev; + + if (req->status < 0) { + ERROR(cdev, "%s queue req: %d\n", ep->name, req->status); + return req->status; + } + + return 0; +} +#endif + + static void f_audio_complete(struct usb_ep *ep, struct usb_request *req) { struct f_audio *audio = req->context; int status = req->status; u32 data = 0; struct usb_ep *out_ep = audio->out_ep; +#ifdef WLAN_AOW_ENABLED + struct usb_ep *aowctrl_out_ep = audio->aowctrl_out_ep; + struct usb_ep *aowctrl_in_ep = audio->aowctrl_in_ep; +#endif switch (status) { case 0: /* normal completion? */ - if (ep == out_ep) + if (ep == out_ep) { + spin_lock(&audio->lock); f_audio_out_ep_complete(ep, req); + spin_unlock(&audio->lock); + } +#ifdef WLAN_AOW_ENABLED + else if (ep == aowctrl_out_ep) { + spin_lock (&audio->aowctrl_lock); + f_audio_aowctrl_out_ep_complete(ep, req); + spin_unlock (&audio->aowctrl_lock); + } + else if (ep == aowctrl_in_ep) { + spin_lock (&audio->aowctrl_lock); + f_audio_aowctrl_in_ep_complete(ep, req); + spin_unlock (&audio->aowctrl_lock); + } +#endif else if (audio->set_con) { memcpy(&data, req->buf, req->length); audio->set_con->set(audio->set_con, audio->set_cmd, @@ -459,11 +1516,11 @@ * Audio class messages; interface activation uses set_alt(). */ switch (ctrl->bRequestType) { - case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE: + case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_AUDIO_SET_INTF: value = audio_set_intf_req(f, ctrl); break; - case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE: + case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_AUDIO_GET_INTF: value = audio_get_intf_req(f, ctrl); break; @@ -489,20 +1546,234 @@ return value; } +static void free_out_ep_reqs(struct f_audio *audio) +{ + struct usb_request *req; + + while (!list_empty(&audio->req_queue)) { + req = list_first_entry(&(audio->req_queue), struct usb_request, list); + list_del (&req->list); + kfree(req->buf); + usb_ep_dequeue(audio->out_ep, req); + usb_ep_free_request (audio->out_ep, req); + } +} + +#ifdef WLAN_AOW_ENABLED +static void free_aowctrl_ep_reqs(struct f_audio *audio) +{ + if (audio->aowctrl_out_req) { + if (audio->aowctrl_out_req->buf) { + kfree(audio->aowctrl_out_req->buf); + audio->aowctrl_out_req->buf = NULL; + } + + usb_ep_dequeue(audio->aowctrl_out_ep, audio->aowctrl_out_req); + usb_ep_free_request(audio->aowctrl_out_ep, audio->aowctrl_out_req); + audio->aowctrl_out_req = NULL; + } + + if (audio->aowctrl_in_req) { + if (audio->aowctrl_in_req->buf) { + kfree(audio->aowctrl_in_req->buf); + audio->aowctrl_in_req->buf = NULL; + } + + usb_ep_dequeue(audio->aowctrl_in_ep, audio->aowctrl_in_req); + usb_ep_free_request (audio->aowctrl_in_ep, audio->aowctrl_in_req); + audio->aowctrl_in_req = NULL; + } +} + +static int set_wlan_audioparams(u8 bBitResolution, u8 tSamFreq[1][3]) +{ + audio_type_t audiotype; + + /* Return if the wlan calls are not registered. */ + if (!is_aow_wlan_calls_registered()) { + return 0; + } + + /* TODO: As and when new sample sizes and rates are added, modify + the below checks. */ + + if ((0x80 == tSamFreq[0][0]) && (0xBB == tSamFreq[0][1])) { + /* 48 KHz */ + + switch (bBitResolution) + { + case 16: + audiotype = SAMP_RATE_48k_SAMP_SIZE_16; + break; + + case 24: + audiotype = SAMP_RATE_48k_SAMP_SIZE_24; + break; + + default: + printk("%s: Unsupported sample size. bBitResolution=%u.\n", + __func__, + bBitResolution); + return -EINVAL; + } + } else { + printk("%s: Unsupported sampling rate. " + "tSamFreq[0][0]=0x%x, tSamFreq[0][1]=0x%x\n", + __func__, + tSamFreq[0][0], + tSamFreq[0][1]); + return -EINVAL; + } + + usb_aow_dev.tx.set_audioparams(audiotype); + + return 0; +} +#endif /* WLAN_AOW_ENABLED */ + + + static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct f_audio *audio = func_to_audio(f); struct usb_composite_dev *cdev = f->config->cdev; struct usb_ep *out_ep = audio->out_ep; struct usb_request *req; + int selected_req_buf_size = 0; + int num_chan_pairs = 0; int i = 0, err = 0; +#ifdef WLAN_AOW_ENABLED + struct usb_ep *aowctrl_out_ep = audio->aowctrl_out_ep; + struct usb_ep *aowctrl_in_ep = audio->aowctrl_in_ep; + + struct usb_request *aowctrl_out_req = NULL; + struct usb_request *aowctrl_in_req = NULL; + + u8 bBitResolution = 0; + u8 tSamFreq[1][3] = { + [0][0] = 0, + [0][1] = 0, + }; +#endif + DBG(cdev, "intf %d, alt %d\n", intf, alt); + ERROR(cdev, "intf %d, alt %d\n", intf, alt); if (intf == 1) { - if (alt == 1) { + spin_lock(&audio->lock); + + if (alt != 0) { + if(!(audio->copy_buf)) { + audio->copy_buf = f_audio_buffer_alloc(max_audio_buf_size); + } + + if (audio->copy_buf == -ENOMEM) { + audio->copy_buf = NULL; + spin_unlock(&audio->lock); + return -ENOMEM; + } +#ifdef WLAN_AOW_ENABLED + printk("altsetting requested=%d alsetting expected=%d\n", + alt, + g_expected_alt_setting); + + if((1 != audio->urb_created) && (alt == g_expected_alt_setting)) { +#else + if((1 != audio->urb_created) || (audio->altSetting != alt)) { +#endif + usb_ep_disable(out_ep); + free_out_ep_reqs(audio); + audio->altSetting = (u8)alt; + audio->curAltSetting = (u8)alt; + switch(alt) { + case 1: + audio->out_desc = &as_out_ep_alt_1_desc; +#ifdef WLAN_AOW_ENABLED + bBitResolution = as_type_i_1_desc.bBitResolution; + tSamFreq[0][0] = as_type_i_1_desc.tSamFreq[0][0]; + tSamFreq[0][1] = as_type_i_1_desc.tSamFreq[0][1]; +#endif /* WLAN_AOW_ENABLED */ + break; + case 2: + audio->out_desc = &as_out_ep_alt_2_desc; +#ifdef WLAN_AOW_ENABLED + bBitResolution = as_type_i_2_desc.bBitResolution; + tSamFreq[0][0] = as_type_i_2_desc.tSamFreq[0][0]; + tSamFreq[0][1] = as_type_i_2_desc.tSamFreq[0][1]; +#endif /* WLAN_AOW_ENABLED */ + break; + case 3: + audio->out_desc = &as_out_ep_alt_3_desc; +#ifdef WLAN_AOW_ENABLED + bBitResolution = as_type_i_3_desc.bBitResolution; + tSamFreq[0][0] = as_type_i_3_desc.tSamFreq[0][0]; + tSamFreq[0][1] = as_type_i_3_desc.tSamFreq[0][1]; +#endif /* WLAN_AOW_ENABLED */ + break; + case 4: + audio->out_desc = &as_out_ep_alt_4_desc; +#ifdef WLAN_AOW_ENABLED + bBitResolution = as_type_i_4_desc.bBitResolution; + tSamFreq[0][0] = as_type_i_4_desc.tSamFreq[0][0]; + tSamFreq[0][1] = as_type_i_4_desc.tSamFreq[0][1]; +#endif /* WLAN_AOW_ENABLED */ + break; +#ifdef USB_24BIT_AUDIO_ENABLED + case 5: + audio->out_desc = &as_out_ep_alt_5_desc; +#ifdef WLAN_AOW_ENABLED + bBitResolution = as_type_i_5_desc.bBitResolution; + tSamFreq[0][0] = as_type_i_5_desc.tSamFreq[0][0]; + tSamFreq[0][1] = as_type_i_5_desc.tSamFreq[0][1]; +#endif /* WLAN_AOW_ENABLED */ + break; + case 6: + audio->out_desc = &as_out_ep_alt_6_desc; +#ifdef WLAN_AOW_ENABLED + bBitResolution = as_type_i_6_desc.bBitResolution; + tSamFreq[0][0] = as_type_i_6_desc.tSamFreq[0][0]; + tSamFreq[0][1] = as_type_i_6_desc.tSamFreq[0][1]; +#endif /* WLAN_AOW_ENABLED */ + break; + case 7: + audio->out_desc = &as_out_ep_alt_7_desc; +#ifdef WLAN_AOW_ENABLED + bBitResolution = as_type_i_7_desc.bBitResolution; + tSamFreq[0][0] = as_type_i_7_desc.tSamFreq[0][0]; + tSamFreq[0][1] = as_type_i_7_desc.tSamFreq[0][1]; +#endif /* WLAN_AOW_ENABLED */ + break; + case 8: + audio->out_desc = &as_out_ep_alt_8_desc; +#ifdef WLAN_AOW_ENABLED + bBitResolution = as_type_i_8_desc.bBitResolution; + tSamFreq[0][0] = as_type_i_8_desc.tSamFreq[0][0]; + tSamFreq[0][1] = as_type_i_8_desc.tSamFreq[0][1]; +#endif /* WLAN_AOW_ENABLED */ + break; +#endif /* USB_24BIT_AUDIO_ENABLED */ + default: + ERROR (cdev, "Invalid Alternate Setting: intf %d, alt %d\n", intf, alt); + } + usb_ep_enable(out_ep, audio->out_desc); out_ep->driver_data = audio; +#ifdef WLAN_AOW_ENABLED + set_wlan_audioparams(bBitResolution, tSamFreq); +#endif + +#ifdef USB_24BIT_AUDIO_ENABLED + if (alt > 4) { + selected_req_buf_size = req_buf_size_24bit; + num_chan_pairs = alt - 4; + } else { +#endif /* USB_24BIT_AUDIO_ENABLED */ + selected_req_buf_size = req_buf_size; + num_chan_pairs = alt; +#ifdef USB_24BIT_AUDIO_ENABLED + } +#endif /* USB_24BIT_AUDIO_ENABLED */ audio->copy_buf = f_audio_buffer_alloc(audio_buf_size); /* @@ -512,10 +1783,10 @@ for (i = 0; i < req_count && err == 0; i++) { req = usb_ep_alloc_request(out_ep, GFP_ATOMIC); if (req) { - req->buf = kzalloc(req_buf_size, + req->buf = kzalloc(selected_req_buf_size * num_chan_pairs, GFP_ATOMIC); if (req->buf) { - req->length = req_buf_size; + req->length = selected_req_buf_size * num_chan_pairs; req->context = audio; req->complete = f_audio_complete; @@ -529,23 +1800,126 @@ err = -ENOMEM; } else err = -ENOMEM; - } - + list_add_tail(&req->list, &audio->req_queue); + } + audio->urb_created = 1; + } } else { struct f_audio_buf *copy_buf = audio->copy_buf; + audio->curAltSetting = alt; if (copy_buf) { - list_add_tail(©_buf->list, - &audio->play_queue); - schedule_work(&audio->playback_work); + if (copy_buf->actual != 0) { + audio->copy_buf = NULL; + list_element_no++; + list_add_tail(©_buf->list, &audio->play_queue); + schedule_work(&audio->playback_work); + } } } + + spin_unlock(&audio->lock); } +#ifdef WLAN_AOW_ENABLED + else if (intf == 2) { + spin_lock(&audio->aowctrl_lock); + + /* We have only altsetting 0 */ + if (alt != 0) { + ERROR (cdev, "Invalid Alternate Setting: intf %d, alt %d\n", intf, alt); + err = -EINVAL; + spin_unlock(&audio->aowctrl_lock); + goto done; + } + + free_aowctrl_ep_reqs(audio); + + /* Initialization for OUT transfers */ + + audio->aowctrl_out_desc = &vs_aowctrl_out_ep_desc; + + usb_ep_enable(aowctrl_out_ep, audio->aowctrl_out_desc); + + aowctrl_out_ep->driver_data = audio; + + aowctrl_out_req = usb_ep_alloc_request(aowctrl_out_ep, GFP_ATOMIC); + if (aowctrl_out_req) { + aowctrl_out_req->buf = kzalloc(AOWCTRL_PROT_BYTECOUNT, GFP_ATOMIC); + + if (aowctrl_out_req->buf) { + aowctrl_out_req->length = AOWCTRL_PROT_BYTECOUNT; + aowctrl_out_req->context = audio; + aowctrl_out_req->complete = f_audio_complete; + + err = usb_ep_queue(aowctrl_out_ep, + aowctrl_out_req, + GFP_ATOMIC); + if (err) { + ERROR(cdev, + "%s queue req: %d\n", + aowctrl_out_ep->name, + err); + spin_unlock(&audio->aowctrl_lock); + goto done; + } + } else { + err = -ENOMEM; + spin_unlock(&audio->aowctrl_lock); + goto done; + } + } else { + err = -ENOMEM; + spin_unlock(&audio->aowctrl_lock); + goto done; + } + + audio->aowctrl_out_req = aowctrl_out_req; + + + /* Initialization for IN transfers */ + + audio->aowctrl_in_desc = &vs_aowctrl_in_ep_desc; + + usb_ep_enable(aowctrl_in_ep, audio->aowctrl_in_desc); + + aowctrl_in_ep->driver_data = audio; + + aowctrl_in_req = usb_ep_alloc_request(aowctrl_in_ep, GFP_ATOMIC); + if (aowctrl_in_req) { + aowctrl_in_req->buf = kzalloc(AOWCTRL_PROT_BYTECOUNT, GFP_ATOMIC); + + if (aowctrl_in_req->buf) { + aowctrl_in_req->length = AOWCTRL_PROT_BYTECOUNT; + aowctrl_in_req->context = audio; + aowctrl_in_req->complete = f_audio_complete; + } else { + err = -ENOMEM; + spin_unlock(&audio->aowctrl_lock); + goto done; + } + } else { + err = -ENOMEM; + spin_unlock(&audio->aowctrl_lock); + goto done; + } + + audio->aowctrl_in_req = aowctrl_in_req; + } + + g_alt_setting_init_done = 1; + +#endif /* WLAN_AOW_ENABLED */ + +done: + //ERROR(cdev, "TP4: intf %d, alt %d Err = %d\n", intf, alt, err); return err; } static void f_audio_disable(struct usb_function *f) { + struct f_audio *audio = func_to_audio(f); + printk(KERN_ALERT "Inside f_audio_disable\n"); + audio->urb_created = 0; return; } @@ -553,18 +1927,18 @@ static void f_audio_build_desc(struct f_audio *audio) { - struct gaudio *card = &audio->card; - u8 *sam_freq; - int rate; + //struct gaudio *card = &audio->card; + //u8 *sam_freq; + //int rate; /* Set channel numbers */ - input_terminal_desc.bNrChannels = u_audio_get_playback_channels(card); - as_type_i_desc.bNrChannels = u_audio_get_playback_channels(card); +// input_terminal_desc.bNrChannels = u_audio_get_playback_channels(card); +// as_type_i_1_desc.bNrChannels = u_audio_get_playback_channels(card); /* Set sample rates */ - rate = u_audio_get_playback_rate(card); - sam_freq = as_type_i_desc.tSamFreq[0]; - memcpy(sam_freq, &rate, 3); +// rate = u_audio_get_playback_rate(card); +// sam_freq = as_type_i_1_desc.tSamFreq[0]; +// memcpy(sam_freq, &rate, 3); /* Todo: Set Sample bits and other parameters */ @@ -579,6 +1953,10 @@ struct f_audio *audio = func_to_audio(f); int status; struct usb_ep *ep; +#ifdef WLAN_AOW_ENABLED + struct usb_ep *aowctrl_out_ep = NULL, *aowctrl_in_ep = NULL; +#endif + f_audio_build_desc(audio); @@ -597,12 +1975,41 @@ status = -ENODEV; /* allocate instance-specific endpoints */ - ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); + ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_alt_1_desc); if (!ep) goto fail; audio->out_ep = ep; ep->driver_data = cdev; /* claim */ +#ifdef WLAN_AOW_ENABLED + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + vs_aowctrl_intf.bInterfaceNumber = status; + + status = -ENODEV; + + aowctrl_out_ep = usb_ep_autoconfig(cdev->gadget, &vs_aowctrl_out_ep_desc); + + if (!aowctrl_out_ep) { + goto fail; + } + + audio->aowctrl_out_ep = aowctrl_out_ep; + aowctrl_out_ep->driver_data = cdev; /* claim */ + + aowctrl_in_ep = usb_ep_autoconfig(cdev->gadget, &vs_aowctrl_in_ep_desc); + + if (!aowctrl_in_ep) + goto fail; + + audio->aowctrl_in_ep = aowctrl_in_ep; + aowctrl_in_ep->driver_data = cdev; /* claim */ + + usbinfo.dev = audio; +#endif + + status = -ENOMEM; /* supcard all relevant hardware speeds... we expect that when @@ -631,6 +2038,15 @@ usb_free_descriptors(f->descriptors); kfree(audio); + +#ifdef WLAN_AOW_ENABLED + free_aowctrl_ep_reqs(audio); + //TODO: Check on the below + //cancel_delayed_work(&audio->aowctrl_work); + flush_scheduled_work(); + destroy_aowctrl_queues(audio); +#endif + } /*-------------------------------------------------------------------------*/ @@ -651,6 +2067,7 @@ int __init control_selector_init(struct f_audio *audio) { INIT_LIST_HEAD(&audio->cs); +#if defined(FEATURE_UNIT_SUPPORTED) || !defined(CONFIG_MACH_ATHEROS) list_add(&feature_unit.list, &audio->cs); INIT_LIST_HEAD(&feature_unit.control); @@ -661,10 +2078,197 @@ volume_control.data[UAC__MIN] = 0xe3a0; volume_control.data[UAC__MAX] = 0xfff0; volume_control.data[UAC__RES] = 0x0030; +#endif return 0; } +#if defined(CONFIG_MACH_ATHEROS) +static int gaudio_read_procmem(char *buf, char **start, off_t offset, + int count, int *eof, void *data) +{ + int len = 0; + len += sprintf(buf+len,"\nAudio playback count = %li\n", count_audio_playback); + return len; +} +#endif /*--- #if defined(CONFIG_MACH_ATHEROS) ---*/ +#define BUFDUMP_ENABLED_WQ 1 +static int gaudio_readdata_procmem(char *buf, char **start, off_t offset, + int count, int *eof, void *data) +{ + int i, len = 0; + char *src; + + src = &(dst[0][0]); + #ifdef BUFDUMP_ENABLED_WQ + for(i=0; i < count; i++) { + len += sprintf(buf+len,"%x", src[i]); + } + #endif + return len; +} + +#ifdef WLAN_AOW_ENABLED + +/*----------------------------------------------------------------------------- + * The following APIs are exposed for WLAN driver as a part of AoW feature + *-----------------------------------------------------------------------------*/ + +/** + * @brief Initialize the USB AoW Device + */ +static void init_usb_aow_dev(void) +{ + usb_aow_dev.tx.set_audioparams = NULL; + usb_aow_dev.tx.send_data = NULL; +#ifdef WLAN_AOW_TXSCHED_ENABLED + usb_aow_dev.tx.dispatch_data = NULL; +#endif + usb_aow_dev.tx.send_ctrl = NULL; + usb_aow_dev.tx.get_tsf = NULL; +} + + +/** + * @brief Checks whether WLAN APIs are registered with USB or not. + * + * @return 1 if WLAN APIs are registered, 0 if not. + */ +static int is_aow_wlan_calls_registered(void) +{ + int is_registered = 0; + + if ((usb_aow_dev.tx.set_audioparams != NULL) && + (usb_aow_dev.tx.send_data != NULL) && +#ifdef WLAN_AOW_TXSCHED_ENABLED + (usb_aow_dev.tx.dispatch_data != NULL) && +#endif + (usb_aow_dev.tx.send_ctrl != NULL) && + (usb_aow_dev.tx.get_tsf != NULL)) { + is_registered = 1; + } + + return is_registered; +} + +/** + * @brief Accept a control packet from WLAN and transmit it to host. + * + * @param[in] data The packet data. + * @param[in] len Length of thLength of the data. + * + * @return 0 on success, negative value on error. + */ +int usb_aow_rx_ctrl(char* data, int len) +{ + int err; + struct f_audio *audio = usbinfo.dev; + struct usb_composite_dev *cdev = audio->card.func.config->cdev; + + if (!g_alt_setting_init_done || !(audio->aowctrl_in_req)) { + return -EINVAL; + } + + audio->aowctrl_in_req->length = len; + memcpy(audio->aowctrl_in_req->buf, data, len); + + + if (-EINPROGRESS == audio->aowctrl_in_req->status) { + ERROR(cdev, "Cannot accept AoW Control IN request since one is already queued\n"); + return -EINPROGRESS; + } + + err = usb_ep_queue(audio->aowctrl_in_ep, audio->aowctrl_in_req, GFP_ATOMIC); + if (err) { + ERROR(cdev, "%s queue req: %d\n", audio->aowctrl_in_ep->name, err); + return err; + } + + return 0; +} + +/** + * @brief Set frame size to be used. + * + * @param[in] framesize Frame size multiplier. + * Valid values: 1 (2 ms frames) + * : 2 (4 ms frames) + * : 3 (6 ms frames) + * : 4 (8 ms frames) + * @return 0 on success, negative value on error. + */ +int usb_aow_set_frame_size(unsigned int framesize) +{ + if ((framesize < MIN_FRAME_SIZE_FACTOR) || + (framesize > MAX_FRAME_SIZE_FACTOR)) { + return -EINVAL; + } + + g_audio_frame_size = (AUDIO_FRAME_SIZE/MAX_FRAME_SIZE_FACTOR) * framesize; + g_audio_buf_size = g_audio_frame_size * BUF_SIZE_FACTOR; +#ifdef USB_24BIT_AUDIO_ENABLED + g_audio_frame_size_24bit = (AUDIO_FRAME_SIZE_24BIT/MAX_FRAME_SIZE_FACTOR) * framesize; + g_audio_buf_size_24bit = g_audio_frame_size_24bit * BUF_SIZE_FACTOR; +#endif + + return 0; +} + +/** + * @brief Set alt setting to expect. + * + * This is a temporary requirement to work around some USB issues + * related to tear-down and setup of requests on varying alt settings. + * + * @param[in] altsetting Alt setting to expect. Valid values: 1-8 + * + * @return 0 on success, negative value on failure. + */ + +int usb_aow_set_exptd_alt_setting(unsigned int altsetting) +{ + if ((altsetting < MIN_EXPECTED_ALT_SETTING) || + (altsetting > MAX_EXPECTED_ALT_SETTING)) { + return -EINVAL; + } + + g_expected_alt_setting = altsetting; + + return 0; +} + + +/* + * === FUNCTION ====================================================================== + * Name: aow_register_wlan_calls_to_usb + * Description: Register WLAN Transmit related calls, USB device will use them to + * send data to WLAN device. WLAN will call this device on bootup + * ===================================================================================== + */ + +int aow_register_wlan_calls_to_usb(void* set_audioparams, + void* tx_data, +#ifdef WLAN_AOW_TXSCHED_ENABLED + void* dispatch_data, +#endif + void* tx_ctrl, + void* get_tsf) +{ + usb_aow_dev.tx.set_audioparams = set_audioparams; + usb_aow_dev.tx.send_data = tx_data; +#ifdef WLAN_AOW_TXSCHED_ENABLED + usb_aow_dev.tx.dispatch_data = dispatch_data; +#endif + usb_aow_dev.tx.send_ctrl = tx_ctrl; + usb_aow_dev.tx.get_tsf = get_tsf; + + return 0; + +}EXPORT_SYMBOL(aow_register_wlan_calls_to_usb); +#endif + + + /** * audio_bind_config - add USB audio fucntion to a configuration * @c: the configuration to supcard the USB audio function @@ -676,6 +2280,18 @@ { struct f_audio *audio; int status; +#ifdef WLAN_AOW_ENABLED + struct aowctrl_buf *outbuf = NULL; + int j; + + init_usb_aow_dev(); + wlan_aow_register_calls_to_usb(&usb_aow_dev); + aow_register_usb_calls_to_wlan(NULL, + usb_aow_rx_ctrl, + usb_aow_set_frame_size, + usb_aow_set_exptd_alt_setting); +#endif /* WLAN_AOW_ENABLED */ + /* allocate and initialize one new instance */ audio = kzalloc(sizeof *audio, GFP_KERNEL); @@ -685,13 +2301,36 @@ audio->card.func.name = "g_audio"; audio->card.gadget = c->cdev->gadget; + create_proc_read_entry("gaudio", 0, NULL, gaudio_read_procmem, NULL); INIT_LIST_HEAD(&audio->play_queue); + INIT_LIST_HEAD(&audio->req_queue); +#ifdef WLAN_AOW_ENABLED + INIT_LIST_HEAD(&audio->aowctrl_queue); + INIT_LIST_HEAD(&audio->aowctrl_free_queue); + + for(j = 0; j < AOWCTRL_QUEUE_LEN; j++) + { + outbuf = aowctrl_buffer_alloc(AOWCTRL_PROT_BYTECOUNT); + + if (NULL == outbuf) { + return -ENOMEM; + } + + list_add_tail(&outbuf->list, &audio->aowctrl_free_queue); + } +#endif + spin_lock_init(&audio->lock); +#ifdef WLAN_AOW_ENABLED + spin_lock_init (&audio->aowctrl_lock); +#endif +#ifdef REMOVED_ALSA /* set up ASLA audio devices */ status = gaudio_setup(&audio->card); if (status < 0) goto setup_fail; +#endif audio->card.func.strings = audio_strings; audio->card.func.bind = f_audio_bind; @@ -699,18 +2338,25 @@ audio->card.func.set_alt = f_audio_set_alt; audio->card.func.setup = f_audio_setup; audio->card.func.disable = f_audio_disable; - audio->out_desc = &as_out_ep_desc; + audio->out_desc = &as_out_ep_alt_1_desc; +#ifdef WLAN_AOW_ENABLED + audio->aowctrl_out_desc = &vs_aowctrl_out_ep_desc; + audio->aowctrl_in_desc = &vs_aowctrl_in_ep_desc; +#endif control_selector_init(audio); INIT_WORK(&audio->playback_work, f_audio_playback_work); +#ifdef WLAN_AOW_ENABLED + INIT_WORK(&audio->aowctrl_work, aowctrl_work); +#endif status = usb_add_function(c, &audio->card.func); if (status) goto add_fail; - INFO(c->cdev, "audio_buf_size %d, req_buf_size %d, req_count %d\n", - audio_buf_size, req_buf_size, req_count); + INFO(c->cdev, "max_audio_buf_size %d, req_buf_size %d, req_count %d\n", + max_audio_buf_size, req_buf_size, req_count); return status;