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
297387err :
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
399493static 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) */
0 commit comments