usb: gadget: Add RMNET support using IPA over BAM2BAM

This change adds RMNET support using IPA over BAM2BAM.
Removes all different supported control and data
transports and assumes BAM2BAM_IPA as default mode.
Cleans up QTI Control driver to support only RMNET
and DPL.

Change-Id: I5b763acfb28c2f1832874af786704835314fa9c7
Signed-off-by: Ajay Agarwal <ajaya@codeaurora.org>
This commit is contained in:
Ajay Agarwal 2016-10-21 10:40:45 +05:30
parent 24d0c1f91e
commit 52b9f4271f
6 changed files with 214 additions and 671 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
* Copyright (c) 2012-2016, 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
@ -21,6 +21,8 @@
#include <linux/usb/composite.h>
#include <linux/usb/usb_qdss.h>
#include "u_rmnet.h"
struct usb_qdss_bam_connect_info {
u32 usb_bam_pipe_idx;
u32 peer_pipe_idx;
@ -33,8 +35,8 @@ struct gqdss {
struct usb_ep *ctrl_out;
struct usb_ep *ctrl_in;
struct usb_ep *data;
int (*send_encap_cmd)(u8 port_num, void *buf, size_t len);
void (*notify_modem)(void *g, u8 port_num, int cbits);
int (*send_encap_cmd)(enum qti_port_type qport, void *buf, size_t len);
void (*notify_modem)(void *g, enum qti_port_type qport, int cbits);
};
/* struct f_qdss - USB qdss function driver private structure */

View file

@ -18,15 +18,8 @@
#include <linux/spinlock.h>
#include <linux/usb_bam.h>
#include "usb_gadget_xport.h"
#include "u_ether.h"
#include "u_rmnet.h"
#include "gadget_chips.h"
static unsigned int rmnet_dl_max_pkt_per_xfer = 7;
module_param(rmnet_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(rmnet_dl_max_pkt_per_xfer,
"Maximum packets per transfer for DL aggregation");
#include "u_data_ipa.h"
#define RMNET_NOTIFY_INTERVAL 5
#define RMNET_MAX_NOTIFY_SIZE sizeof(struct usb_cdc_notification)
@ -38,10 +31,9 @@ MODULE_PARM_DESC(rmnet_dl_max_pkt_per_xfer,
* control paths
*/
struct f_rmnet {
struct gether gether_port;
struct usb_function func;
struct grmnet port;
int ifc_id;
u8 port_num;
atomic_t online;
atomic_t ctrl_online;
struct usb_composite_dev *cdev;
@ -53,30 +45,11 @@ 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;
const struct usb_endpoint_descriptor *in_ep_desc_backup;
const struct usb_endpoint_descriptor *out_ep_desc_backup;
};
static unsigned int nr_rmnet_ports;
static unsigned int no_ctrl_smd_ports;
static unsigned int no_ctrl_qti_ports;
static unsigned int no_ctrl_hsic_ports;
static unsigned int no_ctrl_hsuart_ports;
static unsigned int no_data_bam_ports;
static unsigned int no_data_bam2bam_ports;
static unsigned int no_data_hsic_ports;
static unsigned int no_data_hsuart_ports;
static struct rmnet_ports {
enum transport_type data_xport;
enum transport_type ctrl_xport;
unsigned data_xport_num;
unsigned ctrl_xport_num;
unsigned port_num;
struct f_rmnet *port;
} rmnet_ports[NR_RMNET_PORTS];
} rmnet_port;
static struct usb_interface_descriptor rmnet_interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
@ -244,7 +217,7 @@ static void frmnet_ctrl_response_available(struct f_rmnet *dev);
static inline struct f_rmnet *func_to_rmnet(struct usb_function *f)
{
return container_of(f, struct f_rmnet, gether_port.func);
return container_of(f, struct f_rmnet, func);
}
static inline struct f_rmnet *port_to_rmnet(struct grmnet *r)
@ -253,8 +226,7 @@ static inline struct f_rmnet *port_to_rmnet(struct grmnet *r)
}
static struct usb_request *
frmnet_alloc_req(struct usb_ep *ep, unsigned len, size_t extra_buf_alloc,
gfp_t flags)
frmnet_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags)
{
struct usb_request *req;
@ -262,7 +234,7 @@ frmnet_alloc_req(struct usb_ep *ep, unsigned len, size_t extra_buf_alloc,
if (!req)
return ERR_PTR(-ENOMEM);
req->buf = kmalloc(len + extra_buf_alloc, flags);
req->buf = kmalloc(len, flags);
if (!req->buf) {
usb_ep_free_request(ep, req);
return ERR_PTR(-ENOMEM);
@ -308,195 +280,48 @@ static void rmnet_free_ctrl_pkt(struct rmnet_ctrl_pkt *pkt)
static int rmnet_gport_setup(void)
{
int ret;
int port_idx;
int i;
u8 base;
pr_debug("%s: bam ports:%u bam2bam ports:%u data hsic ports:%u\n",
__func__, no_data_bam_ports, no_data_bam2bam_ports,
no_data_hsic_ports);
pr_debug("%s: data hsuart ports:%u smd ports:%u ctrl hsic ports:%u\n",
__func__, no_data_hsuart_ports, no_ctrl_smd_ports,
no_ctrl_hsic_ports);
pr_debug("%s: ctrl hsuart ports:%u nr_rmnet_ports:%u\n",
__func__, no_ctrl_hsuart_ports, nr_rmnet_ports);
if (no_data_bam_ports) {
ret = gbam_setup(no_data_bam_ports);
if (ret < 0)
return ret;
}
if (no_data_bam2bam_ports) {
ret = gbam2bam_setup(no_data_bam2bam_ports);
if (ret < 0)
return ret;
}
if (no_ctrl_smd_ports) {
ret = gsmd_ctrl_setup(FRMNET_CTRL_CLIENT,
no_ctrl_smd_ports, &base);
if (ret)
return ret;
for (i = 0; i < nr_rmnet_ports; i++)
if (rmnet_ports[i].port)
rmnet_ports[i].port->port_num += base;
}
if (no_data_hsic_ports) {
port_idx = ghsic_data_setup(no_data_hsic_ports,
USB_GADGET_RMNET);
if (port_idx < 0)
return port_idx;
for (i = 0; i < nr_rmnet_ports; i++) {
if (rmnet_ports[i].data_xport ==
USB_GADGET_XPORT_HSIC) {
rmnet_ports[i].data_xport_num = port_idx;
port_idx++;
}
}
}
if (no_ctrl_hsic_ports) {
port_idx = ghsic_ctrl_setup(no_ctrl_hsic_ports,
USB_GADGET_RMNET);
if (port_idx < 0)
return port_idx;
for (i = 0; i < nr_rmnet_ports; i++) {
if (rmnet_ports[i].ctrl_xport ==
USB_GADGET_XPORT_HSIC) {
rmnet_ports[i].ctrl_xport_num = port_idx;
port_idx++;
}
}
}
ret = ipa_data_setup(USB_IPA_FUNC_RMNET);
if (ret < 0)
return ret;
return 0;
}
static int gport_rmnet_connect(struct f_rmnet *dev, unsigned intf)
{
int ret;
unsigned port_num;
enum transport_type cxport = rmnet_ports[dev->port_num].ctrl_xport;
enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
int src_connection_idx = 0, dst_connection_idx = 0;
struct usb_gadget *gadget = dev->cdev->gadget;
enum usb_ctrl usb_bam_type;
void *net;
pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
__func__, xport_to_str(cxport), xport_to_str(dxport),
dev, dev->port_num);
port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
switch (cxport) {
case USB_GADGET_XPORT_SMD:
ret = gsmd_ctrl_connect(&dev->port, port_num);
if (ret) {
pr_err("%s: gsmd_ctrl_connect failed: err:%d\n",
__func__, ret);
return ret;
}
break;
case USB_GADGET_XPORT_QTI:
ret = gqti_ctrl_connect(&dev->port, port_num, dev->ifc_id,
dxport, USB_GADGET_RMNET);
if (ret) {
pr_err("%s: gqti_ctrl_connect failed: err:%d\n",
__func__, ret);
return ret;
}
break;
case USB_GADGET_XPORT_HSIC:
ret = ghsic_ctrl_connect(&dev->port, port_num);
if (ret) {
pr_err("%s: ghsic_ctrl_connect failed: err:%d\n",
__func__, ret);
return ret;
}
break;
case USB_GADGET_XPORT_NONE:
break;
default:
pr_err("%s: Un-supported transport: %s\n", __func__,
xport_to_str(cxport));
return -ENODEV;
ret = gqti_ctrl_connect(&dev->port, QTI_PORT_RMNET, dev->ifc_id);
if (ret) {
pr_err("%s: gqti_ctrl_connect failed: err:%d\n",
__func__, ret);
return ret;
}
port_num = rmnet_ports[dev->port_num].data_xport_num;
switch (dxport) {
case USB_GADGET_XPORT_BAM_DMUX:
ret = gbam_connect(&dev->port, port_num,
dxport, src_connection_idx, dst_connection_idx);
if (ret) {
pr_err("%s: gbam_connect failed: err:%d\n",
__func__, ret);
gsmd_ctrl_disconnect(&dev->port, port_num);
return ret;
}
break;
case USB_GADGET_XPORT_BAM2BAM_IPA:
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,
port_num);
dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE,
port_num);
if (dst_connection_idx < 0 || src_connection_idx < 0) {
pr_err("%s: usb_bam_get_connection_idx failed\n",
__func__);
gsmd_ctrl_disconnect(&dev->port, port_num);
return -EINVAL;
}
ret = gbam_connect(&dev->port, port_num,
dxport, src_connection_idx, dst_connection_idx);
if (ret) {
pr_err("%s: gbam_connect failed: err:%d\n",
__func__, ret);
if (cxport == USB_GADGET_XPORT_QTI)
gqti_ctrl_disconnect(&dev->port, port_num);
else
gsmd_ctrl_disconnect(&dev->port, port_num);
return ret;
}
break;
case USB_GADGET_XPORT_HSIC:
ret = ghsic_data_connect(&dev->port, port_num);
if (ret) {
pr_err("%s: ghsic_data_connect failed: err:%d\n",
__func__, ret);
ghsic_ctrl_disconnect(&dev->port, port_num);
return ret;
}
break;
case USB_GADGET_XPORT_ETHER:
gether_enable_sg(&dev->gether_port, true);
net = gether_connect(&dev->gether_port);
if (IS_ERR(net)) {
pr_err("%s: gether_connect failed: err:%ld\n",
__func__, PTR_ERR(net));
if (cxport == USB_GADGET_XPORT_QTI)
gqti_ctrl_disconnect(&dev->port, port_num);
else
gsmd_ctrl_disconnect(&dev->port, port_num);
return PTR_ERR(net);
}
gether_update_dl_max_pkts_per_xfer(&dev->gether_port,
rmnet_dl_max_pkt_per_xfer);
gether_update_dl_max_xfer_size(&dev->gether_port, 16384);
break;
case USB_GADGET_XPORT_NONE:
break;
default:
pr_err("%s: Un-supported transport: %s\n", __func__,
xport_to_str(dxport));
return -ENODEV;
dev->ipa_port.cdev = dev->cdev;
ipa_data_port_select(USB_IPA_FUNC_RMNET);
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);
dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE,
QTI_PORT_RMNET);
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);
return -EINVAL;
}
ret = ipa_data_connect(&dev->ipa_port, USB_IPA_FUNC_RMNET,
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);
return ret;
}
return 0;
@ -504,53 +329,8 @@ static int gport_rmnet_connect(struct f_rmnet *dev, unsigned intf)
static int gport_rmnet_disconnect(struct f_rmnet *dev)
{
unsigned port_num;
enum transport_type cxport = rmnet_ports[dev->port_num].ctrl_xport;
enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
__func__, xport_to_str(cxport), xport_to_str(dxport),
dev, dev->port_num);
port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
switch (cxport) {
case USB_GADGET_XPORT_SMD:
gsmd_ctrl_disconnect(&dev->port, port_num);
break;
case USB_GADGET_XPORT_QTI:
gqti_ctrl_disconnect(&dev->port, port_num);
break;
case USB_GADGET_XPORT_HSIC:
ghsic_ctrl_disconnect(&dev->port, port_num);
break;
case USB_GADGET_XPORT_NONE:
break;
default:
pr_err("%s: Un-supported transport: %s\n", __func__,
xport_to_str(cxport));
return -ENODEV;
}
port_num = rmnet_ports[dev->port_num].data_xport_num;
switch (dxport) {
case USB_GADGET_XPORT_BAM_DMUX:
case USB_GADGET_XPORT_BAM2BAM_IPA:
gbam_disconnect(&dev->port, port_num, dxport);
break;
case USB_GADGET_XPORT_HSIC:
ghsic_data_disconnect(&dev->port, port_num);
break;
case USB_GADGET_XPORT_ETHER:
gether_disconnect(&dev->gether_port);
break;
case USB_GADGET_XPORT_NONE:
break;
default:
pr_err("%s: Un-supported transport: %s\n", __func__,
xport_to_str(dxport));
return -ENODEV;
}
gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET);
ipa_data_disconnect(&dev->ipa_port, USB_IPA_FUNC_RMNET);
return 0;
}
@ -558,7 +338,7 @@ static void frmnet_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_rmnet *dev = func_to_rmnet(f);
pr_debug("%s: portno:%d\n", __func__, dev->port_num);
pr_debug("%s: start unbinding\n", __func__);
if (gadget_is_superspeed(c->cdev->gadget))
usb_free_descriptors(f->ss_descriptors);
if (gadget_is_dualspeed(c->cdev->gadget))
@ -575,8 +355,7 @@ static void frmnet_purge_responses(struct f_rmnet *dev)
unsigned long flags;
struct rmnet_ctrl_pkt *cpkt;
pr_debug("%s: port#%d\n", __func__, dev->port_num);
pr_debug("%s: Purging responses\n", __func__);
spin_lock_irqsave(&dev->lock, flags);
while (!list_empty(&dev->cpkt_resp_q)) {
cpkt = list_first_entry(&dev->cpkt_resp_q,
@ -591,117 +370,46 @@ static void frmnet_purge_responses(struct f_rmnet *dev)
static void frmnet_suspend(struct usb_function *f)
{
struct f_rmnet *dev = func_to_rmnet(f);
unsigned port_num;
enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
bool remote_wakeup_allowed;
struct f_rmnet *dev = func_to_rmnet(f);
bool remote_wakeup_allowed;
if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
remote_wakeup_allowed = f->func_wakeup_allowed;
else
remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;
pr_debug("%s: data xport: %s dev: %p portno: %d remote_wakeup: %d\n",
__func__, xport_to_str(dxport),
dev, dev->port_num, remote_wakeup_allowed);
pr_debug("%s: dev: %p remote_wakeup: %d\n",
__func__, dev, remote_wakeup_allowed);
usb_ep_fifo_flush(dev->notify);
frmnet_purge_responses(dev);
port_num = rmnet_ports[dev->port_num].data_xport_num;
switch (dxport) {
case USB_GADGET_XPORT_BAM_DMUX:
break;
case USB_GADGET_XPORT_BAM2BAM_IPA:
if (remote_wakeup_allowed) {
gbam_suspend(&dev->port, port_num, dxport);
} else {
/*
* When remote wakeup is disabled, IPA 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.
*/
dev->in_ep_desc_backup = dev->port.in->desc;
dev->out_ep_desc_backup = dev->port.out->desc;
pr_debug("in_ep_desc_bkup = %p, out_ep_desc_bkup = %p",
dev->in_ep_desc_backup, dev->out_ep_desc_backup);
pr_debug("%s(): Disconnecting\n", __func__);
gport_rmnet_disconnect(dev);
}
break;
case USB_GADGET_XPORT_HSIC:
break;
case USB_GADGET_XPORT_HSUART:
break;
case USB_GADGET_XPORT_ETHER:
break;
case USB_GADGET_XPORT_NONE:
break;
default:
pr_err("%s: Un-supported transport: %s\n", __func__,
xport_to_str(dxport));
}
ipa_data_suspend(&dev->ipa_port, USB_IPA_FUNC_RMNET,
remote_wakeup_allowed);
}
static void frmnet_resume(struct usb_function *f)
{
struct f_rmnet *dev = func_to_rmnet(f);
unsigned port_num;
enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
int ret;
bool remote_wakeup_allowed;
struct f_rmnet *dev = func_to_rmnet(f);
bool remote_wakeup_allowed;
if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
remote_wakeup_allowed = f->func_wakeup_allowed;
else
remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;
pr_debug("%s: data xport: %s dev: %p portno: %d remote_wakeup: %d\n",
__func__, xport_to_str(dxport),
dev, dev->port_num, remote_wakeup_allowed);
pr_debug("%s: dev: %p remote_wakeup: %d\n",
__func__, dev, remote_wakeup_allowed);
port_num = rmnet_ports[dev->port_num].data_xport_num;
switch (dxport) {
case USB_GADGET_XPORT_BAM_DMUX:
break;
case USB_GADGET_XPORT_BAM2BAM_IPA:
if (remote_wakeup_allowed) {
gbam_resume(&dev->port, port_num, dxport);
} else {
dev->port.in->desc = dev->in_ep_desc_backup;
dev->port.out->desc = dev->out_ep_desc_backup;
pr_debug("%s(): Connecting\n", __func__);
ret = gport_rmnet_connect(dev, dev->ifc_id);
if (ret) {
pr_err("%s: gport_rmnet_connect failed: err:%d\n",
__func__, ret);
}
}
break;
case USB_GADGET_XPORT_HSIC:
break;
case USB_GADGET_XPORT_HSUART:
break;
case USB_GADGET_XPORT_ETHER:
break;
case USB_GADGET_XPORT_NONE:
break;
default:
pr_err("%s: Un-supported transport: %s\n", __func__,
xport_to_str(dxport));
}
ipa_data_resume(&dev->ipa_port, USB_IPA_FUNC_RMNET,
remote_wakeup_allowed);
}
static void frmnet_disable(struct usb_function *f)
{
struct f_rmnet *dev = func_to_rmnet(f);
enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
struct usb_composite_dev *cdev = dev->cdev;
pr_debug("%s: port#%d\n", __func__, dev->port_num);
struct f_rmnet *dev = func_to_rmnet(f);
pr_debug("%s: Disabling\n", __func__);
usb_ep_disable(dev->notify);
dev->notify->driver_data = NULL;
@ -709,11 +417,8 @@ static void frmnet_disable(struct usb_function *f)
frmnet_purge_responses(dev);
if (dxport == USB_GADGET_XPORT_BAM2BAM_IPA &&
gadget_is_dwc3(cdev->gadget)) {
msm_ep_unconfig(dev->port.out);
msm_ep_unconfig(dev->port.in);
}
msm_ep_unconfig(dev->ipa_port.out);
msm_ep_unconfig(dev->ipa_port.in);
gport_rmnet_disconnect(dev);
}
@ -723,12 +428,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 = dev->cdev;
int ret;
struct list_head *cpkt;
pr_debug("%s:dev:%p port#%d\n", __func__, dev, dev->port_num);
struct list_head *cpkt;
pr_debug("%s: dev: %p\n", __func__, dev);
if (dev->notify->driver_data) {
pr_debug("%s: reset port:%d\n", __func__, dev->port_num);
pr_debug("%s: reset port\n", __func__);
usb_ep_disable(dev->notify);
}
@ -749,14 +453,14 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
}
dev->notify->driver_data = dev;
if (!dev->port.in->desc || !dev->port.out->desc) {
if (config_ep_by_speed(cdev->gadget, f, dev->port.in) ||
config_ep_by_speed(cdev->gadget, f, dev->port.out)) {
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__);
ret = -EINVAL;
goto err_disable_ep;
}
dev->port.gadget = dev->cdev->gadget;
dev->ipa_port.cdev = dev->cdev;
}
ret = gport_rmnet_connect(dev, intf);
@ -777,8 +481,8 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
return ret;
err_disable_ep:
dev->port.in->desc = NULL;
dev->port.out->desc = NULL;
dev->ipa_port.in->desc = NULL;
dev->ipa_port.out->desc = NULL;
usb_ep_disable(dev->notify);
return ret;
@ -790,10 +494,9 @@ static void frmnet_ctrl_response_available(struct f_rmnet *dev)
struct usb_cdc_notification *event;
unsigned long flags;
int ret;
struct rmnet_ctrl_pkt *cpkt;
pr_debug("%s:dev:%p portno#%d\n", __func__, dev, dev->port_num);
struct rmnet_ctrl_pkt *cpkt;
pr_debug("%s: dev: %p\n", __func__, dev);
spin_lock_irqsave(&dev->lock, flags);
if (!atomic_read(&dev->online) || !req || !req->buf) {
spin_unlock_irqrestore(&dev->lock, flags);
@ -913,8 +616,7 @@ frmnet_send_cpkt_response(void *gr, void *buf, size_t len)
dev = port_to_rmnet(gr);
pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num);
pr_debug("%s: dev: %p\n", __func__, dev);
if (!atomic_read(&dev->online) || !atomic_read(&dev->ctrl_online)) {
rmnet_free_ctrl_pkt(cpkt);
return 0;
@ -934,32 +636,27 @@ frmnet_cmd_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_rmnet *dev = req->context;
struct usb_composite_dev *cdev;
unsigned port_num;
if (!dev) {
pr_err("%s: rmnet dev is null\n", __func__);
return;
}
pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num);
pr_debug("%s: dev: %p\n", __func__, dev);
cdev = dev->cdev;
if (dev->port.send_encap_cmd) {
port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
dev->port.send_encap_cmd(port_num, req->buf, req->actual);
dev->port.send_encap_cmd(QTI_PORT_RMNET, req->buf, req->actual);
}
}
static void frmnet_notify_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_rmnet *dev = req->context;
int status = req->status;
struct f_rmnet *dev = req->context;
int status = req->status;
unsigned long flags;
struct rmnet_ctrl_pkt *cpkt;
pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num);
pr_debug("%s: dev: %p\n", __func__, dev);
switch (status) {
case -ECONNRESET:
case -ESHUTDOWN:
@ -1021,14 +718,12 @@ frmnet_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
struct f_rmnet *dev = func_to_rmnet(f);
struct usb_composite_dev *cdev = dev->cdev;
struct usb_request *req = cdev->req;
unsigned port_num;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
int ret = -EOPNOTSUPP;
pr_debug("%s:dev:%p port#%d\n", __func__, dev, dev->port_num);
pr_debug("%s: dev: %p\n", __func__, dev);
if (!atomic_read(&dev->online)) {
pr_warn("%s: usb cable is not connected\n", __func__);
return -ENOTCONN;
@ -1085,8 +780,8 @@ frmnet_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
pr_debug("%s: USB_CDC_REQ_SET_CONTROL_LINE_STATE: DTR:%d\n",
__func__, w_value & ACM_CTRL_DTR ? 1 : 0);
if (dev->port.notify_modem) {
port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
dev->port.notify_modem(&dev->port, port_num, w_value);
dev->port.notify_modem(&dev->port,
QTI_PORT_RMNET, w_value);
}
ret = 0;
@ -1135,9 +830,7 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f)
pr_err("%s: usb epin autoconfig failed\n", __func__);
return -ENODEV;
}
dev->port.in = ep;
/* Update same for u_ether which uses gether port struct */
dev->gether_port.in_ep = ep;
dev->ipa_port.in = ep;
ep->driver_data = cdev;
ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_out_desc);
@ -1146,9 +839,7 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f)
ret = -ENODEV;
goto ep_auto_out_fail;
}
dev->port.out = ep;
/* Update same for u_ether which uses gether port struct */
dev->gether_port.out_ep = ep;
dev->ipa_port.out = ep;
ep->driver_data = cdev;
ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_notify_desc);
@ -1162,7 +853,6 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f)
dev->notify_req = frmnet_alloc_req(ep,
sizeof(struct usb_cdc_notification),
cdev->gadget->extra_buf_alloc,
GFP_KERNEL);
if (IS_ERR(dev->notify_req)) {
pr_err("%s: unable to allocate memory for notify req\n",
@ -1218,10 +908,9 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f)
}
}
pr_debug("%s: RmNet(%d) %s Speed, IN:%s OUT:%s\n",
__func__, dev->port_num,
gadget_is_dualspeed(cdev->gadget) ? "dual" : "full",
dev->port.in->name, dev->port.out->name);
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;
@ -1238,16 +927,16 @@ ep_notify_alloc_fail:
dev->notify->driver_data = NULL;
dev->notify = NULL;
ep_auto_notify_fail:
dev->port.out->driver_data = NULL;
dev->port.out = NULL;
dev->ipa_port.out->driver_data = NULL;
dev->ipa_port.out = NULL;
ep_auto_out_fail:
dev->port.in->driver_data = NULL;
dev->port.in = NULL;
dev->ipa_port.in->driver_data = NULL;
dev->ipa_port.in = NULL;
return ret;
}
static int frmnet_bind_config(struct usb_configuration *c, unsigned portno)
static int frmnet_bind_config(struct usb_configuration *c)
{
int status;
struct f_rmnet *dev;
@ -1255,32 +944,7 @@ static int frmnet_bind_config(struct usb_configuration *c, unsigned portno)
unsigned long flags;
pr_debug("%s: usb config:%p\n", __func__, c);
if (portno >= nr_rmnet_ports) {
pr_err("%s: supporting ports#%u port_id:%u\n", __func__,
nr_rmnet_ports, portno);
return -ENODEV;
}
dev = rmnet_ports[portno].port;
if (rmnet_ports[portno].data_xport == USB_GADGET_XPORT_ETHER) {
struct net_device *net = gether_setup_name_default("usb_rmnet");
if (IS_ERR(net)) {
pr_err("%s: gether_setup failed\n", __func__);
return PTR_ERR(net);
}
dev->gether_port.ioport = netdev_priv(net);
gether_set_gadget(net, c->cdev->gadget);
status = gether_register_netdev(net);
if (status < 0) {
pr_err("%s: gether_register_netdev failed\n", __func__);
free_netdev(net);
return status;
}
}
dev = &rmnet_port;
if (rmnet_string_defs[0].id == 0) {
status = usb_string_id(c->cdev);
if (status < 0) {
@ -1293,8 +957,8 @@ static int frmnet_bind_config(struct usb_configuration *c, unsigned portno)
spin_lock_irqsave(&dev->lock, flags);
dev->cdev = c->cdev;
f = &dev->gether_port.func;
f->name = kasprintf(GFP_ATOMIC, "rmnet%d", portno);
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__);
@ -1312,7 +976,6 @@ static int frmnet_bind_config(struct usb_configuration *c, unsigned portno)
dev->port.send_cpkt_response = frmnet_send_cpkt_response;
dev->port.disconnect = frmnet_disconnect;
dev->port.connect = frmnet_connect;
dev->gether_port.cdc_filter = 0;
status = usb_add_function(c, f);
if (status) {
@ -1327,17 +990,6 @@ static int frmnet_bind_config(struct usb_configuration *c, unsigned portno)
return status;
}
static void frmnet_unbind_config(void)
{
int i;
for (i = 0; i < nr_rmnet_ports; i++)
if (rmnet_ports[i].data_xport == USB_GADGET_XPORT_ETHER) {
gether_cleanup(rmnet_ports[i].port->gether_port.ioport);
rmnet_ports[i].port->gether_port.ioport = NULL;
}
}
static int rmnet_init(void)
{
return gqti_ctrl_init();
@ -1345,130 +997,25 @@ static int rmnet_init(void)
static void frmnet_cleanup(void)
{
int i;
gqti_ctrl_cleanup();
for (i = 0; i < nr_rmnet_ports; i++)
kfree(rmnet_ports[i].port);
gbam_cleanup();
nr_rmnet_ports = 0;
no_ctrl_smd_ports = 0;
no_ctrl_qti_ports = 0;
no_data_bam_ports = 0;
no_data_bam2bam_ports = 0;
no_ctrl_hsic_ports = 0;
no_data_hsic_ports = 0;
no_ctrl_hsuart_ports = 0;
no_data_hsuart_ports = 0;
kfree(&rmnet_port);
}
static int frmnet_init_port(const char *ctrl_name, const char *data_name,
const char *port_name)
{
struct f_rmnet *dev;
struct rmnet_ports *rmnet_port;
int ret;
int i;
struct f_rmnet *dev;
if (nr_rmnet_ports >= NR_RMNET_PORTS) {
pr_err("%s: Max-%d instances supported\n",
__func__, NR_RMNET_PORTS);
return -EINVAL;
}
pr_debug("%s: port#:%d, ctrl port: %s data port: %s\n",
__func__, nr_rmnet_ports, ctrl_name, data_name);
pr_debug("%s: ctrl port: %s data port: %s\n",
__func__, ctrl_name, data_name);
dev = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->port_num = nr_rmnet_ports;
spin_lock_init(&dev->lock);
INIT_LIST_HEAD(&dev->cpkt_resp_q);
rmnet_port = &rmnet_ports[nr_rmnet_ports];
rmnet_port->port = dev;
rmnet_port->port_num = nr_rmnet_ports;
rmnet_port->ctrl_xport = str_to_xport(ctrl_name);
rmnet_port->data_xport = str_to_xport(data_name);
switch (rmnet_port->ctrl_xport) {
case USB_GADGET_XPORT_SMD:
rmnet_port->ctrl_xport_num = no_ctrl_smd_ports;
no_ctrl_smd_ports++;
break;
case USB_GADGET_XPORT_QTI:
rmnet_port->ctrl_xport_num = no_ctrl_qti_ports;
no_ctrl_qti_ports++;
break;
case USB_GADGET_XPORT_HSIC:
ghsic_ctrl_set_port_name(port_name, ctrl_name);
rmnet_port->ctrl_xport_num = no_ctrl_hsic_ports;
no_ctrl_hsic_ports++;
break;
case USB_GADGET_XPORT_HSUART:
rmnet_port->ctrl_xport_num = no_ctrl_hsuart_ports;
no_ctrl_hsuart_ports++;
break;
case USB_GADGET_XPORT_NONE:
break;
default:
pr_err("%s: Un-supported transport: %u\n", __func__,
rmnet_port->ctrl_xport);
ret = -ENODEV;
goto fail_probe;
}
switch (rmnet_port->data_xport) {
case USB_GADGET_XPORT_BAM2BAM:
/* Override BAM2BAM to BAM_DMUX for old ABI compatibility */
rmnet_port->data_xport = USB_GADGET_XPORT_BAM_DMUX;
/* fall-through */
case USB_GADGET_XPORT_BAM_DMUX:
rmnet_port->data_xport_num = no_data_bam_ports;
no_data_bam_ports++;
break;
case USB_GADGET_XPORT_BAM2BAM_IPA:
rmnet_port->data_xport_num = no_data_bam2bam_ports;
no_data_bam2bam_ports++;
break;
case USB_GADGET_XPORT_HSIC:
ghsic_data_set_port_name(port_name, data_name);
rmnet_port->data_xport_num = no_data_hsic_ports;
no_data_hsic_ports++;
break;
case USB_GADGET_XPORT_HSUART:
rmnet_port->data_xport_num = no_data_hsuart_ports;
no_data_hsuart_ports++;
break;
case USB_GADGET_XPORT_ETHER:
case USB_GADGET_XPORT_NONE:
break;
default:
pr_err("%s: Un-supported transport: %u\n", __func__,
rmnet_port->data_xport);
ret = -ENODEV;
goto fail_probe;
}
nr_rmnet_ports++;
rmnet_port = *dev;
return 0;
fail_probe:
for (i = 0; i < nr_rmnet_ports; i++)
kfree(rmnet_ports[i].port);
nr_rmnet_ports = 0;
no_ctrl_smd_ports = 0;
no_ctrl_qti_ports = 0;
no_data_bam_ports = 0;
no_ctrl_hsic_ports = 0;
no_data_hsic_ports = 0;
no_ctrl_hsuart_ports = 0;
no_data_hsuart_ports = 0;
return ret;
}

View file

@ -14,11 +14,11 @@
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/usb/usb_ctrl_qti.h>
#include <soc/qcom/bam_dmux.h>
#include <linux/miscdevice.h>
#include <linux/debugfs.h>
#include "u_rmnet.h"
#include "usb_gadget_xport.h"
#include "f_qdss.h"
#define RMNET_CTRL_QTI_NAME "rmnet_ctrl"
#define DPL_CTRL_QTI_NAME "dpl_ctrl"
@ -54,18 +54,18 @@ struct qti_ctrl_port {
struct list_head cpkt_req_q;
spinlock_t lock;
enum gadget_type gtype;
enum qti_port_type port_type;
unsigned host_to_modem;
unsigned copied_to_modem;
unsigned copied_from_modem;
unsigned modem_to_host;
unsigned drp_cpkt_cnt;
};
static struct qti_ctrl_port *ctrl_port[NR_QTI_PORTS];
static struct qti_ctrl_port *ctrl_port[QTI_NUM_PORTS];
static inline int qti_ctrl_lock(atomic_t *excl)
{
if (atomic_inc_return(excl) == 1) {
if (atomic_inc_return(excl) == 1)
return 0;
atomic_dec(excl);
return -EBUSY;
@ -76,6 +76,32 @@ static inline void qti_ctrl_unlock(atomic_t *excl)
atomic_dec(excl);
}
static struct rmnet_ctrl_pkt *alloc_rmnet_ctrl_pkt(unsigned len, gfp_t flags)
{
struct rmnet_ctrl_pkt *pkt;
pkt = kzalloc(sizeof(struct rmnet_ctrl_pkt), flags);
if (!pkt)
return ERR_PTR(-ENOMEM);
pkt->buf = kmalloc(len, flags);
if (!pkt->buf) {
kfree(pkt);
return ERR_PTR(-ENOMEM);
}
pkt->len = len;
return pkt;
}
static void free_rmnet_ctrl_pkt(struct rmnet_ctrl_pkt *pkt)
{
kfree(pkt->buf);
kfree(pkt);
}
static void qti_ctrl_queue_notify(struct qti_ctrl_port *port)
{
unsigned long flags;
@ -106,7 +132,8 @@ static void qti_ctrl_queue_notify(struct qti_ctrl_port *port)
wake_up(&port->read_wq);
}
static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len)
static int gqti_ctrl_send_cpkt_tomodem(enum qti_port_type qport,
void *buf, size_t len)
{
unsigned long flags;
struct qti_ctrl_port *port;
@ -118,12 +145,11 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len)
return -EINVAL;
}
if (portno >= NR_QTI_PORTS) {
pr_err("%s: Invalid QTI port %d\n", __func__, portno);
if (qport >= QTI_NUM_PORTS) {
pr_err("%s: Invalid QTI port %d\n", __func__, qport);
return -ENODEV;
}
port = ctrl_port[portno];
port = ctrl_port[qport];
cpkt = alloc_rmnet_ctrl_pkt(len, GFP_ATOMIC);
if (IS_ERR(cpkt)) {
pr_err("%s: Unable to allocate ctrl pkt\n", __func__);
@ -133,8 +159,8 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len)
memcpy(cpkt->buf, buf, len);
cpkt->len = len;
pr_debug("%s: gtype:%d: Add to cpkt_req_q packet with len = %zu\n",
__func__, port->gtype, len);
pr_debug("%s: port type:%d: Add to cpkt_req_q packet with len = %zu\n",
__func__, port->port_type, len);
spin_lock_irqsave(&port->lock, flags);
/* drop cpkt if port is not open */
@ -159,71 +185,51 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len)
}
static void
gqti_ctrl_notify_modem(void *gptr, u8 portno, int val)
gqti_ctrl_notify_modem(void *gptr, enum qti_port_type qport, int val)
{
struct qti_ctrl_port *port;
if (portno >= NR_QTI_PORTS) {
pr_err("%s: Invalid QTI port %d\n", __func__, portno);
if (qport >= QTI_NUM_PORTS) {
pr_err("%s: Invalid QTI port %d\n", __func__, qport);
return;
}
port = ctrl_port[portno];
port = ctrl_port[qport];
atomic_set(&port->line_state, val);
/* send 0 len pkt to qti to notify state change */
qti_ctrl_queue_notify(port);
}
int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf,
enum transport_type dxport, enum gadget_type gtype)
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: gtype:%d gadget:%p\n", __func__, gtype, gr);
if (port_num >= NR_QTI_PORTS) {
pr_err("%s: Invalid QTI port %d\n", __func__, port_num);
pr_debug("%s: port type:%d gadget:%p\n", __func__, qport, gr);
if (qport >= QTI_NUM_PORTS) {
pr_err("%s: Invalid QTI port %d\n", __func__, qport);
return -ENODEV;
}
port = ctrl_port[port_num];
port = ctrl_port[qport];
if (!port) {
pr_err("%s: gadget port is null\n", __func__);
return -ENODEV;
}
spin_lock_irqsave(&port->lock, flags);
port->gtype = gtype;
if (dxport == USB_GADGET_XPORT_BAM_DMUX) {
/*
* BAM-DMUX data transport is used for RMNET and DPL
* on some targets where IPA is not available.
* Set endpoint type as BAM-DMUX and interface
* id as channel number. This information is
* sent to user space via EP_LOOKUP ioctl.
*
*/
port->port_type = qport;
port->ep_type = DATA_EP_TYPE_HSUSB;
port->intf = intf;
port->ep_type = DATA_EP_TYPE_BAM_DMUX;
port->intf = (gtype == USB_GADGET_RMNET) ?
BAM_DMUX_USB_RMNET_0 :
BAM_DMUX_USB_DPL;
port->ipa_prod_idx = 0;
port->ipa_cons_idx = 0;
} else {
port->ep_type = DATA_EP_TYPE_HSUSB;
port->intf = intf;
}
if (gr && port->gtype == USB_GADGET_RMNET) {
if (gr && port->port_type == QTI_PORT_RMNET) {
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->gtype == USB_GADGET_DPL) {
} 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;
@ -231,7 +237,7 @@ int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf,
atomic_set(&port->line_state, 1);
} else {
spin_unlock_irqrestore(&port->lock, flags);
pr_err("%s(): Port is used without gtype.\n", __func__);
pr_err("%s(): Port is used without port type.\n", __func__);
return -ENODEV;
}
@ -251,7 +257,7 @@ int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf,
return 0;
}
void gqti_ctrl_disconnect(void *gr, u8 port_num)
void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport)
{
struct qti_ctrl_port *port;
unsigned long flags;
@ -261,13 +267,12 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num)
pr_debug("%s: gadget:%p\n", __func__, gr);
if (port_num >= NR_QTI_PORTS) {
pr_err("%s: Invalid QTI port %d\n", __func__, port_num);
if (qport >= QTI_NUM_PORTS) {
pr_err("%s: Invalid QTI port %d\n", __func__, qport);
return;
}
port = ctrl_port[port_num];
port = ctrl_port[qport];
if (!port) {
pr_err("%s: gadget port is null\n", __func__);
return;
@ -282,17 +287,17 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num)
port->ipa_cons_idx = -1;
port->port_usb = NULL;
if (gr && port->gtype == USB_GADGET_RMNET) {
if (gr && port->port_type == QTI_PORT_RMNET) {
g_rmnet = (struct grmnet *)gr;
g_rmnet->send_encap_cmd = NULL;
g_rmnet->notify_modem = NULL;
} else if (gr && port->gtype == USB_GADGET_DPL) {
} 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->gtype);
__func__, port->port_type);
}
while (!list_empty(&port->cpkt_req_q)) {
@ -309,18 +314,17 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num)
qti_ctrl_queue_notify(port);
}
void gqti_ctrl_update_ipa_pipes(void *gr, u8 port_num, u32 ipa_prod,
u32 ipa_cons)
void gqti_ctrl_update_ipa_pipes(void *gr, enum qti_port_type qport,
u32 ipa_prod, u32 ipa_cons)
{
struct qti_ctrl_port *port;
if (port_num >= NR_QTI_PORTS) {
pr_err("%s: Invalid QTI port %d\n", __func__, port_num);
if (qport >= QTI_NUM_PORTS) {
pr_err("%s: Invalid QTI port %d\n", __func__, qport);
return;
}
port = ctrl_port[port_num];
port = ctrl_port[qport];
port->ipa_prod_idx = ipa_prod;
port->ipa_cons_idx = ipa_cons;
@ -492,12 +496,12 @@ qti_ctrl_write(struct file *fp, const char __user *buf, size_t count,
spin_lock_irqsave(&port->lock, flags);
if (port && port->port_usb) {
if (port->gtype == USB_GADGET_RMNET) {
if (port->port_type == QTI_PORT_RMNET) {
g_rmnet = (struct grmnet *)port->port_usb;
} else {
spin_unlock_irqrestore(&port->lock, flags);
pr_err("%s(): unrecognized gadget type(%d).\n",
__func__, port->gtype);
__func__, port->port_type);
return -EINVAL;
}
@ -530,15 +534,15 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
struct ep_info info;
int val, ret = 0;
pr_debug("%s: Received command %d for gtype:%d\n",
__func__, cmd, port->gtype);
pr_debug("%s: Received command %d for port type:%d\n",
__func__, cmd, port->port_type);
if (qti_ctrl_lock(&port->ioctl_excl))
return -EBUSY;
switch (cmd) {
case QTI_CTRL_MODEM_OFFLINE:
if (port && (port->gtype == USB_GADGET_DPL)) {
if (port && (port->port_type == QTI_PORT_DPL)) {
pr_err("%s(): Modem Offline not handled\n", __func__);
goto exit_ioctl;
}
@ -550,7 +554,7 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
gr->disconnect(gr);
break;
case QTI_CTRL_MODEM_ONLINE:
if (port && (port->gtype == USB_GADGET_DPL)) {
if (port && (port->port_type == QTI_PORT_DPL)) {
pr_err("%s(): Modem Online not handled\n", __func__);
goto exit_ioctl;
}
@ -568,13 +572,13 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
pr_err("copying to user space failed");
ret = -EFAULT;
}
pr_debug("%s: Sent line_state: %d for gtype:%d\n", __func__,
atomic_read(&port->line_state), port->gtype);
pr_debug("%s: Sent line_state: %d for port type:%d\n", __func__,
atomic_read(&port->line_state), port->port_type);
break;
case QTI_CTRL_EP_LOOKUP:
pr_debug("%s(): EP_LOOKUP for gtype:%d\n", __func__,
port->gtype);
pr_debug("%s(): EP_LOOKUP for port type:%d\n", __func__,
port->port_type);
val = atomic_read(&port->connected);
if (!val) {
pr_err_ratelimited("EP_LOOKUP failed: not connected\n");
@ -593,9 +597,9 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
info.ipa_ep_pair.cons_pipe_num = port->ipa_cons_idx;
info.ipa_ep_pair.prod_pipe_num = port->ipa_prod_idx;
pr_debug("%s(): gtype:%d ep_type:%d intf:%d\n",
__func__, port->gtype, info.ph_ep_info.ep_type,
info.ph_ep_info.peripheral_iface_id);
pr_debug("%s(): port type:%d ep_type:%d intf:%d\n",
__func__, port->port_type, info.ph_ep_info.ep_type,
info.ph_ep_info.peripheral_iface_id);
pr_debug("%s(): ipa_cons_idx:%d ipa_prod_idx:%d\n",
__func__, info.ipa_ep_pair.cons_pipe_num,
@ -650,7 +654,7 @@ static int qti_ctrl_read_stats(struct seq_file *s, void *unused)
unsigned long flags;
int i;
for (i = 0; i < NR_QTI_PORTS; i++) {
for (i = 0; i < QTI_NUM_PORTS; i++) {
port = ctrl_port[i];
if (!port)
continue;
@ -687,7 +691,7 @@ static ssize_t qti_ctrl_reset_stats(struct file *file,
int i;
unsigned long flags;
for (i = 0; i < NR_QTI_PORTS; i++) {
for (i = 0; i < QTI_NUM_PORTS; i++) {
port = ctrl_port[i];
if (!port)
continue;
@ -762,10 +766,9 @@ int gqti_ctrl_init(void)
int ret, i, sz = QTI_CTRL_NAME_LEN;
struct qti_ctrl_port *port = NULL;
for (i = 0; i < NR_QTI_PORTS; i++) {
for (i = 0; i < QTI_NUM_PORTS; i++) {
port = kzalloc(sizeof(struct qti_ctrl_port), GFP_KERNEL);
if (!port) {
pr_err("Failed to allocate rmnet control device\n");
ret = -ENOMEM;
goto fail_init;
}
@ -787,16 +790,16 @@ int gqti_ctrl_init(void)
port->ipa_prod_idx = -1;
port->ipa_cons_idx = -1;
if (i == 0)
if (i == QTI_PORT_RMNET)
strlcat(port->name, RMNET_CTRL_QTI_NAME, sz);
else if (i == DPL_QTI_CTRL_PORT_NO)
else if (i == QTI_PORT_DPL)
strlcat(port->name, DPL_CTRL_QTI_NAME, sz);
else
snprintf(port->name, sz, "%s%d",
RMNET_CTRL_QTI_NAME, i);
RMNET_CTRL_QTI_NAME, i);
port->ctrl_device.name = port->name;
if (i == DPL_QTI_CTRL_PORT_NO)
if (i == QTI_PORT_DPL)
port->ctrl_device.fops = &dpl_qti_ctrl_fops;
else
port->ctrl_device.fops = &qti_ctrl_fops;
@ -809,7 +812,6 @@ int gqti_ctrl_init(void)
}
}
qti_ctrl_debugfs_init();
return ret;
fail_init:
@ -825,7 +827,7 @@ void gqti_ctrl_cleanup(void)
{
int i;
for (i = 0; i < NR_QTI_PORTS; i++) {
for (i = 0; i < QTI_NUM_PORTS; i++) {
misc_deregister(&ctrl_port[i]->ctrl_device);
kfree(ctrl_port[i]);
ctrl_port[i] = NULL;

View file

@ -23,6 +23,7 @@
#include <linux/usb_bam.h>
#include "u_data_ipa.h"
#include "u_rmnet.h"
struct ipa_data_ch_info {
struct usb_request *rx_req;
@ -564,6 +565,11 @@ static void ipa_data_connect_work(struct work_struct *w)
atomic_set(&port->pipe_connect_notified, 1);
}
if (port->func_type == USB_IPA_FUNC_RMNET) {
gqti_ctrl_update_ipa_pipes(port->port_usb, QTI_PORT_RMNET,
gport->ipa_producer_ep, gport->ipa_consumer_ep);
}
pr_debug("ipa_producer_ep:%d ipa_consumer_ep:%d\n",
gport->ipa_producer_ep,
gport->ipa_consumer_ep);
@ -1135,7 +1141,7 @@ int ipa_data_setup(enum ipa_func_type func)
}
if (ipa_data_wq) {
pr_debug("ipa_data_wq is already setup.");
goto free_rndis_data;
return 0;
}
ipa_data_wq = alloc_workqueue("k_usb_ipa_data",

View file

@ -20,6 +20,8 @@
#include <linux/ipa_usb.h>
#include <linux/usb_bam.h>
#include "u_rmnet.h"
enum ipa_func_type {
USB_IPA_FUNC_ECM,
USB_IPA_FUNC_MBIM,
@ -87,4 +89,6 @@ void *rndis_qc_get_ipa_rx_cb(void);
bool rndis_qc_get_skip_ep_config(void);
void *rndis_qc_get_ipa_tx_cb(void);
void rndis_ipa_reset_trigger(void);
void gqti_ctrl_update_ipa_pipes(void *gr, enum qti_port_type qport,
u32 ipa_prod, u32 ipa_cons);
#endif

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2011-2016, 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
@ -19,18 +19,19 @@
#include <linux/workqueue.h>
struct rmnet_ctrl_pkt {
void *buf;
int len;
void *buf;
int len;
struct list_head list;
};
enum qti_port_type {
QTI_PORT_RMNET,
QTI_PORT_DPL,
QTI_NUM_PORTS
};
struct grmnet {
struct usb_function func;
struct usb_gadget *gadget;
struct usb_ep *in;
struct usb_ep *out;
/* to usb host, aka laptop, windows pc etc. Will
* be filled by usb driver of rmnet functionality
*/
@ -39,18 +40,13 @@ struct grmnet {
/* to modem, and to be filled by driver implementing
* control function
*/
int (*send_encap_cmd)(u8 port_num, void *buf, size_t len);
void (*notify_modem)(void *g, u8 port_num, int cbits);
int (*send_encap_cmd)(enum qti_port_type qport, void *buf, size_t len);
void (*notify_modem)(void *g, enum qti_port_type qport, int cbits);
void (*disconnect)(struct grmnet *g);
void (*connect)(struct grmnet *g);
};
#define NR_QTI_PORTS (NR_RMNET_PORTS + NR_DPL_PORTS)
#define NR_RMNET_PORTS 4
#define NR_DPL_PORTS 1
enum ctrl_client {
FRMNET_CTRL_CLIENT,
GPS_CTRL_CLIENT,
@ -58,22 +54,8 @@ enum ctrl_client {
NR_CTRL_CLIENTS
};
int gbam_setup(unsigned int no_bam_port);
int gbam2bam_setup(unsigned int no_bam2bam_port);
void gbam_cleanup(void);
int gbam_connect(struct grmnet *gr, u8 port_num,
enum transport_type trans, u8 src_connection_idx,
u8 dst_connection_idx);
void gbam_disconnect(struct grmnet *gr, u8 port_num,
enum transport_type trans);
void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans);
void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans);
int gbam_mbim_setup(void);
int gbam_mbim_connect(struct usb_gadget *g, struct usb_ep *in,
struct usb_ep *out);
void gbam_mbim_disconnect(void);
int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num);
int gsmd_ctrl_setup(enum ctrl_client client_num, unsigned int count,
u8 *first_port_idx);
int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf);
void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport);
int gqti_ctrl_init(void);
void gqti_ctrl_cleanup(void);
#endif /* __U_RMNET_H*/