From c27a77a194aff24c5f42c145f46789e05cb99870 Mon Sep 17 00:00:00 2001 From: Jianhui Zhao Date: Thu, 18 May 2023 11:07:18 +0800 Subject: [PATCH] kernel: Add some modems support Signed-off-by: Jianhui Zhao --- .../hack-5.4/960-support-some-modems.patch | 256 ++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 target/linux/generic/hack-5.4/960-support-some-modems.patch diff --git a/target/linux/generic/hack-5.4/960-support-some-modems.patch b/target/linux/generic/hack-5.4/960-support-some-modems.patch new file mode 100644 index 0000000000..93ae6a2a1a --- /dev/null +++ b/target/linux/generic/hack-5.4/960-support-some-modems.patch @@ -0,0 +1,256 @@ +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -507,6 +507,24 @@ static const u8 default_modem_addr[ETH_A + + static const u8 buggy_fw_addr[ETH_ALEN] = {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}; + ++#if 1 //Added by Quectel ++#include ++struct sk_buff *qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) ++{ ++ if (dev->udev->descriptor.idVendor != cpu_to_le16(0x2C7C)) ++ return skb; ++ // Skip Ethernet header from message ++ if (skb_pull(skb, ETH_HLEN)) { ++ return skb; ++ } else { ++ dev_err(&dev->intf->dev, "Packet Dropped "); ++ } ++ // Filter the packet out, release it ++ dev_kfree_skb_any(skb); ++ return NULL; ++} ++#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 +@@ -801,6 +819,22 @@ static int qmi_wwan_bind(struct usbnet * + } + dev->net->netdev_ops = &qmi_wwan_netdev_ops; + dev->net->sysfs_groups[0] = &qmi_wwan_sysfs_attr_group; ++ ++#if 1 //Added by Quectel ++ if (dev->udev->descriptor.idVendor == cpu_to_le16(0x2C7C)) { ++ dev_info(&intf->dev, "QuectelEC25&EC21&EG91&EG95&EG06&EP06&EM06&BG96&AG35 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, //USB_CDC_REQ_SET_CONTROL_LINE_STATE ++ 0x21, //USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE ++ 1, //active CDC DTR ++ intf->cur_altsetting->desc.bInterfaceNumber, ++ NULL, 0, 100); ++ } ++#endif ++ + err: + return status; + } +@@ -892,6 +926,9 @@ static const struct driver_info qmi_wwan + .unbind = qmi_wwan_unbind, + .manage_power = qmi_wwan_manage_power, + .rx_fixup = qmi_wwan_rx_fixup, ++#if 1 //Added by Quectel ++ .tx_fixup = qmi_wwan_tx_fixup, ++#endif + }; + + static const struct driver_info qmi_wwan_info_quirk_dtr = { +@@ -938,6 +975,14 @@ static const struct driver_info qmi_wwan + .driver_info = (unsigned long)&qmi_wwan_info_quirk_dtr + + static const struct usb_device_id products[] = { ++#if 1 //Added by Quectel ++ { QMI_FIXED_INTF(0x2C7C, 0x0125, 4) }, /* Quectel EC25 */ ++ { 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, 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), +@@ -1047,6 +1092,7 @@ static const struct usb_device_id produc + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0801)}, /* Quectel RM520N */ ++ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x030b)}, /* Quectel Quectel EM060K-GL EM120K-GL */ + + /* 3. Combined interface devices matching on interface number */ + {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -595,6 +595,25 @@ static void option_instat_callback(struc + #define SIERRA_VENDOR_ID 0x1199 + #define SIERRA_PRODUCT_EM9191 0x90d3 + ++#if 1 // Added by gl ++#define LONGSUNG_PRODUCT_U9300C 0x9b3c ++ ++/* FORGE PRODUCT */ ++#define FORGE_VENDOR_ID 0x05c6 ++ ++#define FORGE_PRODUCT_SLM750 0xf601 ++ ++/* NODECOM PRODUCT */ ++#define NODECOM_VENDOR_ID 0x1508 ++ ++#define NODECOM_PRODUCT_NL660 0x1001 ++ ++/* NEOWAY PRODUCT */ ++#define NEOWAY_VENDOR_ID 0x2949 ++ ++#define NEOWAY_PRODUCT_N720 0x8243 ++#endif ++ + /* Device flags */ + + /* Highest interface number which can be used with NCTRL() and RSVD() */ +@@ -614,6 +633,15 @@ static void option_instat_callback(struc + + + static const struct usb_device_id option_ids[] = { ++#if 1 // Added by gl ++ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9215) }, /* Quectel EC20 */ ++ { USB_DEVICE(QUECTEL_VENDOR_ID, 0x0435) }, /* Quectel AG35 */ ++ { USB_DEVICE(ZTE_VENDOR_ID, 0x0536) },/* MZ386 */ ++ { USB_DEVICE(LONGCHEER_VENDOR_ID, LONGSUNG_PRODUCT_U9300C) }, ++ { USB_DEVICE(FORGE_VENDOR_ID, FORGE_PRODUCT_SLM750) }, ++ { USB_DEVICE(NODECOM_VENDOR_ID, NODECOM_PRODUCT_NL660) }, ++ { USB_DEVICE(NEOWAY_VENDOR_ID, NEOWAY_PRODUCT_N720) }, ++#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) }, +@@ -2294,7 +2322,104 @@ static int option_probe(struct usb_seria + return -ENODEV; + + /* Store the device flags so we can use them during attach. */ +- usb_set_serial_data(serial, (void *)device_flags); ++#if 1 //Added by Quectel ++ //Quectel UC20's interface 4 can be used as USB network device ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && \ ++ serial->dev->descriptor.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 (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && \ ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x9215) \ ++ && serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4) ++ return -ENODEV; ++ //Quectel EC25&EC21&EG91&EG95&EG06&EP06&EM06&BG96/AG35's interface 4 can be used as USB network device ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C) && \ ++ serial->dev->descriptor.idProduct != cpu_to_le16(0x6026) \ ++ && serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4) ++ return -ENODEV; ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C) && \ ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x6026) \ ++ && serial->interface->cur_altsetting->desc.bInterfaceNumber<= 1) ++ return -ENODEV; ++ ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) { ++ __u16 idProduct = le16_to_cpu(serial->dev->descriptor.idProduct); ++ struct usb_interface_descriptor *intf = &serial->interface->cur_altsetting->desc; ++ ++ if (intf->bInterfaceClass != 0xFF || intf->bInterfaceSubClass == 0x42) { ++ //ECM, RNDIS, NCM, MBIM, ACM, UAC, ADB ++ return -ENODEV; ++ } ++ ++ if ((idProduct&0xF000) == 0x0000) { ++ //MDM interface 4 is QMI ++ if (intf->bInterfaceNumber == 4 && intf->bNumEndpoints == 3 ++ && intf->bInterfaceSubClass == 0xFF && intf->bInterfaceProtocol == 0xFF) ++ return -ENODEV; ++ } ++ } ++#endif ++ ++ #if 1 //Added by Quectel ++ //For USB Auto Suspend ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x9090)) { ++ pm_runtime_set_autosuspend_delay(&serial->dev->dev, 3000); ++ usb_enable_autosuspend(serial->dev); ++ } ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x9003)) { ++ pm_runtime_set_autosuspend_delay(&serial->dev->dev, 3000); ++ usb_enable_autosuspend(serial->dev); ++ } ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x9215)) { ++ pm_runtime_set_autosuspend_delay(&serial->dev->dev, 3000); ++ usb_set_serial_data(serial, (void *)device_flags); ++ usb_enable_autosuspend(serial->dev); ++ } ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) { ++ pm_runtime_set_autosuspend_delay(&serial->dev->dev, 3000); ++ usb_enable_autosuspend(serial->dev); ++ } ++#endif ++ ++ #if 1 //Added by Quectel ++ //For USB Remote Wakeup ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x9090)) { ++ device_init_wakeup(&serial->dev->dev, 1); //usb remote wakeup ++ } ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x9003)) { ++ device_init_wakeup(&serial->dev->dev, 1); //usb remote wakeup ++ } ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x9215)) { ++ device_init_wakeup(&serial->dev->dev, 1); //usb remote wakeup ++ } ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) { ++ device_init_wakeup(&serial->dev->dev, 1); //usb remote wakeup ++ } ++#endif ++ ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x19d2) && ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x1476) && ++ serial->interface->cur_altsetting->desc. bInterfaceNumber == 3) ++ return -ENODEV; ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x19d2) && ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x1476) && ++ serial->interface->cur_altsetting->desc. bInterfaceNumber == 4) ++ return -ENODEV; ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x19d2) && ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x1509) && ++ serial->interface->cur_altsetting->desc. bInterfaceNumber == 4) ++ return -ENODEV; ++ if (serial->dev->descriptor.idVendor == cpu_to_le16(0x19d2) && ++ serial->dev->descriptor.idProduct == cpu_to_le16(0x1509) && ++ serial->interface->cur_altsetting->desc. bInterfaceNumber == 5) ++ return -ENODEV; + + return 0; + } +--- a/drivers/usb/serial/usb_wwan.c ++++ b/drivers/usb/serial/usb_wwan.c +@@ -478,6 +478,20 @@ static struct urb *usb_wwan_setup_urb(st + 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 ++ + if (intfdata->use_zlp && dir == USB_DIR_OUT) + urb->transfer_flags |= URB_ZERO_PACKET; + -- 2.34.1