18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * multi.c -- Multifunction Composite driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 David Brownell 68c2ecf20Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation 78c2ecf20Sopenharmony_ci * Copyright (C) 2009 Samsung Electronics 88c2ecf20Sopenharmony_ci * Author: Michal Nazarewicz (mina86@mina86.com) 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "u_serial.h" 178c2ecf20Sopenharmony_ci#if defined USB_ETH_RNDIS 188c2ecf20Sopenharmony_ci# undef USB_ETH_RNDIS 198c2ecf20Sopenharmony_ci#endif 208c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_G_MULTI_RNDIS 218c2ecf20Sopenharmony_ci# define USB_ETH_RNDIS y 228c2ecf20Sopenharmony_ci#endif 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define DRIVER_DESC "Multifunction Composite Gadget" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michal Nazarewicz"); 298c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "f_mass_storage.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include "u_ecm.h" 358c2ecf20Sopenharmony_ci#ifdef USB_ETH_RNDIS 368c2ecf20Sopenharmony_ci# include "u_rndis.h" 378c2ecf20Sopenharmony_ci# include "rndis.h" 388c2ecf20Sopenharmony_ci#endif 398c2ecf20Sopenharmony_ci#include "u_ether.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciUSB_GADGET_COMPOSITE_OPTIONS(); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciUSB_ETHERNET_MODULE_PARAMETERS(); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/***************************** Device Descriptor ****************************/ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define MULTI_VENDOR_NUM 0x1d6b /* Linux Foundation */ 488c2ecf20Sopenharmony_ci#define MULTI_PRODUCT_NUM 0x0104 /* Multifunction Composite Gadget */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cienum { 528c2ecf20Sopenharmony_ci __MULTI_NO_CONFIG, 538c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_G_MULTI_RNDIS 548c2ecf20Sopenharmony_ci MULTI_RNDIS_CONFIG_NUM, 558c2ecf20Sopenharmony_ci#endif 568c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_G_MULTI_CDC 578c2ecf20Sopenharmony_ci MULTI_CDC_CONFIG_NUM, 588c2ecf20Sopenharmony_ci#endif 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic struct usb_device_descriptor device_desc = { 638c2ecf20Sopenharmony_ci .bLength = sizeof device_desc, 648c2ecf20Sopenharmony_ci .bDescriptorType = USB_DT_DEVICE, 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* .bcdUSB = DYNAMIC */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci .bDeviceClass = USB_CLASS_MISC /* 0xEF */, 698c2ecf20Sopenharmony_ci .bDeviceSubClass = 2, 708c2ecf20Sopenharmony_ci .bDeviceProtocol = 1, 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* Vendor and product id can be overridden by module parameters. */ 738c2ecf20Sopenharmony_ci .idVendor = cpu_to_le16(MULTI_VENDOR_NUM), 748c2ecf20Sopenharmony_ci .idProduct = cpu_to_le16(MULTI_PRODUCT_NUM), 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic const struct usb_descriptor_header *otg_desc[2]; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cienum { 808c2ecf20Sopenharmony_ci MULTI_STRING_RNDIS_CONFIG_IDX = USB_GADGET_FIRST_AVAIL_IDX, 818c2ecf20Sopenharmony_ci MULTI_STRING_CDC_CONFIG_IDX, 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic struct usb_string strings_dev[] = { 858c2ecf20Sopenharmony_ci [USB_GADGET_MANUFACTURER_IDX].s = "", 868c2ecf20Sopenharmony_ci [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, 878c2ecf20Sopenharmony_ci [USB_GADGET_SERIAL_IDX].s = "", 888c2ecf20Sopenharmony_ci [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS", 898c2ecf20Sopenharmony_ci [MULTI_STRING_CDC_CONFIG_IDX].s = "Multifunction with CDC ECM", 908c2ecf20Sopenharmony_ci { } /* end of list */ 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic struct usb_gadget_strings *dev_strings[] = { 948c2ecf20Sopenharmony_ci &(struct usb_gadget_strings){ 958c2ecf20Sopenharmony_ci .language = 0x0409, /* en-us */ 968c2ecf20Sopenharmony_ci .strings = strings_dev, 978c2ecf20Sopenharmony_ci }, 988c2ecf20Sopenharmony_ci NULL, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/****************************** Configurations ******************************/ 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic struct fsg_module_parameters fsg_mod_data = { .stall = 1 }; 1078c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_GADGET_DEBUG_FILES 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#else 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* 1148c2ecf20Sopenharmony_ci * Number of buffers we will use. 1158c2ecf20Sopenharmony_ci * 2 is usually enough for good buffering pipeline 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciFSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_acm; 1248c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_msg; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/********** RNDIS **********/ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#ifdef USB_ETH_RNDIS 1298c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_rndis; 1308c2ecf20Sopenharmony_cistatic struct usb_function *f_acm_rndis; 1318c2ecf20Sopenharmony_cistatic struct usb_function *f_rndis; 1328c2ecf20Sopenharmony_cistatic struct usb_function *f_msg_rndis; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int rndis_do_config(struct usb_configuration *c) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci int ret; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (gadget_is_otg(c->cdev->gadget)) { 1398c2ecf20Sopenharmony_ci c->descriptors = otg_desc; 1408c2ecf20Sopenharmony_ci c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci f_rndis = usb_get_function(fi_rndis); 1448c2ecf20Sopenharmony_ci if (IS_ERR(f_rndis)) 1458c2ecf20Sopenharmony_ci return PTR_ERR(f_rndis); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci ret = usb_add_function(c, f_rndis); 1488c2ecf20Sopenharmony_ci if (ret < 0) 1498c2ecf20Sopenharmony_ci goto err_func_rndis; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci f_acm_rndis = usb_get_function(fi_acm); 1528c2ecf20Sopenharmony_ci if (IS_ERR(f_acm_rndis)) { 1538c2ecf20Sopenharmony_ci ret = PTR_ERR(f_acm_rndis); 1548c2ecf20Sopenharmony_ci goto err_func_acm; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci ret = usb_add_function(c, f_acm_rndis); 1588c2ecf20Sopenharmony_ci if (ret) 1598c2ecf20Sopenharmony_ci goto err_conf; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci f_msg_rndis = usb_get_function(fi_msg); 1628c2ecf20Sopenharmony_ci if (IS_ERR(f_msg_rndis)) { 1638c2ecf20Sopenharmony_ci ret = PTR_ERR(f_msg_rndis); 1648c2ecf20Sopenharmony_ci goto err_fsg; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci ret = usb_add_function(c, f_msg_rndis); 1688c2ecf20Sopenharmony_ci if (ret) 1698c2ecf20Sopenharmony_ci goto err_run; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci return 0; 1728c2ecf20Sopenharmony_cierr_run: 1738c2ecf20Sopenharmony_ci usb_put_function(f_msg_rndis); 1748c2ecf20Sopenharmony_cierr_fsg: 1758c2ecf20Sopenharmony_ci usb_remove_function(c, f_acm_rndis); 1768c2ecf20Sopenharmony_cierr_conf: 1778c2ecf20Sopenharmony_ci usb_put_function(f_acm_rndis); 1788c2ecf20Sopenharmony_cierr_func_acm: 1798c2ecf20Sopenharmony_ci usb_remove_function(c, f_rndis); 1808c2ecf20Sopenharmony_cierr_func_rndis: 1818c2ecf20Sopenharmony_ci usb_put_function(f_rndis); 1828c2ecf20Sopenharmony_ci return ret; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic __ref int rndis_config_register(struct usb_composite_dev *cdev) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci static struct usb_configuration config = { 1888c2ecf20Sopenharmony_ci .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM, 1898c2ecf20Sopenharmony_ci .bmAttributes = USB_CONFIG_ATT_SELFPOWER, 1908c2ecf20Sopenharmony_ci }; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s; 1938c2ecf20Sopenharmony_ci config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return usb_add_config(cdev, &config, rndis_do_config); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci#else 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic __ref int rndis_config_register(struct usb_composite_dev *cdev) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci#endif 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/********** CDC ECM **********/ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_G_MULTI_CDC 2118c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_ecm; 2128c2ecf20Sopenharmony_cistatic struct usb_function *f_acm_multi; 2138c2ecf20Sopenharmony_cistatic struct usb_function *f_ecm; 2148c2ecf20Sopenharmony_cistatic struct usb_function *f_msg_multi; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int cdc_do_config(struct usb_configuration *c) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci int ret; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (gadget_is_otg(c->cdev->gadget)) { 2218c2ecf20Sopenharmony_ci c->descriptors = otg_desc; 2228c2ecf20Sopenharmony_ci c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci f_ecm = usb_get_function(fi_ecm); 2268c2ecf20Sopenharmony_ci if (IS_ERR(f_ecm)) 2278c2ecf20Sopenharmony_ci return PTR_ERR(f_ecm); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci ret = usb_add_function(c, f_ecm); 2308c2ecf20Sopenharmony_ci if (ret < 0) 2318c2ecf20Sopenharmony_ci goto err_func_ecm; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* implicit port_num is zero */ 2348c2ecf20Sopenharmony_ci f_acm_multi = usb_get_function(fi_acm); 2358c2ecf20Sopenharmony_ci if (IS_ERR(f_acm_multi)) { 2368c2ecf20Sopenharmony_ci ret = PTR_ERR(f_acm_multi); 2378c2ecf20Sopenharmony_ci goto err_func_acm; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci ret = usb_add_function(c, f_acm_multi); 2418c2ecf20Sopenharmony_ci if (ret) 2428c2ecf20Sopenharmony_ci goto err_conf; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci f_msg_multi = usb_get_function(fi_msg); 2458c2ecf20Sopenharmony_ci if (IS_ERR(f_msg_multi)) { 2468c2ecf20Sopenharmony_ci ret = PTR_ERR(f_msg_multi); 2478c2ecf20Sopenharmony_ci goto err_fsg; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci ret = usb_add_function(c, f_msg_multi); 2518c2ecf20Sopenharmony_ci if (ret) 2528c2ecf20Sopenharmony_ci goto err_run; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_cierr_run: 2568c2ecf20Sopenharmony_ci usb_put_function(f_msg_multi); 2578c2ecf20Sopenharmony_cierr_fsg: 2588c2ecf20Sopenharmony_ci usb_remove_function(c, f_acm_multi); 2598c2ecf20Sopenharmony_cierr_conf: 2608c2ecf20Sopenharmony_ci usb_put_function(f_acm_multi); 2618c2ecf20Sopenharmony_cierr_func_acm: 2628c2ecf20Sopenharmony_ci usb_remove_function(c, f_ecm); 2638c2ecf20Sopenharmony_cierr_func_ecm: 2648c2ecf20Sopenharmony_ci usb_put_function(f_ecm); 2658c2ecf20Sopenharmony_ci return ret; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic __ref int cdc_config_register(struct usb_composite_dev *cdev) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci static struct usb_configuration config = { 2718c2ecf20Sopenharmony_ci .bConfigurationValue = MULTI_CDC_CONFIG_NUM, 2728c2ecf20Sopenharmony_ci .bmAttributes = USB_CONFIG_ATT_SELFPOWER, 2738c2ecf20Sopenharmony_ci }; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s; 2768c2ecf20Sopenharmony_ci config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return usb_add_config(cdev, &config, cdc_do_config); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci#else 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic __ref int cdc_config_register(struct usb_composite_dev *cdev) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci#endif 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/****************************** Gadget Bind ******************************/ 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int __ref multi_bind(struct usb_composite_dev *cdev) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct usb_gadget *gadget = cdev->gadget; 2978c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_G_MULTI_CDC 2988c2ecf20Sopenharmony_ci struct f_ecm_opts *ecm_opts; 2998c2ecf20Sopenharmony_ci#endif 3008c2ecf20Sopenharmony_ci#ifdef USB_ETH_RNDIS 3018c2ecf20Sopenharmony_ci struct f_rndis_opts *rndis_opts; 3028c2ecf20Sopenharmony_ci#endif 3038c2ecf20Sopenharmony_ci struct fsg_opts *fsg_opts; 3048c2ecf20Sopenharmony_ci struct fsg_config config; 3058c2ecf20Sopenharmony_ci int status; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (!can_support_ecm(cdev->gadget)) { 3088c2ecf20Sopenharmony_ci dev_err(&gadget->dev, "controller '%s' not usable\n", 3098c2ecf20Sopenharmony_ci gadget->name); 3108c2ecf20Sopenharmony_ci return -EINVAL; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_G_MULTI_CDC 3148c2ecf20Sopenharmony_ci fi_ecm = usb_get_function_instance("ecm"); 3158c2ecf20Sopenharmony_ci if (IS_ERR(fi_ecm)) 3168c2ecf20Sopenharmony_ci return PTR_ERR(fi_ecm); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci gether_set_qmult(ecm_opts->net, qmult); 3218c2ecf20Sopenharmony_ci if (!gether_set_host_addr(ecm_opts->net, host_addr)) 3228c2ecf20Sopenharmony_ci pr_info("using host ethernet address: %s", host_addr); 3238c2ecf20Sopenharmony_ci if (!gether_set_dev_addr(ecm_opts->net, dev_addr)) 3248c2ecf20Sopenharmony_ci pr_info("using self ethernet address: %s", dev_addr); 3258c2ecf20Sopenharmony_ci#endif 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci#ifdef USB_ETH_RNDIS 3288c2ecf20Sopenharmony_ci fi_rndis = usb_get_function_instance("rndis"); 3298c2ecf20Sopenharmony_ci if (IS_ERR(fi_rndis)) { 3308c2ecf20Sopenharmony_ci status = PTR_ERR(fi_rndis); 3318c2ecf20Sopenharmony_ci goto fail; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci rndis_opts = container_of(fi_rndis, struct f_rndis_opts, func_inst); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci gether_set_qmult(rndis_opts->net, qmult); 3378c2ecf20Sopenharmony_ci if (!gether_set_host_addr(rndis_opts->net, host_addr)) 3388c2ecf20Sopenharmony_ci pr_info("using host ethernet address: %s", host_addr); 3398c2ecf20Sopenharmony_ci if (!gether_set_dev_addr(rndis_opts->net, dev_addr)) 3408c2ecf20Sopenharmony_ci pr_info("using self ethernet address: %s", dev_addr); 3418c2ecf20Sopenharmony_ci#endif 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci#if (defined CONFIG_USB_G_MULTI_CDC && defined USB_ETH_RNDIS) 3448c2ecf20Sopenharmony_ci /* 3458c2ecf20Sopenharmony_ci * If both ecm and rndis are selected then: 3468c2ecf20Sopenharmony_ci * 1) rndis borrows the net interface from ecm 3478c2ecf20Sopenharmony_ci * 2) since the interface is shared it must not be bound 3488c2ecf20Sopenharmony_ci * twice - in ecm's _and_ rndis' binds, so do it here. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci gether_set_gadget(ecm_opts->net, cdev->gadget); 3518c2ecf20Sopenharmony_ci status = gether_register_netdev(ecm_opts->net); 3528c2ecf20Sopenharmony_ci if (status) 3538c2ecf20Sopenharmony_ci goto fail0; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci rndis_borrow_net(fi_rndis, ecm_opts->net); 3568c2ecf20Sopenharmony_ci ecm_opts->bound = true; 3578c2ecf20Sopenharmony_ci#endif 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* set up serial link layer */ 3608c2ecf20Sopenharmony_ci fi_acm = usb_get_function_instance("acm"); 3618c2ecf20Sopenharmony_ci if (IS_ERR(fi_acm)) { 3628c2ecf20Sopenharmony_ci status = PTR_ERR(fi_acm); 3638c2ecf20Sopenharmony_ci goto fail0; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* set up mass storage function */ 3678c2ecf20Sopenharmony_ci fi_msg = usb_get_function_instance("mass_storage"); 3688c2ecf20Sopenharmony_ci if (IS_ERR(fi_msg)) { 3698c2ecf20Sopenharmony_ci status = PTR_ERR(fi_msg); 3708c2ecf20Sopenharmony_ci goto fail1; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers); 3738c2ecf20Sopenharmony_ci fsg_opts = fsg_opts_from_func_inst(fi_msg); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci fsg_opts->no_configfs = true; 3768c2ecf20Sopenharmony_ci status = fsg_common_set_num_buffers(fsg_opts->common, fsg_num_buffers); 3778c2ecf20Sopenharmony_ci if (status) 3788c2ecf20Sopenharmony_ci goto fail2; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci status = fsg_common_set_cdev(fsg_opts->common, cdev, config.can_stall); 3818c2ecf20Sopenharmony_ci if (status) 3828c2ecf20Sopenharmony_ci goto fail_set_cdev; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci fsg_common_set_sysfs(fsg_opts->common, true); 3858c2ecf20Sopenharmony_ci status = fsg_common_create_luns(fsg_opts->common, &config); 3868c2ecf20Sopenharmony_ci if (status) 3878c2ecf20Sopenharmony_ci goto fail_set_cdev; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci fsg_common_set_inquiry_string(fsg_opts->common, config.vendor_name, 3908c2ecf20Sopenharmony_ci config.product_name); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* allocate string IDs */ 3938c2ecf20Sopenharmony_ci status = usb_string_ids_tab(cdev, strings_dev); 3948c2ecf20Sopenharmony_ci if (unlikely(status < 0)) 3958c2ecf20Sopenharmony_ci goto fail_string_ids; 3968c2ecf20Sopenharmony_ci device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (gadget_is_otg(gadget) && !otg_desc[0]) { 3998c2ecf20Sopenharmony_ci struct usb_descriptor_header *usb_desc; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci usb_desc = usb_otg_descriptor_alloc(gadget); 4028c2ecf20Sopenharmony_ci if (!usb_desc) 4038c2ecf20Sopenharmony_ci goto fail_string_ids; 4048c2ecf20Sopenharmony_ci usb_otg_descriptor_init(gadget, usb_desc); 4058c2ecf20Sopenharmony_ci otg_desc[0] = usb_desc; 4068c2ecf20Sopenharmony_ci otg_desc[1] = NULL; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* register configurations */ 4108c2ecf20Sopenharmony_ci status = rndis_config_register(cdev); 4118c2ecf20Sopenharmony_ci if (unlikely(status < 0)) 4128c2ecf20Sopenharmony_ci goto fail_otg_desc; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci status = cdc_config_register(cdev); 4158c2ecf20Sopenharmony_ci if (unlikely(status < 0)) 4168c2ecf20Sopenharmony_ci goto fail_otg_desc; 4178c2ecf20Sopenharmony_ci usb_composite_overwrite_options(cdev, &coverwrite); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* we're done */ 4208c2ecf20Sopenharmony_ci dev_info(&gadget->dev, DRIVER_DESC "\n"); 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* error recovery */ 4258c2ecf20Sopenharmony_cifail_otg_desc: 4268c2ecf20Sopenharmony_ci kfree(otg_desc[0]); 4278c2ecf20Sopenharmony_ci otg_desc[0] = NULL; 4288c2ecf20Sopenharmony_cifail_string_ids: 4298c2ecf20Sopenharmony_ci fsg_common_remove_luns(fsg_opts->common); 4308c2ecf20Sopenharmony_cifail_set_cdev: 4318c2ecf20Sopenharmony_ci fsg_common_free_buffers(fsg_opts->common); 4328c2ecf20Sopenharmony_cifail2: 4338c2ecf20Sopenharmony_ci usb_put_function_instance(fi_msg); 4348c2ecf20Sopenharmony_cifail1: 4358c2ecf20Sopenharmony_ci usb_put_function_instance(fi_acm); 4368c2ecf20Sopenharmony_cifail0: 4378c2ecf20Sopenharmony_ci#ifdef USB_ETH_RNDIS 4388c2ecf20Sopenharmony_ci usb_put_function_instance(fi_rndis); 4398c2ecf20Sopenharmony_cifail: 4408c2ecf20Sopenharmony_ci#endif 4418c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_G_MULTI_CDC 4428c2ecf20Sopenharmony_ci usb_put_function_instance(fi_ecm); 4438c2ecf20Sopenharmony_ci#endif 4448c2ecf20Sopenharmony_ci return status; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic int multi_unbind(struct usb_composite_dev *cdev) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_G_MULTI_CDC 4508c2ecf20Sopenharmony_ci usb_put_function(f_msg_multi); 4518c2ecf20Sopenharmony_ci#endif 4528c2ecf20Sopenharmony_ci#ifdef USB_ETH_RNDIS 4538c2ecf20Sopenharmony_ci usb_put_function(f_msg_rndis); 4548c2ecf20Sopenharmony_ci#endif 4558c2ecf20Sopenharmony_ci usb_put_function_instance(fi_msg); 4568c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_G_MULTI_CDC 4578c2ecf20Sopenharmony_ci usb_put_function(f_acm_multi); 4588c2ecf20Sopenharmony_ci#endif 4598c2ecf20Sopenharmony_ci#ifdef USB_ETH_RNDIS 4608c2ecf20Sopenharmony_ci usb_put_function(f_acm_rndis); 4618c2ecf20Sopenharmony_ci#endif 4628c2ecf20Sopenharmony_ci usb_put_function_instance(fi_acm); 4638c2ecf20Sopenharmony_ci#ifdef USB_ETH_RNDIS 4648c2ecf20Sopenharmony_ci usb_put_function(f_rndis); 4658c2ecf20Sopenharmony_ci usb_put_function_instance(fi_rndis); 4668c2ecf20Sopenharmony_ci#endif 4678c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_G_MULTI_CDC 4688c2ecf20Sopenharmony_ci usb_put_function(f_ecm); 4698c2ecf20Sopenharmony_ci usb_put_function_instance(fi_ecm); 4708c2ecf20Sopenharmony_ci#endif 4718c2ecf20Sopenharmony_ci kfree(otg_desc[0]); 4728c2ecf20Sopenharmony_ci otg_desc[0] = NULL; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci return 0; 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/****************************** Some noise ******************************/ 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic struct usb_composite_driver multi_driver = { 4828c2ecf20Sopenharmony_ci .name = "g_multi", 4838c2ecf20Sopenharmony_ci .dev = &device_desc, 4848c2ecf20Sopenharmony_ci .strings = dev_strings, 4858c2ecf20Sopenharmony_ci .max_speed = USB_SPEED_SUPER, 4868c2ecf20Sopenharmony_ci .bind = multi_bind, 4878c2ecf20Sopenharmony_ci .unbind = multi_unbind, 4888c2ecf20Sopenharmony_ci .needs_serial = 1, 4898c2ecf20Sopenharmony_ci}; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cimodule_usb_composite_driver(multi_driver); 492