From a86fe70b61b4e724fbab306bb7856a47fd8c8b11 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Mon, 1 Feb 2016 18:50:28 -0800 Subject: [PATCH] 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 --- drivers/usb/gadget/function/f_rndis.c | 2 +- drivers/usb/gadget/function/rndis.c | 59 ++++++++++++++++++++++++--- drivers/usb/gadget/function/rndis.h | 7 +++- 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 */