import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / usb / gadget / f_rndis.c
index 36e8c44d8e5e2fb04222b86b4e9fbc4d3a493083..e5b387faed3dee31eef427d8ddd4c41bb41d0905 100644 (file)
@@ -25,6 +25,9 @@
 #include "u_ether.h"
 #include "rndis.h"
 
+#define F_RNDIS_LOG "USB_RNDIS"
+
+#define f_rndis_debug          0
 
 /*
  * This function is an RNDIS Ethernet port -- a Microsoft protocol that's
  *   - MS-Windows drivers sometimes emit undocumented requests.
  */
 
+static unsigned int rndis_dl_max_pkt_per_xfer = 3;
+module_param(rndis_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rndis_dl_max_pkt_per_xfer,
+       "Maximum packets per transfer for DL aggregation");
+
+static unsigned int rndis_ul_max_pkt_per_xfer = 1;
+module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer,
+       "Maximum packets per transfer for UL aggregation");
+
 struct f_rndis {
        struct gether                   port;
        u8                              ctrl_id, data_id;
@@ -364,19 +377,43 @@ static struct usb_gadget_strings *rndis_strings[] = {
        NULL,
 };
 
+u32 rndis_test_last_resp_id = 0;
+
 /*-------------------------------------------------------------------------*/
 
 static struct sk_buff *rndis_add_header(struct gether *port,
                                        struct sk_buff *skb)
 {
        struct sk_buff *skb2;
-
-       skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
-       if (skb2)
-               rndis_add_hdr(skb2);
-
-       dev_kfree_skb_any(skb);
-       return skb2;
+       struct rndis_packet_msg_type *header = NULL;
+       struct f_rndis *rndis = func_to_rndis(&port->func);
+
+       if (rndis->port.multi_pkt_xfer) {
+               if (port->header) {
+                       header = port->header;
+                       memset(header, 0, sizeof(*header));
+                       header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET);
+                       header->MessageLength = cpu_to_le32(skb->len +
+                                                       sizeof(*header));
+                       header->DataOffset = cpu_to_le32(36);
+                       header->DataLength = cpu_to_le32(skb->len);
+                       pr_debug("MessageLength:%d DataLength:%d\n",
+                                               header->MessageLength,
+                                               header->DataLength);
+                       return skb;
+               } else {
+                       pr_err("RNDIS header is NULL.\n");
+                       return NULL;
+               }
+       } else {
+               skb2 = skb_realloc_headroom(skb,
+                               sizeof(struct rndis_packet_msg_type));
+               if (skb2)
+                       rndis_add_hdr(skb2);
+
+               dev_kfree_skb(skb);
+               return skb2;
+       }
 }
 
 static void rndis_response_available(void *_rndis)
@@ -408,9 +445,14 @@ static void rndis_response_available(void *_rndis)
 static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
 {
        struct f_rndis                  *rndis = req->context;
-       struct usb_composite_dev        *cdev = rndis->port.func.config->cdev;
+       struct usb_composite_dev        *cdev;
        int                             status = req->status;
 
+       if (!rndis->port.func.config || !rndis->port.func.config->cdev)
+               return;
+       else
+               cdev = rndis->port.func.config->cdev;
+
        /* after TX:
         *  - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
         *  - RNDIS_RESPONSE_AVAILABLE (status/irq)
@@ -447,7 +489,14 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
 static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
 {
        struct f_rndis                  *rndis = req->context;
+       struct usb_composite_dev        *cdev;
        int                             status;
+       rndis_init_msg_type             *buf;
+
+       if (!rndis->port.func.config || !rndis->port.func.config->cdev)
+               return;
+       else
+               cdev = rndis->port.func.config->cdev;
 
        /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
 //     spin_lock(&dev->lock);
@@ -455,6 +504,23 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
        if (status < 0)
                pr_err("RNDIS command error %d, %d/%d\n",
                        status, req->actual, req->length);
+
+       buf = (rndis_init_msg_type *)req->buf;
+
+       if (buf->MessageType == RNDIS_MSG_INIT) {
+               if (buf->MaxTransferSize > 2048){
+                       rndis->port.multi_pkt_xfer = 1;
+                       rndis->port.dl_max_transfer_len = buf->MaxTransferSize;
+               }else{
+                       rndis->port.multi_pkt_xfer = 0;
+               }               
+               DBG(cdev, "%s: MaxTransferSize: %d : Multi_pkt_txr: %s\n",
+                               __func__, buf->MaxTransferSize,
+                               rndis->port.multi_pkt_xfer ? "enabled" :
+                                                           "disabled");
+               if (rndis_dl_max_pkt_per_xfer <= 1)
+                       rndis->port.multi_pkt_xfer = 0;
+       }
 //     spin_unlock(&dev->lock);
 }
 
@@ -472,6 +538,12 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
        /* composite driver infrastructure handles everything except
         * CDC class messages; interface activation uses set_alt().
         */
+
+       if (f_rndis_debug){
+               pr_debug("rndis_setup , ctrl->bRequestType is 0x%x, ctrl->bRequest is 0x%x, w_index is 0x%x, w_value is 0x%x\n" ,
+       ctrl->bRequestType , ctrl->bRequest, w_index, w_value) ;
+       }
+
        switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
 
        /* RNDIS uses the CDC command encapsulation mechanism to implement
@@ -495,6 +567,8 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
                else {
                        u8 *buf;
                        u32 n;
+                       u32 MsgType, MsgLength, MsgID;
+                       __le32 *tmp;
 
                        /* return the result */
                        buf = rndis_get_next_response(rndis->config, &n);
@@ -502,8 +576,18 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
                                memcpy(req->buf, buf, n);
                                req->complete = rndis_response_complete;
                                req->context = rndis;
+                               tmp = (__le32 *)buf;
+                               MsgType   = get_unaligned_le32(tmp++);
+                               MsgLength = get_unaligned_le32(tmp++);
+                               MsgID = get_unaligned_le32(tmp++);
+
                                rndis_free_response(rndis->config, buf);
                                value = n;
+
+                               if (f_rndis_debug){
+                                       pr_debug("rndis_setup, rndis response MsgLength %d, msg type is 0x%x, RequestID is 0x%x\n", MsgLength, MsgType, MsgID);
+                               }
+                               rndis_test_last_resp_id = MsgID ;
                        }
                        /* else stalls ... spec says to avoid that */
                }
@@ -511,6 +595,10 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 
        default:
 invalid:
+               pr_err("invalid control req%02x.%02x v%04x i%04x l%d\n",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       w_value, w_index, w_length);
+
                VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
                        ctrl->bRequestType, ctrl->bRequest,
                        w_value, w_index, w_length);
@@ -539,14 +627,18 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
        struct usb_composite_dev *cdev = f->config->cdev;
 
        /* we know alt == 0 */
+       printk( F_RNDIS_LOG "rndis_set_alt - interface : %d, rndis ctrl id : %d, rndis data id : %d\n" ,
+       intf, rndis->ctrl_id, rndis->data_id);
 
        if (intf == rndis->ctrl_id) {
                if (rndis->notify->driver_data) {
                        VDBG(cdev, "reset rndis control %d\n", intf);
+                       printk( F_RNDIS_LOG "reset rndis control %d\n", intf);
                        usb_ep_disable(rndis->notify);
                }
                if (!rndis->notify->desc) {
                        VDBG(cdev, "init rndis ctrl %d\n", intf);
+                       printk( F_RNDIS_LOG "init rndis ctrl %d\n", intf);
                        if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
                                goto fail;
                }
@@ -558,11 +650,13 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 
                if (rndis->port.in_ep->driver_data) {
                        DBG(cdev, "reset rndis\n");
+                       printk( F_RNDIS_LOG "reset rndis\n");
                        gether_disconnect(&rndis->port);
                }
 
                if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
                        DBG(cdev, "init rndis\n");
+                       printk( F_RNDIS_LOG "init rndis\n");
                        if (config_ep_by_speed(cdev->gadget, f,
                                               rndis->port.in_ep) ||
                            config_ep_by_speed(cdev->gadget, f,
@@ -614,6 +708,7 @@ static void rndis_disable(struct usb_function *f)
                return;
 
        DBG(cdev, "rndis deactivated\n");
+       printk( F_RNDIS_LOG "rndis deactivated\n");
 
        rndis_uninit(rndis->config);
        gether_disconnect(&rndis->port);
@@ -637,6 +732,7 @@ static void rndis_open(struct gether *geth)
        struct usb_composite_dev *cdev = geth->func.config->cdev;
 
        DBG(cdev, "%s\n", __func__);
+       printk( F_RNDIS_LOG "%s\n", __func__);
 
        rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3,
                                bitrate(cdev->gadget) / 100);
@@ -648,6 +744,7 @@ static void rndis_close(struct gether *geth)
        struct f_rndis          *rndis = func_to_rndis(&geth->func);
 
        DBG(geth->func.config->cdev, "%s\n", __func__);
+       printk( F_RNDIS_LOG "%s\n", __func__);
 
        rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
        rndis_signal_disconnect(rndis->config);
@@ -665,6 +762,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
        int                     status;
        struct usb_ep           *ep;
 
+       printk( F_RNDIS_LOG \
+                       "%s: rndis_bind begin \n", \
+                       __func__);
+
        /* allocate instance-specific interface IDs */
        status = usb_interface_id(c, f);
        if (status < 0)
@@ -748,6 +849,7 @@ rndis_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);
+       rndis_set_max_pkt_xfer(rndis->config, rndis_ul_max_pkt_per_xfer);
 
        if (rndis->manufacturer && rndis->vendorID &&
                        rndis_set_param_vendor(rndis->config, rndis->vendorID,
@@ -759,6 +861,13 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
         * until we're activated via set_alt().
         */
 
+       printk( F_RNDIS_LOG
+                               "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+                       gadget_is_superspeed(c->cdev->gadget) ? "super" :
+                       gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+                       rndis->port.in_ep->name, rndis->port.out_ep->name,
+                       rndis->notify->name);
+
        DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
                        gadget_is_superspeed(c->cdev->gadget) ? "super" :
                        gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
@@ -792,6 +901,11 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
 {
        struct f_rndis          *rndis = func_to_rndis(f);
 
+       printk( F_RNDIS_LOG \
+                       "%s: rndis_unbind \n", \
+                       __func__);
+
+
        rndis_deregister(rndis->config);
        rndis_exit();
 
@@ -821,12 +935,12 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
        if (!can_support_rndis(c) || !ethaddr)
                return -EINVAL;
 
-       if (rndis_string_defs[0].id == 0) {
-               /* ... and setup RNDIS itself */
-               status = rndis_init();
-               if (status < 0)
-                       return status;
+       /* setup RNDIS itself */
+       status = rndis_init();
+       if (status < 0)
+               return status;
 
+       if (rndis_string_defs[0].id == 0) {
                status = usb_string_ids_tab(c->cdev, rndis_string_defs);
                if (status)
                        return status;
@@ -854,6 +968,8 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
        rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
        rndis->port.wrap = rndis_add_header;
        rndis->port.unwrap = rndis_rm_hdr;
+       rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer;
+       rndis->port.dl_max_pkts_per_xfer = rndis_dl_max_pkt_per_xfer;
 
        rndis->port.func.name = "rndis";
        rndis->port.func.strings = rndis_strings;
@@ -870,5 +986,9 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
 fail:
                rndis_exit();
        }
+
+       printk( F_RNDIS_LOG \
+                       "%s: rndis_bind_config_vendor done, status is %d \n", \
+                       __func__, status);
        return status;
 }