Loading drivers/usb/gadget/f_mbim.c +19 −110 Original line number Diff line number Diff line Loading @@ -118,9 +118,6 @@ struct f_mbim { struct mbim_ep_descs fs; struct mbim_ep_descs hs; const struct usb_endpoint_descriptor *in_ep_desc_backup; const struct usb_endpoint_descriptor *out_ep_desc_backup; u8 ctrl_id, data_id; bool data_interface_up; Loading Loading @@ -720,65 +717,6 @@ static int mbim_bam_setup(int no_ports) return 0; } static int mbim_bam_connect(struct f_mbim *dev) { int ret; u8 src_connection_idx, dst_connection_idx; struct usb_gadget *gadget = dev->cdev->gadget; enum peer_bam bam_name = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ? IPA_P_BAM : A2_P_BAM; int port_num; pr_info("dev:%p portno:%d\n", dev, dev->port_num); port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, MBIM_DEFAULT_PORT); if (port_num < 0) return port_num; ret = bam2bam_data_port_select(port_num); if (ret) { pr_err("mbim port select failed err: %d\n", ret); return ret; } src_connection_idx = usb_bam_get_connection_idx(gadget->name, bam_name, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, dev->port_num); dst_connection_idx = usb_bam_get_connection_idx(gadget->name, bam_name, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, dev->port_num); if (src_connection_idx < 0 || dst_connection_idx < 0) { pr_err("%s: usb_bam_get_connection_idx failed\n", __func__); return ret; } port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, dev->port_num); if (port_num < 0) return port_num; ret = bam_data_connect(&dev->bam_port, port_num, dev->xport, src_connection_idx, dst_connection_idx, USB_FUNC_MBIM); if (ret) { pr_err("bam_data_setup failed: err:%d\n", ret); return ret; } pr_info("mbim bam connected\n"); return 0; } static int mbim_bam_disconnect(struct f_mbim *dev) { int port_num; pr_info("%s - dev:%p port:%d\n", __func__, dev, dev->port_num); port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, dev->port_num); if (port_num < 0) return port_num; bam_data_disconnect(&dev->bam_port, port_num); return 0; } /* -------------------------------------------------------------------------*/ static inline void mbim_reset_values(struct f_mbim *mbim) Loading Loading @@ -1353,9 +1291,14 @@ static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } } pr_debug("Activate mbim\n"); mbim_bam_connect(mbim); ret = bam_data_connect(&mbim->bam_port, mbim->xport, mbim->port_num, USB_FUNC_MBIM); if (ret) { pr_err("bam_data_setup failed:err:%d\n", ret); goto fail; } } else { pr_info("PORTS already SET\n"); } Loading @@ -1366,7 +1309,8 @@ static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt) * perform bam data disconnect handshake upon usb * disconnect */ mbim_bam_disconnect(mbim); bam_data_disconnect(&mbim->bam_port, USB_FUNC_MBIM, mbim->port_num); if (mbim->xport == USB_GADGET_XPORT_BAM2BAM_IPA && mbim->data_interface_up && gadget_is_dwc3(cdev->gadget)) { Loading Loading @@ -1444,7 +1388,7 @@ static void mbim_disable(struct usb_function *f) msm_ep_unconfig(mbim->bam_port.in); } mbim_bam_disconnect(mbim); bam_data_disconnect(&mbim->bam_port, USB_FUNC_MBIM, mbim->port_num); mbim->data_interface_up = false; pr_info("mbim deactivated\n"); Loading @@ -1456,7 +1400,6 @@ static void mbim_suspend(struct usb_function *f) { bool remote_wakeup_allowed; struct f_mbim *mbim = func_to_mbim(f); int port_num; pr_info("mbim suspended\n"); Loading @@ -1481,39 +1424,17 @@ static void mbim_suspend(struct usb_function *f) return; } if (remote_wakeup_allowed) { port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, MBIM_ACTIVE_PORT); if (port_num < 0) return; bam_data_suspend(port_num); } else { /* * When remote wakeup is disabled, IPA BAM is disconnected * because it cannot send new data until the USB bus is resumed. * Endpoint descriptors info is saved before it gets reset by * the BAM disconnect API. This lets us restore this info when * the USB bus is resumed. */ if (mbim->bam_port.in->desc) mbim->in_ep_desc_backup = mbim->bam_port.in->desc; if (mbim->bam_port.out->desc) mbim->out_ep_desc_backup = mbim->bam_port.out->desc; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", mbim->in_ep_desc_backup, mbim->out_ep_desc_backup); if (!remote_wakeup_allowed) atomic_set(&mbim->online, 0); mbim_bam_disconnect(mbim); } bam_data_suspend(&mbim->bam_port, mbim->port_num, USB_FUNC_MBIM, remote_wakeup_allowed); } static void mbim_resume(struct usb_function *f) { bool remote_wakeup_allowed; struct f_mbim *mbim = func_to_mbim(f); int port_num; pr_info("mbim resumed\n"); Loading @@ -1536,23 +1457,11 @@ static void mbim_resume(struct usb_function *f) return; } if (remote_wakeup_allowed) { port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, MBIM_ACTIVE_PORT); if (port_num < 0) return; bam_data_resume(port_num); } else { /* Restore endpoint descriptors info. */ mbim->bam_port.in->desc = mbim->in_ep_desc_backup; mbim->bam_port.out->desc = mbim->out_ep_desc_backup; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", mbim->in_ep_desc_backup, mbim->out_ep_desc_backup); if (!remote_wakeup_allowed) atomic_set(&mbim->online, 1); mbim_bam_connect(mbim); } bam_data_resume(&mbim->bam_port, mbim->port_num, USB_FUNC_MBIM, remote_wakeup_allowed); } static int mbim_func_suspend(struct usb_function *f, unsigned char options) Loading drivers/usb/gadget/f_qc_ecm.c +25 −102 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ struct f_ecm_qc { struct qc_gether port; u8 ctrl_id, data_id; enum transport_type xport; u8 port_num; char ethaddr[14]; struct usb_ep *notify; Loading @@ -78,8 +79,6 @@ struct f_ecm_qc { struct data_port bam_port; bool ecm_mdm_ready_trigger; const struct usb_endpoint_descriptor *in_ep_desc_backup; const struct usb_endpoint_descriptor *out_ep_desc_backup; bool data_interface_up; }; Loading Loading @@ -448,72 +447,6 @@ static void ecm_qc_notify(struct f_ecm_qc *ecm) ecm_qc_do_notify(ecm); } static int ecm_qc_bam_connect(struct f_ecm_qc *dev) { int ret; u8 src_connection_idx, dst_connection_idx; struct usb_composite_dev *cdev = dev->port.func.config->cdev; struct usb_gadget *gadget = cdev->gadget; enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ? IPA_P_BAM : A2_P_BAM; int port_num; port_num = (u_bam_data_func_to_port(USB_FUNC_ECM, ECM_QC_DEFAULT_PORT)); if (port_num < 0) return port_num; ret = bam2bam_data_port_select(port_num); if (ret) { pr_err("ecm_qc port select failed with err:%d\n", ret); return ret; } dev->bam_port.cdev = cdev; dev->bam_port.func = &dev->port.func; dev->bam_port.in = dev->port.in_ep; dev->bam_port.out = dev->port.out_ep; /* currently we use the first connection */ src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0); dst_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); if (src_connection_idx < 0 || dst_connection_idx < 0) { pr_err("usb_bam_get_connection_idx failed\n"); return ret; } ret = bam_data_connect(&dev->bam_port, port_num, dev->xport, src_connection_idx, dst_connection_idx, USB_FUNC_ECM); if (ret) { pr_err("bam_data_connect failed: err:%d\n", ret); return ret; } pr_debug("ecm bam connected\n"); dev->is_open = dev->ecm_mdm_ready_trigger ? true : false; ecm_qc_notify(dev); return 0; } static int ecm_qc_bam_disconnect(struct f_ecm_qc *dev) { int port_num; pr_debug("%s: dev:%p. Disconnect BAM.\n", __func__, dev); __ecm->ecm_mdm_ready_trigger = false; port_num = (u_bam_data_func_to_port(USB_FUNC_ECM, ECM_QC_DEFAULT_PORT)); if (port_num < 0) return port_num; bam_data_disconnect(&dev->bam_port, port_num); return 0; } void *ecm_qc_get_ipa_rx_cb(void) { return ipa_params.ecm_ipa_rx_dp_notify; Loading Loading @@ -680,7 +613,8 @@ static int ecm_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) * path. Only after the BAM data path is disconnected, * we can disconnect the port from the network layer. */ ecm_qc_bam_disconnect(ecm); bam_data_disconnect(&ecm->bam_port, USB_FUNC_ECM, ecm->port_num); if (ecm->xport != USB_GADGET_XPORT_BAM2BAM_IPA) { gether_qc_disconnect_name(&ecm->port, "ecm0"); } else if (ecm->data_interface_up && Loading Loading @@ -723,8 +657,16 @@ static int ecm_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } } if (ecm_qc_bam_connect(ecm)) ecm->bam_port.cdev = cdev; ecm->bam_port.func = &ecm->port.func; ecm->bam_port.in = ecm->port.in_ep; ecm->bam_port.out = ecm->port.out_ep; if (bam_data_connect(&ecm->bam_port, ecm->xport, ecm->port_num, USB_FUNC_ECM)) goto fail; ecm->is_open = ecm->ecm_mdm_ready_trigger ? true : false; } ecm->data_interface_up = alt; Loading Loading @@ -763,7 +705,8 @@ static void ecm_qc_disable(struct usb_function *f) DBG(cdev, "ecm deactivated\n"); if (ecm->port.in_ep->driver_data) { ecm_qc_bam_disconnect(ecm); bam_data_disconnect(&ecm->bam_port, USB_FUNC_ECM, ecm->port_num); if (ecm->xport != USB_GADGET_XPORT_BAM2BAM_IPA) gether_qc_disconnect_name(&ecm->port, "ecm0"); } else { Loading Loading @@ -791,7 +734,6 @@ static void ecm_qc_suspend(struct usb_function *f) { struct f_ecm_qc *ecm = func_to_ecm_qc(f); bool remote_wakeup_allowed; int port_num; /* Is DATA interface initialized? */ if (!ecm->data_interface_up) { Loading @@ -806,24 +748,11 @@ static void ecm_qc_suspend(struct usb_function *f) f->config->cdev->gadget->remote_wakeup; pr_debug("%s(): remote_wakeup:%d\n:", __func__, remote_wakeup_allowed); if (remote_wakeup_allowed) { port_num = (u_bam_data_func_to_port(USB_FUNC_ECM, ECM_QC_ACTIVE_PORT)); if (port_num < 0) return; bam_data_suspend(port_num); } else { /* * When remote wakeup is disabled, IPA BAM is disconnected * because it cannot send new data until the USB bus is resumed. * Endpoint descriptors info is saved before it gets reset by * the BAM disconnect API. This lets us restore this info when * the USB bus is resumed. */ ecm->in_ep_desc_backup = ecm->bam_port.in->desc; ecm->out_ep_desc_backup = ecm->bam_port.out->desc; ecm_qc_bam_disconnect(ecm); } if (!remote_wakeup_allowed) __ecm->ecm_mdm_ready_trigger = false; bam_data_suspend(&ecm->bam_port, ecm->port_num, USB_FUNC_ECM, remote_wakeup_allowed); pr_debug("ecm suspended\n"); } Loading @@ -832,7 +761,6 @@ static void ecm_qc_resume(struct usb_function *f) { struct f_ecm_qc *ecm = func_to_ecm_qc(f); bool remote_wakeup_allowed; int port_num; if (!ecm->data_interface_up) { pr_err("%s(): data interface was not up\n", __func__); Loading @@ -845,17 +773,12 @@ static void ecm_qc_resume(struct usb_function *f) remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; if (remote_wakeup_allowed) { port_num = (u_bam_data_func_to_port(USB_FUNC_ECM, ECM_QC_ACTIVE_PORT)); if (port_num < 0) return; bam_data_resume(port_num); } else { /* Restore endpoint descriptors info. */ ecm->bam_port.in->desc = ecm->in_ep_desc_backup; ecm->bam_port.out->desc = ecm->out_ep_desc_backup; ecm_qc_bam_connect(ecm); bam_data_resume(&ecm->bam_port, ecm->port_num, USB_FUNC_ECM, remote_wakeup_allowed); if (!remote_wakeup_allowed) { ecm->is_open = ecm->ecm_mdm_ready_trigger ? true : false; ecm_qc_notify(ecm); } pr_debug("ecm resumed\n"); Loading drivers/usb/gadget/f_qc_rndis.c +25 −116 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ * Copyright (C) 2008 Nokia Corporation * Copyright (C) 2009 Samsung Electronics * Author: Michal Nazarewicz (mina86@mina86.com) * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 Loading Loading @@ -98,9 +98,8 @@ struct f_rndis_qc { atomic_t notify_count; struct data_port bam_port; enum transport_type xport; u8 port_num; bool net_ready_trigger; const struct usb_endpoint_descriptor *in_ep_desc_backup; const struct usb_endpoint_descriptor *out_ep_desc_backup; }; static struct ipa_usb_init_params rndis_ipa_params; Loading Loading @@ -416,77 +415,6 @@ static inline void rndis_qc_unlock(atomic_t *excl) atomic_dec(excl); } /* MSM bam support */ static int rndis_qc_bam_connect(struct f_rndis_qc *dev) { int ret; u8 src_connection_idx, dst_connection_idx; struct usb_composite_dev *cdev = dev->port.func.config->cdev; struct usb_gadget *gadget = cdev->gadget; enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ? IPA_P_BAM : A2_P_BAM; int port_num; dev->bam_port.cdev = cdev; dev->bam_port.func = &dev->port.func; dev->bam_port.in = dev->port.in_ep; dev->bam_port.out = dev->port.out_ep; port_num = (u_bam_data_func_to_port(USB_FUNC_RNDIS, RNDIS_QC_ACTIVE_PORT)); if (port_num < 0) return port_num; ret = bam2bam_data_port_select(port_num); if (ret) { pr_err("qc rndis bam port setup failed err:%d\n", ret); return ret; } /* currently we use the first connection */ src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0); dst_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); if (src_connection_idx < 0 || dst_connection_idx < 0) { pr_err("%s: usb_bam_get_connection_idx failed\n", __func__); return ret; } if (peer_bam == A2_P_BAM) ret = bam_data_connect(&dev->bam_port, port_num, USB_GADGET_XPORT_BAM2BAM, src_connection_idx, dst_connection_idx, USB_FUNC_RNDIS); else { ret = bam_data_connect(&dev->bam_port, port_num, USB_GADGET_XPORT_BAM2BAM_IPA, src_connection_idx, dst_connection_idx, USB_FUNC_RNDIS); rndis_qc_open(&dev->port); } if (ret) { pr_err("bam_data_connect failed: err:%d\n", ret); return ret; } pr_info("rndis bam connected\n"); return 0; } static int rndis_qc_bam_disconnect(struct f_rndis_qc *dev) { int port_num; pr_debug("dev:%p. %s Disconnect BAM.\n", dev, __func__); port_num = (u_bam_data_func_to_port(USB_FUNC_RNDIS, RNDIS_QC_ACTIVE_PORT)); if (port_num < 0) return port_num; bam_data_disconnect(&dev->bam_port, port_num); return 0; } /*-------------------------------------------------------------------------*/ static struct sk_buff *rndis_qc_add_header(struct qc_gether *port, Loading Loading @@ -730,7 +658,8 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) * path. Only after the BAM data path is disconnected, * we can disconnect the port from the network layer. */ rndis_qc_bam_disconnect(rndis); bam_data_disconnect(&rndis->bam_port, USB_FUNC_RNDIS, rndis->port_num); if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) gether_qc_disconnect_name(&rndis->port, Loading Loading @@ -776,15 +705,23 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) */ rndis->port.cdc_filter = 0; if (rndis_qc_bam_connect(rndis)) rndis->bam_port.cdev = cdev; rndis->bam_port.func = &rndis->port.func; rndis->bam_port.in = rndis->port.in_ep; rndis->bam_port.out = rndis->port.out_ep; if (bam_data_connect(&rndis->bam_port, rndis->xport, rndis->port_num, USB_FUNC_RNDIS)) goto fail; DBG(cdev, "RNDIS RX/TX early activation ...\n"); if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) { net = gether_qc_connect_name(&rndis->port, "rndis0", false); else } else { rndis_qc_open(&rndis->port); net = gether_qc_get_net("rndis0"); } if (IS_ERR(net)) return PTR_ERR(net); Loading @@ -809,7 +746,7 @@ static void rndis_qc_disable(struct usb_function *f) pr_info("rndis deactivated\n"); rndis_uninit(rndis->config); rndis_qc_bam_disconnect(rndis); bam_data_disconnect(&rndis->bam_port, USB_FUNC_RNDIS, rndis->port_num); if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) gether_qc_disconnect_name(&rndis->port, "rndis0"); Loading @@ -826,7 +763,6 @@ static void rndis_qc_suspend(struct usb_function *f) { struct f_rndis_qc *rndis = func_to_rndis_qc(f); bool remote_wakeup_allowed; int port_num; if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; Loading @@ -836,13 +772,7 @@ static void rndis_qc_suspend(struct usb_function *f) pr_info("%s(): start rndis suspend: remote_wakeup_allowed:%d\n:", __func__, remote_wakeup_allowed); if (remote_wakeup_allowed) { port_num = (u_bam_data_func_to_port(USB_FUNC_RNDIS, RNDIS_QC_ACTIVE_PORT)); if (port_num < 0) return; bam_data_suspend(port_num); } else { if (!remote_wakeup_allowed) { /* This is required as Linux host side RNDIS driver doesn't * send RNDIS_MESSAGE_PACKET_FILTER before suspending USB bus. * Hence we perform same operations explicitly here for Linux Loading @@ -850,26 +780,11 @@ static void rndis_qc_suspend(struct usb_function *f) * already updated due to receiving of PACKET_FILTER. */ rndis_flow_control(rndis->config, true); /* * When remote wakeup is disabled, IPA BAM is disconnected * because it cannot send new data until the USB bus is resumed. * Endpoint descriptors info is saved before it gets reset by * the BAM disconnect API. This lets us restore this info when * the USB bus is resumed. */ if (rndis->bam_port.in->desc) rndis->in_ep_desc_backup = rndis->bam_port.in->desc; if (rndis->bam_port.out->desc) rndis->out_ep_desc_backup = rndis->bam_port.out->desc; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", rndis->in_ep_desc_backup, rndis->out_ep_desc_backup); pr_debug("%s(): Disconnecting\n", __func__); rndis_qc_bam_disconnect(rndis); } bam_data_suspend(&rndis->bam_port, rndis->port_num, USB_FUNC_RNDIS, remote_wakeup_allowed); pr_debug("rndis suspended\n"); } Loading @@ -877,7 +792,6 @@ static void rndis_qc_resume(struct usb_function *f) { struct f_rndis_qc *rndis = func_to_rndis_qc(f); bool remote_wakeup_allowed; int port_num; pr_debug("%s: rndis resumed\n", __func__); Loading @@ -892,17 +806,12 @@ static void rndis_qc_resume(struct usb_function *f) else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; if (remote_wakeup_allowed) { port_num = (u_bam_data_func_to_port(USB_FUNC_RNDIS, RNDIS_QC_ACTIVE_PORT)); if (port_num < 0) return; bam_data_resume(port_num); } else { /* Restore endpoint descriptors info. */ rndis->bam_port.in->desc = rndis->in_ep_desc_backup; rndis->bam_port.out->desc = rndis->out_ep_desc_backup; rndis_qc_bam_connect(rndis); bam_data_resume(&rndis->bam_port, rndis->port_num, USB_FUNC_RNDIS, remote_wakeup_allowed); if (!remote_wakeup_allowed) { if (rndis->xport == USB_GADGET_XPORT_BAM2BAM_IPA) rndis_qc_open(&rndis->port); /* * Linux Host doesn't sends RNDIS_MSG_INIT or non-zero value * set with RNDIS_MESSAGE_PACKET_FILTER after performing bus Loading drivers/usb/gadget/u_bam_data.c +107 −28 Original line number Diff line number Diff line Loading @@ -1362,20 +1362,23 @@ static void bam_data_free_reqs(struct bam_data_port *port) } } void bam_data_disconnect(struct data_port *gr, u8 port_num) void bam_data_disconnect(struct data_port *gr, enum function_type func, u8 dev_port_num) { struct bam_data_port *port; struct bam_data_ch_info *d; struct sk_buff *skb = NULL; unsigned long flags; int port_num; pr_debug("dev:%p port number:%d\n", gr, port_num); if (port_num >= n_bam2bam_data_ports) { port_num = u_bam_data_func_to_port(func, dev_port_num); if (port_num < 0 || port_num >= n_bam2bam_data_ports) { pr_err("invalid bam2bam portno#%d\n", port_num); return; } pr_debug("dev:%p port number:%d\n", gr, port_num); if (!gr) { pr_err("data port is null\n"); return; Loading Loading @@ -1479,26 +1482,49 @@ void bam_data_disconnect(struct data_port *gr, u8 port_num) spin_unlock_irqrestore(&port->port_lock, flags); } int bam_data_connect(struct data_port *gr, u8 port_num, enum transport_type trans, u8 src_connection_idx, u8 dst_connection_idx, enum function_type func) int bam_data_connect(struct data_port *gr, enum transport_type trans, u8 dev_port_num, enum function_type func) { struct bam_data_port *port; struct bam_data_ch_info *d; int ret; int ret, port_num; unsigned long flags; pr_debug("dev:%p port#%d\n", gr, port_num); if (port_num >= n_bam2bam_data_ports) { pr_err("invalid portno#%d\n", port_num); return -ENODEV; } enum peer_bam bam_name; u8 src_connection_idx, dst_connection_idx; if (!gr) { pr_err("data port is null\n"); return -ENODEV; } port_num = u_bam_data_func_to_port(func, dev_port_num); if (port_num < 0 || port_num >= n_bam2bam_data_ports) { pr_err("invalid portno#%d\n", port_num); return -EINVAL; } pr_debug("dev:%p port#%d\n", gr, port_num); bam_name = (trans == USB_GADGET_XPORT_BAM2BAM_IPA) ? IPA_P_BAM : A2_P_BAM; ret = bam2bam_data_port_select(port_num); if (ret) { pr_err("mbim port select failed err: %d\n", ret); return ret; } src_connection_idx = usb_bam_get_connection_idx(gr->cdev->gadget->name, bam_name, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, dev_port_num); dst_connection_idx = usb_bam_get_connection_idx(gr->cdev->gadget->name, bam_name, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, dev_port_num); if (src_connection_idx < 0 || dst_connection_idx < 0) { pr_err("%s: usb_bam_get_connection_idx failed\n", __func__); return ret; } port = bam2bam_data_ports[port_num]; spin_lock_irqsave(&port->port_lock, flags); Loading Loading @@ -1815,40 +1841,93 @@ static void bam_data_stop(void *param, enum usb_bam_pipe_dir dir) } } void bam_data_suspend(u8 port_num) void bam_data_suspend(struct data_port *port_usb, u8 dev_port_num, enum function_type func, bool remote_wakeup_enabled) { struct bam_data_port *port; unsigned long flags; int port_num; port_num = u_bam_data_func_to_port(func, dev_port_num); if (port_num < 0 || port_num >= n_bam2bam_data_ports) { pr_err("invalid bam2bam portno#%d\n", port_num); return; } pr_debug("%s: suspended port %d\n", __func__, port_num); port = bam2bam_data_ports[port_num]; if (port) { if (!port) { pr_err("%s(): Port is NULL.\n", __func__); return; } /* suspend with remote wakeup disabled */ if (!remote_wakeup_enabled) { /* * When remote wakeup is disabled, IPA BAM is disconnected * because it cannot send new data until the USB bus is resumed. * Endpoint descriptors info is saved before it gets reset by * the BAM disconnect API. This lets us restore this info when * the USB bus is resumed. */ port_usb->in_ep_desc_backup = port_usb->in->desc; port_usb->out_ep_desc_backup = port_usb->out->desc; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", port_usb->in_ep_desc_backup, port_usb->out_ep_desc_backup); bam_data_disconnect(port_usb, func, dev_port_num); return; } spin_lock_irqsave(&port->port_lock, flags); port->last_event = U_BAM_DATA_SUSPEND_E; queue_work(bam_data_wq, &port->suspend_w); spin_unlock_irqrestore(&port->port_lock, flags); } else { pr_err("%s(): Port is NULL.\n", __func__); } } void bam_data_resume(u8 port_num) void bam_data_resume(struct data_port *port_usb, u8 dev_port_num, enum function_type func, bool remote_wakeup_enabled) { struct bam_data_port *port; unsigned long flags; int port_num; port_num = u_bam_data_func_to_port(func, dev_port_num); if (port_num < 0 || port_num >= n_bam2bam_data_ports) { pr_err("invalid bam2bam portno#%d\n", port_num); return; } pr_debug("%s: resumed port %d\n", __func__, port_num); port = bam2bam_data_ports[port_num]; if (port) { if (!port) { pr_err("%s(): Port is NULL.\n", __func__); return; } /* resume with remote wakeup disabled */ if (!remote_wakeup_enabled) { /* Restore endpoint descriptors info. */ port_usb->in->desc = port_usb->in_ep_desc_backup; port_usb->out->desc = port_usb->out_ep_desc_backup; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", port_usb->in_ep_desc_backup, port_usb->out_ep_desc_backup); bam_data_connect(port_usb, port->data_ch.trans, dev_port_num, func); return; } spin_lock_irqsave(&port->port_lock, flags); port->last_event = U_BAM_DATA_RESUME_E; queue_work(bam_data_wq, &port->resume_w); spin_unlock_irqrestore(&port->port_lock, flags); } else { pr_err("%s(): Port is NULL.\n", __func__); } } void bam_data_flush_workqueue(void) Loading drivers/usb/gadget/u_bam_data.h +18 −14 Original line number Diff line number Diff line /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -33,23 +33,27 @@ struct data_port { struct usb_ep *out; int ipa_consumer_ep; int ipa_producer_ep; const struct usb_endpoint_descriptor *in_ep_desc_backup; const struct usb_endpoint_descriptor *out_ep_desc_backup; }; int bam2bam_data_port_select(int portno); void bam_data_disconnect(struct data_port *gr, u8 port_num); void bam_data_disconnect(struct data_port *gr, enum function_type func, u8 dev_port_num); int bam_data_connect(struct data_port *gr, u8 port_num, enum transport_type trans, u8 src_connection_idx, u8 dst_connection_idx, enum function_type func); int bam_data_connect(struct data_port *gr, enum transport_type trans, u8 dev_port_num, enum function_type func); int bam_data_setup(enum function_type func, unsigned int no_bam2bam_port); void bam_data_flush_workqueue(void); void bam_data_suspend(u8 port_num); void bam_data_suspend(struct data_port *port_usb, u8 dev_port_num, enum function_type func, bool remote_wakeup_enabled); void bam_data_resume(u8 port_num); void bam_data_resume(struct data_port *port_usb, u8 dev_port_num, enum function_type func, bool remote_wakeup_enabled); void u_bam_data_set_dl_max_xfer_size(u32 dl_max_transfer_size); Loading Loading
drivers/usb/gadget/f_mbim.c +19 −110 Original line number Diff line number Diff line Loading @@ -118,9 +118,6 @@ struct f_mbim { struct mbim_ep_descs fs; struct mbim_ep_descs hs; const struct usb_endpoint_descriptor *in_ep_desc_backup; const struct usb_endpoint_descriptor *out_ep_desc_backup; u8 ctrl_id, data_id; bool data_interface_up; Loading Loading @@ -720,65 +717,6 @@ static int mbim_bam_setup(int no_ports) return 0; } static int mbim_bam_connect(struct f_mbim *dev) { int ret; u8 src_connection_idx, dst_connection_idx; struct usb_gadget *gadget = dev->cdev->gadget; enum peer_bam bam_name = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ? IPA_P_BAM : A2_P_BAM; int port_num; pr_info("dev:%p portno:%d\n", dev, dev->port_num); port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, MBIM_DEFAULT_PORT); if (port_num < 0) return port_num; ret = bam2bam_data_port_select(port_num); if (ret) { pr_err("mbim port select failed err: %d\n", ret); return ret; } src_connection_idx = usb_bam_get_connection_idx(gadget->name, bam_name, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, dev->port_num); dst_connection_idx = usb_bam_get_connection_idx(gadget->name, bam_name, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, dev->port_num); if (src_connection_idx < 0 || dst_connection_idx < 0) { pr_err("%s: usb_bam_get_connection_idx failed\n", __func__); return ret; } port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, dev->port_num); if (port_num < 0) return port_num; ret = bam_data_connect(&dev->bam_port, port_num, dev->xport, src_connection_idx, dst_connection_idx, USB_FUNC_MBIM); if (ret) { pr_err("bam_data_setup failed: err:%d\n", ret); return ret; } pr_info("mbim bam connected\n"); return 0; } static int mbim_bam_disconnect(struct f_mbim *dev) { int port_num; pr_info("%s - dev:%p port:%d\n", __func__, dev, dev->port_num); port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, dev->port_num); if (port_num < 0) return port_num; bam_data_disconnect(&dev->bam_port, port_num); return 0; } /* -------------------------------------------------------------------------*/ static inline void mbim_reset_values(struct f_mbim *mbim) Loading Loading @@ -1353,9 +1291,14 @@ static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } } pr_debug("Activate mbim\n"); mbim_bam_connect(mbim); ret = bam_data_connect(&mbim->bam_port, mbim->xport, mbim->port_num, USB_FUNC_MBIM); if (ret) { pr_err("bam_data_setup failed:err:%d\n", ret); goto fail; } } else { pr_info("PORTS already SET\n"); } Loading @@ -1366,7 +1309,8 @@ static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt) * perform bam data disconnect handshake upon usb * disconnect */ mbim_bam_disconnect(mbim); bam_data_disconnect(&mbim->bam_port, USB_FUNC_MBIM, mbim->port_num); if (mbim->xport == USB_GADGET_XPORT_BAM2BAM_IPA && mbim->data_interface_up && gadget_is_dwc3(cdev->gadget)) { Loading Loading @@ -1444,7 +1388,7 @@ static void mbim_disable(struct usb_function *f) msm_ep_unconfig(mbim->bam_port.in); } mbim_bam_disconnect(mbim); bam_data_disconnect(&mbim->bam_port, USB_FUNC_MBIM, mbim->port_num); mbim->data_interface_up = false; pr_info("mbim deactivated\n"); Loading @@ -1456,7 +1400,6 @@ static void mbim_suspend(struct usb_function *f) { bool remote_wakeup_allowed; struct f_mbim *mbim = func_to_mbim(f); int port_num; pr_info("mbim suspended\n"); Loading @@ -1481,39 +1424,17 @@ static void mbim_suspend(struct usb_function *f) return; } if (remote_wakeup_allowed) { port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, MBIM_ACTIVE_PORT); if (port_num < 0) return; bam_data_suspend(port_num); } else { /* * When remote wakeup is disabled, IPA BAM is disconnected * because it cannot send new data until the USB bus is resumed. * Endpoint descriptors info is saved before it gets reset by * the BAM disconnect API. This lets us restore this info when * the USB bus is resumed. */ if (mbim->bam_port.in->desc) mbim->in_ep_desc_backup = mbim->bam_port.in->desc; if (mbim->bam_port.out->desc) mbim->out_ep_desc_backup = mbim->bam_port.out->desc; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", mbim->in_ep_desc_backup, mbim->out_ep_desc_backup); if (!remote_wakeup_allowed) atomic_set(&mbim->online, 0); mbim_bam_disconnect(mbim); } bam_data_suspend(&mbim->bam_port, mbim->port_num, USB_FUNC_MBIM, remote_wakeup_allowed); } static void mbim_resume(struct usb_function *f) { bool remote_wakeup_allowed; struct f_mbim *mbim = func_to_mbim(f); int port_num; pr_info("mbim resumed\n"); Loading @@ -1536,23 +1457,11 @@ static void mbim_resume(struct usb_function *f) return; } if (remote_wakeup_allowed) { port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, MBIM_ACTIVE_PORT); if (port_num < 0) return; bam_data_resume(port_num); } else { /* Restore endpoint descriptors info. */ mbim->bam_port.in->desc = mbim->in_ep_desc_backup; mbim->bam_port.out->desc = mbim->out_ep_desc_backup; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", mbim->in_ep_desc_backup, mbim->out_ep_desc_backup); if (!remote_wakeup_allowed) atomic_set(&mbim->online, 1); mbim_bam_connect(mbim); } bam_data_resume(&mbim->bam_port, mbim->port_num, USB_FUNC_MBIM, remote_wakeup_allowed); } static int mbim_func_suspend(struct usb_function *f, unsigned char options) Loading
drivers/usb/gadget/f_qc_ecm.c +25 −102 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ struct f_ecm_qc { struct qc_gether port; u8 ctrl_id, data_id; enum transport_type xport; u8 port_num; char ethaddr[14]; struct usb_ep *notify; Loading @@ -78,8 +79,6 @@ struct f_ecm_qc { struct data_port bam_port; bool ecm_mdm_ready_trigger; const struct usb_endpoint_descriptor *in_ep_desc_backup; const struct usb_endpoint_descriptor *out_ep_desc_backup; bool data_interface_up; }; Loading Loading @@ -448,72 +447,6 @@ static void ecm_qc_notify(struct f_ecm_qc *ecm) ecm_qc_do_notify(ecm); } static int ecm_qc_bam_connect(struct f_ecm_qc *dev) { int ret; u8 src_connection_idx, dst_connection_idx; struct usb_composite_dev *cdev = dev->port.func.config->cdev; struct usb_gadget *gadget = cdev->gadget; enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ? IPA_P_BAM : A2_P_BAM; int port_num; port_num = (u_bam_data_func_to_port(USB_FUNC_ECM, ECM_QC_DEFAULT_PORT)); if (port_num < 0) return port_num; ret = bam2bam_data_port_select(port_num); if (ret) { pr_err("ecm_qc port select failed with err:%d\n", ret); return ret; } dev->bam_port.cdev = cdev; dev->bam_port.func = &dev->port.func; dev->bam_port.in = dev->port.in_ep; dev->bam_port.out = dev->port.out_ep; /* currently we use the first connection */ src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0); dst_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); if (src_connection_idx < 0 || dst_connection_idx < 0) { pr_err("usb_bam_get_connection_idx failed\n"); return ret; } ret = bam_data_connect(&dev->bam_port, port_num, dev->xport, src_connection_idx, dst_connection_idx, USB_FUNC_ECM); if (ret) { pr_err("bam_data_connect failed: err:%d\n", ret); return ret; } pr_debug("ecm bam connected\n"); dev->is_open = dev->ecm_mdm_ready_trigger ? true : false; ecm_qc_notify(dev); return 0; } static int ecm_qc_bam_disconnect(struct f_ecm_qc *dev) { int port_num; pr_debug("%s: dev:%p. Disconnect BAM.\n", __func__, dev); __ecm->ecm_mdm_ready_trigger = false; port_num = (u_bam_data_func_to_port(USB_FUNC_ECM, ECM_QC_DEFAULT_PORT)); if (port_num < 0) return port_num; bam_data_disconnect(&dev->bam_port, port_num); return 0; } void *ecm_qc_get_ipa_rx_cb(void) { return ipa_params.ecm_ipa_rx_dp_notify; Loading Loading @@ -680,7 +613,8 @@ static int ecm_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) * path. Only after the BAM data path is disconnected, * we can disconnect the port from the network layer. */ ecm_qc_bam_disconnect(ecm); bam_data_disconnect(&ecm->bam_port, USB_FUNC_ECM, ecm->port_num); if (ecm->xport != USB_GADGET_XPORT_BAM2BAM_IPA) { gether_qc_disconnect_name(&ecm->port, "ecm0"); } else if (ecm->data_interface_up && Loading Loading @@ -723,8 +657,16 @@ static int ecm_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } } if (ecm_qc_bam_connect(ecm)) ecm->bam_port.cdev = cdev; ecm->bam_port.func = &ecm->port.func; ecm->bam_port.in = ecm->port.in_ep; ecm->bam_port.out = ecm->port.out_ep; if (bam_data_connect(&ecm->bam_port, ecm->xport, ecm->port_num, USB_FUNC_ECM)) goto fail; ecm->is_open = ecm->ecm_mdm_ready_trigger ? true : false; } ecm->data_interface_up = alt; Loading Loading @@ -763,7 +705,8 @@ static void ecm_qc_disable(struct usb_function *f) DBG(cdev, "ecm deactivated\n"); if (ecm->port.in_ep->driver_data) { ecm_qc_bam_disconnect(ecm); bam_data_disconnect(&ecm->bam_port, USB_FUNC_ECM, ecm->port_num); if (ecm->xport != USB_GADGET_XPORT_BAM2BAM_IPA) gether_qc_disconnect_name(&ecm->port, "ecm0"); } else { Loading Loading @@ -791,7 +734,6 @@ static void ecm_qc_suspend(struct usb_function *f) { struct f_ecm_qc *ecm = func_to_ecm_qc(f); bool remote_wakeup_allowed; int port_num; /* Is DATA interface initialized? */ if (!ecm->data_interface_up) { Loading @@ -806,24 +748,11 @@ static void ecm_qc_suspend(struct usb_function *f) f->config->cdev->gadget->remote_wakeup; pr_debug("%s(): remote_wakeup:%d\n:", __func__, remote_wakeup_allowed); if (remote_wakeup_allowed) { port_num = (u_bam_data_func_to_port(USB_FUNC_ECM, ECM_QC_ACTIVE_PORT)); if (port_num < 0) return; bam_data_suspend(port_num); } else { /* * When remote wakeup is disabled, IPA BAM is disconnected * because it cannot send new data until the USB bus is resumed. * Endpoint descriptors info is saved before it gets reset by * the BAM disconnect API. This lets us restore this info when * the USB bus is resumed. */ ecm->in_ep_desc_backup = ecm->bam_port.in->desc; ecm->out_ep_desc_backup = ecm->bam_port.out->desc; ecm_qc_bam_disconnect(ecm); } if (!remote_wakeup_allowed) __ecm->ecm_mdm_ready_trigger = false; bam_data_suspend(&ecm->bam_port, ecm->port_num, USB_FUNC_ECM, remote_wakeup_allowed); pr_debug("ecm suspended\n"); } Loading @@ -832,7 +761,6 @@ static void ecm_qc_resume(struct usb_function *f) { struct f_ecm_qc *ecm = func_to_ecm_qc(f); bool remote_wakeup_allowed; int port_num; if (!ecm->data_interface_up) { pr_err("%s(): data interface was not up\n", __func__); Loading @@ -845,17 +773,12 @@ static void ecm_qc_resume(struct usb_function *f) remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; if (remote_wakeup_allowed) { port_num = (u_bam_data_func_to_port(USB_FUNC_ECM, ECM_QC_ACTIVE_PORT)); if (port_num < 0) return; bam_data_resume(port_num); } else { /* Restore endpoint descriptors info. */ ecm->bam_port.in->desc = ecm->in_ep_desc_backup; ecm->bam_port.out->desc = ecm->out_ep_desc_backup; ecm_qc_bam_connect(ecm); bam_data_resume(&ecm->bam_port, ecm->port_num, USB_FUNC_ECM, remote_wakeup_allowed); if (!remote_wakeup_allowed) { ecm->is_open = ecm->ecm_mdm_ready_trigger ? true : false; ecm_qc_notify(ecm); } pr_debug("ecm resumed\n"); Loading
drivers/usb/gadget/f_qc_rndis.c +25 −116 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ * Copyright (C) 2008 Nokia Corporation * Copyright (C) 2009 Samsung Electronics * Author: Michal Nazarewicz (mina86@mina86.com) * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 Loading Loading @@ -98,9 +98,8 @@ struct f_rndis_qc { atomic_t notify_count; struct data_port bam_port; enum transport_type xport; u8 port_num; bool net_ready_trigger; const struct usb_endpoint_descriptor *in_ep_desc_backup; const struct usb_endpoint_descriptor *out_ep_desc_backup; }; static struct ipa_usb_init_params rndis_ipa_params; Loading Loading @@ -416,77 +415,6 @@ static inline void rndis_qc_unlock(atomic_t *excl) atomic_dec(excl); } /* MSM bam support */ static int rndis_qc_bam_connect(struct f_rndis_qc *dev) { int ret; u8 src_connection_idx, dst_connection_idx; struct usb_composite_dev *cdev = dev->port.func.config->cdev; struct usb_gadget *gadget = cdev->gadget; enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ? IPA_P_BAM : A2_P_BAM; int port_num; dev->bam_port.cdev = cdev; dev->bam_port.func = &dev->port.func; dev->bam_port.in = dev->port.in_ep; dev->bam_port.out = dev->port.out_ep; port_num = (u_bam_data_func_to_port(USB_FUNC_RNDIS, RNDIS_QC_ACTIVE_PORT)); if (port_num < 0) return port_num; ret = bam2bam_data_port_select(port_num); if (ret) { pr_err("qc rndis bam port setup failed err:%d\n", ret); return ret; } /* currently we use the first connection */ src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0); dst_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); if (src_connection_idx < 0 || dst_connection_idx < 0) { pr_err("%s: usb_bam_get_connection_idx failed\n", __func__); return ret; } if (peer_bam == A2_P_BAM) ret = bam_data_connect(&dev->bam_port, port_num, USB_GADGET_XPORT_BAM2BAM, src_connection_idx, dst_connection_idx, USB_FUNC_RNDIS); else { ret = bam_data_connect(&dev->bam_port, port_num, USB_GADGET_XPORT_BAM2BAM_IPA, src_connection_idx, dst_connection_idx, USB_FUNC_RNDIS); rndis_qc_open(&dev->port); } if (ret) { pr_err("bam_data_connect failed: err:%d\n", ret); return ret; } pr_info("rndis bam connected\n"); return 0; } static int rndis_qc_bam_disconnect(struct f_rndis_qc *dev) { int port_num; pr_debug("dev:%p. %s Disconnect BAM.\n", dev, __func__); port_num = (u_bam_data_func_to_port(USB_FUNC_RNDIS, RNDIS_QC_ACTIVE_PORT)); if (port_num < 0) return port_num; bam_data_disconnect(&dev->bam_port, port_num); return 0; } /*-------------------------------------------------------------------------*/ static struct sk_buff *rndis_qc_add_header(struct qc_gether *port, Loading Loading @@ -730,7 +658,8 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) * path. Only after the BAM data path is disconnected, * we can disconnect the port from the network layer. */ rndis_qc_bam_disconnect(rndis); bam_data_disconnect(&rndis->bam_port, USB_FUNC_RNDIS, rndis->port_num); if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) gether_qc_disconnect_name(&rndis->port, Loading Loading @@ -776,15 +705,23 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) */ rndis->port.cdc_filter = 0; if (rndis_qc_bam_connect(rndis)) rndis->bam_port.cdev = cdev; rndis->bam_port.func = &rndis->port.func; rndis->bam_port.in = rndis->port.in_ep; rndis->bam_port.out = rndis->port.out_ep; if (bam_data_connect(&rndis->bam_port, rndis->xport, rndis->port_num, USB_FUNC_RNDIS)) goto fail; DBG(cdev, "RNDIS RX/TX early activation ...\n"); if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) { net = gether_qc_connect_name(&rndis->port, "rndis0", false); else } else { rndis_qc_open(&rndis->port); net = gether_qc_get_net("rndis0"); } if (IS_ERR(net)) return PTR_ERR(net); Loading @@ -809,7 +746,7 @@ static void rndis_qc_disable(struct usb_function *f) pr_info("rndis deactivated\n"); rndis_uninit(rndis->config); rndis_qc_bam_disconnect(rndis); bam_data_disconnect(&rndis->bam_port, USB_FUNC_RNDIS, rndis->port_num); if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) gether_qc_disconnect_name(&rndis->port, "rndis0"); Loading @@ -826,7 +763,6 @@ static void rndis_qc_suspend(struct usb_function *f) { struct f_rndis_qc *rndis = func_to_rndis_qc(f); bool remote_wakeup_allowed; int port_num; if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; Loading @@ -836,13 +772,7 @@ static void rndis_qc_suspend(struct usb_function *f) pr_info("%s(): start rndis suspend: remote_wakeup_allowed:%d\n:", __func__, remote_wakeup_allowed); if (remote_wakeup_allowed) { port_num = (u_bam_data_func_to_port(USB_FUNC_RNDIS, RNDIS_QC_ACTIVE_PORT)); if (port_num < 0) return; bam_data_suspend(port_num); } else { if (!remote_wakeup_allowed) { /* This is required as Linux host side RNDIS driver doesn't * send RNDIS_MESSAGE_PACKET_FILTER before suspending USB bus. * Hence we perform same operations explicitly here for Linux Loading @@ -850,26 +780,11 @@ static void rndis_qc_suspend(struct usb_function *f) * already updated due to receiving of PACKET_FILTER. */ rndis_flow_control(rndis->config, true); /* * When remote wakeup is disabled, IPA BAM is disconnected * because it cannot send new data until the USB bus is resumed. * Endpoint descriptors info is saved before it gets reset by * the BAM disconnect API. This lets us restore this info when * the USB bus is resumed. */ if (rndis->bam_port.in->desc) rndis->in_ep_desc_backup = rndis->bam_port.in->desc; if (rndis->bam_port.out->desc) rndis->out_ep_desc_backup = rndis->bam_port.out->desc; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", rndis->in_ep_desc_backup, rndis->out_ep_desc_backup); pr_debug("%s(): Disconnecting\n", __func__); rndis_qc_bam_disconnect(rndis); } bam_data_suspend(&rndis->bam_port, rndis->port_num, USB_FUNC_RNDIS, remote_wakeup_allowed); pr_debug("rndis suspended\n"); } Loading @@ -877,7 +792,6 @@ static void rndis_qc_resume(struct usb_function *f) { struct f_rndis_qc *rndis = func_to_rndis_qc(f); bool remote_wakeup_allowed; int port_num; pr_debug("%s: rndis resumed\n", __func__); Loading @@ -892,17 +806,12 @@ static void rndis_qc_resume(struct usb_function *f) else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; if (remote_wakeup_allowed) { port_num = (u_bam_data_func_to_port(USB_FUNC_RNDIS, RNDIS_QC_ACTIVE_PORT)); if (port_num < 0) return; bam_data_resume(port_num); } else { /* Restore endpoint descriptors info. */ rndis->bam_port.in->desc = rndis->in_ep_desc_backup; rndis->bam_port.out->desc = rndis->out_ep_desc_backup; rndis_qc_bam_connect(rndis); bam_data_resume(&rndis->bam_port, rndis->port_num, USB_FUNC_RNDIS, remote_wakeup_allowed); if (!remote_wakeup_allowed) { if (rndis->xport == USB_GADGET_XPORT_BAM2BAM_IPA) rndis_qc_open(&rndis->port); /* * Linux Host doesn't sends RNDIS_MSG_INIT or non-zero value * set with RNDIS_MESSAGE_PACKET_FILTER after performing bus Loading
drivers/usb/gadget/u_bam_data.c +107 −28 Original line number Diff line number Diff line Loading @@ -1362,20 +1362,23 @@ static void bam_data_free_reqs(struct bam_data_port *port) } } void bam_data_disconnect(struct data_port *gr, u8 port_num) void bam_data_disconnect(struct data_port *gr, enum function_type func, u8 dev_port_num) { struct bam_data_port *port; struct bam_data_ch_info *d; struct sk_buff *skb = NULL; unsigned long flags; int port_num; pr_debug("dev:%p port number:%d\n", gr, port_num); if (port_num >= n_bam2bam_data_ports) { port_num = u_bam_data_func_to_port(func, dev_port_num); if (port_num < 0 || port_num >= n_bam2bam_data_ports) { pr_err("invalid bam2bam portno#%d\n", port_num); return; } pr_debug("dev:%p port number:%d\n", gr, port_num); if (!gr) { pr_err("data port is null\n"); return; Loading Loading @@ -1479,26 +1482,49 @@ void bam_data_disconnect(struct data_port *gr, u8 port_num) spin_unlock_irqrestore(&port->port_lock, flags); } int bam_data_connect(struct data_port *gr, u8 port_num, enum transport_type trans, u8 src_connection_idx, u8 dst_connection_idx, enum function_type func) int bam_data_connect(struct data_port *gr, enum transport_type trans, u8 dev_port_num, enum function_type func) { struct bam_data_port *port; struct bam_data_ch_info *d; int ret; int ret, port_num; unsigned long flags; pr_debug("dev:%p port#%d\n", gr, port_num); if (port_num >= n_bam2bam_data_ports) { pr_err("invalid portno#%d\n", port_num); return -ENODEV; } enum peer_bam bam_name; u8 src_connection_idx, dst_connection_idx; if (!gr) { pr_err("data port is null\n"); return -ENODEV; } port_num = u_bam_data_func_to_port(func, dev_port_num); if (port_num < 0 || port_num >= n_bam2bam_data_ports) { pr_err("invalid portno#%d\n", port_num); return -EINVAL; } pr_debug("dev:%p port#%d\n", gr, port_num); bam_name = (trans == USB_GADGET_XPORT_BAM2BAM_IPA) ? IPA_P_BAM : A2_P_BAM; ret = bam2bam_data_port_select(port_num); if (ret) { pr_err("mbim port select failed err: %d\n", ret); return ret; } src_connection_idx = usb_bam_get_connection_idx(gr->cdev->gadget->name, bam_name, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, dev_port_num); dst_connection_idx = usb_bam_get_connection_idx(gr->cdev->gadget->name, bam_name, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, dev_port_num); if (src_connection_idx < 0 || dst_connection_idx < 0) { pr_err("%s: usb_bam_get_connection_idx failed\n", __func__); return ret; } port = bam2bam_data_ports[port_num]; spin_lock_irqsave(&port->port_lock, flags); Loading Loading @@ -1815,40 +1841,93 @@ static void bam_data_stop(void *param, enum usb_bam_pipe_dir dir) } } void bam_data_suspend(u8 port_num) void bam_data_suspend(struct data_port *port_usb, u8 dev_port_num, enum function_type func, bool remote_wakeup_enabled) { struct bam_data_port *port; unsigned long flags; int port_num; port_num = u_bam_data_func_to_port(func, dev_port_num); if (port_num < 0 || port_num >= n_bam2bam_data_ports) { pr_err("invalid bam2bam portno#%d\n", port_num); return; } pr_debug("%s: suspended port %d\n", __func__, port_num); port = bam2bam_data_ports[port_num]; if (port) { if (!port) { pr_err("%s(): Port is NULL.\n", __func__); return; } /* suspend with remote wakeup disabled */ if (!remote_wakeup_enabled) { /* * When remote wakeup is disabled, IPA BAM is disconnected * because it cannot send new data until the USB bus is resumed. * Endpoint descriptors info is saved before it gets reset by * the BAM disconnect API. This lets us restore this info when * the USB bus is resumed. */ port_usb->in_ep_desc_backup = port_usb->in->desc; port_usb->out_ep_desc_backup = port_usb->out->desc; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", port_usb->in_ep_desc_backup, port_usb->out_ep_desc_backup); bam_data_disconnect(port_usb, func, dev_port_num); return; } spin_lock_irqsave(&port->port_lock, flags); port->last_event = U_BAM_DATA_SUSPEND_E; queue_work(bam_data_wq, &port->suspend_w); spin_unlock_irqrestore(&port->port_lock, flags); } else { pr_err("%s(): Port is NULL.\n", __func__); } } void bam_data_resume(u8 port_num) void bam_data_resume(struct data_port *port_usb, u8 dev_port_num, enum function_type func, bool remote_wakeup_enabled) { struct bam_data_port *port; unsigned long flags; int port_num; port_num = u_bam_data_func_to_port(func, dev_port_num); if (port_num < 0 || port_num >= n_bam2bam_data_ports) { pr_err("invalid bam2bam portno#%d\n", port_num); return; } pr_debug("%s: resumed port %d\n", __func__, port_num); port = bam2bam_data_ports[port_num]; if (port) { if (!port) { pr_err("%s(): Port is NULL.\n", __func__); return; } /* resume with remote wakeup disabled */ if (!remote_wakeup_enabled) { /* Restore endpoint descriptors info. */ port_usb->in->desc = port_usb->in_ep_desc_backup; port_usb->out->desc = port_usb->out_ep_desc_backup; pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p", port_usb->in_ep_desc_backup, port_usb->out_ep_desc_backup); bam_data_connect(port_usb, port->data_ch.trans, dev_port_num, func); return; } spin_lock_irqsave(&port->port_lock, flags); port->last_event = U_BAM_DATA_RESUME_E; queue_work(bam_data_wq, &port->resume_w); spin_unlock_irqrestore(&port->port_lock, flags); } else { pr_err("%s(): Port is NULL.\n", __func__); } } void bam_data_flush_workqueue(void) Loading
drivers/usb/gadget/u_bam_data.h +18 −14 Original line number Diff line number Diff line /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -33,23 +33,27 @@ struct data_port { struct usb_ep *out; int ipa_consumer_ep; int ipa_producer_ep; const struct usb_endpoint_descriptor *in_ep_desc_backup; const struct usb_endpoint_descriptor *out_ep_desc_backup; }; int bam2bam_data_port_select(int portno); void bam_data_disconnect(struct data_port *gr, u8 port_num); void bam_data_disconnect(struct data_port *gr, enum function_type func, u8 dev_port_num); int bam_data_connect(struct data_port *gr, u8 port_num, enum transport_type trans, u8 src_connection_idx, u8 dst_connection_idx, enum function_type func); int bam_data_connect(struct data_port *gr, enum transport_type trans, u8 dev_port_num, enum function_type func); int bam_data_setup(enum function_type func, unsigned int no_bam2bam_port); void bam_data_flush_workqueue(void); void bam_data_suspend(u8 port_num); void bam_data_suspend(struct data_port *port_usb, u8 dev_port_num, enum function_type func, bool remote_wakeup_enabled); void bam_data_resume(u8 port_num); void bam_data_resume(struct data_port *port_usb, u8 dev_port_num, enum function_type func, bool remote_wakeup_enabled); void u_bam_data_set_dl_max_xfer_size(u32 dl_max_transfer_size); Loading