Loading drivers/usb/gadget/function/f_rmnet.c +364 −195 Original line number Diff line number Diff line Loading @@ -26,20 +26,18 @@ #define RMNET_NOTIFY_INTERVAL 5 #define RMNET_MAX_NOTIFY_SIZE sizeof(struct usb_cdc_notification) #define ACM_CTRL_DTR (1 << 0) /* TODO: use separate structures for data and * control paths */ struct f_rmnet { struct usb_function func; enum qti_port_type qti_port_type; enum ipa_func_type func_type; struct grmnet port; int ifc_id; atomic_t online; atomic_t ctrl_online; struct usb_composite_dev *cdev; struct gadget_ipa_port ipa_port; spinlock_t lock; /* usb eps*/ Loading @@ -47,11 +45,9 @@ struct f_rmnet { struct usb_request *notify_req; /* control info */ struct gadget_ipa_port ipa_port; struct list_head cpkt_resp_q; unsigned long notify_count; unsigned long cpkts_len; } *rmnet_port; }; static struct usb_interface_descriptor rmnet_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, Loading Loading @@ -213,6 +209,70 @@ static struct usb_gadget_strings *rmnet_strings[] = { NULL, }; static struct usb_interface_descriptor dpl_data_intf_desc = { .bLength = sizeof(dpl_data_intf_desc), .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 0, .bNumEndpoints = 1, .bInterfaceClass = 0xff, .bInterfaceSubClass = 0xff, .bInterfaceProtocol = 0xff, }; static struct usb_endpoint_descriptor dpl_hs_data_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(512), }; static struct usb_endpoint_descriptor dpl_ss_data_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }; static struct usb_ss_ep_comp_descriptor dpl_data_ep_comp_desc = { .bLength = sizeof(dpl_data_ep_comp_desc), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .bMaxBurst = 1, .bmAttributes = 0, .wBytesPerInterval = 0, }; static struct usb_descriptor_header *dpl_hs_data_only_desc[] = { (struct usb_descriptor_header *) &dpl_data_intf_desc, (struct usb_descriptor_header *) &dpl_hs_data_desc, NULL, }; static struct usb_descriptor_header *dpl_ss_data_only_desc[] = { (struct usb_descriptor_header *) &dpl_data_intf_desc, (struct usb_descriptor_header *) &dpl_ss_data_desc, (struct usb_descriptor_header *) &dpl_data_ep_comp_desc, NULL, }; /* string descriptors: */ static struct usb_string dpl_string_defs[] = { [0].s = "QDSS DATA", {}, /* end of list */ }; static struct usb_gadget_strings dpl_string_table = { .language = 0x0409, .strings = dpl_string_defs, }; static struct usb_gadget_strings *dpl_strings[] = { &dpl_string_table, NULL, }; static void frmnet_ctrl_response_available(struct f_rmnet *dev); /* ------- misc functions --------------------*/ Loading @@ -227,6 +287,24 @@ static inline struct f_rmnet *port_to_rmnet(struct grmnet *r) return container_of(r, struct f_rmnet, port); } int name_to_prot(struct f_rmnet *dev, const char *name) { if (!name) goto error; if (!strncasecmp("rmnet", name, MAX_INST_NAME_LEN)) { dev->qti_port_type = QTI_PORT_RMNET; dev->func_type = USB_IPA_FUNC_RMNET; } else if (!strncasecmp("dpl", name, MAX_INST_NAME_LEN)) { dev->qti_port_type = QTI_PORT_DPL; dev->func_type = USB_IPA_FUNC_DPL; } return 0; error: return -EINVAL; } static struct usb_request * frmnet_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags) { Loading Loading @@ -279,51 +357,57 @@ static void rmnet_free_ctrl_pkt(struct rmnet_ctrl_pkt *pkt) /* -------------------------------------------*/ static int gport_rmnet_connect(struct f_rmnet *dev, unsigned intf) static int gport_rmnet_connect(struct f_rmnet *dev) { int ret; int src_connection_idx = 0, dst_connection_idx = 0; struct usb_gadget *gadget = dev->cdev->gadget; enum usb_ctrl usb_bam_type; int bam_pipe_num = (dev->qti_port_type == QTI_PORT_DPL) ? 1 : 0; ret = gqti_ctrl_connect(&dev->port, QTI_PORT_RMNET, dev->ifc_id); ret = gqti_ctrl_connect(&dev->port, dev->qti_port_type, dev->ifc_id); if (ret) { pr_err("%s: gqti_ctrl_connect failed: err:%d\n", __func__, ret); return ret; } if (dev->qti_port_type == QTI_PORT_DPL) dev->port.send_encap_cmd(QTI_PORT_DPL, NULL, 0); dev->ipa_port.cdev = dev->cdev; ipa_data_port_select(USB_IPA_FUNC_RMNET); ipa_data_port_select(dev->func_type); usb_bam_type = usb_bam_get_bam_type(gadget->name); src_connection_idx = usb_bam_get_connection_idx(usb_bam_type, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, QTI_PORT_RMNET); if (dev->ipa_port.in) { dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, QTI_PORT_RMNET); IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, bam_pipe_num); } if (dev->ipa_port.out) { src_connection_idx = usb_bam_get_connection_idx(usb_bam_type, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, bam_pipe_num); } if (dst_connection_idx < 0 || src_connection_idx < 0) { pr_err("%s: usb_bam_get_connection_idx failed\n", __func__); gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET); gqti_ctrl_disconnect(&dev->port, dev->qti_port_type); return -EINVAL; } ret = ipa_data_connect(&dev->ipa_port, USB_IPA_FUNC_RMNET, ret = ipa_data_connect(&dev->ipa_port, dev->func_type, src_connection_idx, dst_connection_idx); if (ret) { pr_err("%s: ipa_data_connect failed: err:%d\n", __func__, ret); gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET); gqti_ctrl_disconnect(&dev->port, dev->qti_port_type); return ret; } return 0; } static int gport_rmnet_disconnect(struct f_rmnet *dev) { gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET); ipa_data_disconnect(&dev->ipa_port, USB_IPA_FUNC_RMNET); gqti_ctrl_disconnect(&dev->port, dev->qti_port_type); ipa_data_disconnect(&dev->ipa_port, dev->func_type); return 0; } Loading @@ -333,24 +417,25 @@ static void frmnet_free(struct usb_function *f) opts = container_of(f->fi, struct f_rmnet_opts, func_inst); opts->refcnt--; kfree(rmnet_port); rmnet_port = NULL; } static void frmnet_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_rmnet *dev = func_to_rmnet(f); struct usb_gadget *gadget = c->cdev->gadget; pr_debug("%s: start unbinding\n", __func__); if (gadget_is_superspeed(c->cdev->gadget)) pr_debug("%s: start unbinding\nclear_desc\n", __func__); if (gadget_is_superspeed(gadget) && f->ss_descriptors) usb_free_descriptors(f->ss_descriptors); if (gadget_is_dualspeed(c->cdev->gadget)) if (gadget_is_dualspeed(gadget) && f->hs_descriptors) usb_free_descriptors(f->hs_descriptors); if (f->fs_descriptors) usb_free_descriptors(f->fs_descriptors); if (dev->notify_req) frmnet_free_req(dev->notify, dev->notify_req); kfree(f->name); } static void frmnet_purge_responses(struct f_rmnet *dev) Loading Loading @@ -384,11 +469,11 @@ static void frmnet_suspend(struct usb_function *f) pr_debug("%s: dev: %p remote_wakeup: %d\n", __func__, dev, remote_wakeup_allowed); if (dev->notify) { usb_ep_fifo_flush(dev->notify); frmnet_purge_responses(dev); ipa_data_suspend(&dev->ipa_port, USB_IPA_FUNC_RMNET, remote_wakeup_allowed); } ipa_data_suspend(&dev->ipa_port, dev->func_type, remote_wakeup_allowed); } static void frmnet_resume(struct usb_function *f) Loading @@ -404,8 +489,7 @@ static void frmnet_resume(struct usb_function *f) pr_debug("%s: dev: %p remote_wakeup: %d\n", __func__, dev, remote_wakeup_allowed); ipa_data_resume(&dev->ipa_port, USB_IPA_FUNC_RMNET, remote_wakeup_allowed); ipa_data_resume(&dev->ipa_port, dev->func_type, remote_wakeup_allowed); } static void frmnet_disable(struct usb_function *f) Loading @@ -413,15 +497,13 @@ static void frmnet_disable(struct usb_function *f) struct f_rmnet *dev = func_to_rmnet(f); pr_debug("%s: Disabling\n", __func__); atomic_set(&dev->online, 0); if (dev->notify) { usb_ep_disable(dev->notify); dev->notify->driver_data = NULL; atomic_set(&dev->online, 0); frmnet_purge_responses(dev); } msm_ep_unconfig(dev->ipa_port.out); msm_ep_unconfig(dev->ipa_port.in); gport_rmnet_disconnect(dev); } Loading @@ -430,11 +512,11 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct f_rmnet *dev = func_to_rmnet(f); struct usb_composite_dev *cdev = f->config->cdev; int ret; struct list_head *cpkt; int ret = 0; pr_debug("%s: dev: %p\n", __func__, dev); dev->cdev = cdev; if (dev->notify) { if (dev->notify->driver_data) { pr_debug("%s: reset port\n", __func__); usb_ep_disable(dev->notify); Loading @@ -443,31 +525,42 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ret = config_ep_by_speed(cdev->gadget, f, dev->notify); if (ret) { dev->notify->desc = NULL; ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n", ERROR(cdev, "config_ep_by_speed failed for ep %s, result %d\n", dev->notify->name, ret); return ret; } ret = usb_ep_enable(dev->notify); ret = usb_ep_enable(dev->notify); if (ret) { pr_err("%s: usb ep#%s enable failed, err#%d\n", __func__, dev->notify->name, ret); dev->notify->desc = NULL; return ret; } dev->notify->driver_data = dev; } if (!dev->ipa_port.in->desc || !dev->ipa_port.out->desc) { if (config_ep_by_speed(cdev->gadget, f, dev->ipa_port.in) || config_ep_by_speed(cdev->gadget, f, dev->ipa_port.out)) { pr_err("%s(): config_ep_by_speed failed.\n", __func__); if (dev->ipa_port.in && !dev->ipa_port.in->desc && config_ep_by_speed(cdev->gadget, f, dev->ipa_port.in)) { pr_err("%s(): config_ep_by_speed failed.\n", __func__); dev->ipa_port.in->desc = NULL; ret = -EINVAL; goto err_disable_ep; } dev->ipa_port.cdev = dev->cdev; if (dev->ipa_port.out && !dev->ipa_port.out->desc && config_ep_by_speed(cdev->gadget, f, dev->ipa_port.out)) { pr_err("%s(): config_ep_by_speed failed.\n", __func__); dev->ipa_port.out->desc = NULL; ret = -EINVAL; goto err_disable_ep; } ret = gport_rmnet_connect(dev, intf); ret = gport_rmnet_connect(dev); if (ret) { pr_err("%s(): gport_rmnet_connect fail with err:%d\n", __func__, ret); Loading @@ -475,18 +568,21 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } atomic_set(&dev->online, 1); /* * In case notifications were aborted, but there are pending control * packets in the response queue, re-add the notifications. * In case notifications were aborted, but there are * pending control packets in the response queue, * re-add the notifications. */ if (dev->qti_port_type == QTI_PORT_RMNET) { struct list_head *cpkt; list_for_each(cpkt, &dev->cpkt_resp_q) frmnet_ctrl_response_available(dev); } return ret; err_disable_ep: dev->ipa_port.in->desc = NULL; dev->ipa_port.out->desc = NULL; if (dev->notify && dev->notify->driver_data) usb_ep_disable(dev->notify); return ret; Loading Loading @@ -813,90 +909,98 @@ invalid: return ret; } static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) static int ipa_update_function_bind_params(struct f_rmnet *dev, struct usb_composite_dev *cdev, struct ipa_function_bind_info *info) { struct f_rmnet *dev = func_to_rmnet(f); struct usb_ep *ep; struct usb_composite_dev *cdev = c->cdev; int ret = -ENODEV; struct usb_function *f = &dev->func; int status; if (rmnet_string_defs[0].id == 0) { ret = usb_string_id(c->cdev); if (ret < 0) { pr_err("%s: failed to get string id, err:%d\n", __func__, ret); return ret; } rmnet_string_defs[0].id = ret; } /* maybe allocate device-global string IDs */ if (info->string_defs[0].id != 0) goto skip_string_id_alloc; pr_debug("%s: start binding\n", __func__); dev->ifc_id = usb_interface_id(c, f); if (dev->ifc_id < 0) { pr_err("%s: unable to allocate ifc id, err:%d\n", __func__, dev->ifc_id); return dev->ifc_id; if (info->data_str_idx >= 0 && info->data_desc) { /* data interface label */ status = usb_string_id(cdev); if (status < 0) return status; info->string_defs[info->data_str_idx].id = status; info->data_desc->iInterface = status; } rmnet_interface_desc.bInterfaceNumber = dev->ifc_id; ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_in_desc); skip_string_id_alloc: if (info->data_desc) info->data_desc->bInterfaceNumber = dev->ifc_id; if (info->fs_in_desc) { ep = usb_ep_autoconfig(cdev->gadget, info->fs_in_desc); if (!ep) { pr_err("%s: usb epin autoconfig failed\n", __func__); pr_err("%s: usb epin autoconfig failed\n", __func__); return -ENODEV; } dev->ipa_port.in = ep; ep->driver_data = cdev; } ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_out_desc); if (info->fs_out_desc) { ep = usb_ep_autoconfig(cdev->gadget, info->fs_out_desc); if (!ep) { pr_err("%s: usb epout autoconfig failed\n", __func__); ret = -ENODEV; pr_err("%s: usb epout autoconfig failed\n", __func__); status = -ENODEV; goto ep_auto_out_fail; } dev->ipa_port.out = ep; ep->driver_data = cdev; } ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_notify_desc); if (info->fs_notify_desc) { ep = usb_ep_autoconfig(cdev->gadget, info->fs_notify_desc); if (!ep) { pr_err("%s: usb epnotify autoconfig failed\n", __func__); ret = -ENODEV; pr_err("%s: usb epnotify autoconfig failed\n", __func__); status = -ENODEV; goto ep_auto_notify_fail; } dev->notify = ep; ep->driver_data = cdev; dev->notify_req = frmnet_alloc_req(ep, sizeof(struct usb_cdc_notification), GFP_KERNEL); if (IS_ERR(dev->notify_req)) { pr_err("%s: unable to allocate memory for notify req\n", __func__); ret = -ENOMEM; status = -ENOMEM; goto ep_notify_alloc_fail; } dev->notify_req->complete = frmnet_notify_complete; dev->notify_req->context = dev; } ret = -ENOMEM; f->fs_descriptors = usb_copy_descriptors(rmnet_fs_function); status = -ENOMEM; f->fs_descriptors = usb_copy_descriptors(info->fs_desc_hdr); if (!f->fs_descriptors) { pr_err("%s: no descriptors, usb_copy descriptors(fs)failed\n", __func__); goto fail; } if (gadget_is_dualspeed(cdev->gadget)) { rmnet_hs_in_desc.bEndpointAddress = rmnet_fs_in_desc.bEndpointAddress; rmnet_hs_out_desc.bEndpointAddress = rmnet_fs_out_desc.bEndpointAddress; rmnet_hs_notify_desc.bEndpointAddress = rmnet_fs_notify_desc.bEndpointAddress; if (info->fs_in_desc && info->hs_in_desc) info->hs_in_desc->bEndpointAddress = info->fs_in_desc->bEndpointAddress; if (info->fs_out_desc && info->hs_out_desc) info->hs_out_desc->bEndpointAddress = info->fs_out_desc->bEndpointAddress; if (info->fs_notify_desc && info->hs_notify_desc) info->hs_notify_desc->bEndpointAddress = info->fs_notify_desc->bEndpointAddress; /* copy descriptors, and track endpoint copies */ f->hs_descriptors = usb_copy_descriptors(rmnet_hs_function); f->hs_descriptors = usb_copy_descriptors(info->hs_desc_hdr); if (!f->hs_descriptors) { pr_err("%s: no hs_descriptors, usb_copy descriptors(hs)failed\n", __func__); Loading @@ -905,16 +1009,19 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) } if (gadget_is_superspeed(cdev->gadget)) { rmnet_ss_in_desc.bEndpointAddress = rmnet_fs_in_desc.bEndpointAddress; rmnet_ss_out_desc.bEndpointAddress = rmnet_fs_out_desc.bEndpointAddress; rmnet_ss_notify_desc.bEndpointAddress = rmnet_fs_notify_desc.bEndpointAddress; if (info->fs_in_desc && info->ss_in_desc) info->ss_in_desc->bEndpointAddress = info->fs_in_desc->bEndpointAddress; /* copy descriptors, and track endpoint copies */ f->ss_descriptors = usb_copy_descriptors(rmnet_ss_function); if (info->fs_out_desc && info->ss_out_desc) info->ss_out_desc->bEndpointAddress = info->fs_out_desc->bEndpointAddress; if (info->fs_notify_desc && info->ss_notify_desc) info->ss_notify_desc->bEndpointAddress = info->fs_notify_desc->bEndpointAddress; /* copy descriptors, and track endpoint copies */ f->ss_descriptors = usb_copy_descriptors(info->ss_desc_hdr); if (!f->ss_descriptors) { pr_err("%s: no ss_descriptors,usb_copy descriptors(ss)failed\n", __func__); Loading @@ -922,16 +1029,12 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) } } pr_debug("%s: RmNet %s Speed, IN:%s OUT:%s\n", __func__, gadget_is_dualspeed(cdev->gadget) ? "dual" : "full", dev->ipa_port.in->name, dev->ipa_port.out->name); return 0; fail: if (f->ss_descriptors) if (gadget_is_superspeed(cdev->gadget) && f->ss_descriptors) usb_free_descriptors(f->ss_descriptors); if (f->hs_descriptors) if (gadget_is_dualspeed(cdev->gadget) && f->hs_descriptors) usb_free_descriptors(f->hs_descriptors); if (f->fs_descriptors) usb_free_descriptors(f->fs_descriptors); Loading @@ -947,32 +1050,74 @@ ep_auto_out_fail: dev->ipa_port.in->driver_data = NULL; dev->ipa_port.in = NULL; return status; } static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) { struct f_rmnet *dev = func_to_rmnet(f); struct usb_composite_dev *cdev = c->cdev; int ret = -ENODEV; struct ipa_function_bind_info info = {0}; pr_debug("%s: start binding\n", __func__); dev->ifc_id = usb_interface_id(c, f); if (dev->ifc_id < 0) { pr_err("%s: unable to allocate ifc id, err:%d\n", __func__, dev->ifc_id); return dev->ifc_id; } info.data_str_idx = 0; if (dev->qti_port_type == QTI_PORT_RMNET) { info.string_defs = rmnet_string_defs; info.data_desc = &rmnet_interface_desc; info.fs_in_desc = &rmnet_fs_in_desc; info.fs_out_desc = &rmnet_fs_out_desc; info.fs_notify_desc = &rmnet_fs_notify_desc; info.hs_in_desc = &rmnet_hs_in_desc; info.hs_out_desc = &rmnet_hs_out_desc; info.hs_notify_desc = &rmnet_hs_notify_desc; info.ss_in_desc = &rmnet_ss_in_desc; info.ss_out_desc = &rmnet_ss_out_desc; info.ss_notify_desc = &rmnet_ss_notify_desc; info.fs_desc_hdr = rmnet_fs_function; info.hs_desc_hdr = rmnet_hs_function; info.ss_desc_hdr = rmnet_ss_function; } else { info.string_defs = dpl_string_defs; info.data_desc = &dpl_data_intf_desc; info.fs_in_desc = &dpl_hs_data_desc; info.hs_in_desc = &dpl_hs_data_desc; info.ss_in_desc = &dpl_ss_data_desc; info.fs_desc_hdr = dpl_hs_data_only_desc; info.hs_desc_hdr = dpl_hs_data_only_desc; info.ss_desc_hdr = dpl_ss_data_only_desc; } ret = ipa_update_function_bind_params(dev, cdev, &info); return ret; } static struct usb_function *frmnet_bind_config(struct usb_function_instance *fi) { struct f_rmnet_opts *opts; int status; struct f_rmnet *dev; struct usb_function *f; unsigned long flags; /* allocate and initialize one new instance */ status = -ENOMEM; opts = container_of(fi, struct f_rmnet_opts, func_inst); opts->refcnt++; dev = opts->dev; spin_lock_irqsave(&dev->lock, flags); f = &dev->func; f->name = kasprintf(GFP_ATOMIC, "rmnet%d", 0); spin_unlock_irqrestore(&dev->lock, flags); if (!f->name) { pr_err("%s: cannot allocate memory for name\n", __func__); return ERR_PTR(-ENOMEM); if (dev->qti_port_type == QTI_PORT_RMNET) { f->name = "rmnet"; f->strings = rmnet_strings; } else { f->name = "dpl"; f->strings = dpl_strings; } f->strings = rmnet_strings; f->bind = frmnet_bind; f->unbind = frmnet_unbind; f->disable = frmnet_disable; Loading Loading @@ -1004,21 +1149,53 @@ static void rmnet_free_inst(struct usb_function_instance *f) { struct f_rmnet_opts *opts = container_of(f, struct f_rmnet_opts, func_inst); ipa_data_free(USB_IPA_FUNC_RMNET); ipa_data_free(opts->dev->func_type); kfree(opts->dev); kfree(opts); } static int rmnet_set_inst_name(struct usb_function_instance *fi, const char *name) { int name_len; int ret; int name_len, ret = 0; struct f_rmnet *dev; struct f_rmnet_opts *opts = container_of(fi, struct f_rmnet_opts, func_inst); name_len = strlen(name) + 1; if (name_len > MAX_INST_NAME_LEN) return -ENAMETOOLONG; ret = ipa_data_setup(USB_IPA_FUNC_RMNET); dev = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL); if (!dev) return -ENOMEM; spin_lock_init(&dev->lock); /* Update qti->qti_port_type */ ret = name_to_prot(dev, name); if (ret < 0) { pr_err("%s: failed to find prot for %s instance\n", __func__, name); goto fail; } if (dev->qti_port_type >= QTI_NUM_PORTS || dev->func_type >= USB_IPA_NUM_FUNCS) { pr_err("%s: invalid prot\n", __func__); ret = -EINVAL; goto fail; } INIT_LIST_HEAD(&dev->cpkt_resp_q); ret = ipa_data_setup(dev->func_type); if (ret) goto fail; opts->dev = dev; return 0; fail: kfree(dev); return ret; } Loading Loading @@ -1062,14 +1239,6 @@ static struct usb_function_instance *rmnet_alloc_inst(void) static struct usb_function *rmnet_alloc(struct usb_function_instance *fi) { struct f_rmnet_opts *opts = container_of(fi, struct f_rmnet_opts, func_inst); rmnet_port = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL); if (!rmnet_port) return ERR_PTR(-ENOMEM); opts->dev = rmnet_port; spin_lock_init(&rmnet_port->lock); INIT_LIST_HEAD(&rmnet_port->cpkt_resp_q); return frmnet_bind_config(fi); } Loading drivers/usb/gadget/function/u_ctrl_qti.c +4 −14 Original line number Diff line number Diff line Loading @@ -204,7 +204,6 @@ int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf) { struct qti_ctrl_port *port; struct grmnet *g_rmnet = NULL; struct gqdss *g_dpl = NULL; unsigned long flags; pr_debug("%s: port type:%d gadget:%p\n", __func__, qport, gr); Loading @@ -224,16 +223,12 @@ int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf) port->ep_type = DATA_EP_TYPE_HSUSB; port->intf = intf; if (gr && port->port_type == QTI_PORT_RMNET) { if (gr) { port->port_usb = gr; g_rmnet = (struct grmnet *)gr; g_rmnet->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem; g_rmnet->notify_modem = gqti_ctrl_notify_modem; } else if (gr && port->port_type == QTI_PORT_DPL) { port->port_usb = gr; g_dpl = (struct gqdss *)gr; g_dpl->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem; g_dpl->notify_modem = gqti_ctrl_notify_modem; if (port->port_type == QTI_PORT_DPL) atomic_set(&port->line_state, 1); } else { spin_unlock_irqrestore(&port->lock, flags); Loading Loading @@ -263,7 +258,6 @@ void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport) unsigned long flags; struct rmnet_ctrl_pkt *cpkt; struct grmnet *g_rmnet = NULL; struct gqdss *g_dpl = NULL; pr_debug("%s: gadget:%p\n", __func__, gr); Loading @@ -287,14 +281,10 @@ void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport) port->ipa_cons_idx = -1; port->port_usb = NULL; if (gr && port->port_type == QTI_PORT_RMNET) { if (gr) { g_rmnet = (struct grmnet *)gr; g_rmnet->send_encap_cmd = NULL; g_rmnet->notify_modem = NULL; } else if (gr && port->port_type == QTI_PORT_DPL) { g_dpl = (struct gqdss *)gr; g_dpl->send_encap_cmd = NULL; g_dpl->notify_modem = NULL; } else { pr_err("%s(): unrecognized gadget type(%d).\n", __func__, port->port_type); Loading drivers/usb/gadget/function/u_data_ipa.c +30 −22 Original line number Diff line number Diff line Loading @@ -837,13 +837,16 @@ void ipa_data_suspend(struct gadget_ipa_port *gp, enum ipa_func_type func, * the BAM disconnect API. This lets us restore this info when * the USB bus is resumed. */ if (gp->in) { gp->in_ep_desc_backup = gp->in->desc; pr_debug("in_ep_desc_backup = %p\n", gp->in_ep_desc_backup); } if (gp->out) { gp->out_ep_desc_backup = gp->out->desc; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", gp->in_ep_desc_backup, pr_debug("out_ep_desc_backup = %p\n", gp->out_ep_desc_backup); } ipa_data_disconnect(gp, func); return; } Loading Loading @@ -919,8 +922,8 @@ void ipa_data_resume(struct gadget_ipa_port *gp, enum ipa_func_type func, struct ipa_data_ch_info *port; unsigned long flags; struct usb_gadget *gadget = NULL; u8 src_connection_idx; u8 dst_connection_idx; u8 src_connection_idx = 0; u8 dst_connection_idx = 0; enum usb_ctrl usb_bam_type; pr_debug("dev:%p port number:%d\n", gp, func); Loading @@ -944,20 +947,25 @@ void ipa_data_resume(struct gadget_ipa_port *gp, enum ipa_func_type func, gadget = gp->cdev->gadget; /* resume with remote wakeup disabled */ if (!remote_wakeup_enabled) { int bam_pipe_num = (func == USB_IPA_FUNC_DPL) ? 1 : 0; usb_bam_type = usb_bam_get_bam_type(gadget->name); /* Restore endpoint descriptors info. */ if (gp->in) { gp->in->desc = gp->in_ep_desc_backup; pr_debug("in_ep_desc_backup = %p\n", gp->in_ep_desc_backup); dst_connection_idx = usb_bam_get_connection_idx( usb_bam_type, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, bam_pipe_num); } if (gp->out) { gp->out->desc = gp->out_ep_desc_backup; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", gp->in_ep_desc_backup, pr_debug("out_ep_desc_backup = %p\n", gp->out_ep_desc_backup); usb_bam_type = usb_bam_get_bam_type(gadget->name); src_connection_idx = usb_bam_get_connection_idx(usb_bam_type, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0); dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); src_connection_idx = usb_bam_get_connection_idx( usb_bam_type, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, bam_pipe_num); } ipa_data_connect(gp, func, src_connection_idx, dst_connection_idx); return; Loading drivers/usb/gadget/function/u_data_ipa.h +19 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,25 @@ struct gadget_ipa_port { }; struct ipa_function_bind_info { struct usb_string *string_defs; int data_str_idx; struct usb_interface_descriptor *data_desc; struct usb_endpoint_descriptor *fs_in_desc; struct usb_endpoint_descriptor *fs_out_desc; struct usb_endpoint_descriptor *fs_notify_desc; struct usb_endpoint_descriptor *hs_in_desc; struct usb_endpoint_descriptor *hs_out_desc; struct usb_endpoint_descriptor *hs_notify_desc; struct usb_endpoint_descriptor *ss_in_desc; struct usb_endpoint_descriptor *ss_out_desc; struct usb_endpoint_descriptor *ss_notify_desc; struct usb_descriptor_header **fs_desc_hdr; struct usb_descriptor_header **hs_desc_hdr; struct usb_descriptor_header **ss_desc_hdr; }; /* for configfs support */ #define MAX_INST_NAME_LEN 40 Loading Loading
drivers/usb/gadget/function/f_rmnet.c +364 −195 Original line number Diff line number Diff line Loading @@ -26,20 +26,18 @@ #define RMNET_NOTIFY_INTERVAL 5 #define RMNET_MAX_NOTIFY_SIZE sizeof(struct usb_cdc_notification) #define ACM_CTRL_DTR (1 << 0) /* TODO: use separate structures for data and * control paths */ struct f_rmnet { struct usb_function func; enum qti_port_type qti_port_type; enum ipa_func_type func_type; struct grmnet port; int ifc_id; atomic_t online; atomic_t ctrl_online; struct usb_composite_dev *cdev; struct gadget_ipa_port ipa_port; spinlock_t lock; /* usb eps*/ Loading @@ -47,11 +45,9 @@ struct f_rmnet { struct usb_request *notify_req; /* control info */ struct gadget_ipa_port ipa_port; struct list_head cpkt_resp_q; unsigned long notify_count; unsigned long cpkts_len; } *rmnet_port; }; static struct usb_interface_descriptor rmnet_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, Loading Loading @@ -213,6 +209,70 @@ static struct usb_gadget_strings *rmnet_strings[] = { NULL, }; static struct usb_interface_descriptor dpl_data_intf_desc = { .bLength = sizeof(dpl_data_intf_desc), .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 0, .bNumEndpoints = 1, .bInterfaceClass = 0xff, .bInterfaceSubClass = 0xff, .bInterfaceProtocol = 0xff, }; static struct usb_endpoint_descriptor dpl_hs_data_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(512), }; static struct usb_endpoint_descriptor dpl_ss_data_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }; static struct usb_ss_ep_comp_descriptor dpl_data_ep_comp_desc = { .bLength = sizeof(dpl_data_ep_comp_desc), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .bMaxBurst = 1, .bmAttributes = 0, .wBytesPerInterval = 0, }; static struct usb_descriptor_header *dpl_hs_data_only_desc[] = { (struct usb_descriptor_header *) &dpl_data_intf_desc, (struct usb_descriptor_header *) &dpl_hs_data_desc, NULL, }; static struct usb_descriptor_header *dpl_ss_data_only_desc[] = { (struct usb_descriptor_header *) &dpl_data_intf_desc, (struct usb_descriptor_header *) &dpl_ss_data_desc, (struct usb_descriptor_header *) &dpl_data_ep_comp_desc, NULL, }; /* string descriptors: */ static struct usb_string dpl_string_defs[] = { [0].s = "QDSS DATA", {}, /* end of list */ }; static struct usb_gadget_strings dpl_string_table = { .language = 0x0409, .strings = dpl_string_defs, }; static struct usb_gadget_strings *dpl_strings[] = { &dpl_string_table, NULL, }; static void frmnet_ctrl_response_available(struct f_rmnet *dev); /* ------- misc functions --------------------*/ Loading @@ -227,6 +287,24 @@ static inline struct f_rmnet *port_to_rmnet(struct grmnet *r) return container_of(r, struct f_rmnet, port); } int name_to_prot(struct f_rmnet *dev, const char *name) { if (!name) goto error; if (!strncasecmp("rmnet", name, MAX_INST_NAME_LEN)) { dev->qti_port_type = QTI_PORT_RMNET; dev->func_type = USB_IPA_FUNC_RMNET; } else if (!strncasecmp("dpl", name, MAX_INST_NAME_LEN)) { dev->qti_port_type = QTI_PORT_DPL; dev->func_type = USB_IPA_FUNC_DPL; } return 0; error: return -EINVAL; } static struct usb_request * frmnet_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags) { Loading Loading @@ -279,51 +357,57 @@ static void rmnet_free_ctrl_pkt(struct rmnet_ctrl_pkt *pkt) /* -------------------------------------------*/ static int gport_rmnet_connect(struct f_rmnet *dev, unsigned intf) static int gport_rmnet_connect(struct f_rmnet *dev) { int ret; int src_connection_idx = 0, dst_connection_idx = 0; struct usb_gadget *gadget = dev->cdev->gadget; enum usb_ctrl usb_bam_type; int bam_pipe_num = (dev->qti_port_type == QTI_PORT_DPL) ? 1 : 0; ret = gqti_ctrl_connect(&dev->port, QTI_PORT_RMNET, dev->ifc_id); ret = gqti_ctrl_connect(&dev->port, dev->qti_port_type, dev->ifc_id); if (ret) { pr_err("%s: gqti_ctrl_connect failed: err:%d\n", __func__, ret); return ret; } if (dev->qti_port_type == QTI_PORT_DPL) dev->port.send_encap_cmd(QTI_PORT_DPL, NULL, 0); dev->ipa_port.cdev = dev->cdev; ipa_data_port_select(USB_IPA_FUNC_RMNET); ipa_data_port_select(dev->func_type); usb_bam_type = usb_bam_get_bam_type(gadget->name); src_connection_idx = usb_bam_get_connection_idx(usb_bam_type, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, QTI_PORT_RMNET); if (dev->ipa_port.in) { dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, QTI_PORT_RMNET); IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, bam_pipe_num); } if (dev->ipa_port.out) { src_connection_idx = usb_bam_get_connection_idx(usb_bam_type, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, bam_pipe_num); } if (dst_connection_idx < 0 || src_connection_idx < 0) { pr_err("%s: usb_bam_get_connection_idx failed\n", __func__); gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET); gqti_ctrl_disconnect(&dev->port, dev->qti_port_type); return -EINVAL; } ret = ipa_data_connect(&dev->ipa_port, USB_IPA_FUNC_RMNET, ret = ipa_data_connect(&dev->ipa_port, dev->func_type, src_connection_idx, dst_connection_idx); if (ret) { pr_err("%s: ipa_data_connect failed: err:%d\n", __func__, ret); gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET); gqti_ctrl_disconnect(&dev->port, dev->qti_port_type); return ret; } return 0; } static int gport_rmnet_disconnect(struct f_rmnet *dev) { gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET); ipa_data_disconnect(&dev->ipa_port, USB_IPA_FUNC_RMNET); gqti_ctrl_disconnect(&dev->port, dev->qti_port_type); ipa_data_disconnect(&dev->ipa_port, dev->func_type); return 0; } Loading @@ -333,24 +417,25 @@ static void frmnet_free(struct usb_function *f) opts = container_of(f->fi, struct f_rmnet_opts, func_inst); opts->refcnt--; kfree(rmnet_port); rmnet_port = NULL; } static void frmnet_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_rmnet *dev = func_to_rmnet(f); struct usb_gadget *gadget = c->cdev->gadget; pr_debug("%s: start unbinding\n", __func__); if (gadget_is_superspeed(c->cdev->gadget)) pr_debug("%s: start unbinding\nclear_desc\n", __func__); if (gadget_is_superspeed(gadget) && f->ss_descriptors) usb_free_descriptors(f->ss_descriptors); if (gadget_is_dualspeed(c->cdev->gadget)) if (gadget_is_dualspeed(gadget) && f->hs_descriptors) usb_free_descriptors(f->hs_descriptors); if (f->fs_descriptors) usb_free_descriptors(f->fs_descriptors); if (dev->notify_req) frmnet_free_req(dev->notify, dev->notify_req); kfree(f->name); } static void frmnet_purge_responses(struct f_rmnet *dev) Loading Loading @@ -384,11 +469,11 @@ static void frmnet_suspend(struct usb_function *f) pr_debug("%s: dev: %p remote_wakeup: %d\n", __func__, dev, remote_wakeup_allowed); if (dev->notify) { usb_ep_fifo_flush(dev->notify); frmnet_purge_responses(dev); ipa_data_suspend(&dev->ipa_port, USB_IPA_FUNC_RMNET, remote_wakeup_allowed); } ipa_data_suspend(&dev->ipa_port, dev->func_type, remote_wakeup_allowed); } static void frmnet_resume(struct usb_function *f) Loading @@ -404,8 +489,7 @@ static void frmnet_resume(struct usb_function *f) pr_debug("%s: dev: %p remote_wakeup: %d\n", __func__, dev, remote_wakeup_allowed); ipa_data_resume(&dev->ipa_port, USB_IPA_FUNC_RMNET, remote_wakeup_allowed); ipa_data_resume(&dev->ipa_port, dev->func_type, remote_wakeup_allowed); } static void frmnet_disable(struct usb_function *f) Loading @@ -413,15 +497,13 @@ static void frmnet_disable(struct usb_function *f) struct f_rmnet *dev = func_to_rmnet(f); pr_debug("%s: Disabling\n", __func__); atomic_set(&dev->online, 0); if (dev->notify) { usb_ep_disable(dev->notify); dev->notify->driver_data = NULL; atomic_set(&dev->online, 0); frmnet_purge_responses(dev); } msm_ep_unconfig(dev->ipa_port.out); msm_ep_unconfig(dev->ipa_port.in); gport_rmnet_disconnect(dev); } Loading @@ -430,11 +512,11 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct f_rmnet *dev = func_to_rmnet(f); struct usb_composite_dev *cdev = f->config->cdev; int ret; struct list_head *cpkt; int ret = 0; pr_debug("%s: dev: %p\n", __func__, dev); dev->cdev = cdev; if (dev->notify) { if (dev->notify->driver_data) { pr_debug("%s: reset port\n", __func__); usb_ep_disable(dev->notify); Loading @@ -443,31 +525,42 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt) ret = config_ep_by_speed(cdev->gadget, f, dev->notify); if (ret) { dev->notify->desc = NULL; ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n", ERROR(cdev, "config_ep_by_speed failed for ep %s, result %d\n", dev->notify->name, ret); return ret; } ret = usb_ep_enable(dev->notify); ret = usb_ep_enable(dev->notify); if (ret) { pr_err("%s: usb ep#%s enable failed, err#%d\n", __func__, dev->notify->name, ret); dev->notify->desc = NULL; return ret; } dev->notify->driver_data = dev; } if (!dev->ipa_port.in->desc || !dev->ipa_port.out->desc) { if (config_ep_by_speed(cdev->gadget, f, dev->ipa_port.in) || config_ep_by_speed(cdev->gadget, f, dev->ipa_port.out)) { pr_err("%s(): config_ep_by_speed failed.\n", __func__); if (dev->ipa_port.in && !dev->ipa_port.in->desc && config_ep_by_speed(cdev->gadget, f, dev->ipa_port.in)) { pr_err("%s(): config_ep_by_speed failed.\n", __func__); dev->ipa_port.in->desc = NULL; ret = -EINVAL; goto err_disable_ep; } dev->ipa_port.cdev = dev->cdev; if (dev->ipa_port.out && !dev->ipa_port.out->desc && config_ep_by_speed(cdev->gadget, f, dev->ipa_port.out)) { pr_err("%s(): config_ep_by_speed failed.\n", __func__); dev->ipa_port.out->desc = NULL; ret = -EINVAL; goto err_disable_ep; } ret = gport_rmnet_connect(dev, intf); ret = gport_rmnet_connect(dev); if (ret) { pr_err("%s(): gport_rmnet_connect fail with err:%d\n", __func__, ret); Loading @@ -475,18 +568,21 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } atomic_set(&dev->online, 1); /* * In case notifications were aborted, but there are pending control * packets in the response queue, re-add the notifications. * In case notifications were aborted, but there are * pending control packets in the response queue, * re-add the notifications. */ if (dev->qti_port_type == QTI_PORT_RMNET) { struct list_head *cpkt; list_for_each(cpkt, &dev->cpkt_resp_q) frmnet_ctrl_response_available(dev); } return ret; err_disable_ep: dev->ipa_port.in->desc = NULL; dev->ipa_port.out->desc = NULL; if (dev->notify && dev->notify->driver_data) usb_ep_disable(dev->notify); return ret; Loading Loading @@ -813,90 +909,98 @@ invalid: return ret; } static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) static int ipa_update_function_bind_params(struct f_rmnet *dev, struct usb_composite_dev *cdev, struct ipa_function_bind_info *info) { struct f_rmnet *dev = func_to_rmnet(f); struct usb_ep *ep; struct usb_composite_dev *cdev = c->cdev; int ret = -ENODEV; struct usb_function *f = &dev->func; int status; if (rmnet_string_defs[0].id == 0) { ret = usb_string_id(c->cdev); if (ret < 0) { pr_err("%s: failed to get string id, err:%d\n", __func__, ret); return ret; } rmnet_string_defs[0].id = ret; } /* maybe allocate device-global string IDs */ if (info->string_defs[0].id != 0) goto skip_string_id_alloc; pr_debug("%s: start binding\n", __func__); dev->ifc_id = usb_interface_id(c, f); if (dev->ifc_id < 0) { pr_err("%s: unable to allocate ifc id, err:%d\n", __func__, dev->ifc_id); return dev->ifc_id; if (info->data_str_idx >= 0 && info->data_desc) { /* data interface label */ status = usb_string_id(cdev); if (status < 0) return status; info->string_defs[info->data_str_idx].id = status; info->data_desc->iInterface = status; } rmnet_interface_desc.bInterfaceNumber = dev->ifc_id; ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_in_desc); skip_string_id_alloc: if (info->data_desc) info->data_desc->bInterfaceNumber = dev->ifc_id; if (info->fs_in_desc) { ep = usb_ep_autoconfig(cdev->gadget, info->fs_in_desc); if (!ep) { pr_err("%s: usb epin autoconfig failed\n", __func__); pr_err("%s: usb epin autoconfig failed\n", __func__); return -ENODEV; } dev->ipa_port.in = ep; ep->driver_data = cdev; } ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_out_desc); if (info->fs_out_desc) { ep = usb_ep_autoconfig(cdev->gadget, info->fs_out_desc); if (!ep) { pr_err("%s: usb epout autoconfig failed\n", __func__); ret = -ENODEV; pr_err("%s: usb epout autoconfig failed\n", __func__); status = -ENODEV; goto ep_auto_out_fail; } dev->ipa_port.out = ep; ep->driver_data = cdev; } ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_notify_desc); if (info->fs_notify_desc) { ep = usb_ep_autoconfig(cdev->gadget, info->fs_notify_desc); if (!ep) { pr_err("%s: usb epnotify autoconfig failed\n", __func__); ret = -ENODEV; pr_err("%s: usb epnotify autoconfig failed\n", __func__); status = -ENODEV; goto ep_auto_notify_fail; } dev->notify = ep; ep->driver_data = cdev; dev->notify_req = frmnet_alloc_req(ep, sizeof(struct usb_cdc_notification), GFP_KERNEL); if (IS_ERR(dev->notify_req)) { pr_err("%s: unable to allocate memory for notify req\n", __func__); ret = -ENOMEM; status = -ENOMEM; goto ep_notify_alloc_fail; } dev->notify_req->complete = frmnet_notify_complete; dev->notify_req->context = dev; } ret = -ENOMEM; f->fs_descriptors = usb_copy_descriptors(rmnet_fs_function); status = -ENOMEM; f->fs_descriptors = usb_copy_descriptors(info->fs_desc_hdr); if (!f->fs_descriptors) { pr_err("%s: no descriptors, usb_copy descriptors(fs)failed\n", __func__); goto fail; } if (gadget_is_dualspeed(cdev->gadget)) { rmnet_hs_in_desc.bEndpointAddress = rmnet_fs_in_desc.bEndpointAddress; rmnet_hs_out_desc.bEndpointAddress = rmnet_fs_out_desc.bEndpointAddress; rmnet_hs_notify_desc.bEndpointAddress = rmnet_fs_notify_desc.bEndpointAddress; if (info->fs_in_desc && info->hs_in_desc) info->hs_in_desc->bEndpointAddress = info->fs_in_desc->bEndpointAddress; if (info->fs_out_desc && info->hs_out_desc) info->hs_out_desc->bEndpointAddress = info->fs_out_desc->bEndpointAddress; if (info->fs_notify_desc && info->hs_notify_desc) info->hs_notify_desc->bEndpointAddress = info->fs_notify_desc->bEndpointAddress; /* copy descriptors, and track endpoint copies */ f->hs_descriptors = usb_copy_descriptors(rmnet_hs_function); f->hs_descriptors = usb_copy_descriptors(info->hs_desc_hdr); if (!f->hs_descriptors) { pr_err("%s: no hs_descriptors, usb_copy descriptors(hs)failed\n", __func__); Loading @@ -905,16 +1009,19 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) } if (gadget_is_superspeed(cdev->gadget)) { rmnet_ss_in_desc.bEndpointAddress = rmnet_fs_in_desc.bEndpointAddress; rmnet_ss_out_desc.bEndpointAddress = rmnet_fs_out_desc.bEndpointAddress; rmnet_ss_notify_desc.bEndpointAddress = rmnet_fs_notify_desc.bEndpointAddress; if (info->fs_in_desc && info->ss_in_desc) info->ss_in_desc->bEndpointAddress = info->fs_in_desc->bEndpointAddress; /* copy descriptors, and track endpoint copies */ f->ss_descriptors = usb_copy_descriptors(rmnet_ss_function); if (info->fs_out_desc && info->ss_out_desc) info->ss_out_desc->bEndpointAddress = info->fs_out_desc->bEndpointAddress; if (info->fs_notify_desc && info->ss_notify_desc) info->ss_notify_desc->bEndpointAddress = info->fs_notify_desc->bEndpointAddress; /* copy descriptors, and track endpoint copies */ f->ss_descriptors = usb_copy_descriptors(info->ss_desc_hdr); if (!f->ss_descriptors) { pr_err("%s: no ss_descriptors,usb_copy descriptors(ss)failed\n", __func__); Loading @@ -922,16 +1029,12 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) } } pr_debug("%s: RmNet %s Speed, IN:%s OUT:%s\n", __func__, gadget_is_dualspeed(cdev->gadget) ? "dual" : "full", dev->ipa_port.in->name, dev->ipa_port.out->name); return 0; fail: if (f->ss_descriptors) if (gadget_is_superspeed(cdev->gadget) && f->ss_descriptors) usb_free_descriptors(f->ss_descriptors); if (f->hs_descriptors) if (gadget_is_dualspeed(cdev->gadget) && f->hs_descriptors) usb_free_descriptors(f->hs_descriptors); if (f->fs_descriptors) usb_free_descriptors(f->fs_descriptors); Loading @@ -947,32 +1050,74 @@ ep_auto_out_fail: dev->ipa_port.in->driver_data = NULL; dev->ipa_port.in = NULL; return status; } static int frmnet_bind(struct usb_configuration *c, struct usb_function *f) { struct f_rmnet *dev = func_to_rmnet(f); struct usb_composite_dev *cdev = c->cdev; int ret = -ENODEV; struct ipa_function_bind_info info = {0}; pr_debug("%s: start binding\n", __func__); dev->ifc_id = usb_interface_id(c, f); if (dev->ifc_id < 0) { pr_err("%s: unable to allocate ifc id, err:%d\n", __func__, dev->ifc_id); return dev->ifc_id; } info.data_str_idx = 0; if (dev->qti_port_type == QTI_PORT_RMNET) { info.string_defs = rmnet_string_defs; info.data_desc = &rmnet_interface_desc; info.fs_in_desc = &rmnet_fs_in_desc; info.fs_out_desc = &rmnet_fs_out_desc; info.fs_notify_desc = &rmnet_fs_notify_desc; info.hs_in_desc = &rmnet_hs_in_desc; info.hs_out_desc = &rmnet_hs_out_desc; info.hs_notify_desc = &rmnet_hs_notify_desc; info.ss_in_desc = &rmnet_ss_in_desc; info.ss_out_desc = &rmnet_ss_out_desc; info.ss_notify_desc = &rmnet_ss_notify_desc; info.fs_desc_hdr = rmnet_fs_function; info.hs_desc_hdr = rmnet_hs_function; info.ss_desc_hdr = rmnet_ss_function; } else { info.string_defs = dpl_string_defs; info.data_desc = &dpl_data_intf_desc; info.fs_in_desc = &dpl_hs_data_desc; info.hs_in_desc = &dpl_hs_data_desc; info.ss_in_desc = &dpl_ss_data_desc; info.fs_desc_hdr = dpl_hs_data_only_desc; info.hs_desc_hdr = dpl_hs_data_only_desc; info.ss_desc_hdr = dpl_ss_data_only_desc; } ret = ipa_update_function_bind_params(dev, cdev, &info); return ret; } static struct usb_function *frmnet_bind_config(struct usb_function_instance *fi) { struct f_rmnet_opts *opts; int status; struct f_rmnet *dev; struct usb_function *f; unsigned long flags; /* allocate and initialize one new instance */ status = -ENOMEM; opts = container_of(fi, struct f_rmnet_opts, func_inst); opts->refcnt++; dev = opts->dev; spin_lock_irqsave(&dev->lock, flags); f = &dev->func; f->name = kasprintf(GFP_ATOMIC, "rmnet%d", 0); spin_unlock_irqrestore(&dev->lock, flags); if (!f->name) { pr_err("%s: cannot allocate memory for name\n", __func__); return ERR_PTR(-ENOMEM); if (dev->qti_port_type == QTI_PORT_RMNET) { f->name = "rmnet"; f->strings = rmnet_strings; } else { f->name = "dpl"; f->strings = dpl_strings; } f->strings = rmnet_strings; f->bind = frmnet_bind; f->unbind = frmnet_unbind; f->disable = frmnet_disable; Loading Loading @@ -1004,21 +1149,53 @@ static void rmnet_free_inst(struct usb_function_instance *f) { struct f_rmnet_opts *opts = container_of(f, struct f_rmnet_opts, func_inst); ipa_data_free(USB_IPA_FUNC_RMNET); ipa_data_free(opts->dev->func_type); kfree(opts->dev); kfree(opts); } static int rmnet_set_inst_name(struct usb_function_instance *fi, const char *name) { int name_len; int ret; int name_len, ret = 0; struct f_rmnet *dev; struct f_rmnet_opts *opts = container_of(fi, struct f_rmnet_opts, func_inst); name_len = strlen(name) + 1; if (name_len > MAX_INST_NAME_LEN) return -ENAMETOOLONG; ret = ipa_data_setup(USB_IPA_FUNC_RMNET); dev = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL); if (!dev) return -ENOMEM; spin_lock_init(&dev->lock); /* Update qti->qti_port_type */ ret = name_to_prot(dev, name); if (ret < 0) { pr_err("%s: failed to find prot for %s instance\n", __func__, name); goto fail; } if (dev->qti_port_type >= QTI_NUM_PORTS || dev->func_type >= USB_IPA_NUM_FUNCS) { pr_err("%s: invalid prot\n", __func__); ret = -EINVAL; goto fail; } INIT_LIST_HEAD(&dev->cpkt_resp_q); ret = ipa_data_setup(dev->func_type); if (ret) goto fail; opts->dev = dev; return 0; fail: kfree(dev); return ret; } Loading Loading @@ -1062,14 +1239,6 @@ static struct usb_function_instance *rmnet_alloc_inst(void) static struct usb_function *rmnet_alloc(struct usb_function_instance *fi) { struct f_rmnet_opts *opts = container_of(fi, struct f_rmnet_opts, func_inst); rmnet_port = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL); if (!rmnet_port) return ERR_PTR(-ENOMEM); opts->dev = rmnet_port; spin_lock_init(&rmnet_port->lock); INIT_LIST_HEAD(&rmnet_port->cpkt_resp_q); return frmnet_bind_config(fi); } Loading
drivers/usb/gadget/function/u_ctrl_qti.c +4 −14 Original line number Diff line number Diff line Loading @@ -204,7 +204,6 @@ int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf) { struct qti_ctrl_port *port; struct grmnet *g_rmnet = NULL; struct gqdss *g_dpl = NULL; unsigned long flags; pr_debug("%s: port type:%d gadget:%p\n", __func__, qport, gr); Loading @@ -224,16 +223,12 @@ int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf) port->ep_type = DATA_EP_TYPE_HSUSB; port->intf = intf; if (gr && port->port_type == QTI_PORT_RMNET) { if (gr) { port->port_usb = gr; g_rmnet = (struct grmnet *)gr; g_rmnet->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem; g_rmnet->notify_modem = gqti_ctrl_notify_modem; } else if (gr && port->port_type == QTI_PORT_DPL) { port->port_usb = gr; g_dpl = (struct gqdss *)gr; g_dpl->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem; g_dpl->notify_modem = gqti_ctrl_notify_modem; if (port->port_type == QTI_PORT_DPL) atomic_set(&port->line_state, 1); } else { spin_unlock_irqrestore(&port->lock, flags); Loading Loading @@ -263,7 +258,6 @@ void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport) unsigned long flags; struct rmnet_ctrl_pkt *cpkt; struct grmnet *g_rmnet = NULL; struct gqdss *g_dpl = NULL; pr_debug("%s: gadget:%p\n", __func__, gr); Loading @@ -287,14 +281,10 @@ void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport) port->ipa_cons_idx = -1; port->port_usb = NULL; if (gr && port->port_type == QTI_PORT_RMNET) { if (gr) { g_rmnet = (struct grmnet *)gr; g_rmnet->send_encap_cmd = NULL; g_rmnet->notify_modem = NULL; } else if (gr && port->port_type == QTI_PORT_DPL) { g_dpl = (struct gqdss *)gr; g_dpl->send_encap_cmd = NULL; g_dpl->notify_modem = NULL; } else { pr_err("%s(): unrecognized gadget type(%d).\n", __func__, port->port_type); Loading
drivers/usb/gadget/function/u_data_ipa.c +30 −22 Original line number Diff line number Diff line Loading @@ -837,13 +837,16 @@ void ipa_data_suspend(struct gadget_ipa_port *gp, enum ipa_func_type func, * the BAM disconnect API. This lets us restore this info when * the USB bus is resumed. */ if (gp->in) { gp->in_ep_desc_backup = gp->in->desc; pr_debug("in_ep_desc_backup = %p\n", gp->in_ep_desc_backup); } if (gp->out) { gp->out_ep_desc_backup = gp->out->desc; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", gp->in_ep_desc_backup, pr_debug("out_ep_desc_backup = %p\n", gp->out_ep_desc_backup); } ipa_data_disconnect(gp, func); return; } Loading Loading @@ -919,8 +922,8 @@ void ipa_data_resume(struct gadget_ipa_port *gp, enum ipa_func_type func, struct ipa_data_ch_info *port; unsigned long flags; struct usb_gadget *gadget = NULL; u8 src_connection_idx; u8 dst_connection_idx; u8 src_connection_idx = 0; u8 dst_connection_idx = 0; enum usb_ctrl usb_bam_type; pr_debug("dev:%p port number:%d\n", gp, func); Loading @@ -944,20 +947,25 @@ void ipa_data_resume(struct gadget_ipa_port *gp, enum ipa_func_type func, gadget = gp->cdev->gadget; /* resume with remote wakeup disabled */ if (!remote_wakeup_enabled) { int bam_pipe_num = (func == USB_IPA_FUNC_DPL) ? 1 : 0; usb_bam_type = usb_bam_get_bam_type(gadget->name); /* Restore endpoint descriptors info. */ if (gp->in) { gp->in->desc = gp->in_ep_desc_backup; pr_debug("in_ep_desc_backup = %p\n", gp->in_ep_desc_backup); dst_connection_idx = usb_bam_get_connection_idx( usb_bam_type, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, bam_pipe_num); } if (gp->out) { gp->out->desc = gp->out_ep_desc_backup; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", gp->in_ep_desc_backup, pr_debug("out_ep_desc_backup = %p\n", gp->out_ep_desc_backup); usb_bam_type = usb_bam_get_bam_type(gadget->name); src_connection_idx = usb_bam_get_connection_idx(usb_bam_type, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0); dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); src_connection_idx = usb_bam_get_connection_idx( usb_bam_type, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, bam_pipe_num); } ipa_data_connect(gp, func, src_connection_idx, dst_connection_idx); return; Loading
drivers/usb/gadget/function/u_data_ipa.h +19 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,25 @@ struct gadget_ipa_port { }; struct ipa_function_bind_info { struct usb_string *string_defs; int data_str_idx; struct usb_interface_descriptor *data_desc; struct usb_endpoint_descriptor *fs_in_desc; struct usb_endpoint_descriptor *fs_out_desc; struct usb_endpoint_descriptor *fs_notify_desc; struct usb_endpoint_descriptor *hs_in_desc; struct usb_endpoint_descriptor *hs_out_desc; struct usb_endpoint_descriptor *hs_notify_desc; struct usb_endpoint_descriptor *ss_in_desc; struct usb_endpoint_descriptor *ss_out_desc; struct usb_endpoint_descriptor *ss_notify_desc; struct usb_descriptor_header **fs_desc_hdr; struct usb_descriptor_header **hs_desc_hdr; struct usb_descriptor_header **ss_desc_hdr; }; /* for configfs support */ #define MAX_INST_NAME_LEN 40 Loading