Skip to content

Commit f59b204

Browse files
YiowHurNg-ASUSasus-leslieyu
authored andcommitted
[TinkerS] Enable LTE module qmi driver
Change-Id: Ib63f8948cbd199fdc5bf6545ec400fc862988720
1 parent 8c17aed commit f59b204

File tree

5 files changed

+159
-4
lines changed

5 files changed

+159
-4
lines changed

arch/arm/configs/miniarm-rk3288_defconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ CONFIG_USB_NET_DM9601=y
436436
CONFIG_USB_NET_SMSC75XX=y
437437
CONFIG_USB_NET_SMSC95XX=y
438438
CONFIG_USB_NET_MCS7830=y
439+
CONFIG_USB_NET_QMI_WWAN=y
439440
CONFIG_USB_IPHETH=y
440441
# CONFIG_USB_NET_CDC_SUBSET is not set
441442
# CONFIG_USB_NET_ZAURUS is not set

drivers/net/usb/qmi_wwan.c

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,71 @@
2020
#include <linux/usb/usbnet.h>
2121
#include <linux/usb/cdc-wdm.h>
2222

23+
#if 1 //Added by Quectel
24+
#include <linux/etherdevice.h>
25+
struct sk_buff *qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
26+
{
27+
if (dev->udev->descriptor.idVendor != cpu_to_le16(0x2C7C))
28+
return skb;
29+
// Skip Ethernet header from message
30+
if (dev->net->hard_header_len == 0)
31+
return skb;
32+
else
33+
skb_reset_mac_header(skb); if (skb_pull(skb, ETH_HLEN)) {
34+
return skb;
35+
} else {
36+
dev_err(&dev->intf->dev, "Packet Dropped ");
37+
}
38+
// Filter the packet out, release it
39+
dev_kfree_skb_any(skb);
40+
return NULL;
41+
}
42+
#include <linux/version.h>
43+
#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
44+
static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
45+
{
46+
__be16 proto;
47+
if (dev->udev->descriptor.idVendor != cpu_to_le16(0x2C7C))
48+
return 1;
49+
/* This check is no longer done by usbnet */
50+
if (skb->len < dev->net->hard_header_len)
51+
return 0;
52+
switch (skb->data[0] & 0xf0) {
53+
case 0x40:
54+
proto = htons(ETH_P_IP);
55+
break;
56+
case 0x60:
57+
proto = htons(ETH_P_IPV6);
58+
break;
59+
case 0x00:
60+
if (is_multicast_ether_addr(skb->data))
61+
return 1;
62+
/* possibly bogus destination - rewrite just in case */
63+
skb_reset_mac_header(skb);
64+
goto fix_dest;
65+
default:
66+
/* pass along other packets without modifications */
67+
return 1;
68+
}
69+
if (skb_headroom(skb) < ETH_HLEN)
70+
return 0;
71+
skb_push(skb, ETH_HLEN);
72+
skb_reset_mac_header(skb);
73+
eth_hdr(skb)->h_proto = proto;
74+
memset(eth_hdr(skb)->h_source, 0, ETH_ALEN);
75+
fix_dest:
76+
memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
77+
return 1;
78+
}
79+
80+
/* very simplistic detection of IPv4 or IPv6 headers */
81+
static bool possibly_iphdr(const char *data)
82+
{
83+
return (data[0] & 0xd0) == 0x40;
84+
}
85+
#endif
86+
#endif
87+
2388
/* This driver supports wwan (3G/LTE/?) devices using a vendor
2489
* specific management protocol called Qualcomm MSM Interface (QMI) -
2590
* in addition to the more common AT commands over serial interface
@@ -294,6 +359,31 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
294359
dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */
295360
}
296361
dev->net->netdev_ops = &qmi_wwan_netdev_ops;
362+
#if 1 //Added by Quectel
363+
if (dev->udev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
364+
if (intf->cur_altsetting->desc.bInterfaceClass != 0xff) {
365+
dev_info(&intf->dev, "Quectel module not qmi_wwan mode! please check 'at+qcfg=\"usbnet\"'\n");
366+
return -ENODEV;
367+
}
368+
dev_info(&intf->dev, "Quectel EC25&EC21&EG91&EG95&EG06&EP06&EM06&EG12&EP12&EM12&EG16&EG18&BG96&AG35 work on RawIP mode\n");
369+
dev->net->flags |= IFF_NOARP;
370+
#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
371+
/* make MAC addr easily distinguishable from an IP header */
372+
if (possibly_iphdr(dev->net->dev_addr)) {
373+
dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */
374+
dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */
375+
}
376+
#endif
377+
usb_control_msg(
378+
interface_to_usbdev(intf),
379+
usb_sndctrlpipe(interface_to_usbdev(intf), 0),
380+
0x22, //USB_CDC_REQ_SET_CONTROL_LINE_STATE
381+
0x21, //USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
382+
1, //active CDC DTR
383+
intf->cur_altsetting->desc.bInterfaceNumber,
384+
NULL, 0, 100);
385+
}
386+
#endif
297387
err:
298388
return status;
299389
}
@@ -379,6 +469,10 @@ static const struct driver_info qmi_wwan_info = {
379469
.unbind = qmi_wwan_unbind,
380470
.manage_power = qmi_wwan_manage_power,
381471
.rx_fixup = qmi_wwan_rx_fixup,
472+
#if 1 //Added by Quectel
473+
.tx_fixup = qmi_wwan_tx_fixup,
474+
.rx_fixup = qmi_wwan_rx_fixup,
475+
#endif
382476
};
383477

384478
#define HUAWEI_VENDOR_ID 0x12D1
@@ -397,6 +491,30 @@ static const struct driver_info qmi_wwan_info = {
397491
QMI_FIXED_INTF(vend, prod, 0)
398492

399493
static const struct usb_device_id products[] = {
494+
#if 1 //Added by Quectel
495+
#ifndef QMI_FIXED_INTF
496+
/* map QMI/wwan function by a fixed interface number */
497+
#define QMI_FIXED_INTF(vend, prod, num) \
498+
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
499+
USB_DEVICE_ID_MATCH_INT_INFO, \
500+
.idVendor = vend, \
501+
.idProduct = prod, \
502+
.bInterfaceClass = 0xff, \
503+
.bInterfaceSubClass = 0xff, \
504+
.bInterfaceProtocol = 0xff, \
505+
.driver_info = (unsigned long)&qmi_wwan_force_int##num,
506+
#endif
507+
{ QMI_FIXED_INTF(0x05C6, 0x9003, 4) }, /* Quectel UC20 */
508+
{ QMI_FIXED_INTF(0x2C7C, 0x0125, 4) }, /* Quectel EC25 */
509+
{ QMI_FIXED_INTF(0x2C7C, 0x0121, 4) }, /* Quectel EC21 */
510+
{ QMI_FIXED_INTF(0x05C6, 0x9215, 4) }, /* Quectel EC20 */
511+
{ QMI_FIXED_INTF(0x2C7C, 0x0191, 4) }, /* Quectel EG91 */
512+
{ QMI_FIXED_INTF(0x2C7C, 0x0195, 4) }, /* Quectel EG95 */
513+
{ QMI_FIXED_INTF(0x2C7C, 0x0306, 4) }, /* Quectel EG06/EP06/EM06 */
514+
{ QMI_FIXED_INTF(0x2C7C, 0x0512, 4) }, /* Quectel EG12/EP12/EM12/EG16/EG18 */
515+
{ QMI_FIXED_INTF(0x2C7C, 0x0296, 4) }, /* Quectel BG96 */
516+
{ QMI_FIXED_INTF(0x2C7C, 0x0435, 4) }, /* Quectel AG35 */
517+
#endif
400518
/* 1. CDC ECM like devices match on the control interface */
401519
{ /* Huawei E392, E398 and possibly others sharing both device id and more... */
402520
USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 9),
@@ -793,7 +911,6 @@ static const struct usb_device_id products[] = {
793911
{QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */
794912
{QMI_GOBI_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */
795913
{QMI_GOBI_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */
796-
{QMI_GOBI_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */
797914
{QMI_FIXED_INTF(0x05c6, 0x9215, 4)}, /* Quectel EC20 Mini PCIe */
798915
{QMI_GOBI_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */
799916
{QMI_GOBI_DEVICE(0x05c6, 0x9235)}, /* Top Global Gobi 2000 Modem device (VR306) */

drivers/usb/serial/option.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,11 @@ static const struct usb_device_id option_ids[] = {
10871087
/* Quectel products using Quectel vendor ID */
10881088
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21),
10891089
.driver_info = RSVD(4) },
1090+
{ USB_DEVICE(0x05C6, 0x9215) }, /* Quectel EC20 */
1091+
{ USB_DEVICE(0x2C7C, 0x0191) }, /* Quectel EG91 */
1092+
{ USB_DEVICE(0x2C7C, 0x0195) }, /* Quectel EG95 */
1093+
{ USB_DEVICE(0x2C7C, 0x0512) }, /* Quectel EG12/EP12/EM12/EG16/EG18 */
1094+
{ USB_DEVICE(0x2C7C, 0x0435) }, /* Quectel AG35 */
10901095
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC25),
10911096
.driver_info = RSVD(4) },
10921097
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
@@ -1983,6 +1988,9 @@ static struct usb_serial_driver option_1port_device = {
19831988
#ifdef CONFIG_PM
19841989
.suspend = usb_wwan_suspend,
19851990
.resume = usb_wwan_resume,
1991+
#if 1 //Added by Quectel
1992+
.reset_resume = usb_wwan_resume,
1993+
#endif
19861994
#endif
19871995
};
19881996

@@ -2019,7 +2027,25 @@ static int option_probe(struct usb_serial *serial,
20192027
dev_desc->idProduct == cpu_to_le16(SAMSUNG_PRODUCT_GT_B3730) &&
20202028
iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA)
20212029
return -ENODEV;
2022-
2030+
2031+
#if 1 //Added by Quectel
2032+
//Quectel UC20's interface 4 can be used as USB network device
2033+
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) &&
2034+
serial->dev->descriptor.idProduct == cpu_to_le16(0x9003)
2035+
&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
2036+
return -ENODEV;
2037+
2038+
//Quectel EC20's interface 4 can be used as USB network device
2039+
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) &&
2040+
serial->dev->descriptor.idProduct == cpu_to_le16(0x9215)
2041+
&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
2042+
return -ENODEV;
2043+
2044+
//Quectel EC25&EC21&EG91&EG95&EG06&EP06&EM06&BG96/AG35's interface 4 can be used as USB network device
2045+
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C) &&
2046+
serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
2047+
return -ENODEV;
2048+
#endif
20232049
/* Store the device flags so we can use them during attach. */
20242050
usb_set_serial_data(serial, (void *)device_flags);
20252051

drivers/usb/serial/qcserial.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ static const struct usb_device_id id_table[] = {
9292
{USB_DEVICE(0x03f0, 0x241d)}, /* HP Gobi 2000 QDL device (VP412) */
9393
{USB_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */
9494
{USB_DEVICE(0x05c6, 0x9214)}, /* Acer Gobi 2000 QDL device (VP413) */
95-
{USB_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */
9695
{USB_DEVICE(0x05c6, 0x9264)}, /* Asus Gobi 2000 QDL device (VR305) */
9796
{USB_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */
9897
{USB_DEVICE(0x05c6, 0x9234)}, /* Top Global Gobi 2000 QDL device (VR306) */

drivers/usb/serial/usb_wwan.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,19 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
504504
usb_fill_bulk_urb(urb, serial->dev,
505505
usb_sndbulkpipe(serial->dev, endpoint) | dir,
506506
buf, len, callback, ctx);
507-
507+
#if 1 //Added by Quectel for zero packet
508+
if (dir == USB_DIR_OUT) {
509+
struct usb_device_descriptor *desc = &serial->dev->descriptor;
510+
if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9090))
511+
urb->transfer_flags |= URB_ZERO_PACKET;
512+
if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9003))
513+
urb->transfer_flags |= URB_ZERO_PACKET;
514+
if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9215))
515+
urb->transfer_flags |= URB_ZERO_PACKET;
516+
if (desc->idVendor == cpu_to_le16(0x2C7C))
517+
urb->transfer_flags |= URB_ZERO_PACKET;
518+
}
519+
#endif
508520
return urb;
509521
}
510522

0 commit comments

Comments
 (0)