usb: gadget: Add SPS BAM-to-BAM support
Adding new support to enable USB-Peripheral
BAM-to-BAM transactions.
Changes were added to the UDC to support
"legacy/regular" USB transfers and
endless BAM-to-BAM transfers.
To avoid adding new vendor specific UDC file
to support the new feature and keep the UDC
as a generic as possiblea, USB request holds
a vendor specific data that distinguish between
the two transfer types.
USB BAM will be added in seperate commit.
Change-Id: I3211a122fe5236cda2dbe844b44f52a2b2063baf
Signed-off-by: Ofir Cohen <ofirc@codeaurora.org>
Signed-off-by: Amit Blay <ablay@codeaurora.org>
diff --git a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
index 54566dc..d8a3e60 100644
--- a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
+++ b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
@@ -20,6 +20,7 @@
USB_GADGET_XPORT_SDIO,
USB_GADGET_XPORT_SMD,
USB_GADGET_XPORT_BAM,
+ USB_GADGET_XPORT_BAM2BAM,
USB_GADGET_XPORT_HSIC,
USB_GADGET_XPORT_NONE,
};
@@ -37,6 +38,8 @@
return "SMD";
case USB_GADGET_XPORT_BAM:
return "BAM";
+ case USB_GADGET_XPORT_BAM2BAM:
+ return "BAM2BAM";
case USB_GADGET_XPORT_HSIC:
return "HSIC";
case USB_GADGET_XPORT_NONE:
@@ -56,6 +59,8 @@
return USB_GADGET_XPORT_SMD;
if (!strncasecmp("BAM", name, XPORT_STR_LEN))
return USB_GADGET_XPORT_BAM;
+ if (!strncasecmp("BAM2BAM", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_BAM2BAM;
if (!strncasecmp("HSIC", name, XPORT_STR_LEN))
return USB_GADGET_XPORT_HSIC;
if (!strncasecmp("", name, XPORT_STR_LEN))
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index e084278..6282389 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -155,6 +155,7 @@
#define CAP_ENDPTLISTADDR (0x018UL)
#define CAP_PORTSC (0x044UL)
#define CAP_DEVLC (0x084UL)
+#define CAP_ENDPTPIPEID (0x0BCUL)
#define CAP_USBMODE (hw_bank.lpm ? 0x0C8UL : 0x068UL)
#define CAP_ENDPTSETUPSTAT (hw_bank.lpm ? 0x0D8UL : 0x06CUL)
#define CAP_ENDPTPRIME (hw_bank.lpm ? 0x0DCUL : 0x070UL)
@@ -1638,6 +1639,23 @@
if (!mReq->req.no_interrupt)
mReq->ptr->token |= TD_IOC;
}
+
+ /* MSM Specific: updating the request as required for
+ * SPS mode. Enable MSM proprietary DMA engine acording
+ * to the UDC private data in the request.
+ */
+ if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+ if (mReq->req.udc_priv & MSM_SPS_MODE) {
+ mReq->ptr->token = TD_STATUS_ACTIVE;
+ if (mReq->req.udc_priv & MSM_TBE)
+ mReq->ptr->next = TD_TERMINATE;
+ else
+ mReq->ptr->next = MSM_ETD_TYPE | mReq->dma;
+ if (!mReq->req.no_interrupt)
+ mReq->ptr->token |= MSM_ETD_IOC;
+ }
+ }
+
mReq->ptr->page[0] = mReq->req.dma;
for (i = 1; i < 5; i++)
mReq->ptr->page[i] =
@@ -1680,6 +1698,39 @@
}
mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
+
+ if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+ if (mReq->req.udc_priv & MSM_SPS_MODE) {
+ mEp->qh.ptr->td.next |= MSM_ETD_TYPE;
+ i = hw_cread(CAP_ENDPTPIPEID +
+ mEp->num * sizeof(u32), ~0);
+ /* Read current value of this EPs pipe id */
+ i = (mEp->dir == TX) ?
+ ((i >> MSM_TX_PIPE_ID_OFS) & MSM_PIPE_ID_MASK) :
+ (i & MSM_PIPE_ID_MASK);
+ /* If requested pipe id is different from current,
+ then write it */
+ if (i != (mReq->req.udc_priv & MSM_PIPE_ID_MASK)) {
+ if (mEp->dir == TX)
+ hw_cwrite(
+ CAP_ENDPTPIPEID +
+ mEp->num * sizeof(u32),
+ MSM_PIPE_ID_MASK <<
+ MSM_TX_PIPE_ID_OFS,
+ (mReq->req.udc_priv &
+ MSM_PIPE_ID_MASK)
+ << MSM_TX_PIPE_ID_OFS);
+ else
+ hw_cwrite(
+ CAP_ENDPTPIPEID +
+ mEp->num * sizeof(u32),
+ MSM_PIPE_ID_MASK,
+ mReq->req.udc_priv &
+ MSM_PIPE_ID_MASK);
+ }
+ }
+ }
+
mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */
mEp->qh.ptr->cap |= QH_ZLT;
@@ -1712,6 +1763,10 @@
if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
return -EBUSY;
+ if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID)
+ if ((mReq->req.udc_priv & MSM_SPS_MODE) &&
+ (mReq->req.udc_priv & MSM_TBE))
+ return -EBUSY;
if (mReq->zptr) {
if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
return -EBUSY;
@@ -1756,6 +1811,7 @@
__acquires(mEp->lock)
{
struct ci13xxx_ep *mEpTemp = mEp;
+ unsigned val;
trace("%p", mEp);
@@ -1771,6 +1827,21 @@
list_entry(mEp->qh.queue.next,
struct ci13xxx_req, queue);
list_del_init(&mReq->queue);
+
+ /* MSM Specific: Clear end point proprietary register */
+ if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+ if (mReq->req.udc_priv & MSM_SPS_MODE) {
+ val = hw_cread(CAP_ENDPTPIPEID +
+ mEp->num * sizeof(u32),
+ ~0);
+
+ if (val != MSM_EP_PIPE_ID_RESET_VAL)
+ hw_cwrite(
+ CAP_ENDPTPIPEID +
+ mEp->num * sizeof(u32),
+ ~0, MSM_EP_PIPE_ID_RESET_VAL);
+ }
+ }
mReq->req.status = -ESHUTDOWN;
if (mReq->req.complete != NULL) {
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index b917fe9..35b0712 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -25,6 +25,21 @@
#define RX (0) /* similar to USB_DIR_OUT but can be used as an index */
#define TX (1) /* similar to USB_DIR_IN but can be used as an index */
+/* UDC private data:
+ * 16MSb - Vendor ID | 16 LSb Vendor private data
+ */
+#define CI13XX_REQ_VENDOR_ID(id) (id & 0xFFFF0000UL)
+
+/* MSM specific */
+#define MSM_PIPE_ID_MASK (0x1F)
+#define MSM_TX_PIPE_ID_OFS (16)
+#define MSM_SPS_MODE BIT(5)
+#define MSM_TBE BIT(6)
+#define MSM_ETD_TYPE BIT(1)
+#define MSM_ETD_IOC BIT(9)
+#define MSM_VENDOR_ID BIT(16)
+#define MSM_EP_PIPE_ID_RESET_VAL 0x1F001F
+
/******************************************************************************
* STRUCTURES
*****************************************************************************/
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 32791d9..cbcf5ac 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -18,10 +18,10 @@
#include <linux/spinlock.h>
#include <mach/usb_gadget_xport.h>
+
#include "u_rmnet.h"
#include "gadget_chips.h"
-
#define RMNET_NOTIFY_INTERVAL 5
#define RMNET_MAX_NOTIFY_SIZE sizeof(struct usb_cdc_notification)
@@ -66,6 +66,7 @@
static unsigned int no_ctrl_smd_ports;
static unsigned int no_ctrl_hsic_ports;
static unsigned int no_data_bam_ports;
+static unsigned int no_data_bam2bam_ports;
static unsigned int no_data_hsic_ports;
static struct rmnet_ports {
enum transport_type data_xport;
@@ -241,13 +242,16 @@
int port_idx;
int i;
- pr_debug("%s: bam ports: %u data hsic ports: %u smd ports: %u"
- " ctrl hsic ports: %u nr_rmnet_ports: %u\n",
- __func__, no_data_bam_ports, no_data_hsic_ports,
- no_ctrl_smd_ports, no_ctrl_hsic_ports, nr_rmnet_ports);
+ pr_debug("%s: bam ports: %u bam2bam ports: %u data hsic ports: %u"
+ " smd ports: %u ctrl hsic ports: %u"
+ " nr_rmnet_ports: %u\n",
+ __func__, no_data_bam_ports, no_data_bam2bam_ports,
+ no_data_hsic_ports, no_ctrl_smd_ports,
+ no_ctrl_hsic_ports, nr_rmnet_ports);
- if (no_data_bam_ports) {
- ret = gbam_setup(no_data_bam_ports);
+ if (no_data_bam_ports || no_data_bam2bam_ports) {
+ ret = gbam_setup(no_data_bam_ports,
+ no_data_bam2bam_ports);
if (ret)
return ret;
}
@@ -329,7 +333,11 @@
port_num = rmnet_ports[dev->port_num].data_xport_num;
switch (dxport) {
case USB_GADGET_XPORT_BAM:
- ret = gbam_connect(&dev->port, port_num);
+ case USB_GADGET_XPORT_BAM2BAM:
+ /* currently only one connection (idx 0)
+ is supported */
+ ret = gbam_connect(&dev->port, port_num,
+ dxport, 0);
if (ret) {
pr_err("%s: gbam_connect failed: err:%d\n",
__func__, ret);
@@ -386,7 +394,8 @@
port_num = rmnet_ports[dev->port_num].data_xport_num;
switch (dxport) {
case USB_GADGET_XPORT_BAM:
- gbam_disconnect(&dev->port, port_num);
+ case USB_GADGET_XPORT_BAM2BAM:
+ gbam_disconnect(&dev->port, port_num, dxport);
break;
case USB_GADGET_XPORT_HSIC:
ghsic_data_disconnect(&dev->port, port_num);
@@ -954,6 +963,7 @@
nr_rmnet_ports = 0;
no_ctrl_smd_ports = 0;
no_data_bam_ports = 0;
+ no_data_bam2bam_ports = 0;
no_ctrl_hsic_ports = 0;
no_data_hsic_ports = 0;
}
@@ -1013,6 +1023,10 @@
rmnet_port->data_xport_num = no_data_bam_ports;
no_data_bam_ports++;
break;
+ case USB_GADGET_XPORT_BAM2BAM:
+ rmnet_port->data_xport_num = no_data_bam2bam_ports;
+ no_data_bam2bam_ports++;
+ break;
case USB_GADGET_XPORT_HSIC:
rmnet_port->data_xport_num = no_data_hsic_ports;
no_data_hsic_ports++;
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 70cbd2f..869a541 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -23,12 +23,17 @@
#include <linux/bitops.h>
#include <linux/termios.h>
+#include <mach/usb_gadget_xport.h>
+#include <mach/usb_bam.h>
+
#include "u_rmnet.h"
#define BAM_N_PORTS 1
+#define BAM2BAM_N_PORTS 1
static struct workqueue_struct *gbam_wq;
static int n_bam_ports;
+static int n_bam2bam_ports;
static unsigned bam_ch_ids[] = { 8 };
static const char *bam_ch_names[] = { "bam_dmux_ch_8" };
@@ -68,6 +73,11 @@
#define BAM_CH_OPENED BIT(0)
#define BAM_CH_READY BIT(1)
+#define SPS_PARAMS_PIPE_ID_MASK (0x1F)
+#define SPS_PARAMS_SPS_MODE BIT(5)
+#define SPS_PARAMS_TBE BIT(6)
+#define MSM_VENDOR_ID BIT(16)
+
struct bam_ch_info {
unsigned long flags;
unsigned id;
@@ -81,6 +91,13 @@
struct gbam_port *port;
struct work_struct write_tobam_w;
+ struct usb_request *rx_req;
+ struct usb_request *tx_req;
+
+ u8 src_pipe_idx;
+ u8 dst_pipe_idx;
+ u8 connection_idx;
+
/* stats */
unsigned int pending_with_bam;
unsigned int tohost_drp_cnt;
@@ -96,6 +113,7 @@
spinlock_t port_lock;
struct grmnet *port_usb;
+ struct grmnet *gr;
struct bam_ch_info data_ch;
@@ -108,7 +126,10 @@
struct platform_driver pdrv;
} bam_ports[BAM_N_PORTS];
+struct gbam_port *bam2bam_ports[BAM2BAM_N_PORTS];
static void gbam_start_rx(struct gbam_port *port);
+static void gbam_start_endless_rx(struct gbam_port *port);
+static void gbam_start_endless_tx(struct gbam_port *port);
/*---------------misc functions---------------- */
static void gbam_free_requests(struct usb_ep *ep, struct list_head *head)
@@ -414,6 +435,20 @@
}
}
+static void gbam_endless_rx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ int status = req->status;
+
+ pr_debug("%s status: %d\n", __func__, status);
+}
+
+static void gbam_endless_tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ int status = req->status;
+
+ pr_debug("%s status: %d\n", __func__, status);
+}
+
static void gbam_start_rx(struct gbam_port *port)
{
struct usb_request *req;
@@ -469,6 +504,26 @@
spin_unlock_irqrestore(&port->port_lock, flags);
}
+static void gbam_start_endless_rx(struct gbam_port *port)
+{
+ struct bam_ch_info *d = &port->data_ch;
+ int status;
+
+ status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
+ if (status)
+ pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
+}
+
+static void gbam_start_endless_tx(struct gbam_port *port)
+{
+ struct bam_ch_info *d = &port->data_ch;
+ int status;
+
+ status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
+ if (status)
+ pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
+}
+
static void gbam_start_io(struct gbam_port *port)
{
unsigned long flags;
@@ -520,6 +575,32 @@
}
}
+static void gbam_free_buffers(struct gbam_port *port)
+{
+ struct sk_buff *skb;
+ unsigned long flags;
+ struct bam_ch_info *d;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+
+ if (!port || !port->port_usb)
+ goto free_buf_out;
+
+ d = &port->data_ch;
+
+ gbam_free_requests(port->port_usb->in, &d->tx_idle);
+ gbam_free_requests(port->port_usb->out, &d->rx_idle);
+
+ while ((skb = __skb_dequeue(&d->tx_skb_q)))
+ dev_kfree_skb_any(skb);
+
+ while ((skb = __skb_dequeue(&d->rx_skb_q)))
+ dev_kfree_skb_any(skb);
+
+free_buf_out:
+ spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
static void gbam_disconnect_work(struct work_struct *w)
{
struct gbam_port *port =
@@ -533,6 +614,22 @@
clear_bit(BAM_CH_OPENED, &d->flags);
}
+static void gbam2bam_disconnect_work(struct work_struct *w)
+{
+ struct gbam_port *port =
+ container_of(w, struct gbam_port, disconnect_w);
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ port->port_usb = 0;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ /* disable endpoints */
+ usb_ep_disable(port->gr->out);
+ usb_ep_disable(port->gr->in);
+
+}
+
static void gbam_connect_work(struct work_struct *w)
{
struct gbam_port *port = container_of(w, struct gbam_port, connect_w);
@@ -563,30 +660,47 @@
pr_debug("%s: done\n", __func__);
}
-static void gbam_free_buffers(struct gbam_port *port)
+static void gbam2bam_connect_work(struct work_struct *w)
{
- struct sk_buff *skb;
- unsigned long flags;
- struct bam_ch_info *d;
+ struct gbam_port *port = container_of(w, struct gbam_port, connect_w);
+ struct bam_ch_info *d = &port->data_ch;
+ u32 sps_params;
+ int ret;
- spin_lock_irqsave(&port->port_lock, flags);
+ ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
+ &d->dst_pipe_idx);
+ if (ret) {
+ pr_err("%s: usb_bam_connect failed: err:%d\n",
+ __func__, ret);
+ return;
+ }
- if (!port || !port->port_usb)
- goto free_buf_out;
+ d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_KERNEL);
+ if (!d->rx_req)
+ return;
- d = &port->data_ch;
+ d->rx_req->context = port;
+ d->rx_req->complete = gbam_endless_rx_complete;
+ d->rx_req->length = 0;
+ 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)
+ return;
- gbam_free_requests(port->port_usb->in, &d->tx_idle);
- gbam_free_requests(port->port_usb->out, &d->rx_idle);
+ d->tx_req->context = port;
+ d->tx_req->complete = gbam_endless_tx_complete;
+ d->tx_req->length = 0;
+ sps_params = (SPS_PARAMS_SPS_MODE | d->dst_pipe_idx |
+ MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
+ d->tx_req->udc_priv = sps_params;
- while ((skb = __skb_dequeue(&d->tx_skb_q)))
- dev_kfree_skb_any(skb);
+ /* queue in & out requests */
+ gbam_start_endless_rx(port);
+ gbam_start_endless_tx(port);
- while ((skb = __skb_dequeue(&d->rx_skb_q)))
- dev_kfree_skb_any(skb);
-
-free_buf_out:
- spin_unlock_irqrestore(&port->port_lock, flags);
+ pr_debug("%s: done\n", __func__);
}
/* BAM data channel ready, allow attempt to open */
@@ -673,6 +787,13 @@
}
}
+static void gbam2bam_port_free(int portno)
+{
+ struct gbam_port *port = bam2bam_ports[portno];
+
+ kfree(port);
+}
+
static int gbam_port_alloc(int portno)
{
struct gbam_port *port;
@@ -709,6 +830,32 @@
pdrv->driver.owner = THIS_MODULE;
platform_driver_register(pdrv);
+ pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
+
+ return 0;
+}
+
+static int gbam2bam_port_alloc(int portno)
+{
+ struct gbam_port *port;
+ struct bam_ch_info *d;
+
+ port = kzalloc(sizeof(struct gbam_port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ port->port_num = portno;
+
+ /* port initialization */
+ spin_lock_init(&port->port_lock);
+
+ INIT_WORK(&port->connect_w, gbam2bam_connect_work);
+ INIT_WORK(&port->disconnect_w, gbam2bam_disconnect_work);
+
+ /* data ch */
+ d = &port->data_ch;
+ d->port = port;
+ bam2bam_ports[portno] = port;
pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
@@ -820,7 +967,7 @@
static void gam_debugfs_init(void) { }
#endif
-void gbam_disconnect(struct grmnet *gr, u8 port_num)
+void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans)
{
struct gbam_port *port;
unsigned long flags;
@@ -828,8 +975,17 @@
pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
- if (port_num >= n_bam_ports) {
- pr_err("%s: invalid portno#%d\n", __func__, port_num);
+ if (trans == USB_GADGET_XPORT_BAM &&
+ port_num >= n_bam_ports) {
+ pr_err("%s: invalid bam portno#%d\n",
+ __func__, port_num);
+ return;
+ }
+
+ if (trans == USB_GADGET_XPORT_BAM2BAM &&
+ port_num >= n_bam2bam_ports) {
+ pr_err("%s: invalid bam2bam portno#%d\n",
+ __func__, port_num);
return;
}
@@ -837,24 +993,31 @@
pr_err("%s: grmnet port is null\n", __func__);
return;
}
+ if (trans == USB_GADGET_XPORT_BAM)
+ port = bam_ports[port_num].port;
+ else
+ port = bam2bam_ports[port_num];
- port = bam_ports[port_num].port;
d = &port->data_ch;
+ port->gr = gr;
- gbam_free_buffers(port);
+ if (trans == USB_GADGET_XPORT_BAM) {
+ gbam_free_buffers(port);
- spin_lock_irqsave(&port->port_lock, flags);
- port->port_usb = 0;
- spin_unlock_irqrestore(&port->port_lock, flags);
+ spin_lock_irqsave(&port->port_lock, flags);
+ port->port_usb = 0;
+ spin_unlock_irqrestore(&port->port_lock, flags);
- /* disable endpoints */
- usb_ep_disable(gr->out);
- usb_ep_disable(gr->in);
+ /* disable endpoints */
+ usb_ep_disable(gr->out);
+ usb_ep_disable(gr->in);
+ }
queue_work(gbam_wq, &port->disconnect_w);
}
-int gbam_connect(struct grmnet *gr, u8 port_num)
+int gbam_connect(struct grmnet *gr, u8 port_num,
+ enum transport_type trans, u8 connection_idx)
{
struct gbam_port *port;
struct bam_ch_info *d;
@@ -863,7 +1026,12 @@
pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
- if (port_num >= n_bam_ports) {
+ if (trans == USB_GADGET_XPORT_BAM && port_num >= n_bam_ports) {
+ pr_err("%s: invalid portno#%d\n", __func__, port_num);
+ return -ENODEV;
+ }
+
+ if (trans == USB_GADGET_XPORT_BAM2BAM && port_num >= n_bam2bam_ports) {
pr_err("%s: invalid portno#%d\n", __func__, port_num);
return -ENODEV;
}
@@ -873,7 +1041,11 @@
return -ENODEV;
}
- port = bam_ports[port_num].port;
+ if (trans == USB_GADGET_XPORT_BAM)
+ port = bam_ports[port_num].port;
+ else
+ port = bam2bam_ports[port_num];
+
d = &port->data_ch;
ret = usb_ep_enable(gr->in, gr->in_desc);
@@ -896,29 +1068,35 @@
spin_lock_irqsave(&port->port_lock, flags);
port->port_usb = gr;
- d->to_host = 0;
- d->to_modem = 0;
- d->pending_with_bam = 0;
- d->tohost_drp_cnt = 0;
- d->tomodem_drp_cnt = 0;
+ if (trans == USB_GADGET_XPORT_BAM) {
+ d->to_host = 0;
+ d->to_modem = 0;
+ d->pending_with_bam = 0;
+ d->tohost_drp_cnt = 0;
+ d->tomodem_drp_cnt = 0;
+ }
spin_unlock_irqrestore(&port->port_lock, flags);
+ if (trans == USB_GADGET_XPORT_BAM2BAM)
+ d->connection_idx = connection_idx;
queue_work(gbam_wq, &port->connect_w);
return 0;
}
-int gbam_setup(unsigned int count)
+int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port)
{
int i;
int ret;
- pr_debug("%s: requested ports:%d\n", __func__, count);
+ pr_debug("%s: requested BAM ports:%d and BAM2BAM ports:%d\n",
+ __func__, no_bam_port, no_bam2bam_port);
- if (!count || count > BAM_N_PORTS) {
- pr_err("%s: Invalid num of ports count:%d\n",
- __func__, count);
+ if ((!no_bam_port && !no_bam2bam_port) || no_bam_port > BAM_N_PORTS
+ || no_bam2bam_port > BAM2BAM_N_PORTS) {
+ pr_err("%s: Invalid num of ports count:%d,%d\n",
+ __func__, no_bam_port, no_bam2bam_port);
return -EINVAL;
}
@@ -929,7 +1107,7 @@
return -ENOMEM;
}
- for (i = 0; i < count; i++) {
+ for (i = 0; i < no_bam_port; i++) {
n_bam_ports++;
ret = gbam_port_alloc(i);
if (ret) {
@@ -939,13 +1117,23 @@
}
}
+ for (i = 0; i < no_bam2bam_port; i++) {
+ n_bam2bam_ports++;
+ ret = gbam2bam_port_alloc(i);
+ if (ret) {
+ n_bam2bam_ports--;
+ pr_err("%s: Unable to alloc port:%d\n", __func__, i);
+ goto free_bam_ports;
+ }
+ }
gbam_debugfs_init();
-
return 0;
+
free_bam_ports:
for (i = 0; i < n_bam_ports; i++)
gbam_port_free(i);
-
+ for (i = 0; i < n_bam2bam_ports; i++)
+ gbam2bam_port_free(i);
destroy_workqueue(gbam_wq);
return ret;
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index d8de31e..fd1e124 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -48,10 +48,10 @@
void (*connect)(struct grmnet *g);
};
-int gbam_setup(unsigned int count);
-int gbam_connect(struct grmnet *, u8 port_num);
-void gbam_disconnect(struct grmnet *, u8 port_num);
-
+int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port);
+int gbam_connect(struct grmnet *gr, u8 port_num,
+ enum transport_type trans, u8 connection_idx);
+void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans);
int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num);
int gsmd_ctrl_setup(unsigned int count);
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index 8b08b7a..90cbe54 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -544,12 +544,13 @@
}
for (i = 0; i < count; i++) {
+ n_rmnet_ctrl_ports++;
ret = grmnet_ctrl_smd_port_alloc(i);
if (ret) {
pr_err("%s: Unable to alloc port:%d\n", __func__, i);
+ n_rmnet_ctrl_ports--;
goto free_ctrl_smd_ports;
}
- n_rmnet_ctrl_ports++;
}
return 0;
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index c83035d..47e8427 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -57,6 +57,7 @@
* Note that for writes (IN transfers) some data bytes may still
* reside in a device-side FIFO when the request is reported as
* complete.
+ *@udc_priv: Vendor private data in usage by the UDC.
*
* These are allocated/freed through the endpoint they're used with. The
* hardware's driver can add extra per-request data to the memory it returns,
@@ -92,6 +93,7 @@
int status;
unsigned actual;
+ unsigned udc_priv;
};
/*-------------------------------------------------------------------------*/
@@ -111,7 +113,6 @@
struct usb_request *(*alloc_request) (struct usb_ep *ep,
gfp_t gfp_flags);
void (*free_request) (struct usb_ep *ep, struct usb_request *req);
-
int (*queue) (struct usb_ep *ep, struct usb_request *req,
gfp_t gfp_flags);
int (*dequeue) (struct usb_ep *ep, struct usb_request *req);