aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb/qmi_wwan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/usb/qmi_wwan.c')
-rw-r--r--drivers/net/usb/qmi_wwan.c46
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);