18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * nokia.c -- Nokia Composite Gadget Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008-2010 Nokia Corporation 68c2ecf20Sopenharmony_ci * Contact: Felipe Balbi <felipe.balbi@nokia.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This gadget driver borrows from serial.c which is: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) 118c2ecf20Sopenharmony_ci * Copyright (C) 2008 by David Brownell 128c2ecf20Sopenharmony_ci * Copyright (C) 2008 by Nokia Corporation 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/device.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "u_serial.h" 208c2ecf20Sopenharmony_ci#include "u_ether.h" 218c2ecf20Sopenharmony_ci#include "u_phonet.h" 228c2ecf20Sopenharmony_ci#include "u_ecm.h" 238c2ecf20Sopenharmony_ci#include "f_mass_storage.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Defines */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define NOKIA_VERSION_NUM 0x0211 288c2ecf20Sopenharmony_ci#define NOKIA_LONG_NAME "N900 (PC-Suite Mode)" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciUSB_GADGET_COMPOSITE_OPTIONS(); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ciUSB_ETHERNET_MODULE_PARAMETERS(); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic struct fsg_module_parameters fsg_mod_data = { 358c2ecf20Sopenharmony_ci .stall = 0, 368c2ecf20Sopenharmony_ci .luns = 2, 378c2ecf20Sopenharmony_ci .removable_count = 2, 388c2ecf20Sopenharmony_ci .removable = { 1, 1, }, 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_GADGET_DEBUG_FILES 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#else 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * Number of buffers we will use. 498c2ecf20Sopenharmony_ci * 2 is usually enough for good buffering pipeline 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#endif /* CONFIG_USB_DEBUG */ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ciFSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define NOKIA_VENDOR_ID 0x0421 /* Nokia */ 588c2ecf20Sopenharmony_ci#define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* string IDs are assigned dynamically */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic char manufacturer_nokia[] = "Nokia"; 658c2ecf20Sopenharmony_cistatic const char description_nokia[] = "PC-Suite Configuration"; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct usb_string strings_dev[] = { 688c2ecf20Sopenharmony_ci [USB_GADGET_MANUFACTURER_IDX].s = manufacturer_nokia, 698c2ecf20Sopenharmony_ci [USB_GADGET_PRODUCT_IDX].s = NOKIA_LONG_NAME, 708c2ecf20Sopenharmony_ci [USB_GADGET_SERIAL_IDX].s = "", 718c2ecf20Sopenharmony_ci [STRING_DESCRIPTION_IDX].s = description_nokia, 728c2ecf20Sopenharmony_ci { } /* end of list */ 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic struct usb_gadget_strings stringtab_dev = { 768c2ecf20Sopenharmony_ci .language = 0x0409, /* en-us */ 778c2ecf20Sopenharmony_ci .strings = strings_dev, 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic struct usb_gadget_strings *dev_strings[] = { 818c2ecf20Sopenharmony_ci &stringtab_dev, 828c2ecf20Sopenharmony_ci NULL, 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic struct usb_device_descriptor device_desc = { 868c2ecf20Sopenharmony_ci .bLength = USB_DT_DEVICE_SIZE, 878c2ecf20Sopenharmony_ci .bDescriptorType = USB_DT_DEVICE, 888c2ecf20Sopenharmony_ci /* .bcdUSB = DYNAMIC */ 898c2ecf20Sopenharmony_ci .bDeviceClass = USB_CLASS_COMM, 908c2ecf20Sopenharmony_ci .idVendor = cpu_to_le16(NOKIA_VENDOR_ID), 918c2ecf20Sopenharmony_ci .idProduct = cpu_to_le16(NOKIA_PRODUCT_ID), 928c2ecf20Sopenharmony_ci .bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM), 938c2ecf20Sopenharmony_ci /* .iManufacturer = DYNAMIC */ 948c2ecf20Sopenharmony_ci /* .iProduct = DYNAMIC */ 958c2ecf20Sopenharmony_ci .bNumConfigurations = 1, 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* Module */ 1018c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Nokia composite gadget driver for N900"); 1028c2ecf20Sopenharmony_ciMODULE_AUTHOR("Felipe Balbi"); 1038c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/*-------------------------------------------------------------------------*/ 1068c2ecf20Sopenharmony_cistatic struct usb_function *f_acm_cfg1; 1078c2ecf20Sopenharmony_cistatic struct usb_function *f_acm_cfg2; 1088c2ecf20Sopenharmony_cistatic struct usb_function *f_ecm_cfg1; 1098c2ecf20Sopenharmony_cistatic struct usb_function *f_ecm_cfg2; 1108c2ecf20Sopenharmony_cistatic struct usb_function *f_obex1_cfg1; 1118c2ecf20Sopenharmony_cistatic struct usb_function *f_obex2_cfg1; 1128c2ecf20Sopenharmony_cistatic struct usb_function *f_obex1_cfg2; 1138c2ecf20Sopenharmony_cistatic struct usb_function *f_obex2_cfg2; 1148c2ecf20Sopenharmony_cistatic struct usb_function *f_phonet_cfg1; 1158c2ecf20Sopenharmony_cistatic struct usb_function *f_phonet_cfg2; 1168c2ecf20Sopenharmony_cistatic struct usb_function *f_msg_cfg1; 1178c2ecf20Sopenharmony_cistatic struct usb_function *f_msg_cfg2; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic struct usb_configuration nokia_config_500ma_driver = { 1218c2ecf20Sopenharmony_ci .label = "Bus Powered", 1228c2ecf20Sopenharmony_ci .bConfigurationValue = 1, 1238c2ecf20Sopenharmony_ci /* .iConfiguration = DYNAMIC */ 1248c2ecf20Sopenharmony_ci .bmAttributes = USB_CONFIG_ATT_ONE, 1258c2ecf20Sopenharmony_ci .MaxPower = 500, 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic struct usb_configuration nokia_config_100ma_driver = { 1298c2ecf20Sopenharmony_ci .label = "Self Powered", 1308c2ecf20Sopenharmony_ci .bConfigurationValue = 2, 1318c2ecf20Sopenharmony_ci /* .iConfiguration = DYNAMIC */ 1328c2ecf20Sopenharmony_ci .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, 1338c2ecf20Sopenharmony_ci .MaxPower = 100, 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_acm; 1378c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_ecm; 1388c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_obex1; 1398c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_obex2; 1408c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_phonet; 1418c2ecf20Sopenharmony_cistatic struct usb_function_instance *fi_msg; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int nokia_bind_config(struct usb_configuration *c) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct usb_function *f_acm; 1468c2ecf20Sopenharmony_ci struct usb_function *f_phonet = NULL; 1478c2ecf20Sopenharmony_ci struct usb_function *f_obex1 = NULL; 1488c2ecf20Sopenharmony_ci struct usb_function *f_ecm; 1498c2ecf20Sopenharmony_ci struct usb_function *f_obex2 = NULL; 1508c2ecf20Sopenharmony_ci struct usb_function *f_msg; 1518c2ecf20Sopenharmony_ci int status = 0; 1528c2ecf20Sopenharmony_ci int obex1_stat = -1; 1538c2ecf20Sopenharmony_ci int obex2_stat = -1; 1548c2ecf20Sopenharmony_ci int phonet_stat = -1; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (!IS_ERR(fi_phonet)) { 1578c2ecf20Sopenharmony_ci f_phonet = usb_get_function(fi_phonet); 1588c2ecf20Sopenharmony_ci if (IS_ERR(f_phonet)) 1598c2ecf20Sopenharmony_ci pr_debug("could not get phonet function\n"); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (!IS_ERR(fi_obex1)) { 1638c2ecf20Sopenharmony_ci f_obex1 = usb_get_function(fi_obex1); 1648c2ecf20Sopenharmony_ci if (IS_ERR(f_obex1)) 1658c2ecf20Sopenharmony_ci pr_debug("could not get obex function 0\n"); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (!IS_ERR(fi_obex2)) { 1698c2ecf20Sopenharmony_ci f_obex2 = usb_get_function(fi_obex2); 1708c2ecf20Sopenharmony_ci if (IS_ERR(f_obex2)) 1718c2ecf20Sopenharmony_ci pr_debug("could not get obex function 1\n"); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci f_acm = usb_get_function(fi_acm); 1758c2ecf20Sopenharmony_ci if (IS_ERR(f_acm)) { 1768c2ecf20Sopenharmony_ci status = PTR_ERR(f_acm); 1778c2ecf20Sopenharmony_ci goto err_get_acm; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci f_ecm = usb_get_function(fi_ecm); 1818c2ecf20Sopenharmony_ci if (IS_ERR(f_ecm)) { 1828c2ecf20Sopenharmony_ci status = PTR_ERR(f_ecm); 1838c2ecf20Sopenharmony_ci goto err_get_ecm; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci f_msg = usb_get_function(fi_msg); 1878c2ecf20Sopenharmony_ci if (IS_ERR(f_msg)) { 1888c2ecf20Sopenharmony_ci status = PTR_ERR(f_msg); 1898c2ecf20Sopenharmony_ci goto err_get_msg; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_phonet)) { 1938c2ecf20Sopenharmony_ci phonet_stat = usb_add_function(c, f_phonet); 1948c2ecf20Sopenharmony_ci if (phonet_stat) 1958c2ecf20Sopenharmony_ci pr_debug("could not add phonet function\n"); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_obex1)) { 1998c2ecf20Sopenharmony_ci obex1_stat = usb_add_function(c, f_obex1); 2008c2ecf20Sopenharmony_ci if (obex1_stat) 2018c2ecf20Sopenharmony_ci pr_debug("could not add obex function 0\n"); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_obex2)) { 2058c2ecf20Sopenharmony_ci obex2_stat = usb_add_function(c, f_obex2); 2068c2ecf20Sopenharmony_ci if (obex2_stat) 2078c2ecf20Sopenharmony_ci pr_debug("could not add obex function 1\n"); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci status = usb_add_function(c, f_acm); 2118c2ecf20Sopenharmony_ci if (status) 2128c2ecf20Sopenharmony_ci goto err_conf; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci status = usb_add_function(c, f_ecm); 2158c2ecf20Sopenharmony_ci if (status) { 2168c2ecf20Sopenharmony_ci pr_debug("could not bind ecm config %d\n", status); 2178c2ecf20Sopenharmony_ci goto err_ecm; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci status = usb_add_function(c, f_msg); 2218c2ecf20Sopenharmony_ci if (status) 2228c2ecf20Sopenharmony_ci goto err_msg; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (c == &nokia_config_500ma_driver) { 2258c2ecf20Sopenharmony_ci f_acm_cfg1 = f_acm; 2268c2ecf20Sopenharmony_ci f_ecm_cfg1 = f_ecm; 2278c2ecf20Sopenharmony_ci f_phonet_cfg1 = f_phonet; 2288c2ecf20Sopenharmony_ci f_obex1_cfg1 = f_obex1; 2298c2ecf20Sopenharmony_ci f_obex2_cfg1 = f_obex2; 2308c2ecf20Sopenharmony_ci f_msg_cfg1 = f_msg; 2318c2ecf20Sopenharmony_ci } else { 2328c2ecf20Sopenharmony_ci f_acm_cfg2 = f_acm; 2338c2ecf20Sopenharmony_ci f_ecm_cfg2 = f_ecm; 2348c2ecf20Sopenharmony_ci f_phonet_cfg2 = f_phonet; 2358c2ecf20Sopenharmony_ci f_obex1_cfg2 = f_obex1; 2368c2ecf20Sopenharmony_ci f_obex2_cfg2 = f_obex2; 2378c2ecf20Sopenharmony_ci f_msg_cfg2 = f_msg; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return status; 2418c2ecf20Sopenharmony_cierr_msg: 2428c2ecf20Sopenharmony_ci usb_remove_function(c, f_ecm); 2438c2ecf20Sopenharmony_cierr_ecm: 2448c2ecf20Sopenharmony_ci usb_remove_function(c, f_acm); 2458c2ecf20Sopenharmony_cierr_conf: 2468c2ecf20Sopenharmony_ci if (!obex2_stat) 2478c2ecf20Sopenharmony_ci usb_remove_function(c, f_obex2); 2488c2ecf20Sopenharmony_ci if (!obex1_stat) 2498c2ecf20Sopenharmony_ci usb_remove_function(c, f_obex1); 2508c2ecf20Sopenharmony_ci if (!phonet_stat) 2518c2ecf20Sopenharmony_ci usb_remove_function(c, f_phonet); 2528c2ecf20Sopenharmony_ci usb_put_function(f_msg); 2538c2ecf20Sopenharmony_cierr_get_msg: 2548c2ecf20Sopenharmony_ci usb_put_function(f_ecm); 2558c2ecf20Sopenharmony_cierr_get_ecm: 2568c2ecf20Sopenharmony_ci usb_put_function(f_acm); 2578c2ecf20Sopenharmony_cierr_get_acm: 2588c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_obex2)) 2598c2ecf20Sopenharmony_ci usb_put_function(f_obex2); 2608c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_obex1)) 2618c2ecf20Sopenharmony_ci usb_put_function(f_obex1); 2628c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_phonet)) 2638c2ecf20Sopenharmony_ci usb_put_function(f_phonet); 2648c2ecf20Sopenharmony_ci return status; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic int nokia_bind(struct usb_composite_dev *cdev) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct usb_gadget *gadget = cdev->gadget; 2708c2ecf20Sopenharmony_ci struct fsg_opts *fsg_opts; 2718c2ecf20Sopenharmony_ci struct fsg_config fsg_config; 2728c2ecf20Sopenharmony_ci int status; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci status = usb_string_ids_tab(cdev, strings_dev); 2758c2ecf20Sopenharmony_ci if (status < 0) 2768c2ecf20Sopenharmony_ci goto err_usb; 2778c2ecf20Sopenharmony_ci device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; 2788c2ecf20Sopenharmony_ci device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; 2798c2ecf20Sopenharmony_ci status = strings_dev[STRING_DESCRIPTION_IDX].id; 2808c2ecf20Sopenharmony_ci nokia_config_500ma_driver.iConfiguration = status; 2818c2ecf20Sopenharmony_ci nokia_config_100ma_driver.iConfiguration = status; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (!gadget_is_altset_supported(gadget)) { 2848c2ecf20Sopenharmony_ci status = -ENODEV; 2858c2ecf20Sopenharmony_ci goto err_usb; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci fi_phonet = usb_get_function_instance("phonet"); 2898c2ecf20Sopenharmony_ci if (IS_ERR(fi_phonet)) 2908c2ecf20Sopenharmony_ci pr_debug("could not find phonet function\n"); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci fi_obex1 = usb_get_function_instance("obex"); 2938c2ecf20Sopenharmony_ci if (IS_ERR(fi_obex1)) 2948c2ecf20Sopenharmony_ci pr_debug("could not find obex function 1\n"); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci fi_obex2 = usb_get_function_instance("obex"); 2978c2ecf20Sopenharmony_ci if (IS_ERR(fi_obex2)) 2988c2ecf20Sopenharmony_ci pr_debug("could not find obex function 2\n"); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci fi_acm = usb_get_function_instance("acm"); 3018c2ecf20Sopenharmony_ci if (IS_ERR(fi_acm)) { 3028c2ecf20Sopenharmony_ci status = PTR_ERR(fi_acm); 3038c2ecf20Sopenharmony_ci goto err_obex2_inst; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci fi_ecm = usb_get_function_instance("ecm"); 3078c2ecf20Sopenharmony_ci if (IS_ERR(fi_ecm)) { 3088c2ecf20Sopenharmony_ci status = PTR_ERR(fi_ecm); 3098c2ecf20Sopenharmony_ci goto err_acm_inst; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci fi_msg = usb_get_function_instance("mass_storage"); 3138c2ecf20Sopenharmony_ci if (IS_ERR(fi_msg)) { 3148c2ecf20Sopenharmony_ci status = PTR_ERR(fi_msg); 3158c2ecf20Sopenharmony_ci goto err_ecm_inst; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* set up mass storage function */ 3198c2ecf20Sopenharmony_ci fsg_config_from_params(&fsg_config, &fsg_mod_data, fsg_num_buffers); 3208c2ecf20Sopenharmony_ci fsg_config.vendor_name = "Nokia"; 3218c2ecf20Sopenharmony_ci fsg_config.product_name = "N900"; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci fsg_opts = fsg_opts_from_func_inst(fi_msg); 3248c2ecf20Sopenharmony_ci fsg_opts->no_configfs = true; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci status = fsg_common_set_num_buffers(fsg_opts->common, fsg_num_buffers); 3278c2ecf20Sopenharmony_ci if (status) 3288c2ecf20Sopenharmony_ci goto err_msg_inst; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci status = fsg_common_set_cdev(fsg_opts->common, cdev, fsg_config.can_stall); 3318c2ecf20Sopenharmony_ci if (status) 3328c2ecf20Sopenharmony_ci goto err_msg_buf; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci fsg_common_set_sysfs(fsg_opts->common, true); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci status = fsg_common_create_luns(fsg_opts->common, &fsg_config); 3378c2ecf20Sopenharmony_ci if (status) 3388c2ecf20Sopenharmony_ci goto err_msg_buf; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci fsg_common_set_inquiry_string(fsg_opts->common, fsg_config.vendor_name, 3418c2ecf20Sopenharmony_ci fsg_config.product_name); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* finally register the configuration */ 3448c2ecf20Sopenharmony_ci status = usb_add_config(cdev, &nokia_config_500ma_driver, 3458c2ecf20Sopenharmony_ci nokia_bind_config); 3468c2ecf20Sopenharmony_ci if (status < 0) 3478c2ecf20Sopenharmony_ci goto err_msg_luns; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci status = usb_add_config(cdev, &nokia_config_100ma_driver, 3508c2ecf20Sopenharmony_ci nokia_bind_config); 3518c2ecf20Sopenharmony_ci if (status < 0) 3528c2ecf20Sopenharmony_ci goto err_put_cfg1; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci usb_composite_overwrite_options(cdev, &coverwrite); 3558c2ecf20Sopenharmony_ci dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cierr_put_cfg1: 3608c2ecf20Sopenharmony_ci usb_put_function(f_acm_cfg1); 3618c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_obex1_cfg1)) 3628c2ecf20Sopenharmony_ci usb_put_function(f_obex1_cfg1); 3638c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_obex2_cfg1)) 3648c2ecf20Sopenharmony_ci usb_put_function(f_obex2_cfg1); 3658c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_phonet_cfg1)) 3668c2ecf20Sopenharmony_ci usb_put_function(f_phonet_cfg1); 3678c2ecf20Sopenharmony_ci usb_put_function(f_ecm_cfg1); 3688c2ecf20Sopenharmony_cierr_msg_luns: 3698c2ecf20Sopenharmony_ci fsg_common_remove_luns(fsg_opts->common); 3708c2ecf20Sopenharmony_cierr_msg_buf: 3718c2ecf20Sopenharmony_ci fsg_common_free_buffers(fsg_opts->common); 3728c2ecf20Sopenharmony_cierr_msg_inst: 3738c2ecf20Sopenharmony_ci usb_put_function_instance(fi_msg); 3748c2ecf20Sopenharmony_cierr_ecm_inst: 3758c2ecf20Sopenharmony_ci usb_put_function_instance(fi_ecm); 3768c2ecf20Sopenharmony_cierr_acm_inst: 3778c2ecf20Sopenharmony_ci usb_put_function_instance(fi_acm); 3788c2ecf20Sopenharmony_cierr_obex2_inst: 3798c2ecf20Sopenharmony_ci if (!IS_ERR(fi_obex2)) 3808c2ecf20Sopenharmony_ci usb_put_function_instance(fi_obex2); 3818c2ecf20Sopenharmony_ci if (!IS_ERR(fi_obex1)) 3828c2ecf20Sopenharmony_ci usb_put_function_instance(fi_obex1); 3838c2ecf20Sopenharmony_ci if (!IS_ERR(fi_phonet)) 3848c2ecf20Sopenharmony_ci usb_put_function_instance(fi_phonet); 3858c2ecf20Sopenharmony_cierr_usb: 3868c2ecf20Sopenharmony_ci return status; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int nokia_unbind(struct usb_composite_dev *cdev) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_obex1_cfg2)) 3928c2ecf20Sopenharmony_ci usb_put_function(f_obex1_cfg2); 3938c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_obex2_cfg2)) 3948c2ecf20Sopenharmony_ci usb_put_function(f_obex2_cfg2); 3958c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_obex1_cfg1)) 3968c2ecf20Sopenharmony_ci usb_put_function(f_obex1_cfg1); 3978c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_obex2_cfg1)) 3988c2ecf20Sopenharmony_ci usb_put_function(f_obex2_cfg1); 3998c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_phonet_cfg1)) 4008c2ecf20Sopenharmony_ci usb_put_function(f_phonet_cfg1); 4018c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(f_phonet_cfg2)) 4028c2ecf20Sopenharmony_ci usb_put_function(f_phonet_cfg2); 4038c2ecf20Sopenharmony_ci usb_put_function(f_acm_cfg1); 4048c2ecf20Sopenharmony_ci usb_put_function(f_acm_cfg2); 4058c2ecf20Sopenharmony_ci usb_put_function(f_ecm_cfg1); 4068c2ecf20Sopenharmony_ci usb_put_function(f_ecm_cfg2); 4078c2ecf20Sopenharmony_ci usb_put_function(f_msg_cfg1); 4088c2ecf20Sopenharmony_ci usb_put_function(f_msg_cfg2); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci usb_put_function_instance(fi_msg); 4118c2ecf20Sopenharmony_ci usb_put_function_instance(fi_ecm); 4128c2ecf20Sopenharmony_ci if (!IS_ERR(fi_obex2)) 4138c2ecf20Sopenharmony_ci usb_put_function_instance(fi_obex2); 4148c2ecf20Sopenharmony_ci if (!IS_ERR(fi_obex1)) 4158c2ecf20Sopenharmony_ci usb_put_function_instance(fi_obex1); 4168c2ecf20Sopenharmony_ci if (!IS_ERR(fi_phonet)) 4178c2ecf20Sopenharmony_ci usb_put_function_instance(fi_phonet); 4188c2ecf20Sopenharmony_ci usb_put_function_instance(fi_acm); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic struct usb_composite_driver nokia_driver = { 4248c2ecf20Sopenharmony_ci .name = "g_nokia", 4258c2ecf20Sopenharmony_ci .dev = &device_desc, 4268c2ecf20Sopenharmony_ci .strings = dev_strings, 4278c2ecf20Sopenharmony_ci .max_speed = USB_SPEED_HIGH, 4288c2ecf20Sopenharmony_ci .bind = nokia_bind, 4298c2ecf20Sopenharmony_ci .unbind = nokia_unbind, 4308c2ecf20Sopenharmony_ci}; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cimodule_usb_composite_driver(nokia_driver); 433