.._rk3568 ec20">
当前位置:   article > 正文

RK3568-ANDROID11-4G-EC20-(详细步骤)_rk3568 ec20

rk3568 ec20

注意:硬件可以先使用USB转接板把模块接到电脑上,使用AT指令把模块调好。

原理图

 

  1. //DTS配置
  2. kernel\arch\arm64\boot\dts\rockchip\rk3568-evb1-ddr4-v10.dtsi
  3. + rk_modem: rk-modem {
  4. + compatible="4g-modem-platdata";
  5. + 4G,power-gpio = <&gpio4 RK_PD2 GPIO_ACTIVE_LOW>; //4G/5G_EN-MODEM_ON-GPIO4_D2
  6. + 4G,reset-gpio = <&gpio0 RK_PD5 GPIO_ACTIVE_HIGH>;//4G/5G_RST-MODEM_RST-GPIO0_D5
  7. + status = "okay";
  8. + };

 驱动

  1. RK3568\kernel\drivers\usb\serial\option.c
  2. +static const struct usb_device_id option_ids[] = {
  3. + #if 1 //Added by Quectel
  4. + { USB_DEVICE(0x2C7C, 0x0125) }, /* Quectel EC20 R2.0/EC20 R2.1/EC25/EG25-G/EM05 */
  5. + { USB_DEVICE(0x2C7C, 0x0121) }, /* Quectel EC21/EG21-G */
  6. + { USB_DEVICE(0x2C7C, 0x0191) }, /* Quectel EG91 */
  7. + { USB_DEVICE(0x2C7C, 0x0195) }, /* Quectel EG95 */
  8. + { USB_DEVICE(0x2C7C, 0x0306) }, /* Quectel EG06/EP06/EM06 */
  9. + { USB_DEVICE(0x2C7C, 0x0512) }, /* Quectel EG12/EM12/EG18 */
  10. + { USB_DEVICE(0x2C7C, 0x0296) }, /* Quectel BG96 */
  11. + { USB_DEVICE(0x2C7C, 0x0700) }, /* Quectel BG95/BG77/BG600L-M3/BC69 */
  12. + { USB_DEVICE(0x2C7C, 0x0435) }, /* Quectel AG35 */
  13. + { USB_DEVICE(0x2C7C, 0x0415) }, /* Quectel AG15 */
  14. + { USB_DEVICE(0x2C7C, 0x0452) }, /* Quectel AG520R */
  15. + { USB_DEVICE(0x2C7C, 0x0455) }, /* Quectel AG550R */
  16. + { USB_DEVICE(0x2C7C, 0x0620) }, /* Quectel EG20 */
  17. + { USB_DEVICE(0x2C7C, 0x0800) }, /* Quectel RG500Q/RM500Q/RG510Q/RM510Q */
  18. + { USB_DEVICE(0x1E0E,0x9001),//SIM8200EAM2
  19. + .driver_info = RSVD(4) | RSVD(5) | RSVD(6) | RSVD(6)},
  20. + #endif
  21. +}
  22. static struct usb_serial_driver option_1port_device = {
  23. .driver = {
  24. .owner = THIS_MODULE,
  25. .name = "option1",
  26. },
  27. .description = "GSM modem (1-port)",
  28. .id_table = option_ids,
  29. .num_ports = 1,
  30. .probe = option_probe,
  31. .open = usb_wwan_open,
  32. .close = usb_wwan_close,
  33. .dtr_rts = usb_wwan_dtr_rts,
  34. .write = usb_wwan_write,
  35. .write_room = usb_wwan_write_room,
  36. .chars_in_buffer = usb_wwan_chars_in_buffer,
  37. .tiocmget = usb_wwan_tiocmget,
  38. .tiocmset = usb_wwan_tiocmset,
  39. .ioctl = usb_wwan_ioctl,
  40. .attach = option_attach,
  41. .release = option_release,
  42. .port_probe = usb_wwan_port_probe,
  43. .port_remove = usb_wwan_port_remove,
  44. .read_int_callback = option_instat_callback,
  45. #ifdef CONFIG_PM
  46. .suspend = usb_wwan_suspend,
  47. .resume = usb_wwan_resume,
  48. + #if 1
  49. + .reset_resume = usb_wwan_resume,
  50. + #endif
  51. #endif
  52. };
  1. RK3568\kernel\drivers\usb\serial\usb_wwan.c
  2. static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
  3. int endpoint,
  4. int dir, void *ctx, char *buf, int len,
  5. void (*callback) (struct urb *))
  6. {
  7. struct usb_serial *serial = port->serial;
  8. struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
  9. struct urb *urb;
  10. struct usb_device_descriptor *desc = &serial->dev->descriptor;
  11. urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
  12. if (!urb)
  13. return NULL;
  14. usb_fill_bulk_urb(urb, serial->dev,
  15. usb_sndbulkpipe(serial->dev, endpoint) | dir,
  16. buf, len, callback, ctx);
  17. if (intfdata->use_zlp && dir == USB_DIR_OUT)
  18. urb->transfer_flags |= URB_ZERO_PACKET;
  19. if (dir == USB_DIR_OUT) {
  20. if ((desc->idVendor == cpu_to_le16(0x1286) &&
  21. desc->idProduct == cpu_to_le16(0x4e3c)))
  22. urb->transfer_flags |= URB_ZERO_PACKET;
  23. + if (desc->idVendor == cpu_to_le16(0x2c7c))
  24. + urb->transfer_flags |= URB_ZERO_PACKET;
  25. }
  26. return urb;
  27. }

添加qmi_wwan_q.c(放在最后)

修改Makefile(qmi_wwan_q.o的生成就是编译到了)

  1. RK3568\kernel\drivers\net\usb\Makefile
  2. obj-$(CONFIG_USB_NET_QMI_WWAN) += qmi_wwan.o
  3. +obj-$(CONFIG_USB_NET_QMI_WWAN) += qmi_wwan_q.o

然后就是添加cdc-wdmo节点

  1. RK3568\system\core\init\devices.cpp
  2. void DeviceHandler::HandleUevent(const Uevent& uevent) {
  3. if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
  4. FixupSysPermissions(uevent.path, uevent.subsystem);
  5. }
  6. // if it's not a /dev device, nothing to do
  7. if (uevent.major < 0 || uevent.minor < 0) return;
  8. std::string devpath;
  9. std::vector<std::string> links;
  10. bool block = false;
  11. if (uevent.subsystem == "block") {
  12. block = true;
  13. devpath = "/dev/block/" + Basename(uevent.path);
  14. if (StartsWith(uevent.path, "/devices")) {
  15. links = GetBlockDeviceSymlinks(uevent);
  16. }
  17. } else if (const auto subsystem =
  18. std::find(subsystems_.cbegin(), subsystems_.cend(), uevent.subsystem);
  19. subsystem != subsystems_.cend()) {
  20. devpath = subsystem->ParseDevPath(uevent);
  21. } else if (uevent.subsystem == "usb") {
  22. if (!uevent.device_name.empty()) {
  23. devpath = "/dev/" + uevent.device_name;
  24. } else {
  25. // This imitates the file system that would be created
  26. // if we were using devfs instead.
  27. // Minors are broken up into groups of 128, starting at "001"
  28. int bus_id = uevent.minor / 128 + 1;
  29. int device_id = uevent.minor % 128 + 1;
  30. devpath = StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
  31. }
  32. + #if 1 //add by quectel for mknod /dev/cdc-wdmo
  33. + } else if (uevent.subsystem == "usbmisc" && !uevent.device_name.empty()) {
  34. + devpath = "/dev/" + uevent.device_name;
  35. + #endif
  36. } else if (StartsWith(uevent.subsystem, "usb")) {
  37. // ignore other USB events
  38. return;
  39. } else {
  40. devpath = "/dev/" + Basename(uevent.path);
  41. }
  42. mkdir_recursive(Dirname(devpath), 0755);
  43. HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);
  44. // Duplicate /dev/ashmem device and name it /dev/ashmem<boot_id>.
  45. // TODO(b/111903542): remove once all users of /dev/ashmem are migrated to libcutils API.
  46. HandleAshmemUevent(uevent);
  47. }

然后编译可以看到出现以下节点就可以完成驱动方面的调试

  1. console:/ $ su
  2. console:/ #
  3. console:/ # ls -l dev/ttyUSB*
  4. crw-rw-rw- 1 radio radio 188, 0 2022-01-27 12:33 dev/ttyUSB0
  5. crw-rw-rw- 1 radio radio 188, 1 2022-01-27 12:33 dev/ttyUSB1
  6. crw-rw-rw- 1 radio radio 188, 2 2022-01-27 14:02 dev/ttyUSB2
  7. crw-rw-rw- 1 radio radio 188, 3 2022-01-27 12:33 dev/ttyUSB3
  8. console:/ #
  9. console:/ # ls -l dev/cdc-wdm0
  10. crw-rw---- 1 radio radio 180, 176 2022-01-27 12:33 dev/cdc-wdm0

//####################################################################//

 1.从资源包获取对于文件并且更新(一定要确认你的库是支持的,大部分的问题都是库不对

\Quectel_Android_RIL_Driver_V3.3.41_master_beta\libquectel-ril\arm64-v8a

使用了chat、ip-down、ip-up、ql-ril.conf

\Quectel_Android_RIL_Driver_V3.3.62_master_beta\libquectel-ril\arm64-v8a

使用了libreference-ril.so(改名为libreference-ril-ec20.so)

  1. \vendor\rockchip\common\phone\bin\chat
  2. \vendor\rockchip\common\phone\etc\ppp\ip-down
  3. \vendor\rockchip\common\phone\etc\ppp\ip-up
  4. \vendor\rockchip\common\phone\etc\ql-ril.conf
  5. \vendor\rockchip\common\phone\lib\libreference-ril-ec20.so

2.添加设置复制进代码后的路径

  1. rk3568\vendor\rockchip\common\phone\phone.mk
  2. #########################################################
  3. # 3G Dongle SUPPORT
  4. #########################################################
  5. -#PRODUCT_COPY_FILES += \
  6. -# $(CUR_PATH)/phone/etc/ppp/ip-down:system/etc/ppp/ip-down \
  7. -# $(CUR_PATH)/phone/etc/ppp/ip-up:system/etc/ppp/ip-up \
  8. -# $(CUR_PATH)/phone/etc/ppp/call-pppd:system/etc/ppp/call-pppd \
  9. -# $(CUR_PATH)/phone/etc/operator_table:system/etc/operator_table
  10. +PRODUCT_COPY_FILES += \
  11. + $(CUR_PATH)/phone/etc/ppp/ip-down:system/etc/ppp/ip-down \
  12. + $(CUR_PATH)/phone/etc/ppp/ip-up:system/etc/ppp/ip-up \
  13. + $(CUR_PATH)/phone/bin/chat:system/bin/chat \
  14. + $(CUR_PATH)/phone/lib/libreference-ril-ec20.so:vendor/lib64/libreference-ril-ec20.so \
  15. + $(CUR_PATH)/phone/etc/ppp/ql-ril.conf:system/etc/ql-ril.conf \
  16. + $(CUR_PATH)/etc/spn-conf.xml:system/etc/spn-conf.xml

RK3568\out\target\product\rk3568_r\vendor\lib64\libreference-ril-ec20.so

注意:检查libreference-ril-ec20.so是否更新到,可以使用对比文件看一下内容是否一样,我有遇到编译完,库没有更新的现象,要清理代码才能编进去,前期可以使用adb push进行验证。

3.关闭SELINUX

  1. RK3568\device\rockchip\common\BoardConfig.mk
  2. -BOARD_SELINUX_ENFORCING ?= true
  3. +BOARD_SELINUX_ENFORCING ?= false

 遇到一修改就卡死在android动画,最后把DDR降频就可以进入系统了。

4.打开BOARD_HAVE_DONGLE 和BOARD_HAS_RK_4G_MODEM 

建议分开打开,编译会有错误。

  1. RK3568\device\rockchip\common\BoardConfig.mk
  2. #enable 3g dongle
  3. - BOARD_HAVE_DONGLE ?= false
  4. + BOARD_HAVE_DONGLE ?= true
  5. ifeq ($(BOARD_HAVE_DONGLE),true)
  6. PRODUCT_PACKAGES += \
  7. android.hardware.radio@1.2-radio-service \
  8. android.hardware.radio.config@1.0-service
  9. PRODUCT_PACKAGES += \
  10. rild \
  11. com.android.phone.common
  12. endif
  13. #for rk 4g modem
  14. -BOARD_HAS_RK_4G_MODEM ?= false
  15. +BOARD_HAS_RK_4G_MODEM ?= true
  16. ifeq ($(strip $(BOARD_HAS_RK_4G_MODEM)),true)
  17. DEVICE_MANIFEST_FILE += device/rockchip/common/4g_modem/manifest.xml
  18. endif

BOARD_HAVE_DONGLE报错

  1. [ 30% 283/935] target C++: usb_dongle <= external/usb_modeswitch/usb_dongle/Misc.cpp
  2. FAILED: out/target/product/rk3568_r/obj/EXECUTABLES/usb_dongle_intermediates/Misc.o
  3. 解决方法:
  4. \external\usb_modeswitch\usb_dongle\Android.mk
  5. - common_local_tidy_flags := -warnings-as-errors=clang-analyzer-security*,cert-*
  6. + #common_local_tidy_flags := -warnings-as-errors=clang-analyzer-security*,cert-*

BOARD_HAS_RK_4G_MODEM 报错(manifest.xml文件)

//报错android.hardware.radio.deprecated

  1. 解决方法:
  2. RK3568\device\rockchip\common\manifest.xml
  3. <hal format="hidl">
  4. <name>android.hardware.radio</name>
  5. <transport>hwbinder</transport>
  6. <fqname>@1.1::IRadio/slot1</fqname>
  7. <fqname>@1.1::IRadio/slot2</fqname>
  8. <fqname>@1.2::ISap/slot1</fqname>
  9. </hal>
  10. - <hal format="hidl">
  11. - <name>android.hardware.radio.deprecated</name>
  12. - <transport>hwbinder</transport>
  13. - <version>1.0</version>
  14. - <interface>
  15. - <name>IOemHook</name>
  16. - <instance>slot1</instance>
  17. - </interface>
  18. - </hal>
  19. - <kernel target-level="5"/>
  20. - </manifest>
  21. RK3568\device\rockchip\common\4g_modem\manifest.xml
  22. <manifest version="1.0" type="device">
  23. <hal format="hidl">
  24. <name>android.hardware.radio</name>
  25. <transport>hwbinder</transport>
  26. <fqname>@1.1::IRadio/slot1</fqname>
  27. <fqname>@1.1::IRadio/slot2</fqname>
  28. <fqname>@1.2::ISap/slot1</fqname>
  29. </hal>
  30. <hal format="hidl">
  31. <name>android.hardware.radio.deprecated</name>
  32. <transport>hwbinder</transport>
  33. <version>1.0</version>
  34. <interface>
  35. <name>IOemHook</name>
  36. <instance>slot1</instance>
  37. </interface>
  38. </hal>
  39. <hal format="hidl">
  40. - <name>android.hardware.radio.config</name>
  41. + <name>android.hardware.radio</name>
  42. <transport>hwbinder</transport>
  43. <version>1.0</version>
  44. <interface>
  45. - <name>IRadioConfig</name>
  46. + <name>IRadio</name>
  47. - <instance>default</instance>
  48. + <instance>slot1</instance>
  49. </interface>
  50. </hal>
  51. </manifest>

5.打开BOARD_HAS_RK_4G_MODEM属性之后加载的库,

        这里修改成了我预制的libreference-ril-ec20.so(设置的是vendor.rild.libpath属性)

  1. RK3568\device\rockchip\common\device.mk
  2. ifeq ($(strip $(BOARD_HAS_RK_4G_MODEM)),true)
  3. PRODUCT_PACKAGES += \
  4. CarrierDefaultApp \
  5. CarrierConfig \
  6. rild \
  7. - librk-ril \
  8. + libreference-ril-ec20 \
  9. dhcpcd
  10. PRODUCT_COPY_FILES += vendor/rockchip/common/phone/etc/apns-full-conf.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/apns-conf.xml
  11. PRODUCT_PACKAGES += \
  12. android.hardware.radio@1.2-radio-service \
  13. android.hardware.radio.config@1.0-service
  14. PRODUCT_PROPERTY_OVERRIDES += \
  15. ro.boot.noril=false \
  16. ro.telephony.default_network=9
  17. ifeq ($(strip $(TARGET_ARCH)), arm64)
  18. PRODUCT_PROPERTY_OVERRIDES += \
  19. - vendor.rild.libpath=/vendor/lib64/librk-ril.so
  20. + vendor.rild.libpath=/vendor/lib64/libreference-ril-ec20.so
  21. PRODUCT_COPY_FILES += \
  22. $(LOCAL_PATH)/4g_modem/bin64/dhcpcd:$(TARGET_COPY_OUT_VENDOR)/bin/dhcpcd \
  23. $(LOCAL_PATH)/4g_modem/lib64/librk-ril.so:$(TARGET_COPY_OUT_VENDOR)/lib64/librk-ril.so
  24. else
  25. PRODUCT_PROPERTY_OVERRIDES += \
  26. - vendor.rild.libpath=/vendor/lib/librk-ril.so
  27. + vendor.rild.libpath=/vendor/lib/libreference-ril-ec20.so
  28. PRODUCT_COPY_FILES += \
  29. $(LOCAL_PATH)/4g_modem/bin32/dhcpcd:$(TARGET_COPY_OUT_VENDOR)/bin/dhcpcd \
  30. $(LOCAL_PATH)/4g_modem/lib32/librk-ril.so:$(TARGET_COPY_OUT_VENDOR)/lib/librk-ril.so
  31. endif
  32. endif

设置属性(rild.libpath) 

  1. RK3568\device\rockchip\rk356x\device.mk
  2. PRODUCT_PROPERTY_OVERRIDES += \
  3. ro.ril.ecclist=112,911 \
  4. ro.opengles.version=196610 \
  5. wifi.interface=wlan0 \
  6. + ro.telephony.default_network=9 \
  7. + rild.libpath=/vendor/lib64/libreference-ril-ec20.so \
  8. + rild.libargs=-d /dev/ttyUSB2 \
  9. ro.audio.monitorOrientation=true \
  10. debug.nfc.fw_download=false \
  11. debug.nfc.se=false \
  12. vendor.hwc.compose_policy=1 \
  13. sys.wallpaper.rgb565=0 \
  14. sf.power.control=2073600 \
  15. sys.rkadb.root=0 \
  16. ro.sf.fakerotation=false \
  17. ro.tether.denied=false \
  18. sys.resolution.changed=false \
  19. ro.default.size=100 \
  20. ro.product.usbfactory=rockchip_usb \
  21. wifi.supplicant_scan_interval=15 \
  22. ro.factory.tool=0 \
  23. ro.kernel.android.checkjni=0 \
  24. ro.build.shutdown_timeout=6 \
  25. persist.enable_task_snapshots=false \
  26. ro.vendor.frameratelock=true
  27. #

6.去掉property:ro.boot.noril

如果存在电话这一项,就执行下面的内容

设置setprop ro.radio.noril 为true

暂停ril-daemon服务

  1. - a/device/rockchip/common/init.rk30board.rc
  2. + b/device/rockchip/common/init.rk30board.rc
  3. @@ -238,7 +238,7 @@ on property:sys.boot_completed=1
  4. # for telephony function
  5. -on property:ro.boot.noril=true
  6. - setprop ro.radio.noril true
  7. - stop ril-daemon
  8. +#on property:ro.boot.noril=true
  9. +# setprop ro.radio.noril true
  10. +# stop ril-daemon

7.添加权限

  1. \device\rockchip\common\ueventd.rockchip.rc
  2. # for radio
  3. /dev/ttyUSB* 0666 radio radio
  4. #for cdc-wdm0
  5. /dev/cdc-wdm* 0660 radio radio

8.根据上述属性打开rild的库

  1. RK3568\hardware\ril\rild\rild.c
  2. #if defined(PRODUCT_COMPATIBLE_PROPERTY)
  3. #define LIB_PATH_PROPERTY "vendor.rild.libpath"
  4. #define LIB_ARGS_PROPERTY "vendor.rild.libargs"
  5. #else
  6. #define LIB_PATH_PROPERTY "rild.libpath"
  7. #define LIB_ARGS_PROPERTY "rild.libargs"
  8. #endif
  9. #define MAX_LIB_ARGS 16

根据第五点设置的库,可以使用串口指令查看加载库是否正确

  1. console:/ # getprop | grep rild
  2. [rild.libargs]: [-d]
  3. [rild.libpath]: [/vendor/lib64/libreference-ril-ec20.so]
  4. [vendor.rild.libpath]: [/vendor/lib64/libreference-ril-ec20.so]

9.修改传进去的库的名称 /vendor/lib64/libreference-ril-ec20.so设置成这个参数

  1. RK3568\hardware\ril\rild\rild.rc
  2. -#service vendor.ril-daemon /vendor/bin/hw/rild
  3. -# class main
  4. -# user radio
  5. -# group radio cache inet misc audio log readproc wakelock
  6. -# capabilities BLOCK_SUSPEND NET_ADMIN NET_RAW
  7. +service ril-daemon /vendor/bin/hw/rild -l /vendor/lib64/libreference-ril-ec20.so
  8. + class main
  9. + user root
  10. + group radio cache inet misc audio sdcard_rw log
  11. + capabilities BLOCK_SUSPEND NET_ADMIN NET_RAW

 10.4G上网正常,但状态栏中没有4G图标(完全没有图标):

  1. device\rockchip\rk356x\overlay\frameworks\base\core\res\res\value\config.xml
  2. <string-array translatable="false" name="networkAttributes">
  3. <item>"wifi,1,1,2,-1,true"</item>
  4. + <item>"mobile,0,0,0,-1,true"</item>
  5. + <item>"mobile_mms,2,0,2,60000,true"</item>
  6. + <item>"mobile_supl,3,0,2,60000,true"</item>
  7. + <item>"mobile_dun,4,0,2,60000,true"</item>
  8. + <item>"mobile_hipri,5,0,3,60000,true"</item>
  9. + <item>"mobile_fota,10,0,2,60000,true"</item>
  10. + <item>"mobile_ims,11,0,2,60000,true"</item>
  11. + <item>"mobile_cbs,12,0,2,60000,true"</item>
  12. <item>"bluetooth,7,7,0,-1,true"</item>
  13. <item>"ethernet,9,9,9,-1,true"</item>

11. 4G物联网卡,把APN加入

  1. 在\vendor\rockchip\common\phone\etc\apns-full-conf.xml中增加
  2. <apn carrier="China Telecom" mcc="460" mnc="11" apn="ctnet" type="default,supl" />
  3. <apn carrier="中国移动物联网4G" mcc="460" mnc="04" apn="cmiot" type="default,supl" />
  4. <apn carrier="中国移动物联网2G" mcc="460" mnc="04" apn="cmmtm" type="default,supl" />
  5. <apn carrier="中国联通物联网gzm2mapn" mcc="460" mnc="06" apn="unim2m.gzm2mapn" port="80" type="default,supl" />
  6. <apn carrier="中国联通物联网njm2mapn" mcc="460" mnc="06" apn="unim2m.njm2mapn" type="default,supl" />
  7. <apn carrier="中国电信物联网m2m" mcc="460" mnc="03" apn="CTNET" user="m2m" password="vnet.mobi" type="default" />

 12.设置APN打开

  1. RK3568\device\rockchip\common\overlay\frameworks\base\core\res\res\values\config.xml
  2. - <bool name="config_voice_capable">false</bool>
  3. + <bool name="config_voice_capable">true</bool>

 13.遇到开机未插4G模块,就一直报错的问题,甚至把系统拉起不来

打印报错

[ 2650.466038] init: Control message: Could not find 'android.hardware.radio@1.1::IRadio/slot1' for ctl.interface_start from pid: 149 (/system/bin/hwservicemanager)
  1. RK3568\system\core\init\init.cpp
  2. static bool HandleControlMessage(std::string_view message, const std::string& name,
  3. pid_t from_pid) {
  4. std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid);
  5. std::string process_cmdline;
  6. ......
  7. const auto& function = it->second;
  8. if (auto result = function(service); !result.ok()) {
  9. LOG(ERROR) << "Control message: Could not ctl." << message << " for '" << name
  10. << "' from pid: " << from_pid << " (" << process_cmdline
  11. << "): " << result.error();
  12. return false;
  13. }
  14. + if(strcmp(name.c_str(),"android.hardware.radio@1.1::IRadio/slot1") != 0) {
  15. LOG(INFO) << "Control message: Processed ctl." << message << " for '" << name
  16. << "' from pid: " << from_pid << " (" << process_cmdline << ")";
  17. + }
  18. return true;
  19. }
  1. RK3568\system\hwservicemanager\ServiceManager.cpp
  2. static void tryStartService(const std::string& fqName, const std::string& name) {
  3. using ::android::base::SetProperty;
  4. // The "happy path" here is starting up a service that is configured as a
  5. // lazy HAL, but we aren't sure that is the case. If the service doesn't
  6. // have an 'interface' entry in its .rc file OR if the service is already
  7. // running, then this will be a no-op. So, for instance, if a service is
  8. // deadlocked during startup, you will see this message repeatedly.
  9. + if(strcmp(fqName.c_str(),"android.hardware.radio@1.1::IRadio") != 0) {
  10. LOG(INFO) << "Since " << fqName << "/" << name
  11. << " is not registered, trying to start it as a lazy HAL.";
  12. + }
  13. std::thread([=] {
  14. (void)SetProperty("ctl.interface_start", fqName + "/" + name);
  15. }).detach();
  16. }
  1. RK3568\system\libhidl\transport\ServiceManagement.cpp
  2. void wait(bool timeout) {
  3. using std::literals::chrono_literals::operator""s;
  4. if (!mRegisteredForNotifications) {
  5. // As an alternative, just sleep for a second and return
  6. LOG(WARNING) << "Waiting one second for " << mInterfaceName << "/" << mInstanceName;
  7. sleep(1);
  8. return;
  9. }
  10. std::unique_lock<std::mutex> lock(mMutex);
  11. do {
  12. mCondition.wait_for(lock, 1s, [this]{
  13. return mRegistered;
  14. });
  15. if (mRegistered) {
  16. break;
  17. }
  18. + if(strcmp(mInterfaceName.c_str(),"android.hardware.radio@1.1::IRadio") != 0) {
  19. LOG(WARNING) << "Waited one second for " << mInterfaceName << "/" << mInstanceName;
  20. + }
  21. } while (!timeout);
  22. }
  23. sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
  24. const std::string& instance,
  25. bool retry, bool getStub) {
  26. // In case of legacy or we were not asked to retry, don't.
  27. if (vintfLegacy || !retry) break;
  28. if (waiter != nullptr) {
  29. + if(strcmp(descriptor.c_str(),"android.hardware.radio@1.1::IRadio") != 0) {
  30. ALOGI("getService: Trying again for %s/%s...", descriptor.c_str(), instance.c_str());
  31. + }
  32. waiter->wait(true /* timeout */);
  33. }
  34. }
  35. return nullptr;
  36. }

 //###############################################################//

qmi_wwan_q.c源码,之前有遇到图标拨号都有,就是没有上不了网,换成这个驱动就可以了。

仅供参考,亲测有效。

  1. RK3568\kernel\drivers\net\usb\qmi_wwan_q.c
  2. /*
  3. * Copyright (c) 2012 Bjørn Mork <bjorn@mork.no>
  4. *
  5. * The probing code is heavily inspired by cdc_ether, which is:
  6. * Copyright (C) 2003-2005 by David Brownell
  7. * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * version 2 as published by the Free Software Foundation.
  12. */
  13. #include <linux/module.h>
  14. #include <linux/netdevice.h>
  15. #include <linux/ethtool.h>
  16. #include <linux/etherdevice.h>
  17. #include <linux/mii.h>
  18. #include <linux/usb.h>
  19. #include <linux/usb/cdc.h>
  20. #include <linux/usb/usbnet.h>
  21. #include <linux/usb/cdc-wdm.h>
  22. /* This driver supports wwan (3G/LTE/?) devices using a vendor
  23. * specific management protocol called Qualcomm MSM Interface (QMI) -
  24. * in addition to the more common AT commands over serial interface
  25. * management
  26. *
  27. * QMI is wrapped in CDC, using CDC encapsulated commands on the
  28. * control ("master") interface of a two-interface CDC Union
  29. * resembling standard CDC ECM. The devices do not use the control
  30. * interface for any other CDC messages. Most likely because the
  31. * management protocol is used in place of the standard CDC
  32. * notifications NOTIFY_NETWORK_CONNECTION and NOTIFY_SPEED_CHANGE
  33. *
  34. * Alternatively, control and data functions can be combined in a
  35. * single USB interface.
  36. *
  37. * Handling a protocol like QMI is out of the scope for any driver.
  38. * It is exported as a character device using the cdc-wdm driver as
  39. * a subdriver, enabling userspace applications ("modem managers") to
  40. * handle it.
  41. *
  42. * These devices may alternatively/additionally be configured using AT
  43. * commands on a serial interface
  44. */
  45. /* driver specific data */
  46. struct qmi_wwan_state {
  47. struct usb_driver *subdriver;
  48. atomic_t pmcount;
  49. unsigned long unused;
  50. struct usb_interface *control;
  51. struct usb_interface *data;
  52. };
  53. /* default ethernet address used by the modem */
  54. static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3};
  55. #if 1 //Added by Quectel
  56. #include <linux/etherdevice.h>
  57. #include <net/arp.h>
  58. #include <net/ip.h>
  59. #include <net/ipv6.h>
  60. /*
  61. Quectel_WCDMA&LTE_Linux_USB_Driver_User_Guide_V1.9.pdf
  62. 5.6. Test QMAP on GobiNet or QMI WWAN
  63. 0 - no QMAP
  64. 1 - QMAP (Aggregation protocol)
  65. X - QMAP (Multiplexing and Aggregation protocol)
  66. */
  67. #define QUECTEL_WWAN_QMAP 4
  68. #if defined(QUECTEL_WWAN_QMAP)
  69. #define QUECTEL_QMAP_MUX_ID 0x81
  70. static uint __read_mostly qmap_mode = 0;
  71. module_param( qmap_mode, uint, S_IRUGO);
  72. module_param_named( rx_qmap, qmap_mode, uint, S_IRUGO );
  73. #endif
  74. #ifdef CONFIG_BRIDGE
  75. //#define QUECTEL_BRIDGE_MODE
  76. #endif
  77. #ifdef QUECTEL_BRIDGE_MODE
  78. static uint __read_mostly bridge_mode = BIT(0)/*|BIT(1)*/;
  79. module_param( bridge_mode, uint, S_IRUGO );
  80. #endif
  81. #if defined(QUECTEL_WWAN_QMAP)
  82. typedef struct sQmiWwanQmap
  83. {
  84. struct usbnet *mpNetDev;
  85. atomic_t refcount;
  86. struct net_device *mpQmapNetDev[QUECTEL_WWAN_QMAP];
  87. uint link_state;
  88. uint qmap_mode;
  89. #ifdef QUECTEL_BRIDGE_MODE
  90. uint bridge_mode;
  91. uint bridge_ipv4;
  92. unsigned char bridge_mac[ETH_ALEN];
  93. #endif
  94. } sQmiWwanQmap;
  95. struct qmap_priv {
  96. struct net_device *real_dev;
  97. u8 offset_id;
  98. #ifdef QUECTEL_BRIDGE_MODE
  99. uint bridge_mode;
  100. uint bridge_ipv4;
  101. unsigned char bridge_mac[ETH_ALEN];
  102. #endif
  103. };
  104. struct qmap_hdr {
  105. u8 cd_rsvd_pad;
  106. u8 mux_id;
  107. u16 pkt_len;
  108. } __packed;
  109. #ifdef QUECTEL_BRIDGE_MODE
  110. static int is_qmap_netdev(const struct net_device *netdev);
  111. #endif
  112. #endif
  113. #ifdef QUECTEL_BRIDGE_MODE
  114. static int bridge_arp_reply(struct net_device *net, struct sk_buff *skb, uint bridge_ipv4) {
  115. struct arphdr *parp;
  116. u8 *arpptr, *sha;
  117. u8 sip[4], tip[4], ipv4[4];
  118. struct sk_buff *reply = NULL;
  119. ipv4[0] = (bridge_ipv4 >> 24) & 0xFF;
  120. ipv4[1] = (bridge_ipv4 >> 16) & 0xFF;
  121. ipv4[2] = (bridge_ipv4 >> 8) & 0xFF;
  122. ipv4[3] = (bridge_ipv4 >> 0) & 0xFF;
  123. parp = arp_hdr(skb);
  124. if (parp->ar_hrd == htons(ARPHRD_ETHER) && parp->ar_pro == htons(ETH_P_IP)
  125. && parp->ar_op == htons(ARPOP_REQUEST) && parp->ar_hln == 6 && parp->ar_pln == 4) {
  126. arpptr = (u8 *)parp + sizeof(struct arphdr);
  127. sha = arpptr;
  128. arpptr += net->addr_len; /* sha */
  129. memcpy(sip, arpptr, sizeof(sip));
  130. arpptr += sizeof(sip);
  131. arpptr += net->addr_len; /* tha */
  132. memcpy(tip, arpptr, sizeof(tip));
  133. pr_info("%s sip = %d.%d.%d.%d, tip=%d.%d.%d.%d, ipv4=%d.%d.%d.%d\n", netdev_name(net),
  134. sip[0], sip[1], sip[2], sip[3], tip[0], tip[1], tip[2], tip[3], ipv4[0], ipv4[1], ipv4[2], ipv4[3]);
  135. //wwan0 sip = 10.151.137.255, tip=10.151.138.0, ipv4=10.151.137.255
  136. if (tip[0] == ipv4[0] && tip[1] == ipv4[1] && (tip[2]&0xFC) == (ipv4[2]&0xFC) && tip[3] != ipv4[3])
  137. reply = arp_create(ARPOP_REPLY, ETH_P_ARP, *((__be32 *)sip), net, *((__be32 *)tip), sha, default_modem_addr, sha);
  138. if (reply) {
  139. skb_reset_mac_header(reply);
  140. __skb_pull(reply, skb_network_offset(reply));
  141. reply->ip_summed = CHECKSUM_UNNECESSARY;
  142. reply->pkt_type = PACKET_HOST;
  143. netif_rx_ni(reply);
  144. }
  145. return 1;
  146. }
  147. return 0;
  148. }
  149. static struct sk_buff *bridge_mode_tx_fixup(struct net_device *net, struct sk_buff *skb, uint bridge_ipv4, unsigned char *bridge_mac) {
  150. struct ethhdr *ehdr;
  151. const struct iphdr *iph;
  152. skb_reset_mac_header(skb);
  153. ehdr = eth_hdr(skb);
  154. if (ehdr->h_proto == htons(ETH_P_ARP)) {
  155. if (bridge_ipv4)
  156. bridge_arp_reply(net, skb, bridge_ipv4);
  157. return NULL;
  158. }
  159. iph = ip_hdr(skb);
  160. //DBG("iphdr: ");
  161. //PrintHex((void *)iph, sizeof(struct iphdr));
  162. // 1 0.000000000 0.0.0.0 255.255.255.255 DHCP 362 DHCP Request - Transaction ID 0xe7643ad7
  163. if (ehdr->h_proto == htons(ETH_P_IP) && iph->protocol == IPPROTO_UDP && iph->saddr == 0x00000000 && iph->daddr == 0xFFFFFFFF) {
  164. //if (udp_hdr(skb)->dest == htons(67)) //DHCP Request
  165. {
  166. memcpy(bridge_mac, ehdr->h_source, ETH_ALEN);
  167. pr_info("%s PC Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n", netdev_name(net),
  168. bridge_mac[0], bridge_mac[1], bridge_mac[2], bridge_mac[3], bridge_mac[4], bridge_mac[5]);
  169. }
  170. }
  171. if (memcmp(ehdr->h_source, bridge_mac, ETH_ALEN)) {
  172. return NULL;
  173. }
  174. return skb;
  175. }
  176. #endif
  177. #if defined(QUECTEL_WWAN_QMAP)
  178. static ssize_t qmap_mode_show(struct device *dev, struct device_attribute *attr, char *buf) {
  179. struct net_device *netdev = to_net_dev(dev);
  180. struct usbnet * usbnetdev = netdev_priv( netdev );
  181. struct qmi_wwan_state *info = (void *)&usbnetdev->data;
  182. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused;
  183. return snprintf(buf, PAGE_SIZE, "%d\n", pQmapDev->qmap_mode);
  184. }
  185. static DEVICE_ATTR(qmap_mode, S_IRUGO, qmap_mode_show, NULL);
  186. static ssize_t link_state_show(struct device *dev, struct device_attribute *attr, char *buf) {
  187. struct net_device *netdev = to_net_dev(dev);
  188. struct usbnet * usbnetdev = netdev_priv( netdev );
  189. struct qmi_wwan_state *info = (void *)&usbnetdev->data;
  190. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused;
  191. return snprintf(buf, PAGE_SIZE, "0x%x\n", pQmapDev->link_state);
  192. }
  193. static ssize_t link_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) {
  194. struct net_device *netdev = to_net_dev(dev);
  195. struct usbnet * usbnetdev = netdev_priv( netdev );
  196. struct qmi_wwan_state *info = (void *)&usbnetdev->data;
  197. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused;
  198. unsigned link_state = 0;
  199. unsigned old_link = pQmapDev->link_state;
  200. link_state = simple_strtoul(buf, NULL, 0);
  201. if (pQmapDev->qmap_mode == 1)
  202. pQmapDev->link_state = !!link_state;
  203. else if (pQmapDev->qmap_mode > 1) {
  204. if (0 < link_state && link_state <= pQmapDev->qmap_mode)
  205. pQmapDev->link_state |= (1 << (link_state - 1));
  206. else if (0x80 < link_state && link_state <= (0x80 + pQmapDev->qmap_mode))
  207. pQmapDev->link_state &= ~(1 << ((link_state&0xF) - 1));
  208. }
  209. if (old_link != pQmapDev->link_state)
  210. dev_info(dev, "link_state 0x%x -> 0x%x\n", old_link, pQmapDev->link_state);
  211. return count;
  212. }
  213. #ifdef QUECTEL_BRIDGE_MODE
  214. static ssize_t bridge_mode_show(struct device *dev, struct device_attribute *attr, char *buf) {
  215. struct net_device *netdev = to_net_dev(dev);
  216. uint bridge_mode = 0;
  217. if (is_qmap_netdev(netdev)) {
  218. struct qmap_priv *priv = netdev_priv(netdev);
  219. bridge_mode = priv->bridge_mode;
  220. }
  221. else {
  222. struct usbnet * usbnetdev = netdev_priv( netdev );
  223. struct qmi_wwan_state *info = (void *)&usbnetdev->data;
  224. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused;
  225. bridge_mode = pQmapDev->bridge_mode;
  226. }
  227. return snprintf(buf, PAGE_SIZE, "%u\n", bridge_mode);
  228. }
  229. static ssize_t bridge_ipv4_show(struct device *dev, struct device_attribute *attr, char *buf) {
  230. struct net_device *netdev = to_net_dev(dev);
  231. unsigned int bridge_ipv4 = 0;
  232. unsigned char ipv4[4];
  233. if (is_qmap_netdev(netdev)) {
  234. struct qmap_priv *priv = netdev_priv(netdev);
  235. bridge_ipv4 = priv->bridge_ipv4;
  236. }
  237. else {
  238. struct usbnet * usbnetdev = netdev_priv( netdev );
  239. struct qmi_wwan_state *info = (void *)&usbnetdev->data;
  240. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused;
  241. bridge_ipv4 = pQmapDev->bridge_ipv4;
  242. }
  243. ipv4[0] = (bridge_ipv4 >> 24) & 0xFF;
  244. ipv4[1] = (bridge_ipv4 >> 16) & 0xFF;
  245. ipv4[2] = (bridge_ipv4 >> 8) & 0xFF;
  246. ipv4[3] = (bridge_ipv4 >> 0) & 0xFF;
  247. return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n", ipv4[0], ipv4[1], ipv4[2], ipv4[3]);
  248. }
  249. static ssize_t bridge_ipv4_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) {
  250. struct net_device *netdev = to_net_dev(dev);
  251. if (is_qmap_netdev(netdev)) {
  252. struct qmap_priv *priv = netdev_priv(netdev);
  253. priv->bridge_ipv4 = simple_strtoul(buf, NULL, 16);
  254. }
  255. else {
  256. struct usbnet * usbnetdev = netdev_priv( netdev );
  257. struct qmi_wwan_state *info = (void *)&usbnetdev->data;
  258. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused;
  259. pQmapDev->bridge_ipv4 = simple_strtoul(buf, NULL, 16);
  260. }
  261. return count;
  262. }
  263. #endif
  264. static DEVICE_ATTR(link_state, S_IWUSR | S_IRUGO, link_state_show, link_state_store);
  265. #ifdef QUECTEL_BRIDGE_MODE
  266. static DEVICE_ATTR(bridge_mode, S_IRUGO, bridge_mode_show, NULL);
  267. static DEVICE_ATTR(bridge_ipv4, S_IWUSR | S_IRUGO, bridge_ipv4_show, bridge_ipv4_store);
  268. #endif
  269. static struct attribute *qmi_wwan_sysfs_attrs[] = {
  270. &dev_attr_link_state.attr,
  271. &dev_attr_qmap_mode.attr,
  272. #ifdef QUECTEL_BRIDGE_MODE
  273. &dev_attr_bridge_mode.attr,
  274. &dev_attr_bridge_ipv4.attr,
  275. #endif
  276. NULL,
  277. };
  278. static struct attribute_group qmi_wwan_sysfs_attr_group = {
  279. .attrs = qmi_wwan_sysfs_attrs,
  280. };
  281. #ifdef QUECTEL_BRIDGE_MODE
  282. static struct attribute *qmi_qmap_sysfs_attrs[] = {
  283. &dev_attr_bridge_mode.attr,
  284. &dev_attr_bridge_ipv4.attr,
  285. NULL,
  286. };
  287. static struct attribute_group qmi_qmap_sysfs_attr_group = {
  288. .attrs = qmi_qmap_sysfs_attrs,
  289. };
  290. #endif
  291. static int qmap_open(struct net_device *dev)
  292. {
  293. struct qmap_priv *priv = netdev_priv(dev);
  294. struct net_device *real_dev = priv->real_dev;
  295. if (!(priv->real_dev->flags & IFF_UP))
  296. return -ENETDOWN;
  297. if (netif_carrier_ok(real_dev))
  298. netif_carrier_on(dev);
  299. return 0;
  300. }
  301. static int qmap_stop(struct net_device *pNet)
  302. {
  303. netif_carrier_off(pNet);
  304. return 0;
  305. }
  306. static int qmap_start_xmit(struct sk_buff *skb, struct net_device *pNet)
  307. {
  308. int err;
  309. struct qmap_priv *priv = netdev_priv(pNet);
  310. unsigned int len;
  311. struct qmap_hdr *hdr;
  312. skb_reset_mac_header(skb);
  313. #ifdef QUECTEL_BRIDGE_MODE
  314. if (priv->bridge_mode && bridge_mode_tx_fixup(pNet, skb, priv->bridge_ipv4, priv->bridge_mac) == NULL) {
  315. dev_kfree_skb_any (skb);
  316. return NETDEV_TX_OK;
  317. }
  318. #endif
  319. if (skb_pull(skb, ETH_HLEN) == NULL) {
  320. dev_kfree_skb_any (skb);
  321. return NETDEV_TX_OK;
  322. }
  323. len = skb->len;
  324. hdr = (struct qmap_hdr *)skb_push(skb, sizeof(struct qmap_hdr));
  325. hdr->cd_rsvd_pad = 0;
  326. hdr->mux_id = QUECTEL_QMAP_MUX_ID + priv->offset_id;
  327. hdr->pkt_len = cpu_to_be16(len);
  328. skb->dev = priv->real_dev;
  329. err = dev_queue_xmit(skb);
  330. if (err == NET_XMIT_SUCCESS) {
  331. pNet->stats.tx_packets++;
  332. pNet->stats.tx_bytes += skb->len;
  333. } else {
  334. pNet->stats.tx_errors++;
  335. }
  336. return err;
  337. }
  338. static const struct net_device_ops qmap_netdev_ops = {
  339. .ndo_open = qmap_open,
  340. .ndo_stop = qmap_stop,
  341. .ndo_start_xmit = qmap_start_xmit,
  342. };
  343. static int qmap_register_device(sQmiWwanQmap * pDev, u8 offset_id)
  344. {
  345. struct net_device *real_dev = pDev->mpNetDev->net;
  346. struct net_device *qmap_net;
  347. struct qmap_priv *priv;
  348. int err;
  349. qmap_net = alloc_etherdev(sizeof(*priv));
  350. if (!qmap_net)
  351. return -ENOBUFS;
  352. SET_NETDEV_DEV(qmap_net, &real_dev->dev);
  353. priv = netdev_priv(qmap_net);
  354. priv->offset_id = offset_id;
  355. priv->real_dev = real_dev;
  356. sprintf(qmap_net->name, "%s.%d", real_dev->name, offset_id + 1);
  357. qmap_net->netdev_ops = &qmap_netdev_ops;
  358. memcpy (qmap_net->dev_addr, real_dev->dev_addr, ETH_ALEN);
  359. #ifdef QUECTEL_BRIDGE_MODE
  360. priv->bridge_mode = !!(pDev->bridge_mode & BIT(offset_id));
  361. qmap_net->sysfs_groups[0] = &qmi_qmap_sysfs_attr_group;
  362. #endif
  363. err = register_netdev(qmap_net);
  364. if (err < 0)
  365. goto out_free_newdev;
  366. netif_device_attach (qmap_net);
  367. pDev->mpQmapNetDev[offset_id] = qmap_net;
  368. qmap_net->flags |= IFF_NOARP;
  369. dev_info(&real_dev->dev, "%s %s\n", __func__, qmap_net->name);
  370. return 0;
  371. out_free_newdev:
  372. free_netdev(qmap_net);
  373. return err;
  374. }
  375. static void qmap_unregister_device(sQmiWwanQmap * pDev, u8 offset_id) {
  376. struct net_device *net = pDev->mpQmapNetDev[offset_id];
  377. if (net != NULL) {
  378. netif_carrier_off( net );
  379. unregister_netdev (net);
  380. free_netdev(net);
  381. }
  382. }
  383. #ifdef CONFIG_ANDROID
  384. static int qmap_ndo_do_ioctl(struct net_device *dev,struct ifreq *ifr, int cmd) {
  385. int rc = -EOPNOTSUPP;
  386. uint link_state = 0;
  387. switch (cmd) {
  388. case 0x89F1: //SIOCDEVPRIVATE
  389. rc = copy_from_user(&link_state, ifr->ifr_ifru.ifru_data, sizeof(link_state));
  390. if (!rc) {
  391. char buf[32];
  392. snprintf(buf, sizeof(buf), "%u", link_state);
  393. link_state_store(&dev->dev, NULL, buf, strlen(buf));
  394. }
  395. break;
  396. default:
  397. break;
  398. }
  399. return rc;
  400. }
  401. #endif
  402. #ifdef QUECTEL_BRIDGE_MODE
  403. static int is_qmap_netdev(const struct net_device *netdev) {
  404. return netdev->netdev_ops == &qmap_netdev_ops;
  405. }
  406. #endif
  407. #endif
  408. static struct sk_buff *qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) {
  409. //MDM9x07,MDM9628,MDM9x40,SDX20,SDX24 only work on RAW IP mode
  410. if ((dev->driver_info->flags & FLAG_NOARP) == 0)
  411. return skb;
  412. // Skip Ethernet header from message
  413. if (dev->net->hard_header_len == 0)
  414. return skb;
  415. else
  416. skb_reset_mac_header(skb);
  417. #ifdef QUECTEL_BRIDGE_MODE
  418. {
  419. struct qmi_wwan_state *info = (void *)&dev->data;
  420. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused;
  421. if (pQmapDev->bridge_mode && bridge_mode_tx_fixup(dev->net, skb, pQmapDev->bridge_ipv4, pQmapDev->bridge_mac) == NULL) {
  422. dev_kfree_skb_any (skb);
  423. return NULL;
  424. }
  425. }
  426. #endif
  427. if (skb_pull(skb, ETH_HLEN)) {
  428. return skb;
  429. } else {
  430. dev_err(&dev->intf->dev, "Packet Dropped ");
  431. }
  432. // Filter the packet out, release it
  433. dev_kfree_skb_any(skb);
  434. return NULL;
  435. }
  436. #endif
  437. /* Make up an ethernet header if the packet doesn't have one.
  438. *
  439. * A firmware bug common among several devices cause them to send raw
  440. * IP packets under some circumstances. There is no way for the
  441. * driver/host to know when this will happen. And even when the bug
  442. * hits, some packets will still arrive with an intact header.
  443. *
  444. * The supported devices are only capably of sending IPv4, IPv6 and
  445. * ARP packets on a point-to-point link. Any packet with an ethernet
  446. * header will have either our address or a broadcast/multicast
  447. * address as destination. ARP packets will always have a header.
  448. *
  449. * This means that this function will reliably add the appropriate
  450. * header iff necessary, provided our hardware address does not start
  451. * with 4 or 6.
  452. *
  453. * Another common firmware bug results in all packets being addressed
  454. * to 00:a0:c6:00:00:00 despite the host address being different.
  455. * This function will also fixup such packets.
  456. */
  457. static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
  458. {
  459. __be16 proto;
  460. #ifdef QUECTEL_BRIDGE_MODE
  461. struct qmi_wwan_state *info = (void *)&dev->data;
  462. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused;
  463. #endif
  464. /* This check is no longer done by usbnet */
  465. if (skb->len < dev->net->hard_header_len)
  466. return 0;
  467. switch (skb->data[0] & 0xf0) {
  468. case 0x40:
  469. proto = htons(ETH_P_IP);
  470. break;
  471. case 0x60:
  472. proto = htons(ETH_P_IPV6);
  473. break;
  474. case 0x00:
  475. if (is_multicast_ether_addr(skb->data))
  476. return 1;
  477. /* possibly bogus destination - rewrite just in case */
  478. skb_reset_mac_header(skb);
  479. goto fix_dest;
  480. default:
  481. /* pass along other packets without modifications */
  482. return 1;
  483. }
  484. if (skb_headroom(skb) < ETH_HLEN)
  485. return 0;
  486. skb_push(skb, ETH_HLEN);
  487. skb_reset_mac_header(skb);
  488. eth_hdr(skb)->h_proto = proto;
  489. memset(eth_hdr(skb)->h_source, 0, ETH_ALEN);
  490. #if 1 //Added by Quectel
  491. //some kernel will drop ethernet packet which's souce mac is all zero
  492. memcpy(eth_hdr(skb)->h_source, default_modem_addr, ETH_ALEN);
  493. #endif
  494. #ifdef QUECTEL_BRIDGE_MODE
  495. if (pQmapDev->bridge_mode) {
  496. memcpy(eth_hdr(skb)->h_dest, pQmapDev->bridge_mac, ETH_ALEN);
  497. }
  498. #endif
  499. fix_dest:
  500. memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
  501. return 1;
  502. }
  503. #if defined(QUECTEL_WWAN_QMAP)
  504. static struct sk_buff *qmap_qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) {
  505. struct qmi_wwan_state *info = (void *)&dev->data;
  506. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused;
  507. struct qmap_hdr *qhdr;
  508. if (unlikely(pQmapDev == NULL)) {
  509. goto drop_skb;
  510. } else if (unlikely(pQmapDev->qmap_mode && !pQmapDev->link_state)) {
  511. dev_dbg(&dev->net->dev, "link_state 0x%x, drop skb, len = %u\n", pQmapDev->link_state, skb->len);
  512. goto drop_skb;
  513. } else if (pQmapDev->qmap_mode == 0) {
  514. return qmi_wwan_tx_fixup(dev, skb, flags);
  515. }
  516. else if (pQmapDev->qmap_mode > 1) {
  517. qhdr = (struct qmap_hdr *)skb->data;
  518. if (qhdr->cd_rsvd_pad != 0) {
  519. goto drop_skb;
  520. }
  521. if ((qhdr->mux_id&0xF0) != 0x80) {
  522. goto drop_skb;
  523. }
  524. return skb;
  525. }
  526. else {
  527. if (qmi_wwan_tx_fixup(dev, skb, flags)) {
  528. qhdr = (struct qmap_hdr *)skb_push(skb, sizeof(struct qmap_hdr));
  529. qhdr->cd_rsvd_pad = 0;
  530. qhdr->mux_id = QUECTEL_QMAP_MUX_ID;
  531. qhdr->pkt_len = cpu_to_be16(skb->len - sizeof(struct qmap_hdr));
  532. return skb;
  533. }
  534. else {
  535. return NULL;
  536. }
  537. }
  538. drop_skb:
  539. dev_kfree_skb_any (skb);
  540. return NULL;
  541. }
  542. static int qmap_qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
  543. {
  544. struct qmi_wwan_state *info = (void *)&dev->data;
  545. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused;
  546. static int debug_len = 0;
  547. int debug_pkts = 0;
  548. int update_len = skb->len;
  549. if (pQmapDev->qmap_mode == 0)
  550. return qmi_wwan_rx_fixup(dev, skb);
  551. while (skb->len > sizeof(struct qmap_hdr)) {
  552. struct qmap_hdr *qhdr = (struct qmap_hdr *)skb->data;
  553. struct net_device *qmap_net;
  554. struct sk_buff *qmap_skb;
  555. #ifdef QUECTEL_BRIDGE_MODE
  556. uint bridge_mode = 0;
  557. unsigned char *bridge_mac;
  558. #endif
  559. __be16 proto;
  560. int pkt_len;
  561. u8 offset_id = 0;
  562. int err;
  563. unsigned len = (be16_to_cpu(qhdr->pkt_len) + sizeof(struct qmap_hdr));
  564. if (skb->len < (be16_to_cpu(qhdr->pkt_len) + sizeof(struct qmap_hdr))) {
  565. dev_info(&dev->net->dev, "drop qmap unknow pkt, len=%d, pkt_len=%d\n", skb->len, be16_to_cpu(qhdr->pkt_len));
  566. goto out;
  567. }
  568. debug_pkts++;
  569. if (qhdr->cd_rsvd_pad & 0x80) {
  570. dev_info(&dev->net->dev, "drop qmap command packet %x\n", qhdr->cd_rsvd_pad);
  571. goto skip_pkt;;
  572. }
  573. offset_id = qhdr->mux_id - QUECTEL_QMAP_MUX_ID;
  574. if (offset_id >= pQmapDev->qmap_mode) {
  575. dev_info(&dev->net->dev, "drop qmap unknow mux_id %x\n", qhdr->mux_id);
  576. goto skip_pkt;
  577. }
  578. qmap_net = pQmapDev->mpQmapNetDev[offset_id];
  579. if (qmap_net == NULL) {
  580. dev_info(&dev->net->dev, "drop qmap unknow mux_id %x\n", qhdr->mux_id);
  581. goto skip_pkt;
  582. }
  583. switch (skb->data[sizeof(struct qmap_hdr)] & 0xf0) {
  584. case 0x40:
  585. proto = htons(ETH_P_IP);
  586. break;
  587. case 0x60:
  588. proto = htons(ETH_P_IPV6);
  589. break;
  590. default:
  591. goto skip_pkt;
  592. }
  593. pkt_len = be16_to_cpu(qhdr->pkt_len) - (qhdr->cd_rsvd_pad&0x3F);
  594. qmap_skb = netdev_alloc_skb(qmap_net, ETH_HLEN + pkt_len);
  595. if (qmap_skb == NULL) {
  596. dev_info(&dev->net->dev, "fail to alloc skb, pkt_len = %d\n", pkt_len);
  597. return 0;
  598. }
  599. skb_reset_mac_header(qmap_skb);
  600. memcpy(eth_hdr(qmap_skb)->h_source, default_modem_addr, ETH_ALEN);
  601. memcpy(eth_hdr(qmap_skb)->h_dest, qmap_net->dev_addr, ETH_ALEN);
  602. eth_hdr(qmap_skb)->h_proto = proto;
  603. memcpy(skb_put(qmap_skb, ETH_HLEN + pkt_len) + ETH_HLEN, skb->data + sizeof(struct qmap_hdr), pkt_len);
  604. #ifdef QUECTEL_BRIDGE_MODE
  605. if (pQmapDev->qmap_mode > 1) {
  606. struct qmap_priv *priv = netdev_priv(qmap_net);
  607. bridge_mode = priv->bridge_mode;
  608. bridge_mac = priv->bridge_mac;
  609. }
  610. else {
  611. bridge_mode = pQmapDev->bridge_mode;
  612. bridge_mac = pQmapDev->bridge_mac;
  613. }
  614. if (bridge_mode) {
  615. memcpy(eth_hdr(qmap_skb)->h_dest, bridge_mac, ETH_ALEN);
  616. }
  617. #endif
  618. if (pQmapDev->qmap_mode > 1) {
  619. qmap_skb->protocol = eth_type_trans (qmap_skb, qmap_net);
  620. memset(qmap_skb->cb, 0, sizeof(struct skb_data));
  621. err = netif_rx(qmap_skb);
  622. if (err == NET_RX_SUCCESS) {
  623. qmap_net->stats.rx_packets++;
  624. qmap_net->stats.rx_bytes += qmap_skb->len;
  625. } else {
  626. qmap_net->stats.rx_errors++;
  627. }
  628. }
  629. else {
  630. usbnet_skb_return(dev, qmap_skb);
  631. }
  632. skip_pkt:
  633. skb_pull(skb, len);
  634. }
  635. out:
  636. if (update_len > debug_len) {
  637. debug_len = update_len;
  638. dev_info(&dev->net->dev, "rx_pkts=%d, rx_len=%d\n", debug_pkts, debug_len);
  639. }
  640. return 0;
  641. }
  642. #endif
  643. /* very simplistic detection of IPv4 or IPv6 headers */
  644. static bool possibly_iphdr(const char *data)
  645. {
  646. return (data[0] & 0xd0) == 0x40;
  647. }
  648. /* disallow addresses which may be confused with IP headers */
  649. static int qmi_wwan_mac_addr(struct net_device *dev, void *p)
  650. {
  651. int ret;
  652. struct sockaddr *addr = p;
  653. ret = eth_prepare_mac_addr_change(dev, p);
  654. if (ret < 0)
  655. return ret;
  656. if (possibly_iphdr(addr->sa_data))
  657. return -EADDRNOTAVAIL;
  658. eth_commit_mac_addr_change(dev, p);
  659. return 0;
  660. }
  661. static const struct net_device_ops qmi_wwan_netdev_ops = {
  662. .ndo_open = usbnet_open,
  663. .ndo_stop = usbnet_stop,
  664. .ndo_start_xmit = usbnet_start_xmit,
  665. .ndo_tx_timeout = usbnet_tx_timeout,
  666. .ndo_change_mtu = usbnet_change_mtu,
  667. .ndo_set_mac_address = qmi_wwan_mac_addr,
  668. .ndo_validate_addr = eth_validate_addr,
  669. #if defined(QUECTEL_WWAN_QMAP) && defined(CONFIG_ANDROID)
  670. .ndo_do_ioctl = qmap_ndo_do_ioctl,
  671. #endif
  672. };
  673. /* using a counter to merge subdriver requests with our own into a
  674. * combined state
  675. */
  676. static int qmi_wwan_manage_power(struct usbnet *dev, int on)
  677. {
  678. struct qmi_wwan_state *info = (void *)&dev->data;
  679. int rv;
  680. dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__,
  681. atomic_read(&info->pmcount), on);
  682. if ((on && atomic_add_return(1, &info->pmcount) == 1) ||
  683. (!on && atomic_dec_and_test(&info->pmcount))) {
  684. /* need autopm_get/put here to ensure the usbcore sees
  685. * the new value
  686. */
  687. rv = usb_autopm_get_interface(dev->intf);
  688. dev->intf->needs_remote_wakeup = on;
  689. if (!rv)
  690. usb_autopm_put_interface(dev->intf);
  691. }
  692. return 0;
  693. }
  694. static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on)
  695. {
  696. struct usbnet *dev = usb_get_intfdata(intf);
  697. /* can be called while disconnecting */
  698. if (!dev)
  699. return 0;
  700. return qmi_wwan_manage_power(dev, on);
  701. }
  702. /* collect all three endpoints and register subdriver */
  703. static int qmi_wwan_register_subdriver(struct usbnet *dev)
  704. {
  705. int rv;
  706. struct usb_driver *subdriver = NULL;
  707. struct qmi_wwan_state *info = (void *)&dev->data;
  708. /* collect bulk endpoints */
  709. rv = usbnet_get_endpoints(dev, info->data);
  710. if (rv < 0)
  711. goto err;
  712. /* update status endpoint if separate control interface */
  713. if (info->control != info->data)
  714. dev->status = &info->control->cur_altsetting->endpoint[0];
  715. /* require interrupt endpoint for subdriver */
  716. if (!dev->status) {
  717. rv = -EINVAL;
  718. goto err;
  719. }
  720. /* for subdriver power management */
  721. atomic_set(&info->pmcount, 0);
  722. /* register subdriver */
  723. subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc,
  724. 4096, &qmi_wwan_cdc_wdm_manage_power);
  725. if (IS_ERR(subdriver)) {
  726. dev_err(&info->control->dev, "subdriver registration failed\n");
  727. rv = PTR_ERR(subdriver);
  728. goto err;
  729. }
  730. /* prevent usbnet from using status endpoint */
  731. dev->status = NULL;
  732. /* save subdriver struct for suspend/resume wrappers */
  733. info->subdriver = subdriver;
  734. err:
  735. return rv;
  736. }
  737. static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
  738. {
  739. int status = -1;
  740. u8 *buf = intf->cur_altsetting->extra;
  741. int len = intf->cur_altsetting->extralen;
  742. struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
  743. struct usb_cdc_union_desc *cdc_union = NULL;
  744. struct usb_cdc_ether_desc *cdc_ether = NULL;
  745. u32 found = 0;
  746. struct usb_driver *driver = driver_of(intf);
  747. struct qmi_wwan_state *info = (void *)&dev->data;
  748. BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) <
  749. sizeof(struct qmi_wwan_state)));
  750. /* set up initial state */
  751. info->control = intf;
  752. info->data = intf;
  753. /* and a number of CDC descriptors */
  754. while (len > 3) {
  755. struct usb_descriptor_header *h = (void *)buf;
  756. /* ignore any misplaced descriptors */
  757. if (h->bDescriptorType != USB_DT_CS_INTERFACE)
  758. goto next_desc;
  759. /* buf[2] is CDC descriptor subtype */
  760. switch (buf[2]) {
  761. case USB_CDC_HEADER_TYPE:
  762. if (found & 1 << USB_CDC_HEADER_TYPE) {
  763. dev_dbg(&intf->dev, "extra CDC header\n");
  764. goto err;
  765. }
  766. if (h->bLength != sizeof(struct usb_cdc_header_desc)) {
  767. dev_dbg(&intf->dev, "CDC header len %u\n",
  768. h->bLength);
  769. goto err;
  770. }
  771. break;
  772. case USB_CDC_UNION_TYPE:
  773. if (found & 1 << USB_CDC_UNION_TYPE) {
  774. dev_dbg(&intf->dev, "extra CDC union\n");
  775. goto err;
  776. }
  777. if (h->bLength != sizeof(struct usb_cdc_union_desc)) {
  778. dev_dbg(&intf->dev, "CDC union len %u\n",
  779. h->bLength);
  780. goto err;
  781. }
  782. cdc_union = (struct usb_cdc_union_desc *)buf;
  783. break;
  784. case USB_CDC_ETHERNET_TYPE:
  785. if (found & 1 << USB_CDC_ETHERNET_TYPE) {
  786. dev_dbg(&intf->dev, "extra CDC ether\n");
  787. goto err;
  788. }
  789. if (h->bLength != sizeof(struct usb_cdc_ether_desc)) {
  790. dev_dbg(&intf->dev, "CDC ether len %u\n",
  791. h->bLength);
  792. goto err;
  793. }
  794. cdc_ether = (struct usb_cdc_ether_desc *)buf;
  795. break;
  796. }
  797. /* Remember which CDC functional descriptors we've seen. Works
  798. * for all types we care about, of which USB_CDC_ETHERNET_TYPE
  799. * (0x0f) is the highest numbered
  800. */
  801. if (buf[2] < 32)
  802. found |= 1 << buf[2];
  803. next_desc:
  804. len -= h->bLength;
  805. buf += h->bLength;
  806. }
  807. /* Use separate control and data interfaces if we found a CDC Union */
  808. if (cdc_union) {
  809. info->data = usb_ifnum_to_if(dev->udev,
  810. cdc_union->bSlaveInterface0);
  811. if (desc->bInterfaceNumber != cdc_union->bMasterInterface0 ||
  812. !info->data) {
  813. dev_err(&intf->dev,
  814. "bogus CDC Union: master=%u, slave=%u\n",
  815. cdc_union->bMasterInterface0,
  816. cdc_union->bSlaveInterface0);
  817. goto err;
  818. }
  819. }
  820. /* errors aren't fatal - we can live with the dynamic address */
  821. if (cdc_ether) {
  822. dev->hard_mtu = le16_to_cpu(cdc_ether->wMaxSegmentSize);
  823. usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress);
  824. }
  825. /* claim data interface and set it up */
  826. if (info->control != info->data) {
  827. status = usb_driver_claim_interface(driver, info->data, dev);
  828. if (status < 0)
  829. goto err;
  830. }
  831. status = qmi_wwan_register_subdriver(dev);
  832. if (status < 0 && info->control != info->data) {
  833. usb_set_intfdata(info->data, NULL);
  834. usb_driver_release_interface(driver, info->data);
  835. }
  836. /* Never use the same address on both ends of the link, even
  837. * if the buggy firmware told us to.
  838. */
  839. if (ether_addr_equal(dev->net->dev_addr, default_modem_addr))
  840. eth_hw_addr_random(dev->net);
  841. /* make MAC addr easily distinguishable from an IP header */
  842. if (possibly_iphdr(dev->net->dev_addr)) {
  843. dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */
  844. dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */
  845. }
  846. dev->net->netdev_ops = &qmi_wwan_netdev_ops;
  847. #if 1 //Added by Quectel
  848. if (dev->driver_info->flags & FLAG_NOARP) {
  849. dev_info(&intf->dev, "Quectel EC25&EC21&EG91&EG95&EG06&EP06&EM06&EG12&EP12&EM12&EG16&EG18&BG96&AG35 work on RawIP mode\n");
  850. dev->net->flags |= IFF_NOARP;
  851. usb_control_msg(
  852. interface_to_usbdev(intf),
  853. usb_sndctrlpipe(interface_to_usbdev(intf), 0),
  854. 0x22, //USB_CDC_REQ_SET_CONTROL_LINE_STATE
  855. 0x21, //USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
  856. 1, //active CDC DTR
  857. intf->cur_altsetting->desc.bInterfaceNumber,
  858. NULL, 0, 100);
  859. }
  860. //to advoid module report mtu 1460, but rx 1500 bytes IP packets, and cause the customer's system crash
  861. //next setting can make usbnet.c:usbnet_change_mtu() do not modify rx_urb_size according to hard mtu
  862. dev->rx_urb_size = ETH_DATA_LEN + ETH_HLEN + 6;
  863. #if defined(QUECTEL_WWAN_QMAP)
  864. if (qmap_mode > QUECTEL_WWAN_QMAP)
  865. qmap_mode = QUECTEL_WWAN_QMAP;
  866. if (!status)
  867. {
  868. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)kzalloc(sizeof(sQmiWwanQmap), GFP_KERNEL);
  869. if (pQmapDev == NULL)
  870. return -ENODEV;
  871. #ifdef QUECTEL_BRIDGE_MODE
  872. pQmapDev->bridge_mode = bridge_mode;
  873. #endif
  874. pQmapDev->mpNetDev = dev;
  875. pQmapDev->link_state = 1;
  876. if (dev->driver_info->flags & FLAG_NOARP)
  877. {
  878. int idProduct = le16_to_cpu(dev->udev->descriptor.idProduct);
  879. int lte_a = (idProduct == 0x0306 || idProduct == 0x0512 || idProduct == 0x0620 || idProduct == 0x0800);
  880. pQmapDev->qmap_mode = qmap_mode;
  881. if (lte_a || dev->udev->speed == USB_SPEED_SUPER) {
  882. if (pQmapDev->qmap_mode == 0) {
  883. pQmapDev->qmap_mode = 1; //force use QMAP
  884. if(qmap_mode == 0)
  885. qmap_mode = 1; //old quectel-CM only check sys/module/wwan0/parameters/qmap_mode
  886. }
  887. }
  888. if (pQmapDev->qmap_mode) {
  889. if (idProduct == 0x0121 || idProduct == 0x0125 || idProduct == 0x0435) //MDM9x07
  890. dev->rx_urb_size = 4*1024;
  891. else if (lte_a || dev->udev->speed == USB_SPEED_SUPER)
  892. dev->rx_urb_size = 32*1024;
  893. else
  894. dev->rx_urb_size = 32*1024;
  895. //for these modules, if send pakcet before qmi_start_network, or cause host PC crash, or cause modules crash
  896. if (lte_a || dev->udev->speed == USB_SPEED_SUPER)
  897. pQmapDev->link_state = 0;
  898. }
  899. }
  900. info->unused = (unsigned long)pQmapDev;
  901. dev->net->sysfs_groups[0] = &qmi_wwan_sysfs_attr_group;
  902. dev_info(&intf->dev, "rx_urb_size = %zd\n", dev->rx_urb_size);
  903. }
  904. #endif
  905. #endif
  906. err:
  907. return status;
  908. }
  909. static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf)
  910. {
  911. struct qmi_wwan_state *info = (void *)&dev->data;
  912. struct usb_driver *driver = driver_of(intf);
  913. struct usb_interface *other;
  914. if (info->subdriver && info->subdriver->disconnect)
  915. info->subdriver->disconnect(info->control);
  916. /* allow user to unbind using either control or data */
  917. if (intf == info->control)
  918. other = info->data;
  919. else
  920. other = info->control;
  921. /* only if not shared */
  922. if (other && intf != other) {
  923. usb_set_intfdata(other, NULL);
  924. usb_driver_release_interface(driver, other);
  925. }
  926. info->subdriver = NULL;
  927. info->data = NULL;
  928. info->control = NULL;
  929. }
  930. /* suspend/resume wrappers calling both usbnet and the cdc-wdm
  931. * subdriver if present.
  932. *
  933. * NOTE: cdc-wdm also supports pre/post_reset, but we cannot provide
  934. * wrappers for those without adding usbnet reset support first.
  935. */
  936. static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message)
  937. {
  938. struct usbnet *dev = usb_get_intfdata(intf);
  939. struct qmi_wwan_state *info = (void *)&dev->data;
  940. int ret;
  941. /* Both usbnet_suspend() and subdriver->suspend() MUST return 0
  942. * in system sleep context, otherwise, the resume callback has
  943. * to recover device from previous suspend failure.
  944. */
  945. ret = usbnet_suspend(intf, message);
  946. if (ret < 0)
  947. goto err;
  948. if (intf == info->control && info->subdriver &&
  949. info->subdriver->suspend)
  950. ret = info->subdriver->suspend(intf, message);
  951. if (ret < 0)
  952. usbnet_resume(intf);
  953. err:
  954. return ret;
  955. }
  956. static int qmi_wwan_resume(struct usb_interface *intf)
  957. {
  958. struct usbnet *dev = usb_get_intfdata(intf);
  959. struct qmi_wwan_state *info = (void *)&dev->data;
  960. int ret = 0;
  961. bool callsub = (intf == info->control && info->subdriver &&
  962. info->subdriver->resume);
  963. if (callsub)
  964. ret = info->subdriver->resume(intf);
  965. if (ret < 0)
  966. goto err;
  967. ret = usbnet_resume(intf);
  968. if (ret < 0 && callsub)
  969. info->subdriver->suspend(intf, PMSG_SUSPEND);
  970. err:
  971. return ret;
  972. }
  973. static int qmi_wwan_reset_resume(struct usb_interface *intf)
  974. {
  975. dev_info(&intf->dev, "device do not support reset_resume\n");
  976. intf->needs_binding = 1;
  977. return -EOPNOTSUPP;
  978. }
  979. static const struct driver_info qmi_wwan_info = {
  980. .description = "WWAN/QMI device",
  981. .flags = FLAG_WWAN,
  982. .bind = qmi_wwan_bind,
  983. .unbind = qmi_wwan_unbind,
  984. .manage_power = qmi_wwan_manage_power,
  985. .rx_fixup = qmi_wwan_rx_fixup,
  986. };
  987. static const struct driver_info qmi_wwan_raw_ip_info = {
  988. .description = "WWAN/QMI device",
  989. .flags = FLAG_WWAN | FLAG_RX_ASSEMBLE | FLAG_NOARP | FLAG_SEND_ZLP,
  990. .bind = qmi_wwan_bind,
  991. .unbind = qmi_wwan_unbind,
  992. .manage_power = qmi_wwan_manage_power,
  993. #if defined(QUECTEL_WWAN_QMAP)
  994. .tx_fixup = qmap_qmi_wwan_tx_fixup,
  995. .rx_fixup = qmap_qmi_wwan_rx_fixup,
  996. #else
  997. .tx_fixup = qmi_wwan_tx_fixup,
  998. .rx_fixup = qmi_wwan_rx_fixup,
  999. #endif
  1000. };
  1001. /* map QMI/wwan function by a fixed interface number */
  1002. #define QMI_FIXED_INTF(vend, prod, num) \
  1003. USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \
  1004. .driver_info = (unsigned long)&qmi_wwan_info
  1005. #define QMI_FIXED_RAWIP_INTF(vend, prod, num) \
  1006. USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \
  1007. .driver_info = (unsigned long)&qmi_wwan_raw_ip_info
  1008. static const struct usb_device_id products[] = {
  1009. #if 1 //Added by Quectel
  1010. { QMI_FIXED_INTF(0x05C6, 0x9003, 4) }, /* Quectel UC20 */
  1011. { QMI_FIXED_INTF(0x05C6, 0x9215, 4) }, /* Quectel EC20 (MDM9215) */
  1012. { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0125, 4) }, /* Quectel EC20 (MDM9X07)/EC25/EG25 */
  1013. { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0121, 4) }, /* Quectel EC21 */
  1014. { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0191, 4) }, /* Quectel EG91 */
  1015. { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0195, 4) }, /* Quectel EG95 */
  1016. { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0306, 4) }, /* Quectel EG06/EP06/EM06 */
  1017. { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0512, 4) }, /* Quectel EG12/EP12/EM12/EG16/EG18 */
  1018. { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0296, 4) }, /* Quectel BG96 */
  1019. { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0435, 4) }, /* Quectel AG35 */
  1020. { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0620, 4) }, /* Quectel EG20 */
  1021. { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0800, 4) }, /* Quectel RG500 */
  1022. #endif
  1023. { } /* END */
  1024. };
  1025. MODULE_DEVICE_TABLE(usb, products);
  1026. static int qmi_wwan_probe(struct usb_interface *intf,
  1027. const struct usb_device_id *prod)
  1028. {
  1029. struct usb_device_id *id = (struct usb_device_id *)prod;
  1030. /* Workaround to enable dynamic IDs. This disables usbnet
  1031. * blacklisting functionality. Which, if required, can be
  1032. * reimplemented here by using a magic "blacklist" value
  1033. * instead of 0 in the static device id table
  1034. */
  1035. if (!id->driver_info) {
  1036. dev_dbg(&intf->dev, "setting defaults for dynamic device id\n");
  1037. id->driver_info = (unsigned long)&qmi_wwan_info;
  1038. }
  1039. if (intf->cur_altsetting->desc.bInterfaceClass != 0xff) {
  1040. dev_info(&intf->dev, "Quectel module not qmi_wwan mode! please check 'at+qcfg=\"usbnet\"'\n");
  1041. return -ENODEV;
  1042. }
  1043. return usbnet_probe(intf, id);
  1044. }
  1045. #if defined(QUECTEL_WWAN_QMAP)
  1046. static int qmap_qmi_wwan_probe(struct usb_interface *intf,
  1047. const struct usb_device_id *prod)
  1048. {
  1049. int status = qmi_wwan_probe(intf, prod);
  1050. if (!status) {
  1051. struct usbnet *dev = usb_get_intfdata(intf);
  1052. struct qmi_wwan_state *info = (void *)&dev->data;
  1053. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused;
  1054. unsigned i;
  1055. if (pQmapDev) {
  1056. if (pQmapDev->qmap_mode == 1) {
  1057. pQmapDev->mpQmapNetDev[0] = dev->net;
  1058. }
  1059. else if (pQmapDev->qmap_mode > 1) {
  1060. for (i = 0; i < pQmapDev->qmap_mode; i++) {
  1061. qmap_register_device(pQmapDev, i);
  1062. }
  1063. }
  1064. }
  1065. }
  1066. return status;
  1067. }
  1068. static void qmap_qmi_wwan_disconnect(struct usb_interface *intf)
  1069. {
  1070. struct usbnet *dev = usb_get_intfdata(intf);
  1071. struct qmi_wwan_state *info = (void *)&dev->data;
  1072. sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused;
  1073. if (pQmapDev) {
  1074. if (pQmapDev->qmap_mode > 1) {
  1075. unsigned i;
  1076. for (i = 0; i < pQmapDev->qmap_mode; i++) {
  1077. qmap_unregister_device(pQmapDev, i);
  1078. }
  1079. }
  1080. kfree(pQmapDev);
  1081. }
  1082. usbnet_disconnect(intf);
  1083. }
  1084. #endif
  1085. static struct usb_driver qmi_wwan_driver = {
  1086. .name = "qmi_wwan_q",
  1087. .id_table = products,
  1088. .probe = qmi_wwan_probe,
  1089. #if defined(QUECTEL_WWAN_QMAP)
  1090. .probe = qmap_qmi_wwan_probe,
  1091. .disconnect = qmap_qmi_wwan_disconnect,
  1092. #else
  1093. .probe = qmi_wwan_probe,
  1094. .disconnect = usbnet_disconnect,
  1095. #endif
  1096. .suspend = qmi_wwan_suspend,
  1097. .resume = qmi_wwan_resume,
  1098. .reset_resume = qmi_wwan_reset_resume,
  1099. .supports_autosuspend = 1,
  1100. .disable_hub_initiated_lpm = 1,
  1101. };
  1102. module_usb_driver(qmi_wwan_driver);
  1103. MODULE_AUTHOR("Bjørn Mork <bjorn@mork.no>");
  1104. MODULE_DESCRIPTION("Qualcomm MSM Interface (QMI) WWAN driver");
  1105. MODULE_LICENSE("GPL");
  1106. #define QUECTEL_WWAN_VERSION "Quectel_Linux&Android_QMI_WWAN_Driver_V1.1"
  1107. MODULE_VERSION(QUECTEL_WWAN_VERSION);

生活一步一个脚印,每一步都不容易,请珍惜当下! 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/275170
推荐阅读
相关标签
  

闽ICP备14008679号