From cd209ee52b849586bc1a17b30fd869a369f100d9 Mon Sep 17 00:00:00 2001 From: Elson Roy Serrao Date: Tue, 6 Apr 2021 14:15:54 -0700 Subject: [PATCH 1/2] usb: gadget: Add qti_usb gadget driver This change adds qti_gadget driver for early USB enumeration. This is a snapshot of the driver from msm-4.14 as of commit 26acafd0651("usb: gadget: qti: Add support for MBIM OS descriptor handling"). Change-Id: Ie6d3a6584d396132827949a30608d1efb2408e77 Signed-off-by: Elson Roy Serrao --- drivers/usb/gadget/function/f_gsi.c | 9 + drivers/usb/gadget/function/f_gsi.h | 3 + drivers/usb/gadget/legacy/Kconfig | 10 + drivers/usb/gadget/legacy/Makefile | 2 + drivers/usb/gadget/legacy/qti_gadget.c | 677 +++++++++++++++++++++++++ include/linux/usb/composite.h | 3 + 6 files changed, 704 insertions(+) create mode 100644 drivers/usb/gadget/legacy/qti_gadget.c diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 689c64630dca..ca805f812663 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -3000,6 +3000,7 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) struct gsi_function_bind_info info = {0}; struct f_gsi *gsi = func_to_gsi(f); struct rndis_params *params; + struct usb_os_desc *descs[1]; struct gsi_opts *opts; int status; __u8 class; @@ -3202,6 +3203,14 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) f->os_desc_n = 1; f->os_desc_table[0].os_desc = &opts->os_desc; f->os_desc_table[0].if_id = gsi->data_id; + opts->os_desc.ext_compat_id = opts->ext_compat_id; + descs[0] = &opts->os_desc; + snprintf(sub_compatible_id, sizeof(sub_compatible_id), + "%u", c->bConfigurationValue); + memcpy(descs[0]->ext_compat_id, compatible_id, + strlen(compatible_id)); + memcpy(descs[0]->ext_compat_id + 8, sub_compatible_id, + strlen(sub_compatible_id)); } break; case IPA_USB_RMNET: diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index a9993cfdfb8a..8230c581772c 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -88,6 +88,9 @@ /* ID for Microsoft OS String */ #define GSI_MBIM_OS_STRING_ID 0xEE +static char compatible_id[256] = "ALTRCFG"; +static char sub_compatible_id[8]; + #define EVT_NONE 0 #define EVT_UNINITIALIZED 1 #define EVT_INITIALIZED 2 diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index abf7a059427f..e33c138f6e2d 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -350,6 +350,16 @@ config USB_G_PRINTER For more information, see Documentation/usb/gadget_printer.rst which includes sample code for accessing the device file. +config USB_G_QTI + tristate "QTI composite gadget" + select USB_LIBCOMPOSITE + help + This gadget provides support for multi-configuration + composite device. + Functions can be specified via devicetree properties, + along with PID and PID details which can also also be + updated using kernel commandline using module parameters. + if TTY config USB_CDC_COMPOSITE diff --git a/drivers/usb/gadget/legacy/Makefile b/drivers/usb/gadget/legacy/Makefile index 4d864bf82799..58ed5ecea086 100644 --- a/drivers/usb/gadget/legacy/Makefile +++ b/drivers/usb/gadget/legacy/Makefile @@ -24,6 +24,7 @@ g_webcam-y := webcam.o g_ncm-y := ncm.o g_acm_ms-y := acm_ms.o g_tcm_usb_gadget-y := tcm_usb_gadget.o +g_qti_gadget-y := qti_gadget.o obj-$(CONFIG_USB_ZERO) += g_zero.o obj-$(CONFIG_USB_AUDIO) += g_audio.o @@ -44,3 +45,4 @@ obj-$(CONFIG_USB_G_NCM) += g_ncm.o obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o obj-$(CONFIG_USB_RAW_GADGET) += raw_gadget.o +obj-$(CONFIG_USB_G_QTI) += g_qti_gadget.o diff --git a/drivers/usb/gadget/legacy/qti_gadget.c b/drivers/usb/gadget/legacy/qti_gadget.c new file mode 100644 index 000000000000..dc8af82d3992 --- /dev/null +++ b/drivers/usb/gadget/legacy/qti_gadget.c @@ -0,0 +1,677 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +struct qti_usb_function { + struct usb_function_instance *fi; + struct usb_function *f; + + struct list_head list; +}; + +#define MAX_FUNC_NAME_LEN 48 +#define MAX_CFG_NAME_LEN 128 + +#define QW_SIGN_LEN 14 + +char qw_sign[QW_SIGN_LEN] = "MSFT100"; + +struct qti_usb_config { + struct usb_configuration c; + + /* List of functions bound to this config */ + struct list_head func_list; + /* List of qti_usb_functions bound to this config */ + struct list_head qti_funcs; +}; + +struct qti_usb_gadget { + struct usb_composite_dev cdev; + struct usb_composite_driver composite; + + const char *composition_funcs; + bool enabled; + struct device *dev; + struct device_node *cfg_node; +}; + +static char manufacturer_string[256] = "Qualcomm Technologies, Inc"; +module_param_string(manufacturer, manufacturer_string, + sizeof(manufacturer_string), 0644); +MODULE_PARM_DESC(quirks, "String representing name of manufacturer"); + +static char product_string[256] = "USB_device!_SN:12345"; +module_param_string(product, product_string, + sizeof(product_string), 0644); +MODULE_PARM_DESC(quirks, "String representing product string"); + +static char serialno_string[256] = "12345"; + +static char usb_pid_string[256]; +module_param_string(usb_pid, usb_pid_string, sizeof(usb_pid_string), 0644); +MODULE_PARM_DESC(quirks, "String representing product id"); + +/* String Table */ +static struct usb_string strings_dev[] = { + [USB_GADGET_MANUFACTURER_IDX].s = manufacturer_string, + [USB_GADGET_PRODUCT_IDX].s = product_string, + [USB_GADGET_SERIAL_IDX].s = serialno_string, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab_dev = { + .language = 0x0409, /* en-us */ + .strings = strings_dev, +}; + +static struct usb_gadget_strings *dev_strings[] = { + &stringtab_dev, + NULL, +}; + +static void qti_configs_remove_funcs(struct qti_usb_gadget *qg) +{ + struct usb_configuration *c; + + list_for_each_entry(c, &qg->cdev.configs, list) { + struct qti_usb_config *cfg; + struct usb_function *f, *tmp; + + cfg = container_of(c, struct qti_usb_config, c); + + list_for_each_entry_safe_reverse(f, tmp, &c->functions, list) { + + list_move(&f->list, &cfg->func_list); + if (f->unbind) { + dev_dbg(&qg->cdev.gadget->dev, + "unbind function '%s'/%pK\n", + f->name, f); + f->unbind(c, f); + } + } + c->fullspeed = 0; + c->highspeed = 0; + c->superspeed = 0; + c->superspeed_plus = 0; + c->next_interface_id = 0; + memset(c->interface, 0, sizeof(c->interface)); + } +} + +static int qti_composite_bind(struct usb_gadget *gadget, + struct usb_gadget_driver *gdriver) +{ + struct usb_composite_driver *composite = to_cdriver(gdriver); + struct qti_usb_gadget *qg = container_of(composite, + struct qti_usb_gadget, composite); + struct usb_composite_dev *cdev = &qg->cdev; + struct usb_configuration *c; + struct usb_string *s; + int ret = -EINVAL; + + cdev->gadget = gadget; + set_gadget_data(gadget, cdev); + spin_lock_init(&qg->cdev.lock); + + ret = composite_dev_prepare(composite, cdev); + if (ret) + return ret; + + if (list_empty(&cdev->configs)) { + pr_err("No configurations found in %s.\n", composite->name); + ret = -EINVAL; + goto composite_cleanup; + } + + list_for_each_entry(c, &cdev->configs, list) { + struct qti_usb_config *qcfg; + + qcfg = container_of(c, struct qti_usb_config, c); + if (list_empty(&qcfg->func_list)) { + pr_err("Config %s/%d of %s doesn't have a function.\n", + c->label, c->bConfigurationValue, + qg->composite.name); + goto composite_cleanup; + } + } + + s = usb_gstrings_attach(cdev, dev_strings, USB_GADGET_FIRST_AVAIL_IDX); + if (IS_ERR(s)) { + ret = PTR_ERR(s); + goto composite_cleanup; + } + + cdev->desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id; + cdev->desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id; + cdev->desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id; + + /* Go through all configs, attach all functions */ + list_for_each_entry(c, &qg->cdev.configs, list) { + struct qti_usb_config *qcfg; + struct usb_function *f, *tmp; + + qcfg = container_of(c, struct qti_usb_config, c); + + list_for_each_entry_safe(f, tmp, &qcfg->func_list, list) { + list_del(&f->list); + ret = usb_add_function(c, f); + if (ret) { + list_add(&f->list, &qcfg->func_list); + goto remove_funcs; + } + } + usb_ep_autoconfig_reset(cdev->gadget); + } + + if (cdev->use_os_string) { + ret = composite_os_desc_req_prepare(cdev, gadget->ep0); + if (ret) + goto remove_funcs; + } + + usb_ep_autoconfig_reset(cdev->gadget); + + return 0; + +remove_funcs: + qti_configs_remove_funcs(qg); +composite_cleanup: + composite_dev_cleanup(cdev); + return ret; +} + +static void qti_composite_unbind(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev; + struct qti_usb_gadget *qg; + + cdev = get_gadget_data(gadget); + qg = container_of(cdev, struct qti_usb_gadget, cdev); + + qti_configs_remove_funcs(qg); + composite_dev_cleanup(cdev); + usb_ep_autoconfig_reset(cdev->gadget); + cdev->gadget = NULL; + set_gadget_data(gadget, NULL); +} + +static const struct usb_gadget_driver qti_gadget_driver = { + .bind = qti_composite_bind, + .unbind = qti_composite_unbind, + .setup = composite_setup, + .reset = composite_disconnect, + .disconnect = composite_disconnect, + .suspend = composite_suspend, + .resume = composite_resume, + + .max_speed = USB_SPEED_SUPER_PLUS, + .driver = { + .owner = THIS_MODULE, + .name = "qti-gadget", + }, +}; + +static void qti_usb_funcs_free(struct qti_usb_config *qcfg) +{ + struct usb_function *f, *tmp; + struct qti_usb_function *qf, *qf_tmp; + + list_for_each_entry_safe(f, tmp, &qcfg->func_list, list) { + list_del(&f->list); + usb_put_function(f); + + /* find corresponding function_instance and free it */ + list_for_each_entry_safe(qf, qf_tmp, &qcfg->qti_funcs, list) { + if (qf->f == f) { + list_del(&qf->list); + usb_put_function_instance(qf->fi); + kfree(qf); + break; + } + } + } +} + +static void qti_cleanup_configs_funcs(struct qti_usb_gadget *qg) +{ + struct usb_configuration *c, *c_tmp; + + list_for_each_entry_safe(c, c_tmp, &qg->cdev.configs, list) { + struct qti_usb_config *qcfg; + + qcfg = container_of(c, struct qti_usb_config, c); + WARN_ON(!list_empty(&qcfg->c.functions)); + + qti_usb_funcs_free(qcfg); + + list_del(&qcfg->c.list); + kfree(qcfg->c.label); + kfree(qcfg); + } +} + +static int qti_usb_func_alloc(struct qti_usb_config *qcfg, + const char *name) +{ + struct qti_usb_function *qf; + struct usb_function_instance *fi; + struct usb_composite_dev *cdev = qcfg->c.cdev; + struct usb_function *f; + char buf[MAX_FUNC_NAME_LEN]; + char *func_name; + char *instance_name; + int ret; + + ret = scnprintf(buf, MAX_FUNC_NAME_LEN, "%s", name); + if (ret >= MAX_FUNC_NAME_LEN) + return -ENAMETOOLONG; + + func_name = buf; + instance_name = strnchr(func_name, MAX_FUNC_NAME_LEN, '.'); + if (!instance_name) { + pr_err("Can't find . in .:%s\n", buf); + return -EINVAL; + } + *instance_name = '\0'; + instance_name++; + + qf = kzalloc(sizeof(*qf), GFP_KERNEL); + if (!qf) + return -ENOMEM; + + fi = usb_get_function_instance(func_name); + if (IS_ERR(fi)) { + kfree(qf); + return PTR_ERR(fi); + } + qf->fi = fi; + + if (fi->set_inst_name) { + ret = fi->set_inst_name(fi, instance_name); + if (ret) { + kfree(qf); + usb_put_function_instance(fi); + return ret; + } + } + + f = usb_get_function(fi); + if (IS_ERR(f)) { + kfree(qf); + usb_put_function_instance(fi); + return PTR_ERR(f); + } + qf->f = f; + list_add_tail(&qf->list, &qcfg->qti_funcs); + + /* stash the function until we bind it to the gadget */ + list_add_tail(&f->list, &qcfg->func_list); + + if (!strcmp(instance_name, "mbim")) { + cdev->os_desc_config = &qcfg->c; + cdev->use_os_string = true; + cdev->b_vendor_code = 0xA5; + memcpy(cdev->qw_sign, qw_sign, QW_SIGN_LEN); + } + + return 0; +} + +static int qti_usb_funcs_alloc(struct qti_usb_config *qcfg, + const char *funcs) +{ + char buf[MAX_CFG_NAME_LEN]; + char *fn_name, *next_fn; + int ret = 0; + + ret = scnprintf(buf, MAX_CFG_NAME_LEN, "%s", funcs); + if (ret >= MAX_CFG_NAME_LEN) + return -ENAMETOOLONG; + + fn_name = buf; + while (fn_name) { + next_fn = strnchr(fn_name, MAX_CFG_NAME_LEN, ','); + if (next_fn) + *next_fn++ = '\0'; + + ret = qti_usb_func_alloc(qcfg, fn_name); + if (ret) { + qti_usb_funcs_free(qcfg); + break; + } + + fn_name = next_fn; + } + + return ret; +} + +static int qti_usb_config_add(struct qti_usb_gadget *gadget, + const char *name, u8 num) +{ + struct qti_usb_config *qcfg; + int ret = 0, val = 0; + + qcfg = kzalloc(sizeof(*qcfg), GFP_KERNEL); + if (!qcfg) + return -ENOMEM; + + qcfg->c.label = kstrdup(name, GFP_KERNEL); + if (!qcfg->c.label) { + ret = -ENOMEM; + goto free_cfg; + } + qcfg->c.bConfigurationValue = num; + qcfg->c.bmAttributes = USB_CONFIG_ATT_ONE; + qcfg->c.MaxPower = CONFIG_USB_GADGET_VBUS_DRAW; + + ret = of_property_read_u32(gadget->cfg_node, "qcom,bmAttributes", &val); + if (!ret) + qcfg->c.bmAttributes = (u8)val; + + INIT_LIST_HEAD(&qcfg->func_list); + INIT_LIST_HEAD(&qcfg->qti_funcs); + + ret = usb_add_config_only(&gadget->cdev, &qcfg->c); + if (ret) + goto free_label; + + ret = qti_usb_funcs_alloc(qcfg, name); + if (ret) + goto cfg_del; + + return ret; + +cfg_del: + list_del(&qcfg->c.list); +free_label: + kfree(qcfg->c.label); +free_cfg: + kfree(qcfg); + return ret; + +} + +static int qti_usb_configs_make(struct qti_usb_gadget *gadget, + const char *cfgs) +{ + char buf[MAX_CFG_NAME_LEN]; + char *cfg_name, *next_cfg; + int ret = 0; + u8 num = 1; + + ret = scnprintf(buf, MAX_CFG_NAME_LEN, "%s", cfgs); + if (ret >= MAX_CFG_NAME_LEN) + return -ENAMETOOLONG; + + cfg_name = buf; + while (cfg_name) { + next_cfg = strnchr(cfg_name, MAX_CFG_NAME_LEN, '|'); + if (next_cfg) + *next_cfg++ = '\0'; + + ret = qti_usb_config_add(gadget, cfg_name, num); + if (ret) + break; + + cfg_name = next_cfg; + num++; + } + + return ret; +} + +static int qti_gadget_register(struct qti_usb_gadget *qg) +{ + int ret; + + if (qg->enabled) + return -EINVAL; + + ret = qti_usb_configs_make(qg, qg->composition_funcs); + if (ret) + return ret; + + qg->cdev.desc.bLength = USB_DT_DEVICE_SIZE; + qg->cdev.desc.bDescriptorType = USB_DT_DEVICE; + qg->cdev.desc.bcdDevice = cpu_to_le16(get_default_bcdDevice()); + + qg->composite.gadget_driver = qti_gadget_driver; + qg->composite.max_speed = qti_gadget_driver.max_speed; + + qg->composite.gadget_driver.function = kstrdup("qti-gadget", + GFP_KERNEL); + qg->composite.name = qg->composite.gadget_driver.function; + + if (!qg->composite.gadget_driver.function) { + ret = -ENOMEM; + goto free_configs; + } + + ret = usb_gadget_probe_driver(&qg->composite.gadget_driver); + if (ret) + goto free_name; + + qg->enabled = true; + + return 0; + +free_name: + kfree(qg->composite.gadget_driver.function); +free_configs: + qti_cleanup_configs_funcs(qg); + + return ret; +} + +static void qti_gadget_unregister(struct qti_usb_gadget *qg) +{ + if (!qg->enabled) + return; + + usb_gadget_unregister_driver(&qg->composite.gadget_driver); + kfree(qg->composite.gadget_driver.function); + qti_cleanup_configs_funcs(qg); + + qg->enabled = false; +} + +static int qti_gadget_get_properties(struct qti_usb_gadget *gadget) +{ + struct device *dev = gadget->dev; + struct device_node *child = NULL; + int ret = 0, val = 0, pid = 0; + char *start = NULL, *end = NULL; + + ret = device_property_read_u32(dev, "qcom,vid", &val); + if (ret) { + dev_err(dev, "USB gadget idVendor not specified\n"); + return ret; + } + gadget->cdev.desc.idVendor = (u16)val; + + ret = device_property_read_u32(dev, "qcom,class", &val); + if (!ret) + gadget->cdev.desc.bDeviceClass = (u8)val; + + ret = device_property_read_u32(dev, "qcom,subclass", &val); + if (!ret) + gadget->cdev.desc.bDeviceSubClass = (u8)val; + + ret = device_property_read_u32(dev, "qcom,protocol", &val); + if (!ret) + gadget->cdev.desc.bDeviceProtocol = (u8)val; + + /* Check if pid passed via cmdline which takes precedence */ + if (usb_pid_string[0] != 0) { + ret = kstrtoint(usb_pid_string, 16, &val); + if (ret) + return ret; + } else { + ret = device_property_read_u32(dev, "qcom,default-pid", &val); + if (ret) { + dev_dbg(dev, "USB gadget default-pid not specified\n"); + return ret; + } + } + + pid = val; + + /* Extract serial # from kernel cmdline */ + start = strnstr(saved_command_line, "androidboot.serialno=", + strlen(saved_command_line)); + if (start) { + /* If serial # is at the end of the kernel cmdline + * it will be terminated by NULL character + */ + end = strchrnul(start, ' '); + start += strlen("androidboot.serialno="); + strlcpy(serialno_string, start, (end - start)+1); + } + + /* Product string contains a space but in kernel + * cmdline it will be passed with a special character + * '!' instead of space to maintain the design of + * cmdline parameters + */ + strreplace(product_string, '!', ' '); + + /* Go through all the child nodes and find matching pid */ + while ((child = of_get_next_child(dev->of_node, child)) != NULL) { + of_property_read_u32(child, "qcom,pid", &val); + if (val == pid) { + of_property_read_string(child, "qcom,composition", + &gadget->composition_funcs); + + gadget->cfg_node = child; + break; + } + } + + /* Check if couldn't find a matching composition */ + if (gadget->composition_funcs == NULL) + return -EINVAL; + + /* bail out if ffs is specified and let userspace handle it */ + if (strnstr(gadget->composition_funcs, "ffs.", + strlen(gadget->composition_funcs))) { + dev_err(dev, "user should enable ffs\n"); + return -EINVAL; + } + + gadget->cdev.desc.idProduct = (u16)pid; + + return 0; +} + +static ssize_t enabled_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qti_usb_gadget *qg = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%c\n", + qg->enabled ? 'Y' : 'N'); +} + +static ssize_t enabled_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct qti_usb_gadget *qg = dev_get_drvdata(dev); + bool enable; + int ret; + + ret = strtobool(buf, &enable); + if (ret) + return ret; + + if (enable) + qti_gadget_register(qg); + else + qti_gadget_unregister(qg); + + return count; +} +static DEVICE_ATTR_RW(enabled); + +static int qti_gadget_probe(struct platform_device *pdev) +{ + int ret; + struct device *dev = &pdev->dev; + struct qti_usb_gadget *gadget; + + gadget = devm_kzalloc(dev, sizeof(*gadget), GFP_KERNEL); + if (!gadget) + return -ENOMEM; + + platform_set_drvdata(pdev, gadget); + gadget->dev = dev; + INIT_LIST_HEAD(&gadget->cdev.configs); + INIT_LIST_HEAD(&gadget->cdev.gstrings); + + ret = qti_gadget_get_properties(gadget); + if (ret) + return ret; + + ret = qti_gadget_register(gadget); + if (ret) + return ret; + + device_create_file(&pdev->dev, &dev_attr_enabled); + + return 0; +} + +static int qti_gadget_remove(struct platform_device *pdev) +{ + struct qti_usb_gadget *qg = platform_get_drvdata(pdev); + + device_remove_file(&pdev->dev, &dev_attr_enabled); + qti_gadget_unregister(qg); + + return 0; +} + +static const struct of_device_id qti_gadget_dt_match[] = { + { + .compatible = "qcom,usb-gadget", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, qti_gadget_dt_match); + +static struct platform_driver qti_gadget_platform_driver = { + .driver = { + .name = "qti_usb_gadget", + .of_match_table = qti_gadget_dt_match, + }, + .probe = qti_gadget_probe, + .remove = qti_gadget_remove, +}; + +static int __init gadget_qti_init(void) +{ + int ret; + + ret = platform_driver_register(&qti_gadget_platform_driver); + if (ret) { + pr_err("%s: Failed to register qti gadget platform driver\n", + __func__); + } + + return ret; +} +module_init(gadget_qti_init); + +static void __exit gadget_qti_exit(void) +{ + platform_driver_unregister(&qti_gadget_platform_driver); +} +module_exit(gadget_qti_exit); diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index e34f53f40846..ebafa10cbdd3 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -578,6 +578,9 @@ struct usb_composite_overwrite { void usb_composite_overwrite_options(struct usb_composite_dev *cdev, struct usb_composite_overwrite *covr); +int composite_dev_prepare(struct usb_composite_driver *composite, + struct usb_composite_dev *dev); + static inline u16 get_default_bcdDevice(void) { u16 bcdDevice; From 3c50581cf66bd98ff3c8037edf0949bfefba8ea7 Mon Sep 17 00:00:00 2001 From: Elson Roy Serrao Date: Wed, 10 Mar 2021 16:12:18 -0800 Subject: [PATCH 2/2] defconfig: msm: Enable QTI composite gadget on sdxlemur Enable config for qti_usb gadget to enable usb_composition at boot time for sdxlemur. Change-Id: Ifb4ca6001c9516aef491be878afca8b2acb10caf Signed-off-by: Elson Roy Serrao --- arch/arm/configs/vendor/sdxlemur.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/vendor/sdxlemur.config b/arch/arm/configs/vendor/sdxlemur.config index 57b294c6c40f..401cf1e02acc 100644 --- a/arch/arm/configs/vendor/sdxlemur.config +++ b/arch/arm/configs/vendor/sdxlemur.config @@ -226,6 +226,7 @@ CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_USB_CONFIGFS_F_GSI=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_USB_CONFIGFS_F_UAC1=y +CONFIG_USB_G_QTI=y CONFIG_USB_BAM=y CONFIG_USB_RTL8152=y CONFIG_USB_NET_SMSC75XX=y