18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * audio.c -- Audio gadget driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org> 68c2ecf20Sopenharmony_ci * Copyright (C) 2008 Analog Devices, Inc 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* #define VERBOSE_DEBUG */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/usb/composite.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define DRIVER_DESC "Linux USB Audio Gadget" 168c2ecf20Sopenharmony_ci#define DRIVER_VERSION "Feb 2, 2012" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ciUSB_GADGET_COMPOSITE_OPTIONS(); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#ifndef CONFIG_GADGET_UAC1 218c2ecf20Sopenharmony_ci#include "u_uac2.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Playback(USB-IN) Default Stereo - Fl/Fr */ 248c2ecf20Sopenharmony_cistatic int p_chmask = UAC2_DEF_PCHMASK; 258c2ecf20Sopenharmony_cimodule_param(p_chmask, uint, S_IRUGO); 268c2ecf20Sopenharmony_ciMODULE_PARM_DESC(p_chmask, "Playback Channel Mask"); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* Playback Default 48 KHz */ 298c2ecf20Sopenharmony_cistatic int p_srate = UAC2_DEF_PSRATE; 308c2ecf20Sopenharmony_cimodule_param(p_srate, uint, S_IRUGO); 318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(p_srate, "Playback Sampling Rate"); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* Playback Default 16bits/sample */ 348c2ecf20Sopenharmony_cistatic int p_ssize = UAC2_DEF_PSSIZE; 358c2ecf20Sopenharmony_cimodule_param(p_ssize, uint, S_IRUGO); 368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)"); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* Capture(USB-OUT) Default Stereo - Fl/Fr */ 398c2ecf20Sopenharmony_cistatic int c_chmask = UAC2_DEF_CCHMASK; 408c2ecf20Sopenharmony_cimodule_param(c_chmask, uint, S_IRUGO); 418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(c_chmask, "Capture Channel Mask"); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* Capture Default 64 KHz */ 448c2ecf20Sopenharmony_cistatic int c_srate = UAC2_DEF_CSRATE; 458c2ecf20Sopenharmony_cimodule_param(c_srate, uint, S_IRUGO); 468c2ecf20Sopenharmony_ciMODULE_PARM_DESC(c_srate, "Capture Sampling Rate"); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Capture Default 16bits/sample */ 498c2ecf20Sopenharmony_cistatic int c_ssize = UAC2_DEF_CSSIZE; 508c2ecf20Sopenharmony_cimodule_param(c_ssize, uint, S_IRUGO); 518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)"); 528c2ecf20Sopenharmony_ci#else 538c2ecf20Sopenharmony_ci#ifndef CONFIG_GADGET_UAC1_LEGACY 548c2ecf20Sopenharmony_ci#include "u_uac1.h" 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* Playback(USB-IN) Default Stereo - Fl/Fr */ 578c2ecf20Sopenharmony_cistatic int p_chmask = UAC1_DEF_PCHMASK; 588c2ecf20Sopenharmony_cimodule_param(p_chmask, uint, S_IRUGO); 598c2ecf20Sopenharmony_ciMODULE_PARM_DESC(p_chmask, "Playback Channel Mask"); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* Playback Default 48 KHz */ 628c2ecf20Sopenharmony_cistatic int p_srate = UAC1_DEF_PSRATE; 638c2ecf20Sopenharmony_cimodule_param(p_srate, uint, S_IRUGO); 648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(p_srate, "Playback Sampling Rate"); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* Playback Default 16bits/sample */ 678c2ecf20Sopenharmony_cistatic int p_ssize = UAC1_DEF_PSSIZE; 688c2ecf20Sopenharmony_cimodule_param(p_ssize, uint, S_IRUGO); 698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)"); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* Capture(USB-OUT) Default Stereo - Fl/Fr */ 728c2ecf20Sopenharmony_cistatic int c_chmask = UAC1_DEF_CCHMASK; 738c2ecf20Sopenharmony_cimodule_param(c_chmask, uint, S_IRUGO); 748c2ecf20Sopenharmony_ciMODULE_PARM_DESC(c_chmask, "Capture Channel Mask"); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* Capture Default 48 KHz */ 778c2ecf20Sopenharmony_cistatic int c_srate = UAC1_DEF_CSRATE; 788c2ecf20Sopenharmony_cimodule_param(c_srate, uint, S_IRUGO); 798c2ecf20Sopenharmony_ciMODULE_PARM_DESC(c_srate, "Capture Sampling Rate"); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* Capture Default 16bits/sample */ 828c2ecf20Sopenharmony_cistatic int c_ssize = UAC1_DEF_CSSIZE; 838c2ecf20Sopenharmony_cimodule_param(c_ssize, uint, S_IRUGO); 848c2ecf20Sopenharmony_ciMODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)"); 858c2ecf20Sopenharmony_ci#else /* CONFIG_GADGET_UAC1_LEGACY */ 868c2ecf20Sopenharmony_ci#include "u_uac1_legacy.h" 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic char *fn_play = FILE_PCM_PLAYBACK; 898c2ecf20Sopenharmony_cimodule_param(fn_play, charp, S_IRUGO); 908c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fn_play, "Playback PCM device file name"); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic char *fn_cap = FILE_PCM_CAPTURE; 938c2ecf20Sopenharmony_cimodule_param(fn_cap, charp, S_IRUGO); 948c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fn_cap, "Capture PCM device file name"); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic char *fn_cntl = FILE_CONTROL; 978c2ecf20Sopenharmony_cimodule_param(fn_cntl, charp, S_IRUGO); 988c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fn_cntl, "Control device file name"); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int req_buf_size = UAC1_OUT_EP_MAX_PACKET_SIZE; 1018c2ecf20Sopenharmony_cimodule_param(req_buf_size, int, S_IRUGO); 1028c2ecf20Sopenharmony_ciMODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size"); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int req_count = UAC1_REQ_COUNT; 1058c2ecf20Sopenharmony_cimodule_param(req_count, int, S_IRUGO); 1068c2ecf20Sopenharmony_ciMODULE_PARM_DESC(req_count, "ISO OUT endpoint request count"); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int audio_buf_size = UAC1_AUDIO_BUF_SIZE; 1098c2ecf20Sopenharmony_cimodule_param(audio_buf_size, int, S_IRUGO); 1108c2ecf20Sopenharmony_ciMODULE_PARM_DESC(audio_buf_size, "Audio buffer size"); 1118c2ecf20Sopenharmony_ci#endif /* CONFIG_GADGET_UAC1_LEGACY */ 1128c2ecf20Sopenharmony_ci#endif 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* string IDs are assigned dynamically */ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic struct usb_string strings_dev[] = { 1178c2ecf20Sopenharmony_ci [USB_GADGET_MANUFACTURER_IDX].s = "", 1188c2ecf20Sopenharmony_ci [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, 1198c2ecf20Sopenharmony_ci [USB_GADGET_SERIAL_IDX].s = "", 1208c2ecf20Sopenharmony_ci { } /* end of list */ 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic struct usb_gadget_strings stringtab_dev = { 1248c2ecf20Sopenharmony_ci .language = 0x0409, /* en-us */ 1258c2ecf20Sopenharmony_ci .strings = strings_dev, 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic struct usb_gadget_strings *audio_strings[] = { 1298c2ecf20Sopenharmony_ci &stringtab_dev, 1308c2ecf20Sopenharmony_ci NULL, 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#ifndef CONFIG_GADGET_UAC1 1348c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_uac2; 1358c2ecf20Sopenharmony_cistatic struct usb_function *f_uac2; 1368c2ecf20Sopenharmony_ci#else 1378c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_uac1; 1388c2ecf20Sopenharmony_cistatic struct usb_function *f_uac1; 1398c2ecf20Sopenharmony_ci#endif 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! 1448c2ecf20Sopenharmony_ci * Instead: allocate your own, using normal USB-IF procedures. 1458c2ecf20Sopenharmony_ci */ 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/* Thanks to Linux Foundation for donating this product ID. */ 1488c2ecf20Sopenharmony_ci#define AUDIO_VENDOR_NUM 0x1d6b /* Linux Foundation */ 1498c2ecf20Sopenharmony_ci#define AUDIO_PRODUCT_NUM 0x0101 /* Linux-USB Audio Gadget */ 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic struct usb_device_descriptor device_desc = { 1548c2ecf20Sopenharmony_ci .bLength = sizeof device_desc, 1558c2ecf20Sopenharmony_ci .bDescriptorType = USB_DT_DEVICE, 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* .bcdUSB = DYNAMIC */ 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci#ifdef CONFIG_GADGET_UAC1_LEGACY 1608c2ecf20Sopenharmony_ci .bDeviceClass = USB_CLASS_PER_INTERFACE, 1618c2ecf20Sopenharmony_ci .bDeviceSubClass = 0, 1628c2ecf20Sopenharmony_ci .bDeviceProtocol = 0, 1638c2ecf20Sopenharmony_ci#else 1648c2ecf20Sopenharmony_ci .bDeviceClass = USB_CLASS_MISC, 1658c2ecf20Sopenharmony_ci .bDeviceSubClass = 0x02, 1668c2ecf20Sopenharmony_ci .bDeviceProtocol = 0x01, 1678c2ecf20Sopenharmony_ci#endif 1688c2ecf20Sopenharmony_ci /* .bMaxPacketSize0 = f(hardware) */ 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Vendor and product id defaults change according to what configs 1718c2ecf20Sopenharmony_ci * we support. (As does bNumConfigurations.) These values can 1728c2ecf20Sopenharmony_ci * also be overridden by module parameters. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci .idVendor = cpu_to_le16(AUDIO_VENDOR_NUM), 1758c2ecf20Sopenharmony_ci .idProduct = cpu_to_le16(AUDIO_PRODUCT_NUM), 1768c2ecf20Sopenharmony_ci /* .bcdDevice = f(hardware) */ 1778c2ecf20Sopenharmony_ci /* .iManufacturer = DYNAMIC */ 1788c2ecf20Sopenharmony_ci /* .iProduct = DYNAMIC */ 1798c2ecf20Sopenharmony_ci /* NO SERIAL NUMBER */ 1808c2ecf20Sopenharmony_ci .bNumConfigurations = 1, 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic const struct usb_descriptor_header *otg_desc[2]; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic int audio_do_config(struct usb_configuration *c) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci int status; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* FIXME alloc iConfiguration string, set it in c->strings */ 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (gadget_is_otg(c->cdev->gadget)) { 1948c2ecf20Sopenharmony_ci c->descriptors = otg_desc; 1958c2ecf20Sopenharmony_ci c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci#ifdef CONFIG_GADGET_UAC1 1998c2ecf20Sopenharmony_ci f_uac1 = usb_get_function(fi_uac1); 2008c2ecf20Sopenharmony_ci if (IS_ERR(f_uac1)) { 2018c2ecf20Sopenharmony_ci status = PTR_ERR(f_uac1); 2028c2ecf20Sopenharmony_ci return status; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci status = usb_add_function(c, f_uac1); 2068c2ecf20Sopenharmony_ci if (status < 0) { 2078c2ecf20Sopenharmony_ci usb_put_function(f_uac1); 2088c2ecf20Sopenharmony_ci return status; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci#else 2118c2ecf20Sopenharmony_ci f_uac2 = usb_get_function(fi_uac2); 2128c2ecf20Sopenharmony_ci if (IS_ERR(f_uac2)) { 2138c2ecf20Sopenharmony_ci status = PTR_ERR(f_uac2); 2148c2ecf20Sopenharmony_ci return status; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci status = usb_add_function(c, f_uac2); 2188c2ecf20Sopenharmony_ci if (status < 0) { 2198c2ecf20Sopenharmony_ci usb_put_function(f_uac2); 2208c2ecf20Sopenharmony_ci return status; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci#endif 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic struct usb_configuration audio_config_driver = { 2288c2ecf20Sopenharmony_ci .label = DRIVER_DESC, 2298c2ecf20Sopenharmony_ci .bConfigurationValue = 1, 2308c2ecf20Sopenharmony_ci /* .iConfiguration = DYNAMIC */ 2318c2ecf20Sopenharmony_ci .bmAttributes = USB_CONFIG_ATT_SELFPOWER, 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int audio_bind(struct usb_composite_dev *cdev) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci#ifndef CONFIG_GADGET_UAC1 2398c2ecf20Sopenharmony_ci struct f_uac2_opts *uac2_opts; 2408c2ecf20Sopenharmony_ci#else 2418c2ecf20Sopenharmony_ci#ifndef CONFIG_GADGET_UAC1_LEGACY 2428c2ecf20Sopenharmony_ci struct f_uac1_opts *uac1_opts; 2438c2ecf20Sopenharmony_ci#else 2448c2ecf20Sopenharmony_ci struct f_uac1_legacy_opts *uac1_opts; 2458c2ecf20Sopenharmony_ci#endif 2468c2ecf20Sopenharmony_ci#endif 2478c2ecf20Sopenharmony_ci int status; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci#ifndef CONFIG_GADGET_UAC1 2508c2ecf20Sopenharmony_ci fi_uac2 = usb_get_function_instance("uac2"); 2518c2ecf20Sopenharmony_ci if (IS_ERR(fi_uac2)) 2528c2ecf20Sopenharmony_ci return PTR_ERR(fi_uac2); 2538c2ecf20Sopenharmony_ci#else 2548c2ecf20Sopenharmony_ci#ifndef CONFIG_GADGET_UAC1_LEGACY 2558c2ecf20Sopenharmony_ci fi_uac1 = usb_get_function_instance("uac1"); 2568c2ecf20Sopenharmony_ci#else 2578c2ecf20Sopenharmony_ci fi_uac1 = usb_get_function_instance("uac1_legacy"); 2588c2ecf20Sopenharmony_ci#endif 2598c2ecf20Sopenharmony_ci if (IS_ERR(fi_uac1)) 2608c2ecf20Sopenharmony_ci return PTR_ERR(fi_uac1); 2618c2ecf20Sopenharmony_ci#endif 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci#ifndef CONFIG_GADGET_UAC1 2648c2ecf20Sopenharmony_ci uac2_opts = container_of(fi_uac2, struct f_uac2_opts, func_inst); 2658c2ecf20Sopenharmony_ci uac2_opts->p_chmask = p_chmask; 2668c2ecf20Sopenharmony_ci uac2_opts->p_srate = p_srate; 2678c2ecf20Sopenharmony_ci uac2_opts->p_ssize = p_ssize; 2688c2ecf20Sopenharmony_ci uac2_opts->c_chmask = c_chmask; 2698c2ecf20Sopenharmony_ci uac2_opts->c_srate = c_srate; 2708c2ecf20Sopenharmony_ci uac2_opts->c_ssize = c_ssize; 2718c2ecf20Sopenharmony_ci uac2_opts->req_number = UAC2_DEF_REQ_NUM; 2728c2ecf20Sopenharmony_ci#else 2738c2ecf20Sopenharmony_ci#ifndef CONFIG_GADGET_UAC1_LEGACY 2748c2ecf20Sopenharmony_ci uac1_opts = container_of(fi_uac1, struct f_uac1_opts, func_inst); 2758c2ecf20Sopenharmony_ci uac1_opts->p_chmask = p_chmask; 2768c2ecf20Sopenharmony_ci uac1_opts->p_srate = p_srate; 2778c2ecf20Sopenharmony_ci uac1_opts->p_ssize = p_ssize; 2788c2ecf20Sopenharmony_ci uac1_opts->c_chmask = c_chmask; 2798c2ecf20Sopenharmony_ci uac1_opts->c_srate = c_srate; 2808c2ecf20Sopenharmony_ci uac1_opts->c_ssize = c_ssize; 2818c2ecf20Sopenharmony_ci uac1_opts->req_number = UAC1_DEF_REQ_NUM; 2828c2ecf20Sopenharmony_ci#else /* CONFIG_GADGET_UAC1_LEGACY */ 2838c2ecf20Sopenharmony_ci uac1_opts = container_of(fi_uac1, struct f_uac1_legacy_opts, func_inst); 2848c2ecf20Sopenharmony_ci uac1_opts->fn_play = fn_play; 2858c2ecf20Sopenharmony_ci uac1_opts->fn_cap = fn_cap; 2868c2ecf20Sopenharmony_ci uac1_opts->fn_cntl = fn_cntl; 2878c2ecf20Sopenharmony_ci uac1_opts->req_buf_size = req_buf_size; 2888c2ecf20Sopenharmony_ci uac1_opts->req_count = req_count; 2898c2ecf20Sopenharmony_ci uac1_opts->audio_buf_size = audio_buf_size; 2908c2ecf20Sopenharmony_ci#endif /* CONFIG_GADGET_UAC1_LEGACY */ 2918c2ecf20Sopenharmony_ci#endif 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci status = usb_string_ids_tab(cdev, strings_dev); 2948c2ecf20Sopenharmony_ci if (status < 0) 2958c2ecf20Sopenharmony_ci goto fail; 2968c2ecf20Sopenharmony_ci device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; 2978c2ecf20Sopenharmony_ci device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) { 3008c2ecf20Sopenharmony_ci struct usb_descriptor_header *usb_desc; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci usb_desc = usb_otg_descriptor_alloc(cdev->gadget); 3038c2ecf20Sopenharmony_ci if (!usb_desc) { 3048c2ecf20Sopenharmony_ci status = -ENOMEM; 3058c2ecf20Sopenharmony_ci goto fail; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci usb_otg_descriptor_init(cdev->gadget, usb_desc); 3088c2ecf20Sopenharmony_ci otg_desc[0] = usb_desc; 3098c2ecf20Sopenharmony_ci otg_desc[1] = NULL; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci status = usb_add_config(cdev, &audio_config_driver, audio_do_config); 3138c2ecf20Sopenharmony_ci if (status < 0) 3148c2ecf20Sopenharmony_ci goto fail_otg_desc; 3158c2ecf20Sopenharmony_ci usb_composite_overwrite_options(cdev, &coverwrite); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION); 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cifail_otg_desc: 3218c2ecf20Sopenharmony_ci kfree(otg_desc[0]); 3228c2ecf20Sopenharmony_ci otg_desc[0] = NULL; 3238c2ecf20Sopenharmony_cifail: 3248c2ecf20Sopenharmony_ci#ifndef CONFIG_GADGET_UAC1 3258c2ecf20Sopenharmony_ci usb_put_function_instance(fi_uac2); 3268c2ecf20Sopenharmony_ci#else 3278c2ecf20Sopenharmony_ci usb_put_function_instance(fi_uac1); 3288c2ecf20Sopenharmony_ci#endif 3298c2ecf20Sopenharmony_ci return status; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int audio_unbind(struct usb_composite_dev *cdev) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci#ifdef CONFIG_GADGET_UAC1 3358c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_uac1)) 3368c2ecf20Sopenharmony_ci usb_put_function(f_uac1); 3378c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(fi_uac1)) 3388c2ecf20Sopenharmony_ci usb_put_function_instance(fi_uac1); 3398c2ecf20Sopenharmony_ci#else 3408c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_uac2)) 3418c2ecf20Sopenharmony_ci usb_put_function(f_uac2); 3428c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(fi_uac2)) 3438c2ecf20Sopenharmony_ci usb_put_function_instance(fi_uac2); 3448c2ecf20Sopenharmony_ci#endif 3458c2ecf20Sopenharmony_ci kfree(otg_desc[0]); 3468c2ecf20Sopenharmony_ci otg_desc[0] = NULL; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic struct usb_composite_driver audio_driver = { 3528c2ecf20Sopenharmony_ci .name = "g_audio", 3538c2ecf20Sopenharmony_ci .dev = &device_desc, 3548c2ecf20Sopenharmony_ci .strings = audio_strings, 3558c2ecf20Sopenharmony_ci .max_speed = USB_SPEED_HIGH, 3568c2ecf20Sopenharmony_ci .bind = audio_bind, 3578c2ecf20Sopenharmony_ci .unbind = audio_unbind, 3588c2ecf20Sopenharmony_ci}; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cimodule_usb_composite_driver(audio_driver); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 3638c2ecf20Sopenharmony_ciMODULE_AUTHOR("Bryan Wu <cooloney@kernel.org>"); 3648c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3658c2ecf20Sopenharmony_ci 366