Commit f3701546 authored by Martin Tříska's avatar Martin Tříska

Added Quectel-specific patches

parent c42c872e
......@@ -448,6 +448,89 @@ static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3};
static const u8 buggy_fw_addr[ETH_ALEN] = {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00};
#if 1 //add by Quectel
#include <linux/etherdevice.h>
#include <net/ip.h>
#include <net/ipv6.h>
struct sk_buff *qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
const struct ethhdr *ehdr;
skb_reset_mac_header(skb);
ehdr = eth_hdr(skb);
if (ehdr->h_proto == htons(ETH_P_IP)) {
if (unlikely(skb->len <= (sizeof(struct ethhdr) + sizeof(struct iphdr)))) {
goto drop_skb;
}
}
else if (ehdr->h_proto == htons(ETH_P_IPV6)) {
if (unlikely(skb->len <= (sizeof(struct ethhdr) + sizeof(struct ipv6hdr)))) {
goto drop_skb;
}
}
else {
dev_err(&dev->intf->dev, "skb h_proto is %04x\n", ntohs(ehdr->h_proto));
goto drop_skb;
}
if (unlikely(dev->udev->descriptor.idVendor != cpu_to_le16(0x2C7C)))
return skb;
// Skip Ethernet header from message
if (likely((skb_pull(skb, ETH_HLEN))))
return skb;
drop_skb:
dev_err(&dev->intf->dev, "Packet Dropped\n");
// Filter the packet out, release it
dev_kfree_skb_any(skb);
return NULL;
}
#include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
__be16 proto;
if (dev->udev->descriptor.idVendor != cpu_to_le16(0x2C7C))
return 1;
/* This check is no longer done by usbnet */
if (skb->len < dev->net->hard_header_len)
return 0;
switch (skb->data[0] & 0xf0) {
case 0x40:
proto = htons(ETH_P_IP);
break;
case 0x60:
proto = htons(ETH_P_IPV6);
break;
case 0x00:
if (is_multicast_ether_addr(skb->data))
return 1;
/* possibly bogus destination - rewrite just in case */
skb_reset_mac_header(skb);
goto fix_dest;
default:
/* pass along other packets without modifications */
return 1;
}
if (skb_headroom(skb) < ETH_HLEN)
return 0;
skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb);
eth_hdr(skb)->h_proto = proto;
memset(eth_hdr(skb)->h_source, 0, ETH_ALEN);
fix_dest:
memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
return 1;
}
#endif
#endif
/* Make up an ethernet header if the packet doesn't have one.
*
* A firmware bug common among several devices cause them to send raw
......@@ -742,6 +825,21 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
}
dev->net->netdev_ops = &qmi_wwan_netdev_ops;
dev->net->sysfs_groups[0] = &qmi_wwan_sysfs_attr_group;
#if 1 //add by Quectel
if (dev->udev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
dev_info(&intf->dev, "Quectel EC21&EC25 work on RawIP mode\n");
dev->net->flags |= IFF_NOARP;
usb_control_msg(
interface_to_usbdev(intf),
usb_sndctrlpipe(interface_to_usbdev(intf), 0),
0x22,
0x21,
1, //active CDC DTR
intf->cur_altsetting->desc.bInterfaceNumber,
NULL, 0, 100);
}
#endif
err:
return status;
}
......@@ -832,6 +930,12 @@ static const struct driver_info qmi_wwan_info = {
.bind = qmi_wwan_bind,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
#if 1 //add by Quectel
.tx_fixup = qmi_wwan_tx_fixup,
#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
.rx_fixup = qmi_wwan_rx_fixup,
#endif
#endif
.rx_fixup = qmi_wwan_rx_fixup,
};
......@@ -866,6 +970,18 @@ static const struct driver_info qmi_wwan_info_quirk_dtr = {
QMI_FIXED_INTF(vend, prod, 0)
static const struct usb_device_id products[] = {
#if 1 //add by Quectel
{ QMI_FIXED_INTF(0x05C6, 0x9003, 4) }, /* Quectel UC20 */
{ QMI_FIXED_INTF(0x05C6, 0x9215, 4) }, /* Quectel EC20 */
{ QMI_FIXED_INTF(0x2C7C, 0x0125, 4) }, /* Quectel EC25/EC20 R2.0 */
{ QMI_FIXED_INTF(0x2C7C, 0x0121, 4) }, /* Quectel EC21 */
{ QMI_FIXED_INTF(0x2C7C, 0x0191, 4) }, /* Quectel EG91 */
{ QMI_FIXED_INTF(0x2C7C, 0x0195, 4) }, /* Quectel EG95 */
{ QMI_FIXED_INTF(0x2C7C, 0x0306, 4) }, /* Quectel EG06/EP06/EM06 */
{ QMI_FIXED_INTF(0x2C7C, 0x0296, 4) }, /* Quectel BG96 */
{ QMI_FIXED_INTF(0x2C7C, 0x0435, 4) }, /* Quectel AG35 */
#endif
/* 1. CDC ECM like devices match on the control interface */
{ /* Huawei E392, E398 and possibly others sharing both device id and more... */
USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 9),
......@@ -1290,7 +1406,6 @@ static const struct usb_device_id products[] = {
{QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */
{QMI_GOBI_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */
{QMI_GOBI_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */
{QMI_GOBI_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */
{QMI_FIXED_INTF(0x05c6, 0x9215, 4)}, /* Quectel EC20 Mini PCIe */
{QMI_GOBI_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */
{QMI_GOBI_DEVICE(0x05c6, 0x9235)}, /* Top Global Gobi 2000 Modem device (VR306) */
......
......@@ -570,6 +570,18 @@ static void option_instat_callback(struct urb *urb);
static const struct usb_device_id option_ids[] = {
#if 1 //Added by Quectel
{ USB_DEVICE(0x05C6, 0x9090) }, /* Quectel UC15 */
{ USB_DEVICE(0x05C6, 0x9003) }, /* Quectel UC20 */
{ USB_DEVICE(0x05C6, 0x9215) }, /* Quectel EC20 */
{ USB_DEVICE(0x2C7C, 0x0125) }, /* Quectel EC25/EC20 R2.0 */
{ USB_DEVICE(0x2C7C, 0x0121) }, /* Quectel EC21 */
{ USB_DEVICE(0x2C7C, 0x0191) }, /* Quectel EG91 */
{ USB_DEVICE(0x2C7C, 0x0195) }, /* Quectel EG95 */
{ USB_DEVICE(0x2C7C, 0x0306) }, /* Quectel EG06/EP06/EM06 */
{ USB_DEVICE(0x2C7C, 0x0296) }, /* Quectel BG96 */
{ USB_DEVICE(0x2C7C, 0x0435) }, /* Quectel AG35 */
#endif
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
......@@ -2004,6 +2016,9 @@ static struct usb_serial_driver option_1port_device = {
#ifdef CONFIG_PM
.suspend = usb_wwan_suspend,
.resume = usb_wwan_resume,
#if 1 //add by Quectel
.reset_resume = usb_wwan_resume,
#endif
#endif
};
......@@ -2021,6 +2036,21 @@ static int option_probe(struct usb_serial *serial,
struct usb_device_descriptor *dev_desc = &serial->dev->descriptor;
unsigned long device_flags = id->driver_info;
#if 1 //Added by Quectel
//Quectel UC20's interface 4 can be used as USB Network device
if (dev_desc->idVendor == cpu_to_le16(0x05C6) && dev_desc->idProduct == cpu_to_le16(0x9003)
&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
return -ENODEV;
//Quectel EC20's interface 4 can be used as USB Network device
if (dev_desc->idVendor == cpu_to_le16(0x05C6) && dev_desc->idProduct == cpu_to_le16(0x9215)
&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
return -ENODEV;
//Quectel EC25&EC21 's interface 4 can be used as USB Network device
if (dev_desc->idVendor == cpu_to_le16(0x2C7C)
&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
return -ENODEV;
#endif
/* Never bind to the CD-Rom emulation interface */
if (iface_desc->bInterfaceClass == 0x08)
return -ENODEV;
......
......@@ -92,7 +92,6 @@ static const struct usb_device_id id_table[] = {
{USB_DEVICE(0x03f0, 0x241d)}, /* HP Gobi 2000 QDL device (VP412) */
{USB_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */
{USB_DEVICE(0x05c6, 0x9214)}, /* Acer Gobi 2000 QDL device (VP413) */
{USB_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */
{USB_DEVICE(0x05c6, 0x9264)}, /* Asus Gobi 2000 QDL device (VR305) */
{USB_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */
{USB_DEVICE(0x05c6, 0x9234)}, /* Top Global Gobi 2000 QDL device (VR306) */
......
......@@ -502,6 +502,20 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
usb_sndbulkpipe(serial->dev, endpoint) | dir,
buf, len, callback, ctx);
#if 1 //Added by Quectel for Zero Packet
if (dir == USB_DIR_OUT) {
struct usb_device_descriptor *desc = &serial->dev->descriptor;
if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9090))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9003))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9215))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x2C7C))
urb->transfer_flags |= URB_ZERO_PACKET;
}
#endif
return urb;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment