Loading drivers/usb/gadget/android.c +35 −7 Original line number Diff line number Diff line Loading @@ -64,9 +64,9 @@ #include "rndis.c" #include "f_qc_ecm.c" #include "f_mbim.c" #include "f_qc_rndis.c" #include "u_bam_data.c" #include "f_ecm.c" #include "f_qc_rndis.c" #include "u_ether.c" #include "u_qc_ether.c" #ifdef CONFIG_TARGET_CORE Loading Loading @@ -1649,6 +1649,8 @@ static struct android_usb_function ptp_function = { .bind_config = ptp_function_bind_config, }; /* rndis transport string */ static char rndis_transports[MAX_XPORT_STR_LEN]; struct rndis_function_config { u8 ethaddr[ETH_ALEN]; Loading Loading @@ -1741,6 +1743,7 @@ static int rndis_qc_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { int ret; char *trans; struct rndis_function_config *rndis = f->config; if (!rndis) { Loading @@ -1752,11 +1755,17 @@ static int rndis_qc_function_bind_config(struct android_usb_function *f, rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2], rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]); ret = gether_qc_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis"); pr_debug("%s: rndis_transport is %s", __func__, rndis_transports); trans = strim(rndis_transports); if (strcmp("BAM2BAM_IPA", trans)) { ret = gether_qc_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis"); if (ret) { pr_err("%s: gether_setup failed\n", __func__); return ret; } } if (rndis->wceis) { /* "Wireless" RNDIS; auto-detected by Windows */ Loading @@ -1772,7 +1781,7 @@ static int rndis_qc_function_bind_config(struct android_usb_function *f, return rndis_qc_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID, rndis->manufacturer, rndis->max_pkt_per_xfer); rndis->max_pkt_per_xfer, trans); } static void rndis_function_unbind_config(struct android_usb_function *f, Loading @@ -1785,6 +1794,9 @@ static void rndis_function_unbind_config(struct android_usb_function *f, static void rndis_qc_function_unbind_config(struct android_usb_function *f, struct usb_configuration *c) { char *trans = strim(rndis_transports); if (strcmp("BAM2BAM_IPA", trans)) gether_qc_cleanup_name("rndis0"); } Loading Loading @@ -1919,6 +1931,21 @@ static ssize_t rndis_max_pkt_per_xfer_store(struct device *dev, static DEVICE_ATTR(max_pkt_per_xfer, S_IRUGO | S_IWUSR, rndis_max_pkt_per_xfer_show, rndis_max_pkt_per_xfer_store); static ssize_t rndis_transports_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", rndis_transports); } static ssize_t rndis_transports_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { strlcpy(rndis_transports, buf, sizeof(rndis_transports)); return size; } static DEVICE_ATTR(rndis_transports, S_IRUGO | S_IWUSR, rndis_transports_show, rndis_transports_store); static ssize_t rndis_rx_trigger_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) Loading @@ -1941,6 +1968,7 @@ static struct device_attribute *rndis_function_attributes[] = { &dev_attr_ethaddr, &dev_attr_vendorID, &dev_attr_max_pkt_per_xfer, &dev_attr_rndis_transports, &dev_attr_rx_trigger, NULL }; Loading drivers/usb/gadget/f_qc_rndis.c +104 −16 Original line number Diff line number Diff line Loading @@ -33,7 +33,8 @@ #include "u_ether.h" #include "u_qc_ether.h" #include "rndis.h" #include "u_bam_data.h" #include <mach/rndis_ipa.h> /* * This function is an RNDIS Ethernet port -- a Microsoft protocol that's Loading Loading @@ -95,8 +96,13 @@ struct f_rndis_qc { struct usb_request *notify_req; atomic_t notify_count; struct data_port bam_port; enum transport_type xport; }; static struct ipa_usb_init_params rndis_ipa_params; static bool rndis_ipa_supported; static void rndis_qc_open(struct qc_gether *geth); static inline struct f_rndis_qc *func_to_rndis_qc(struct usb_function *f) { return container_of(f, struct f_rndis_qc, port.func); Loading Loading @@ -424,6 +430,8 @@ static int rndis_qc_bam_connect(struct f_rndis_qc *dev) 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; dev->bam_port.cdev = cdev; dev->bam_port.func = &dev->port.func; Loading @@ -431,16 +439,24 @@ static int rndis_qc_bam_connect(struct f_rndis_qc *dev) dev->bam_port.out = dev->port.out_ep; /* currently we use the first connection */ src_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM, src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam, USB_TO_PEER_PERIPHERAL, 0); dst_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM, dst_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam, PEER_PERIPHERAL_TO_USB, 0); if (src_connection_idx < 0 || dst_connection_idx < 0) { pr_err("%s: usb_bam_get_connection_idx failed\n", __func__); return ret; } ret = bam_data_connect(&dev->bam_port, 0, USB_GADGET_XPORT_BAM2BAM, src_connection_idx, dst_connection_idx, USB_FUNC_RNDIS); if (peer_bam == A2_P_BAM) ret = bam_data_connect(&dev->bam_port, 0, USB_GADGET_XPORT_BAM2BAM, src_connection_idx, dst_connection_idx, USB_FUNC_RNDIS); else { ret = bam_data_connect(&dev->bam_port, 0, 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); Loading Loading @@ -586,6 +602,7 @@ static void rndis_qc_command_complete(struct usb_ep *ep, if (buf->MessageType == RNDIS_MSG_INIT) { rndis->max_pkt_size = buf->MaxTransferSize; pr_debug("MaxTransferSize: %d\n", buf->MaxTransferSize); u_bam_data_set_max_xfer_size(rndis->max_pkt_size); } } Loading Loading @@ -694,7 +711,10 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) * we can disconnect the port from the network layer. */ rndis_qc_bam_disconnect(rndis); gether_qc_disconnect_name(&rndis->port, "rndis0"); if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) gether_qc_disconnect_name(&rndis->port, "rndis0"); } if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) { Loading @@ -708,6 +728,16 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) goto fail; } } if (rndis->xport == USB_GADGET_XPORT_BAM2BAM_IPA && gadget_is_dwc3(cdev->gadget)) { if (msm_ep_config(rndis->port.in_ep) || msm_ep_config(rndis->port.out_ep)) { pr_err("%s: ep_config failed\n", __func__); goto fail; } } else pr_debug("RNDIS is being used with non DWC3 core\n"); /* Avoid ZLPs; they can be troublesome. */ rndis->port.is_zlp_ok = false; Loading @@ -730,7 +760,11 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) goto fail; DBG(cdev, "RNDIS RX/TX early activation ...\n"); net = gether_qc_connect_name(&rndis->port, "rndis0", false); if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) net = gether_qc_connect_name(&rndis->port, "rndis0", false); else net = gether_qc_get_net("rndis0"); if (IS_ERR(net)) return PTR_ERR(net); Loading @@ -755,7 +789,10 @@ static void rndis_qc_disable(struct usb_function *f) rndis_uninit(rndis->config); rndis_qc_bam_disconnect(rndis); if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) gether_qc_disconnect_name(&rndis->port, "rndis0"); else rndis_ipa_supported = false; usb_ep_disable(rndis->notify); rndis->notify->driver_data = NULL; Loading Loading @@ -923,7 +960,8 @@ rndis_qc_bind(struct usb_configuration *c, struct usb_function *f) rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0); rndis_set_host_mac(rndis->config, rndis->ethaddr); if (rndis_set_param_vendor(rndis->config, rndis->vendorID, if (rndis->manufacturer && rndis->vendorID && rndis_set_param_vendor(rndis->config, rndis->vendorID, rndis->manufacturer)) goto fail; Loading Loading @@ -989,9 +1027,19 @@ rndis_qc_unbind(struct usb_configuration *c, struct usb_function *f) kfree(rndis->notify_req->buf); usb_ep_free_request(rndis->notify, rndis->notify_req); if (rndis->xport == USB_GADGET_XPORT_BAM2BAM_IPA) { rndis_ipa_cleanup(rndis_ipa_params.private); rndis_ipa_supported = false; } kfree(rndis); } bool is_rndis_ipa_supported(void) { return rndis_ipa_supported; } /* Some controllers can't support RNDIS ... */ static inline bool can_support_rndis_qc(struct usb_configuration *c) { Loading @@ -1014,13 +1062,13 @@ static inline bool can_support_rndis_qc(struct usb_configuration *c) int rndis_qc_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) { return rndis_qc_bind_config_vendor(c, ethaddr, 0, NULL, 1); return rndis_qc_bind_config_vendor(c, ethaddr, 0, NULL, 1, NULL); } int rndis_qc_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], u32 vendorID, const char *manufacturer, u8 max_pkt_per_xfer) u8 max_pkt_per_xfer, char *xport_name) { struct f_rndis_qc *rndis; int status; Loading Loading @@ -1075,13 +1123,26 @@ rndis_qc_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], goto fail; } rndis->xport = str_to_xport(xport_name); /* export host's Ethernet address in CDC format */ if (rndis->xport == USB_GADGET_XPORT_BAM2BAM_IPA) { gether_qc_get_macs(rndis_ipa_params.device_ethaddr, rndis_ipa_params.host_ethaddr); pr_debug("setting host_ethaddr=%pM, device_ethaddr=%pM", rndis_ipa_params.host_ethaddr, rndis_ipa_params.device_ethaddr); rndis_ipa_supported = true; } else memcpy(rndis->ethaddr, ethaddr, ETH_ALEN); rndis->vendorID = vendorID; rndis->manufacturer = manufacturer; /* if max_pkt_per_xfer was not configured set to default value */ rndis->max_pkt_per_xfer = max_pkt_per_xfer ? max_pkt_per_xfer : DEFAULT_MAX_PKT_PER_XFER; u_bam_data_set_max_pkt_num(rndis->max_pkt_per_xfer); /* RNDIS activates when the host changes this filter */ rndis->port.cdc_filter = 0; Loading @@ -1107,9 +1168,23 @@ rndis_qc_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], status = usb_add_function(c, &rndis->port.func); if (status) { kfree(rndis); goto fail; } if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) return status; status = rndis_ipa_init(&rndis_ipa_params); if (status) { pr_err("%s: failed to initialize rndis_ipa\n", __func__); kfree(rndis); goto fail; } else { pr_debug("%s: rndis_ipa successful created\n", __func__); return status; } fail: rndis_exit(); } return status; } Loading Loading @@ -1220,4 +1295,17 @@ static void rndis_qc_cleanup(void) _rndis_qc = NULL; } void *rndis_qc_get_ipa_rx_cb(void) { return rndis_ipa_params.ipa_rx_notify; } void *rndis_qc_get_ipa_tx_cb(void) { return rndis_ipa_params.ipa_tx_notify; } void *rndis_qc_get_ipa_priv(void) { return rndis_ipa_params.private; } drivers/usb/gadget/rndis.c +16 −6 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ #include <asm/io.h> #include <asm/byteorder.h> #include <asm/unaligned.h> #include "u_bam_data.h" #undef VERBOSE_DEBUG Loading Loading @@ -544,14 +544,24 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len, */ retval = 0; if (*params->filter) { params->state = RNDIS_DATA_INITIALIZED; if (!is_rndis_ipa_supported()) { netif_carrier_on(params->dev); if (netif_running(params->dev)) netif_wake_queue(params->dev); } else { params->state = RNDIS_INITIALIZED; if (params->state != RNDIS_DATA_INITIALIZED) u_bam_data_start_rndis_ipa(); } params->state = RNDIS_DATA_INITIALIZED; } else { if (!is_rndis_ipa_supported()) { netif_carrier_off(params->dev); netif_stop_queue(params->dev); } else { if (params->state == RNDIS_DATA_INITIALIZED) u_bam_data_stop_rndis_ipa(); } params->state = RNDIS_INITIALIZED; } break; Loading drivers/usb/gadget/rndis.h +1 −1 Original line number Diff line number Diff line Loading @@ -218,7 +218,7 @@ int rndis_signal_connect (int configNr); int rndis_signal_disconnect (int configNr); int rndis_state (int configNr); extern void rndis_set_host_mac (int configNr, const u8 *addr); extern bool is_rndis_ipa_supported(void); int rndis_init(void); void rndis_exit (void); Loading drivers/usb/gadget/u_bam_data.c +161 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,14 @@ static int n_bam2bam_data_ports; #define SPS_PARAMS_TBE BIT(6) #define MSM_VENDOR_ID BIT(16) struct rndis_data_ch_info { u32 max_transfer_size; u32 max_packets_number; u32 prod_clnt_hdl; u32 cons_clnt_hdl; void *priv; }; struct bam_data_ch_info { unsigned long flags; unsigned id; Loading @@ -55,6 +63,10 @@ struct bam_data_ch_info { struct usb_bam_connect_ipa_params ipa_params; }; static struct work_struct *rndis_conn_w; static struct work_struct *rndis_disconn_w; static bool is_ipa_rndis_net_on; struct bam_data_port { unsigned port_num; unsigned int ref_count; Loading @@ -66,8 +78,15 @@ struct bam_data_port { struct work_struct suspend_w; struct work_struct resume_w; }; struct usb_bam_data_connect_info { u32 usb_bam_pipe_idx; u32 peer_pipe_idx; u32 usb_bam_handle; struct sps_mem_buffer data_fifo; }; struct bam_data_port *bam2bam_data_ports[BAM2BAM_DATA_N_PORTS]; static struct rndis_data_ch_info rndis_data; static void bam2bam_data_suspend_work(struct work_struct *w); static void bam2bam_data_resume_work(struct work_struct *w); Loading Loading @@ -185,6 +204,12 @@ static void bam2bam_data_disconnect_work(struct work_struct *w) if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { if (d->func_type == USB_FUNC_ECM) ecm_ipa_disconnect(d->ipa_params.priv); if (d->func_type == USB_FUNC_RNDIS) { rndis_ipa_pipe_disconnect_notify(d->ipa_params.priv); is_ipa_rndis_net_on = false; } ret = usb_bam_disconnect_ipa(&d->ipa_params); if (ret) pr_err("usb_bam_disconnect_ipa failed: err:%d\n", ret); Loading @@ -200,6 +225,8 @@ static void bam2bam_data_connect_work(struct work_struct *w) connect_w); struct teth_bridge_connect_params connect_params; struct bam_data_ch_info *d = &port->data_ch; struct data_port *d_port = port->port_usb; struct usb_gadget *gadget = d_port->cdev->gadget; ipa_notify_cb usb_notify_cb; void *priv; u32 sps_params; Loading @@ -225,23 +252,76 @@ static void bam2bam_data_connect_work(struct work_struct *w) d->ipa_params.notify = ecm_qc_get_ipa_rx_cb(); d->ipa_params.priv = ecm_qc_get_ipa_priv(); } if (d->func_type == USB_FUNC_RNDIS) { d->ipa_params.notify = rndis_qc_get_ipa_rx_cb(); d->ipa_params.priv = rndis_qc_get_ipa_priv(); } ret = usb_bam_connect_ipa(&d->ipa_params); if (ret) { pr_err("%s: usb_bam_connect_ipa failed: err:%d\n", __func__, ret); return; } if (d->func_type == USB_FUNC_RNDIS && gadget_is_dwc3(gadget)) { u8 idx; struct usb_bam_data_connect_info bam_info; idx = usb_bam_get_connection_idx(gadget->name, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, 0); if (idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } get_bam2bam_connection_info(idx, &bam_info.usb_bam_handle, &bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx, NULL, &bam_info.data_fifo); msm_data_fifo_config(port->port_usb->out, bam_info.data_fifo.phys_base, bam_info.data_fifo.size, bam_info.usb_bam_pipe_idx); } d->ipa_params.dir = PEER_PERIPHERAL_TO_USB; if (d->func_type == USB_FUNC_ECM) { d->ipa_params.notify = ecm_qc_get_ipa_tx_cb(); d->ipa_params.priv = ecm_qc_get_ipa_priv(); } if (d->func_type == USB_FUNC_RNDIS) { d->ipa_params.notify = rndis_qc_get_ipa_tx_cb(); d->ipa_params.priv = rndis_qc_get_ipa_priv(); } ret = usb_bam_connect_ipa(&d->ipa_params); if (ret) { pr_err("%s: usb_bam_connect_ipa failed: err:%d\n", __func__, ret); return; } if (d->func_type == USB_FUNC_RNDIS && gadget_is_dwc3(gadget)) { u8 idx; struct usb_bam_data_connect_info bam_info; idx = usb_bam_get_connection_idx(gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, 0); if (idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } get_bam2bam_connection_info(idx, &bam_info.usb_bam_handle, &bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx, NULL, &bam_info.data_fifo); msm_data_fifo_config(port->port_usb->in, bam_info.data_fifo.phys_base, bam_info.data_fifo.size, bam_info.usb_bam_pipe_idx); } if (d->func_type == USB_FUNC_MBIM) { mbim_configure_params(); Loading Loading @@ -270,6 +350,26 @@ static void bam2bam_data_connect_work(struct work_struct *w) return; } } if (d->func_type == USB_FUNC_RNDIS) { rndis_data.prod_clnt_hdl = d->ipa_params.prod_clnt_hdl; rndis_data.cons_clnt_hdl = d->ipa_params.cons_clnt_hdl; rndis_data.priv = d->ipa_params.priv; ret = rndis_ipa_pipe_connect_notify( rndis_data.cons_clnt_hdl, rndis_data.prod_clnt_hdl, rndis_data.max_transfer_size, rndis_data.max_packets_number, rndis_data.priv); if (ret) { pr_err("%s: failed to connect IPA: err:%d\n", __func__, ret); return; } is_ipa_rndis_net_on = true; } } else { /* transport type is USB_GADGET_XPORT_BAM2BAM */ usb_bam_reset_complete(); ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx); Loading Loading @@ -302,8 +402,15 @@ static void bam2bam_data_connect_work(struct work_struct *w) d->rx_req->complete = bam_data_endless_rx_complete; d->rx_req->length = 0; d->rx_req->no_interrupt = 1; if (d->func_type == USB_FUNC_RNDIS && gadget_is_dwc3(gadget)) { sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | MSM_PRODUCER | d->src_pipe_idx; d->rx_req->length = 32*1024; } else sps_params = (SPS_PARAMS_SPS_MODE | d->src_pipe_idx | MSM_VENDOR_ID) & ~SPS_PARAMS_TBE; d->rx_req->udc_priv = sps_params; d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_KERNEL); if (!d->tx_req) Loading @@ -313,8 +420,14 @@ static void bam2bam_data_connect_work(struct work_struct *w) d->tx_req->complete = bam_data_endless_tx_complete; d->tx_req->length = 0; d->tx_req->no_interrupt = 1; if (d->func_type == USB_FUNC_RNDIS && gadget_is_dwc3(gadget)) { sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | d->dst_pipe_idx; d->tx_req->length = 32*1024; } else sps_params = (SPS_PARAMS_SPS_MODE | d->dst_pipe_idx | MSM_VENDOR_ID) & ~SPS_PARAMS_TBE; d->tx_req->udc_priv = sps_params; /* queue in & out requests */ Loading Loading @@ -376,12 +489,30 @@ static int bam2bam_data_port_alloc(int portno) d->ipa_params.src_client = IPA_CLIENT_USB_PROD; d->ipa_params.dst_client = IPA_CLIENT_USB_CONS; rndis_disconn_w = &port->disconnect_w; done: pr_debug("port:%p portno:%d\n", port, portno); return 0; } void u_bam_data_start_rndis_ipa(void) { pr_debug("%s\n", __func__); if (!is_ipa_rndis_net_on) queue_work(bam_data_wq, rndis_conn_w); } void u_bam_data_stop_rndis_ipa(void) { pr_debug("%s\n", __func__); if (is_ipa_rndis_net_on) queue_work(bam_data_wq, rndis_disconn_w); } void bam_data_disconnect(struct data_port *gr, u8 port_num) { struct bam_data_port *port; Loading Loading @@ -483,6 +614,11 @@ int bam_data_connect(struct data_port *gr, u8 port_num, d->ipa_params.dst_idx = dst_connection_idx; } if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->func_type == USB_FUNC_RNDIS) { rndis_conn_w = &port->connect_w; return 0; } queue_work(bam_data_wq, &port->connect_w); return 0; Loading Loading @@ -650,3 +786,24 @@ static void bam2bam_data_resume_work(struct work_struct *w) if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) usb_bam_resume(&d->ipa_params); } void u_bam_data_set_max_xfer_size(u32 max_transfer_size) { if (!max_transfer_size) { pr_err("%s: invalid parameters\n", __func__); return; } rndis_data.max_transfer_size = max_transfer_size; } void u_bam_data_set_max_pkt_num(u32 max_packets_number) { if (!max_packets_number) { pr_err("%s: invalid parameters\n", __func__); return; } rndis_data.max_packets_number = max_packets_number; } Loading
drivers/usb/gadget/android.c +35 −7 Original line number Diff line number Diff line Loading @@ -64,9 +64,9 @@ #include "rndis.c" #include "f_qc_ecm.c" #include "f_mbim.c" #include "f_qc_rndis.c" #include "u_bam_data.c" #include "f_ecm.c" #include "f_qc_rndis.c" #include "u_ether.c" #include "u_qc_ether.c" #ifdef CONFIG_TARGET_CORE Loading Loading @@ -1649,6 +1649,8 @@ static struct android_usb_function ptp_function = { .bind_config = ptp_function_bind_config, }; /* rndis transport string */ static char rndis_transports[MAX_XPORT_STR_LEN]; struct rndis_function_config { u8 ethaddr[ETH_ALEN]; Loading Loading @@ -1741,6 +1743,7 @@ static int rndis_qc_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { int ret; char *trans; struct rndis_function_config *rndis = f->config; if (!rndis) { Loading @@ -1752,11 +1755,17 @@ static int rndis_qc_function_bind_config(struct android_usb_function *f, rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2], rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]); ret = gether_qc_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis"); pr_debug("%s: rndis_transport is %s", __func__, rndis_transports); trans = strim(rndis_transports); if (strcmp("BAM2BAM_IPA", trans)) { ret = gether_qc_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis"); if (ret) { pr_err("%s: gether_setup failed\n", __func__); return ret; } } if (rndis->wceis) { /* "Wireless" RNDIS; auto-detected by Windows */ Loading @@ -1772,7 +1781,7 @@ static int rndis_qc_function_bind_config(struct android_usb_function *f, return rndis_qc_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID, rndis->manufacturer, rndis->max_pkt_per_xfer); rndis->max_pkt_per_xfer, trans); } static void rndis_function_unbind_config(struct android_usb_function *f, Loading @@ -1785,6 +1794,9 @@ static void rndis_function_unbind_config(struct android_usb_function *f, static void rndis_qc_function_unbind_config(struct android_usb_function *f, struct usb_configuration *c) { char *trans = strim(rndis_transports); if (strcmp("BAM2BAM_IPA", trans)) gether_qc_cleanup_name("rndis0"); } Loading Loading @@ -1919,6 +1931,21 @@ static ssize_t rndis_max_pkt_per_xfer_store(struct device *dev, static DEVICE_ATTR(max_pkt_per_xfer, S_IRUGO | S_IWUSR, rndis_max_pkt_per_xfer_show, rndis_max_pkt_per_xfer_store); static ssize_t rndis_transports_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", rndis_transports); } static ssize_t rndis_transports_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { strlcpy(rndis_transports, buf, sizeof(rndis_transports)); return size; } static DEVICE_ATTR(rndis_transports, S_IRUGO | S_IWUSR, rndis_transports_show, rndis_transports_store); static ssize_t rndis_rx_trigger_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) Loading @@ -1941,6 +1968,7 @@ static struct device_attribute *rndis_function_attributes[] = { &dev_attr_ethaddr, &dev_attr_vendorID, &dev_attr_max_pkt_per_xfer, &dev_attr_rndis_transports, &dev_attr_rx_trigger, NULL }; Loading
drivers/usb/gadget/f_qc_rndis.c +104 −16 Original line number Diff line number Diff line Loading @@ -33,7 +33,8 @@ #include "u_ether.h" #include "u_qc_ether.h" #include "rndis.h" #include "u_bam_data.h" #include <mach/rndis_ipa.h> /* * This function is an RNDIS Ethernet port -- a Microsoft protocol that's Loading Loading @@ -95,8 +96,13 @@ struct f_rndis_qc { struct usb_request *notify_req; atomic_t notify_count; struct data_port bam_port; enum transport_type xport; }; static struct ipa_usb_init_params rndis_ipa_params; static bool rndis_ipa_supported; static void rndis_qc_open(struct qc_gether *geth); static inline struct f_rndis_qc *func_to_rndis_qc(struct usb_function *f) { return container_of(f, struct f_rndis_qc, port.func); Loading Loading @@ -424,6 +430,8 @@ static int rndis_qc_bam_connect(struct f_rndis_qc *dev) 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; dev->bam_port.cdev = cdev; dev->bam_port.func = &dev->port.func; Loading @@ -431,16 +439,24 @@ static int rndis_qc_bam_connect(struct f_rndis_qc *dev) dev->bam_port.out = dev->port.out_ep; /* currently we use the first connection */ src_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM, src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam, USB_TO_PEER_PERIPHERAL, 0); dst_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM, dst_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam, PEER_PERIPHERAL_TO_USB, 0); if (src_connection_idx < 0 || dst_connection_idx < 0) { pr_err("%s: usb_bam_get_connection_idx failed\n", __func__); return ret; } ret = bam_data_connect(&dev->bam_port, 0, USB_GADGET_XPORT_BAM2BAM, src_connection_idx, dst_connection_idx, USB_FUNC_RNDIS); if (peer_bam == A2_P_BAM) ret = bam_data_connect(&dev->bam_port, 0, USB_GADGET_XPORT_BAM2BAM, src_connection_idx, dst_connection_idx, USB_FUNC_RNDIS); else { ret = bam_data_connect(&dev->bam_port, 0, 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); Loading Loading @@ -586,6 +602,7 @@ static void rndis_qc_command_complete(struct usb_ep *ep, if (buf->MessageType == RNDIS_MSG_INIT) { rndis->max_pkt_size = buf->MaxTransferSize; pr_debug("MaxTransferSize: %d\n", buf->MaxTransferSize); u_bam_data_set_max_xfer_size(rndis->max_pkt_size); } } Loading Loading @@ -694,7 +711,10 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) * we can disconnect the port from the network layer. */ rndis_qc_bam_disconnect(rndis); gether_qc_disconnect_name(&rndis->port, "rndis0"); if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) gether_qc_disconnect_name(&rndis->port, "rndis0"); } if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) { Loading @@ -708,6 +728,16 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) goto fail; } } if (rndis->xport == USB_GADGET_XPORT_BAM2BAM_IPA && gadget_is_dwc3(cdev->gadget)) { if (msm_ep_config(rndis->port.in_ep) || msm_ep_config(rndis->port.out_ep)) { pr_err("%s: ep_config failed\n", __func__); goto fail; } } else pr_debug("RNDIS is being used with non DWC3 core\n"); /* Avoid ZLPs; they can be troublesome. */ rndis->port.is_zlp_ok = false; Loading @@ -730,7 +760,11 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) goto fail; DBG(cdev, "RNDIS RX/TX early activation ...\n"); net = gether_qc_connect_name(&rndis->port, "rndis0", false); if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) net = gether_qc_connect_name(&rndis->port, "rndis0", false); else net = gether_qc_get_net("rndis0"); if (IS_ERR(net)) return PTR_ERR(net); Loading @@ -755,7 +789,10 @@ static void rndis_qc_disable(struct usb_function *f) rndis_uninit(rndis->config); rndis_qc_bam_disconnect(rndis); if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) gether_qc_disconnect_name(&rndis->port, "rndis0"); else rndis_ipa_supported = false; usb_ep_disable(rndis->notify); rndis->notify->driver_data = NULL; Loading Loading @@ -923,7 +960,8 @@ rndis_qc_bind(struct usb_configuration *c, struct usb_function *f) rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0); rndis_set_host_mac(rndis->config, rndis->ethaddr); if (rndis_set_param_vendor(rndis->config, rndis->vendorID, if (rndis->manufacturer && rndis->vendorID && rndis_set_param_vendor(rndis->config, rndis->vendorID, rndis->manufacturer)) goto fail; Loading Loading @@ -989,9 +1027,19 @@ rndis_qc_unbind(struct usb_configuration *c, struct usb_function *f) kfree(rndis->notify_req->buf); usb_ep_free_request(rndis->notify, rndis->notify_req); if (rndis->xport == USB_GADGET_XPORT_BAM2BAM_IPA) { rndis_ipa_cleanup(rndis_ipa_params.private); rndis_ipa_supported = false; } kfree(rndis); } bool is_rndis_ipa_supported(void) { return rndis_ipa_supported; } /* Some controllers can't support RNDIS ... */ static inline bool can_support_rndis_qc(struct usb_configuration *c) { Loading @@ -1014,13 +1062,13 @@ static inline bool can_support_rndis_qc(struct usb_configuration *c) int rndis_qc_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) { return rndis_qc_bind_config_vendor(c, ethaddr, 0, NULL, 1); return rndis_qc_bind_config_vendor(c, ethaddr, 0, NULL, 1, NULL); } int rndis_qc_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], u32 vendorID, const char *manufacturer, u8 max_pkt_per_xfer) u8 max_pkt_per_xfer, char *xport_name) { struct f_rndis_qc *rndis; int status; Loading Loading @@ -1075,13 +1123,26 @@ rndis_qc_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], goto fail; } rndis->xport = str_to_xport(xport_name); /* export host's Ethernet address in CDC format */ if (rndis->xport == USB_GADGET_XPORT_BAM2BAM_IPA) { gether_qc_get_macs(rndis_ipa_params.device_ethaddr, rndis_ipa_params.host_ethaddr); pr_debug("setting host_ethaddr=%pM, device_ethaddr=%pM", rndis_ipa_params.host_ethaddr, rndis_ipa_params.device_ethaddr); rndis_ipa_supported = true; } else memcpy(rndis->ethaddr, ethaddr, ETH_ALEN); rndis->vendorID = vendorID; rndis->manufacturer = manufacturer; /* if max_pkt_per_xfer was not configured set to default value */ rndis->max_pkt_per_xfer = max_pkt_per_xfer ? max_pkt_per_xfer : DEFAULT_MAX_PKT_PER_XFER; u_bam_data_set_max_pkt_num(rndis->max_pkt_per_xfer); /* RNDIS activates when the host changes this filter */ rndis->port.cdc_filter = 0; Loading @@ -1107,9 +1168,23 @@ rndis_qc_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], status = usb_add_function(c, &rndis->port.func); if (status) { kfree(rndis); goto fail; } if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) return status; status = rndis_ipa_init(&rndis_ipa_params); if (status) { pr_err("%s: failed to initialize rndis_ipa\n", __func__); kfree(rndis); goto fail; } else { pr_debug("%s: rndis_ipa successful created\n", __func__); return status; } fail: rndis_exit(); } return status; } Loading Loading @@ -1220,4 +1295,17 @@ static void rndis_qc_cleanup(void) _rndis_qc = NULL; } void *rndis_qc_get_ipa_rx_cb(void) { return rndis_ipa_params.ipa_rx_notify; } void *rndis_qc_get_ipa_tx_cb(void) { return rndis_ipa_params.ipa_tx_notify; } void *rndis_qc_get_ipa_priv(void) { return rndis_ipa_params.private; }
drivers/usb/gadget/rndis.c +16 −6 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ #include <asm/io.h> #include <asm/byteorder.h> #include <asm/unaligned.h> #include "u_bam_data.h" #undef VERBOSE_DEBUG Loading Loading @@ -544,14 +544,24 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len, */ retval = 0; if (*params->filter) { params->state = RNDIS_DATA_INITIALIZED; if (!is_rndis_ipa_supported()) { netif_carrier_on(params->dev); if (netif_running(params->dev)) netif_wake_queue(params->dev); } else { params->state = RNDIS_INITIALIZED; if (params->state != RNDIS_DATA_INITIALIZED) u_bam_data_start_rndis_ipa(); } params->state = RNDIS_DATA_INITIALIZED; } else { if (!is_rndis_ipa_supported()) { netif_carrier_off(params->dev); netif_stop_queue(params->dev); } else { if (params->state == RNDIS_DATA_INITIALIZED) u_bam_data_stop_rndis_ipa(); } params->state = RNDIS_INITIALIZED; } break; Loading
drivers/usb/gadget/rndis.h +1 −1 Original line number Diff line number Diff line Loading @@ -218,7 +218,7 @@ int rndis_signal_connect (int configNr); int rndis_signal_disconnect (int configNr); int rndis_state (int configNr); extern void rndis_set_host_mac (int configNr, const u8 *addr); extern bool is_rndis_ipa_supported(void); int rndis_init(void); void rndis_exit (void); Loading
drivers/usb/gadget/u_bam_data.c +161 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,14 @@ static int n_bam2bam_data_ports; #define SPS_PARAMS_TBE BIT(6) #define MSM_VENDOR_ID BIT(16) struct rndis_data_ch_info { u32 max_transfer_size; u32 max_packets_number; u32 prod_clnt_hdl; u32 cons_clnt_hdl; void *priv; }; struct bam_data_ch_info { unsigned long flags; unsigned id; Loading @@ -55,6 +63,10 @@ struct bam_data_ch_info { struct usb_bam_connect_ipa_params ipa_params; }; static struct work_struct *rndis_conn_w; static struct work_struct *rndis_disconn_w; static bool is_ipa_rndis_net_on; struct bam_data_port { unsigned port_num; unsigned int ref_count; Loading @@ -66,8 +78,15 @@ struct bam_data_port { struct work_struct suspend_w; struct work_struct resume_w; }; struct usb_bam_data_connect_info { u32 usb_bam_pipe_idx; u32 peer_pipe_idx; u32 usb_bam_handle; struct sps_mem_buffer data_fifo; }; struct bam_data_port *bam2bam_data_ports[BAM2BAM_DATA_N_PORTS]; static struct rndis_data_ch_info rndis_data; static void bam2bam_data_suspend_work(struct work_struct *w); static void bam2bam_data_resume_work(struct work_struct *w); Loading Loading @@ -185,6 +204,12 @@ static void bam2bam_data_disconnect_work(struct work_struct *w) if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { if (d->func_type == USB_FUNC_ECM) ecm_ipa_disconnect(d->ipa_params.priv); if (d->func_type == USB_FUNC_RNDIS) { rndis_ipa_pipe_disconnect_notify(d->ipa_params.priv); is_ipa_rndis_net_on = false; } ret = usb_bam_disconnect_ipa(&d->ipa_params); if (ret) pr_err("usb_bam_disconnect_ipa failed: err:%d\n", ret); Loading @@ -200,6 +225,8 @@ static void bam2bam_data_connect_work(struct work_struct *w) connect_w); struct teth_bridge_connect_params connect_params; struct bam_data_ch_info *d = &port->data_ch; struct data_port *d_port = port->port_usb; struct usb_gadget *gadget = d_port->cdev->gadget; ipa_notify_cb usb_notify_cb; void *priv; u32 sps_params; Loading @@ -225,23 +252,76 @@ static void bam2bam_data_connect_work(struct work_struct *w) d->ipa_params.notify = ecm_qc_get_ipa_rx_cb(); d->ipa_params.priv = ecm_qc_get_ipa_priv(); } if (d->func_type == USB_FUNC_RNDIS) { d->ipa_params.notify = rndis_qc_get_ipa_rx_cb(); d->ipa_params.priv = rndis_qc_get_ipa_priv(); } ret = usb_bam_connect_ipa(&d->ipa_params); if (ret) { pr_err("%s: usb_bam_connect_ipa failed: err:%d\n", __func__, ret); return; } if (d->func_type == USB_FUNC_RNDIS && gadget_is_dwc3(gadget)) { u8 idx; struct usb_bam_data_connect_info bam_info; idx = usb_bam_get_connection_idx(gadget->name, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, 0); if (idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } get_bam2bam_connection_info(idx, &bam_info.usb_bam_handle, &bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx, NULL, &bam_info.data_fifo); msm_data_fifo_config(port->port_usb->out, bam_info.data_fifo.phys_base, bam_info.data_fifo.size, bam_info.usb_bam_pipe_idx); } d->ipa_params.dir = PEER_PERIPHERAL_TO_USB; if (d->func_type == USB_FUNC_ECM) { d->ipa_params.notify = ecm_qc_get_ipa_tx_cb(); d->ipa_params.priv = ecm_qc_get_ipa_priv(); } if (d->func_type == USB_FUNC_RNDIS) { d->ipa_params.notify = rndis_qc_get_ipa_tx_cb(); d->ipa_params.priv = rndis_qc_get_ipa_priv(); } ret = usb_bam_connect_ipa(&d->ipa_params); if (ret) { pr_err("%s: usb_bam_connect_ipa failed: err:%d\n", __func__, ret); return; } if (d->func_type == USB_FUNC_RNDIS && gadget_is_dwc3(gadget)) { u8 idx; struct usb_bam_data_connect_info bam_info; idx = usb_bam_get_connection_idx(gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, 0); if (idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } get_bam2bam_connection_info(idx, &bam_info.usb_bam_handle, &bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx, NULL, &bam_info.data_fifo); msm_data_fifo_config(port->port_usb->in, bam_info.data_fifo.phys_base, bam_info.data_fifo.size, bam_info.usb_bam_pipe_idx); } if (d->func_type == USB_FUNC_MBIM) { mbim_configure_params(); Loading Loading @@ -270,6 +350,26 @@ static void bam2bam_data_connect_work(struct work_struct *w) return; } } if (d->func_type == USB_FUNC_RNDIS) { rndis_data.prod_clnt_hdl = d->ipa_params.prod_clnt_hdl; rndis_data.cons_clnt_hdl = d->ipa_params.cons_clnt_hdl; rndis_data.priv = d->ipa_params.priv; ret = rndis_ipa_pipe_connect_notify( rndis_data.cons_clnt_hdl, rndis_data.prod_clnt_hdl, rndis_data.max_transfer_size, rndis_data.max_packets_number, rndis_data.priv); if (ret) { pr_err("%s: failed to connect IPA: err:%d\n", __func__, ret); return; } is_ipa_rndis_net_on = true; } } else { /* transport type is USB_GADGET_XPORT_BAM2BAM */ usb_bam_reset_complete(); ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx); Loading Loading @@ -302,8 +402,15 @@ static void bam2bam_data_connect_work(struct work_struct *w) d->rx_req->complete = bam_data_endless_rx_complete; d->rx_req->length = 0; d->rx_req->no_interrupt = 1; if (d->func_type == USB_FUNC_RNDIS && gadget_is_dwc3(gadget)) { sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | MSM_PRODUCER | d->src_pipe_idx; d->rx_req->length = 32*1024; } else sps_params = (SPS_PARAMS_SPS_MODE | d->src_pipe_idx | MSM_VENDOR_ID) & ~SPS_PARAMS_TBE; d->rx_req->udc_priv = sps_params; d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_KERNEL); if (!d->tx_req) Loading @@ -313,8 +420,14 @@ static void bam2bam_data_connect_work(struct work_struct *w) d->tx_req->complete = bam_data_endless_tx_complete; d->tx_req->length = 0; d->tx_req->no_interrupt = 1; if (d->func_type == USB_FUNC_RNDIS && gadget_is_dwc3(gadget)) { sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | d->dst_pipe_idx; d->tx_req->length = 32*1024; } else sps_params = (SPS_PARAMS_SPS_MODE | d->dst_pipe_idx | MSM_VENDOR_ID) & ~SPS_PARAMS_TBE; d->tx_req->udc_priv = sps_params; /* queue in & out requests */ Loading Loading @@ -376,12 +489,30 @@ static int bam2bam_data_port_alloc(int portno) d->ipa_params.src_client = IPA_CLIENT_USB_PROD; d->ipa_params.dst_client = IPA_CLIENT_USB_CONS; rndis_disconn_w = &port->disconnect_w; done: pr_debug("port:%p portno:%d\n", port, portno); return 0; } void u_bam_data_start_rndis_ipa(void) { pr_debug("%s\n", __func__); if (!is_ipa_rndis_net_on) queue_work(bam_data_wq, rndis_conn_w); } void u_bam_data_stop_rndis_ipa(void) { pr_debug("%s\n", __func__); if (is_ipa_rndis_net_on) queue_work(bam_data_wq, rndis_disconn_w); } void bam_data_disconnect(struct data_port *gr, u8 port_num) { struct bam_data_port *port; Loading Loading @@ -483,6 +614,11 @@ int bam_data_connect(struct data_port *gr, u8 port_num, d->ipa_params.dst_idx = dst_connection_idx; } if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->func_type == USB_FUNC_RNDIS) { rndis_conn_w = &port->connect_w; return 0; } queue_work(bam_data_wq, &port->connect_w); return 0; Loading Loading @@ -650,3 +786,24 @@ static void bam2bam_data_resume_work(struct work_struct *w) if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) usb_bam_resume(&d->ipa_params); } void u_bam_data_set_max_xfer_size(u32 max_transfer_size) { if (!max_transfer_size) { pr_err("%s: invalid parameters\n", __func__); return; } rndis_data.max_transfer_size = max_transfer_size; } void u_bam_data_set_max_pkt_num(u32 max_packets_number) { if (!max_packets_number) { pr_err("%s: invalid parameters\n", __func__); return; } rndis_data.max_packets_number = max_packets_number; }