summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorHemant Kumar <hemantk@codeaurora.org>2016-02-01 18:50:28 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:03:04 -0700
commita86fe70b61b4e724fbab306bb7856a47fd8c8b11 (patch)
treeb9fd9fc4d5f5fe6dd4367aa7d51900e239385fb5 /drivers/usb
parentc34d39a5110f5f8fedd664ae1b98d809cd7f56ef (diff)
usb: gadget: Add support for rndis flow control callback
Allow registration for data flow control call back from rndis functions supporting different transport i.e. BAM2BAM_IPA, GSI_IPA. Change-Id: I09df5f7f81e9d9ed0cfd5e54d481db87727bbc75 Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/function/f_rndis.c2
-rw-r--r--drivers/usb/gadget/function/rndis.c59
-rw-r--r--drivers/usb/gadget/function/rndis.h7
3 files changed, 61 insertions, 7 deletions
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index 3a28d8ac3b3d..13888821109d 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -1018,7 +1018,7 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
rndis->port.func.disable = rndis_disable;
rndis->port.func.free_func = rndis_free;
- params = rndis_register(rndis_response_available, rndis);
+ params = rndis_register(rndis_response_available, rndis, NULL);
if (IS_ERR(params)) {
kfree(rndis);
return ERR_CAST(params);
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index 2ec7171b3f04..2c806ea13e90 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -831,10 +831,16 @@ int rndis_msg_parser(struct rndis_params *params, u8 *buf)
case RNDIS_MSG_HALT:
pr_debug("%s: RNDIS_MSG_HALT\n",
__func__);
- params->state = RNDIS_UNINITIALIZED;
- if (params->dev) {
- netif_carrier_off(params->dev);
- netif_stop_queue(params->dev);
+ if (params->state == RNDIS_DATA_INITIALIZED) {
+ if (params->flow_ctrl_enable) {
+ params->flow_ctrl_enable(true, params);
+ } else {
+ if (params->dev) {
+ netif_carrier_off(params->dev);
+ netif_stop_queue(params->dev);
+ }
+ }
+ params->state = RNDIS_UNINITIALIZED;
}
return 0;
@@ -886,7 +892,8 @@ static inline void rndis_put_nr(int nr)
ida_simple_remove(&rndis_ida, nr);
}
-struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v)
+struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v,
+ void (*flow_ctrl_enable)(bool enable, struct rndis_params *params))
{
struct rndis_params *params;
int i;
@@ -930,6 +937,7 @@ struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v)
params->state = RNDIS_UNINITIALIZED;
params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED;
params->resp_avail = resp_avail;
+ params->flow_ctrl_enable = flow_ctrl_enable;
params->v = v;
INIT_LIST_HEAD(&(params->resp_queue));
pr_debug("%s: configNr = %d\n", __func__, i);
@@ -1015,6 +1023,47 @@ void rndis_set_max_pkt_xfer(struct rndis_params *params, u8 max_pkt_per_xfer)
params->max_pkt_per_xfer = max_pkt_per_xfer;
}
+/**
+ * rndis_flow_control: enable/disable flow control with USB RNDIS interface
+ * params - RNDIS network parameter
+ * enable_flow_control - true: perform flow control, false: disable flow control
+ *
+ * In hw accelerated mode, this function triggers functionality to start/stop
+ * endless transfers, otherwise it enables/disables RNDIS network interface.
+ */
+void rndis_flow_control(struct rndis_params *params, bool enable_flow_control)
+{
+ if (!params) {
+ pr_err("%s: failed, params NULL\n", __func__);
+ return;
+ }
+
+ pr_debug("%s(): params->state:%x\n", __func__, params->state);
+
+ if (enable_flow_control) {
+ if (params->state == RNDIS_DATA_INITIALIZED) {
+ if (params->flow_ctrl_enable) {
+ params->flow_ctrl_enable(enable_flow_control, params);
+ } else {
+ netif_carrier_off(params->dev);
+ netif_stop_queue(params->dev);
+ }
+ }
+ params->state = RNDIS_INITIALIZED;
+ } else {
+ if (params->state != RNDIS_DATA_INITIALIZED) {
+ if (params->flow_ctrl_enable) {
+ params->flow_ctrl_enable(enable_flow_control, params);
+ } else {
+ netif_carrier_on(params->dev);
+ if (netif_running(params->dev))
+ netif_wake_queue(params->dev);
+ }
+ }
+ params->state = RNDIS_DATA_INITIALIZED;
+ }
+}
+
void rndis_add_hdr(struct sk_buff *skb)
{
struct rndis_packet_msg_type *header;
diff --git a/drivers/usb/gadget/function/rndis.h b/drivers/usb/gadget/function/rndis.h
index 310cac3f088e..c9edf9cf12d8 100644
--- a/drivers/usb/gadget/function/rndis.h
+++ b/drivers/usb/gadget/function/rndis.h
@@ -193,13 +193,17 @@ typedef struct rndis_params
u8 max_pkt_per_xfer;
const char *vendorDescr;
void (*resp_avail)(void *v);
+ void (*flow_ctrl_enable)(bool enable,
+ struct rndis_params *params);
+
void *v;
struct list_head resp_queue;
} rndis_params;
/* RNDIS Message parser and other useless functions */
int rndis_msg_parser(struct rndis_params *params, u8 *buf);
-struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v);
+struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v,
+ void (*flow_ctrl_enable)(bool enable, struct rndis_params *params));
void rndis_deregister(struct rndis_params *params);
int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev,
u16 *cdc_filter);
@@ -219,5 +223,6 @@ int rndis_signal_connect(struct rndis_params *params);
int rndis_signal_disconnect(struct rndis_params *params);
int rndis_state(struct rndis_params *params);
extern void rndis_set_host_mac(struct rndis_params *params, const u8 *addr);
+void rndis_flow_control(struct rndis_params *params, bool enable_flow_control);
#endif /* _LINUX_RNDIS_H */