diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 584841bb0c08..02aaa3e24b32 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -2965,6 +2965,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 gsi_opts *opts; int status; __u8 class; __u8 subclass; @@ -3157,18 +3158,15 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) info.notify_buf_len = sizeof(struct usb_cdc_notification); mbim_gsi_desc.wMaxSegmentSize = cpu_to_le16(0x800); - /* - * If MBIM is bound in a config other than the first, tell - * Windows about it by returning the num as a string in the - * OS descriptor's subCompatibleID field. Windows only supports - * up to config #4. - */ - if (c->bConfigurationValue >= 2 && - c->bConfigurationValue <= 4) { - log_event_dbg("MBIM in configuration %d", - c->bConfigurationValue); - mbim_gsi_ext_config_desc.function.subCompatibleID[0] = - c->bConfigurationValue + '0'; + if (cdev->use_os_string) { + f->os_desc_table = kzalloc(sizeof(*f->os_desc_table), + GFP_KERNEL); + if (!f->os_desc_table) + return -ENOMEM; + opts = container_of(f->fi, struct gsi_opts, func_inst); + 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; } break; case IPA_USB_RMNET: @@ -3331,6 +3329,7 @@ skip_ipa_init: dereg_rndis: rndis_deregister(gsi->params); + kfree(f->os_desc_table); fail: return status; } @@ -3365,8 +3364,11 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f) rndis_deregister(gsi->params); } - if (gsi->prot_id == IPA_USB_MBIM) - mbim_gsi_ext_config_desc.function.subCompatibleID[0] = 0; + if (gsi->prot_id == IPA_USB_MBIM) { + kfree(f->os_desc_table); + f->os_desc_table = NULL; + f->os_desc_n = 0; + } usb_free_all_descriptors(f); @@ -3766,6 +3768,8 @@ static int gsi_set_inst_name(struct usb_function_instance *fi, char gsi_inst_name[MAX_INST_NAME_LEN + sizeof("gsi.") + 1]; void *ipc_log_ctxt; struct gsi_opts *opts, *opts_prev; + struct usb_os_desc *descs[1]; + char *names[1]; opts = container_of(fi, struct gsi_opts, func_inst); @@ -3799,6 +3803,16 @@ static int gsi_set_inst_name(struct usb_function_instance *fi, fi->group.cg_item.ci_name, &gsi_func_ecm_type); + if (prot_id == IPA_USB_MBIM) { + opts->os_desc.ext_compat_id = opts->ext_compat_id; + INIT_LIST_HEAD(&opts->os_desc.ext_prop); + descs[0] = &opts->os_desc; + names[0] = "MBIM"; + opts->interf_group = usb_os_desc_prepare_interf_dir( + &opts->func_inst.group, 1, + descs, names, THIS_MODULE); + } + gsi = gsi_function_init(prot_id); if (IS_ERR(gsi)) return PTR_ERR(gsi); @@ -3847,6 +3861,8 @@ static void gsi_free_inst(struct usb_function_instance *f) } ipc_log_context_destroy(opts->gsi->ipc_log_ctxt); + if (opts && opts->interf_group) + kfree(opts->interf_group); /* Clear instance status */ gsi_inst_clean(opts); inst_status[prot_id].inst_exist = false; diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index c514d1eb4c9e..5ba7b5088db9 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -21,6 +21,8 @@ #include #include +#include "configfs.h" + #define GSI_RMNET_CTRL_NAME "rmnet_ctrl" #define GSI_MBIM_CTRL_NAME "android_mbim" #define GSI_DPL_CTRL_NAME "dpl_ctrl" @@ -334,6 +336,11 @@ static inline struct f_gsi *c_port_to_gsi(struct gsi_ctrl_port *d) struct gsi_opts { struct usb_function_instance func_inst; struct f_gsi *gsi; + + /* os desc support */ + struct config_group *interf_group; + char ext_compat_id[16]; + struct usb_os_desc os_desc; }; static inline struct gsi_opts *to_gsi_opts(struct config_item *item) @@ -1080,50 +1087,6 @@ static struct usb_gadget_strings *mbim_gsi_strings[] = { NULL, }; -/* Microsoft OS Descriptors */ - -/* - * We specify our own bMS_VendorCode byte which Windows will use - * as the bRequest value in subsequent device get requests. - */ -#define MBIM_VENDOR_CODE 0xA5 - -/* Microsoft Extended Configuration Descriptor Header Section */ -struct mbim_gsi_ext_config_desc_header { - __le32 dwLength; - __le16 bcdVersion; - __le16 wIndex; - __u8 bCount; - __u8 reserved[7]; -}; - -/* Microsoft Extended Configuration Descriptor Function Section */ -struct mbim_gsi_ext_config_desc_function { - __u8 bFirstInterfaceNumber; - __u8 bInterfaceCount; - __u8 compatibleID[8]; - __u8 subCompatibleID[8]; - __u8 reserved[6]; -}; - -/* Microsoft Extended Configuration Descriptor */ -static struct { - struct mbim_gsi_ext_config_desc_header header; - struct mbim_gsi_ext_config_desc_function function; -} mbim_gsi_ext_config_desc = { - .header = { - .dwLength = cpu_to_le32(sizeof(mbim_gsi_ext_config_desc)), - .bcdVersion = cpu_to_le16(0x0100), - .wIndex = cpu_to_le16(4), - .bCount = 1, - }, - .function = { - .bFirstInterfaceNumber = 0, - .bInterfaceCount = 1, - .compatibleID = { 'A', 'L', 'T', 'R', 'C', 'F', 'G' }, - /* .subCompatibleID = DYNAMIC */ - }, -}; /* ecm device descriptors */ #define ECM_QC_LOG2_STATUS_INTERVAL_MSEC 5 #define ECM_QC_STATUS_BYTECOUNT 16 /* 8 byte header + data */