diff options
-rw-r--r-- | drivers/net/usb/qmi_wwan.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 58c83d0..bed34e3 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -10,6 +10,7 @@ #include <linux/netdevice.h> #include <linux/ethtool.h> #include <linux/mii.h> +#include <linux/if_arp.h> #include <linux/usb.h> #include <linux/usb/cdc.h> #include <linux/usb/usbnet.h> @@ -57,9 +58,36 @@ static const char qmi_pm_dev[] = "mdm_hsic_pm0"; * corresponding management interface */ +static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + __be16 protocol = 0; + + skb->dev = dev->net; + + /* assumes RAW IP mode! */ + + switch (skb->data[0] & 0xf0) { + case 0x40: + protocol = htons(ETH_P_IP); + break; + case 0x60: + protocol = htons(ETH_P_IPV6); + break; + default: + pr_err("[%s] qmi_wwan L3 protocol decode error: 0x%02x", + dev->net->name, skb->data[0] & 0xf0); + } + + skb->protocol = protocol; + + return 1; +} + int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id *prod) { struct usb_device *udev; + struct usbnet *unet; + struct net_device *net_dev; int status; udev = interface_to_usbdev(intf); @@ -70,6 +98,19 @@ int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id *prod) return -1; } + unet = usb_get_intfdata(intf); + net_dev = unet->net; + /* set RAWIP protocol */ + net_dev->header_ops = 0; /* No header */ + net_dev->type = ARPHRD_RAWIP; + net_dev->hard_header_len = 0; + net_dev->addr_len = 0; + net_dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); + /* recalculate buffers after changing hard_header_len */ + usbnet_change_mtu(net_dev, net_dev->mtu); + + /* give margin before send DTR high */ + msleep(20); pr_info("%s: send DTR high to modem\n", __func__); status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_CDC_REQ_SET_CONTROL_LINE_STATE, @@ -382,6 +423,7 @@ static const struct driver_info qmi_wwan_info = { .flags = FLAG_WWAN, .bind = qmi_wwan_bind, .manage_power = qmi_wwan_manage_power, + .rx_fixup = qmi_wwan_rx_fixup, }; static const struct driver_info qmi_wwan_shared = { @@ -398,6 +440,7 @@ static const struct driver_info qmi_wwan_gobi = { .bind = qmi_wwan_bind_gobi, .unbind = qmi_wwan_unbind_shared, .manage_power = qmi_wwan_manage_power, + .rx_fixup = qmi_wwan_rx_fixup, }; /* ZTE suck at making USB descriptors */ @@ -407,6 +450,7 @@ static const struct driver_info qmi_wwan_force_int4 = { .bind = qmi_wwan_bind_gobi, .unbind = qmi_wwan_unbind_shared, .manage_power = qmi_wwan_manage_power, + .rx_fixup = qmi_wwan_rx_fixup, .data = BIT(4), /* interface whitelist bitmap */ }; @@ -491,7 +535,7 @@ static const struct usb_device_id products[] = { {QMI_GOBI_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ {QMI_GOBI_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ {QMI_GOBI_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ - {QMI_GOBI_DEVICE(0x05c6, 0x904c)}, /* MDM9x15 */ + {QMI_GOBI_DEVICE(0x05c6, 0x904c)}, /* MDM9x15 */ { } /* END */ }; MODULE_DEVICE_TABLE(usb, products); |