rk3399添加EC25E/EC20...模组_[kernel]/drivers/usb/serial/option.c-程序员宅基地

技术标签: 3G/4G  EC/EC25E/EC20  RIL RILD  quectel-CM  Android底层  RK3399  

搞来搞去搞了很久,差点放弃走人的时候,发现竟然是这点事。。。辛酸史如下:

android6.01-----kernel4.4.36-----编译环境ubuntu16.04

一、kernel driver

内核有4种驱动方式,usb serial、CDC ACM、Gobinet、QMI WWAN,本文选用的是usb serial和QMI WWAN两种驱动。

 

1.usb serial

(1)添加模组的PID/VID。

/kernel/driver/usb/serial/option.c

如果,你添加的是EC20。那么,注释掉以下代码,避免型号冲突。

/kernel/driver/usb/serial/qcserial.c

{USB_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */

/kernel/driver/net/usb/qmi_wwan.c

{QMI_GOBI_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */

此时,在/dev/下可以找到ttyUSB0/ttyUSB1/ttyUSB2/ttyUSB3设备节点

(2)添加零包机制

根据 USB 协议的要求, 需要添加在批量输出传输过程中处理零数据包的机制。

/kernel/drivers/usb/serial/usb_wwan.c

(3)添加重置回调

当 MCU 进入挂起状态时, 某些 USB 主机控制器/集线器将断电或重置模式, 并且在 MCU 退出挂起/休眠模式后, 它们无法恢复 USB 设备。添加以下语句, 以启用重新安置过程。

/kernel/drivers/usb/serial/option.c

(4)如果使用Gobinet、QMI WWAN驱动

/kernel/drivers/usb/serial/option.c

(5)添加内核模块

[*] Device Driver

   [*]USB Support

      [*]USB Serial Converter support

         [*]USB Driver for GSM and CDMA modems

 

2.QMI WWAN

(1)添加PID/VID

/kernel/drivers/net/usb/qmi_wwan.c

如果添加的是EC20型号,请注释以下代码。

/kernel/drivers/usb/serial/qcserial.c

{USB_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */

/kernel/drivers/net/usb/qmi_wwan.c

{QMI_GOBI_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */

此时,在/dev/下可以找到qcqmi0设备节点

(2)添加对原始 IP 模式的支持

       Ec25仅支持原始 IP 模式 (IP 数据包未封装在以太网帧)。因此, 当数据包发送到模块时, 必须剥离以太网标头, 并且从模块接收数据包时添加。

/kernel/drivers/net/usb/qmi_wwan.c

#if 1 //Added by Quectel 
#include <linux/etherdevice.h> 
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; 
} 
#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; 
} 
/* very simplistic detection of IPv4 or IPv6 headers */ 
static bool possibly_iphdr(const char *data) 
{ 
    return (data[0] & 0xd0) == 0x40; 
} 
#endif 
#endif 
……
/* if follow function exist, modify it as below */
static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) 
{ 
……
#if 1 //Added by Quectel
    if (dev->udev->descriptor.idVendor == cpu_to_le16(0x2C7C)) { 
    dev_info(&intf->dev, "Quectel EC25&EC21&EG91&EG95&EG06&EP06&EM06&BG96&AG35 work on RawIP mode\n"); 
    dev->net->flags |= IFF_NOARP; 
#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 )) 
    /* make MAC addr easily distinguishable from an IP header */ 
    if (possibly_iphdr(dev->net->dev_addr)) { 
    dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */ 
    dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */ 
 } 
#endif 
    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; 
}

/* if follow struct exist, modify it as below */ 
static const struct driver_info qmi_wwan_info = 
{ 
……
#if 1 //Added by Quectel 
    .tx_fixup = qmi_wwan_tx_fixup, 
    .rx_fixup = qmi_wwan_rx_fixup, 
#endif 
}

/* if follow struct exist, modify it as below */ 
static const struct driver_info qmi_wwan_force_int4 = { 
…… 
#if 1 //Added by Quectel 
    .tx_fixup = qmi_wwan_tx_fixup, 
    .rx_fixup = qmi_wwan_rx_fixup, 
#endif 
};

(3)添加内核模块

[*]Device Drivers

   [*]Network device support

      [*]USB Network Adapters

         [*]Multi-purpose USB Networking Framework

            <*>QMI WWAN driver for Qualcomm MSM based 3G and LTE modems

 

3.添加内核ppp

[*]Device Driver

   [*]Network device support

      [*]PPP (point-to-point protocol) support

 

4.电源管理

(1)自动挂起

/kernel/drivers/usb/serial/option.c

static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) { 
 struct usb_wwan_intf_private *data; 
……
#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_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 
    /* Store device id so we can use it during attach. */ 
    usb_set_serial_data(serial, (void *)id); 
    return 0; 
}

(2)自动唤醒

/kernel/drivers/usb/serial/option.c

static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) { 
    struct usb_wwan_intf_private *data; 
    ……
#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 
    /* Store device id so we can use it during attach. */ 
    usb_set_serial_data(serial, (void *)id); 
    return 0; 
}

此时,驱动层相关已经添加完了。

如果是linux系统,再添加quectel-CM的拨号工具就可以了。

 

5.quectel-CM拨号

(1)移植quctel-CM源码

放入/hardware/ril/reference-ril/路径下;

(2)添加default.script脚本

android环境,命令udhcpc -h检查版本调用路径:

将default.script脚本放至该路径(或/usr/share/udhcpc/),并注意执行权限。

权限:可在/system/core/libcutils/fs_config.c文件或init.rc文件中的on init中指定

(3)执行quectel-CM

将sudo quectel-CM -s ctnet 命令添加到脚本,并在/etc/init.d/rc中启动脚本。

检查IP/DNS/网关等配置,没问题可以正常启动。

 

 

二.android RIL库

 

1.添加ril源码

(1)移植ril源码

放入/hardware/ril/reference-ril路径

(2)指定rild库路径

/device/rockchip/rkxx/rkxxxxxx/system.prop

rild.llibpath=/system/lib64/libreference-ril.so

rild.libargs=-d /dev/ttyUSB2      //ttyUSB2是AT口

 

2.添加phone进程

源码路径:/packages/apps/PhoneCommon

添加编译:/device/rockchip/rk3399/device.mk

PRODUCT_PACKAGES += com.android.phone.common

在/out/target/product/rkxxsdk/system/app/下出现com.android.phone.common

 

3.android系统设置

(1)添加ril-daemon服务到init.rc

/device/rockchip/rk3399/init.rc

service ril-daemon /system/bin/rild -l /system/lib/libreference-ril.so
    class main
    socket rild stream 660 root radio 
    socket rild-debug stream 660 radio system 
    user root
    group radio cache inet misc audio sdcard_rw log

(android8及以上)

service ril-daemon /vendor/bin/hw/rild -l /vendor/lib64/libreference-ril.so
    class main
    user root
    group radio cache inet misc audio sdcard_rw log

(2)保证rild的root权限

/hardware/ril/rild/rild.c

OpenLib:
#endif
    //switchUser();

    dlHandle = dlopen(rilLibPath, RTLD_NOW);

(3)添加APN

/device/rockchip/rkxx/rkxx.mk

PRODUT_COPY_FILES:= /vendor/rockchip/common/phone/etc/apns-full-conf.xml:system/etc/qpns-conf.xml

检查该文件中是否包含所使用的运营商APN信息,如果没有,添加上相应的APN信息。

比如:使用MCC/MNC来确认,而MCC/MNC的值是通过模块查询到的IMSI码的前五位来确定的。

(4)打开dongle功能

/device/rockchip/common/BoardConfig.mk

BOARD_HAVE_DONGLE ?= true

(5)检查

          logcat -b radio -v time    //查看log

          getprop init.svc.ril-daemon    //检查ril守护进程Runing

          cat init.rc | grep ril-daemon    //检查ril-daemon服务是否生效

           getenforce                             //检查SELinux是否开启,<setenforce 0>命令关闭

           getprop gsm.version.ril-impl  //检查ril版本,出现Quectel_Android_RIL_SR01A41V17,如未出现ril库没有添加上,或者检查phone进程

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/linux_qian/article/details/90715599

智能推荐

seata-server安装、运行(ubuntu)-程序员宅基地

文章浏览阅读1.6k次。seata-server为seata中的事务协调器。seata的wikihttps://github.com/seata/seata/wiki/Home_Chinese一、下载并安装wget -P /opt/downloads https://github.com/seata/seata/releases/download/v0.5.1/seata-server-0..._ubuntu 启动seata

docx转换html(mammoth)_mammoth.browser-程序员宅基地

文章浏览阅读1.1w次,点赞3次,收藏10次。使用mammoth.js将docx文件转换成html前言最近接到一个需求,要求是把docx文档转换成html,显示在页面上,翻了好多资料,尝试了iframe嵌套,但问题是会自动下载,也不会显示html。于是继续搜索,找到了mammoth,一个将docx文件转换成html的东西,最后完美的解决了问题,下面谈谈使用心得吧!实现步骤1 首先将源代码下载了到本地,传送门:http://www.gi..._mammoth.browser

oh-my-posh中conda环境重复显示问题修复-两个(base)_conda出现两个base-程序员宅基地

文章浏览阅读109次。最近升级了最新的powershell7,重新安装oh-my-posh和主题后,突然发现原先正常显示的conda环境标识变成了两个,原先在最前面是没有白色的(base)的,现在显示成两个后,导致该主题后面的时间也换行了,非常不美观.搜索了很久也没找到解决方法,凑合用了两天,今天突然脑袋灵光一闪,改了改配置文件里的加载顺序,还真的好了,记录一下.当然,最好的方式是就ohmyposh初始化移动到。将它俩调换位置,让conda先初始化就可以了。红色的是oh\myposh初始化命令。蓝色的是conda初始化命令。_conda出现两个base

Vite 如何过滤 console.log_vite打包去除console.log的插件-程序员宅基地

文章浏览阅读1.3k次。Vite 如何过滤 console.log_vite打包去除console.log的插件

no swt-win32-3232 in java.library.path的解决方法-程序员宅基地

文章浏览阅读703次。Eclipse 3.2,操作系统是WinXP SP2。需要把eclipse\plugins\org.eclipse.swt.win32.win32.x86_3.2.0.v3232m.jar里面的swt-win32-3232.dll解压缩出来拷贝到WINDOWS\SYSTEM32里面。然后就OK了。是在Eclipse里面运行Springside的ANT Task的时候,如果需要通过consol..._idea \no swt-win32-3349 or swt-win32 in swt.library.path, java.library.path

linux制作xp u盘启动盘,ultraiso制作u盘启动盘linuxu大侠u盘装xp-程序员宅基地

文章浏览阅读179次。Windows系统对每个驱动器均有缓存设置,缓存设置越大,复制的文件容量就越大,由于缓存的传输速度和内存差不多,所以刚开始复制文件速度比较快,当缓存内信息写完,就是正常的写U盘速度,windows7旗舰版32如何,速度自然就会变慢了设置鼠标速度的方法:有了这三步大部分的U盘出现0字节都可以解决的,如果还是不行,那就是你的U盘的Flash芯片坏了那么屏幕两边出现黑屏怎么调呢?以下脚本之家小编就来为大..._linux制作winxp启动盘

随便推点

Windows安装JDK+Maven+Idea插件+nvm等_windows idea nvm-程序员宅基地

文章浏览阅读1k次,点赞18次,收藏22次。SpotBugs介绍 SpotBugs是Findbugs的继任者(Findbugs已经不再维护),用于对Java代码进行静态分析,查找相关的漏洞,SpotBugs比Findbugs拥有更多的校验规则。CodeGeeX可以根据自然语言注释描述的功能自动生成代码,也可以根据已有的代码自动生成后续代码,补全当前行或生成后续若干行,帮助你提高编程效率。SonarLint是一个代码扫描插件,可以随时分析出代码的编写质量,并指出问题所在,对编写规范的代码很有帮助。2.安装完成后,验证版本,出现如下警告。_windows idea nvm

SQL练习及解答 2. 查找入职员工时间排名倒数第三的员工所有信息--limit m,n的使用_找employees里入职员工时间排名倒数第三的员工所有信息-程序员宅基地

文章浏览阅读1.5k次。题目描述查找入职员工时间排名倒数第三的员工所有信息,为了减轻入门难度,目前所有的数据里员工入职的日期都不是同一天CREATE TABLE `employees` (`emp_no` int(11) NOT NULL,`birth_date` date NOT NULL,`first_name` varchar(14) NOT NULL,`last_name` varchar(16) NOT NULL,`gender` char(1) NOT NULL,`hire_date` date NO_找employees里入职员工时间排名倒数第三的员工所有信息

linux中node跨服务执行文件,linux部署node.js服务并启动服务-程序员宅基地

文章浏览阅读130次。Xshell连接服务器输入主机号和账号密码,协议选SSH,SSH端口号为22,进去之后会让你输入账号密码。 进入之后输入 ll命令,如果能显示当前目录下的所有文件,即表示连接成功 安装node.js输入uname -a查看系统版本,我的64位的,到时候下载linux下64位的node我的本机的node是8.x版本的,所以我到官网上下载了历史版本的nodehttps://nodejs.org/en..._node编译linux文件可执行

AI算法工程师 | 01人工智能基础-快速入门_人工智能算法-程序员宅基地

文章浏览阅读6.8k次,点赞12次,收藏84次。站在互联网的角度理解人工智能:人工智能AI(artificial intelligence)是互联网时代发展的必然趋势。_人工智能算法

[python]关键字is和操作符==-程序员宅基地

文章浏览阅读133次。Python中所有类型都通过引用存取, 即便是"基本类型"也不例外, 例如:a=1b=1 a 和 b 的值都是等于1, 1以对象存储,内存中只有一个1的实例, 可用如下代码判断:id(a)#10249792id(b)#10249792id(a)==id(b)#True 同样也可用关键字 is:aisb#True...

python多版本py命令及虚拟环境管理_error: ignored the following versions that require-程序员宅基地

文章浏览阅读1.6w次,点赞2次,收藏6次。创建虚拟环境失败, 已经很久没有用python3这个命令,可能又被系统环境修改的时候弄乱了.花点时间整理下。把从windows store 下载的python3.8版本给卸了, 从官网下载python3.11。py指定python版本,生成虚拟环境,目录下文件名为venv。正常完成requirements下载。使用py 替代 python命令。又从官网下了python3.9。默认py命令创建虚拟环境。_error: ignored the following versions that require a different python versio