海思3531添加移远EC20 4g模块

在linux下加载驱动有两种常用方法:静态加载和动态加载。

  • 静态加载就是把驱动程序直接编译进内核,系统启动后可以直接调用。静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重新编译和下载内核,效率较低。若采用静态加载的驱动较多,会导致内核容量很大,浪费存储空间。
  • 动态加载利用了Linux的module特性,可以在系统启动后用insmod命令添加模块(.ko),在不需要的时候用rmmod命令卸载模块,采用这种动态加载的方式便于驱动程序的调试,同时可以针对产品的功能需求,进行内核的裁剪,将不需要的驱动去除,大大减小了内核的存储容量。

在台式机上,一般采用动态加载的方式;在嵌入式产品里,可以先采用动态加载的方式进行调试,调试成功后再编译进内核。

一开始在纠结是选择模块化添加驱动**.ko还是直接把驱动编译进内核,既然我已经会烧写内核了,那把驱动直接编译进内核也不像想象中那么困难,参照《UC20&EC20 Linux GobiNet User Guide》和网上一些资料,根据自己的理解,总结出海思3531添加移远EC20模块的详细过程。

UC20是3g通信模块,EC20是4g通信模块;

1.   介绍

根据USB规范的规定,所有的USB设备都有供应商ID(VID)和产品识别码(PID),主机通过不同的VID和PID来区别不同的设备,VID和PID都是两个字节长,其中,供应商ID(VID)由供应商向USB执行论坛申请,每个供应商的VID是唯一的,PID由供应商自行决定(理论上来说,不同的产品、相同产品的不同型号、相同型号的不同设计的产品最好采用不同的PID,以便区别相同厂家的不同设备。)

VID和PID其实就相当于USB硬件的识别ID系统,也是通过他们来找到UC20/EC20设备的。

Product

PID

VID

UC20

0x9003

0x05c6

EC20

0x9215

0x05c6

2.   在Linux中集成GobiNet

为了在Linux中为Quectel模块使用NDIS接口(Network Driver InterfaceSpecification,即网络驱动接口规范),必须集成GobiNet驱动程序。在linux核中增加程序需要完成以下三项工作:

1.将编写的源代码添加到Linux内核源代码的相应目录

2.在目录的Kconfig文件中增加新源代码对应项目的编译配置选项

3.在目录的Makefile文件中增加对新源代码的编译条目

2.1    在内核中添加驱动源码

  • 找到海思3531的内核源代码版本并解压它。
  • 将GobiNet驱动程序源代码(ec20/DriveRSourceCode/src下的.c和.h文件)放入($_KERNELROOT)/ drivers / net / usb目录中。($ _KERNELROOT)应该内核源代码的根目录。

2.2    解除USB串口驱动对NDIS接口的绑定

NDIS不是串口设备,因此要在串口驱动中去掉这个端口。在集成GobiNet驱动程序之前,先解除USB串口驱动对NDIS接口的绑定。

  • 打开源代码根目录中的文件:($_KERNELROOT)/drivers/usb/serial/option.c ,然后修改option_probe函数中的源代码。注意到指导书给的修改示例和源代码使用的变量名是不一样的,把变量名也修改成一样。

海思3531添加移远EC20 4g模块_第1张图片

  • 网上还有增加PID&VID这一步(对这两个不了解的,建议去找找资料来看看,这个的意思可以简单理解为这个设备的唯一标识),不过指导书里没有,还是加上了

海思3531添加移远EC20 4g模块_第2张图片

代码如下:

if (serial->dev->descriptor.idVendor== cpu_to_le16(0x05c6) &&
             serial->dev->descriptor.idProduct== cpu_to_le16(0x9215) &&
             serial->interface->cur_altsetting->desc.bInterfaceClass== 0x04)
             return-ENODEV;

2.3    将GobiNet添加到内核树中

  • Kconfig文件定义了Linux内核配置菜单,config USB_GOBI_NET添加到($_KERNELROOT)/drivers/net/usb/Kconfig中。

海思3531添加移远EC20 4g模块_第3张图片

代码如下:

config USB_GOBI_NET

    tristate “Gobi USB Netdriver for Quectel module”

    help

    Support Quectel module.

 

    A modem manager withsupport for GobiNet is recommended.

    To compile this driver as amodule, choose M here: the module will be called GobiNet.
  • 修改($_KERNELROOT)/driver/net/usb/Makefile,在Makefile文件的末尾添加两行代码。

2.4    编译内核并编译驱动程序

在宿主机的Linux内核源码根目录执行以下指令,配置内核。添加GobiNet驱动:

host$ make ARCH=arm menuconfig

Kernel Configuration 界面,依次选择:      

DeviceDrivers  --->

         Network device support  --->

                USB Network Adapters  --->

                     <*>Gobi USB Netdriver for Quectel module

如图3-27所示:Save anAlternate Configuration File

海思3531添加移远EC20 4g模块_第4张图片

海思3531添加移远EC20 4g模块_第5张图片

按照卖家提供的内核依赖资料,选中Multi-purpose USB Networking Framework这一选项。

海思3531添加移远EC20 4g模块_第6张图片

step.1        make menuconfig 出错:

海思3531添加移远EC20 4g模块_第7张图片

海思3531添加移远EC20 4g模块_第8张图片

解决方案:换成 make ARCH=arm CROSS_COMPILE= arm-hisiv100-linux- menuconfig

step.2        make bzImage

makeARCH=arm CROSS_COMPILE= arm-hisi100-linux- bzImage

海思3531添加移远EC20 4g模块_第9张图片

step.3        make modules

make ARCH=armCROSS_COMPILE=arm-hisiv100-linux- modules时出现各种错误

错误1   

drivers/ata/ahci_platform.c:251: error: 'CONFIG_HI_SATA_IOBASE' undeclared here (not in a function)
drivers/ata/ahci_platform.c:253: error: 'CONFIG_HI_SATA_IOSIZE' undeclared here (not in a function)
drivers/ata/ahci_platform.c:257: error: 'CONFIG_HI_SATA_IRQNUM' undeclared here (not in a function)
scripts/Makefile.build:311: recipe for target 'drivers/ata/ahci_platform.o' failed
make[2]: *** [drivers/ata/ahci_platform.o] Error 1
scripts/Makefile.build:441: recipe for target 'drivers/ata' failed
make[1]: *** [drivers/ata] Error 2
Makefile:945: recipe for target 'drivers' failed
make: *** [drivers] Error 2

解决方案

进入内核的drivers/ata/目录,打开Makefile,看到“obj-$(CONFIG_SATA_AHCI_PLATFORM) +=ahci_platform.o libahci.o”;
打开drivers/ata/目录下的Kconfig,搜索ATA_AHCI_PLATFORM,然后将这个下面的几行代码注释掉;   
                    
在内核目录下重新make menuconfig配置保存刚才修改的内核(只需要进入menuconfig,然后保存退出)
之后再make内核,这样能够去掉之前出现的错误

错误2   

drivers/gpio/janz-ttl.c: In function 'ttl_set_value':
drivers/gpio/janz-ttl.c:107: error: implicit declaration of function 'iowrite16be'
scripts/Makefile.build:311: recipe for target 'drivers/gpio/janz-ttl.o' failed
make[2]: *** [drivers/gpio/janz-ttl.o] Error 1
scripts/Makefile.build:441: recipe for target 'drivers/gpio' failed
make[1]: *** [drivers/gpio] Error 2
Makefile:945: recipe for target 'drivers' failed
make: *** [drivers] Error 2

解决方案

在drivers/gpio/janz-ttl.c的前面加上下述定义
#define iowrite16be(v, addr) iowrite16(be16_to_cpu(v), (addr))

错误3

drivers/input/touchscreen/eeti_ts.c: In function 'eeti_ts_irq_active':
drivers/input/touchscreen/eeti_ts.c:65: error: implicit declaration of function 'irq_to_gpio'
scripts/Makefile.build:311: recipe for target 'drivers/input/touchscreen/eeti_ts.o' failed
make[3]: *** [drivers/input/touchscreen/eeti_ts.o] Error 1
scripts/Makefile.build:441: recipe for target 'drivers/input/touchscreen' failed
make[2]: *** [drivers/input/touchscreen] Error 2
scripts/Makefile.build:441: recipe for target 'drivers/input' failed
make[1]: *** [drivers/input] Error 2
Makefile:945: recipe for target 'drivers' failed
make: *** [drivers] Error 2

解决方案:更改的地方总共包括三个文件

  • arch/arm/mach-pxa/raumfeld.c
    
static struct eeti_ts_platform_data eeti_ts_pdata = {
.irq_active_high = 1,
.gpio = GPIO_TOUCH_IRQ,//添加
};
  • /drivers/input/touchscreen/eeti_ts.c
    
struct eeti_ts_priv
{
    struct input_dev *input;
    struct work_struct work;
    struct mutex mutex;
    int irq, irq_active_high;//删除
    int irq, gpio, irq_active_high;//添加
};
static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv)
{
    return gpio_get_value(irq_to_gpio(priv->irq)) == priv->irq_active_high;//删除
    return gpio_get_value(priv->gpio) == priv->irq_active_high;//添加
}


if (pdata)
    priv->irq_active_high = pdata->irq_active_high;
替换为
if (pdata)
{
    priv->gpio = pdata->gpio;
    priv->irq_active_high = pdata->irq_active_high;
}
  • /include/linux/input/eeti_ts.
    
struct eeti_ts_platform_data 
{
    unsigned int irq_active_high;
    unsigned int gpio;//添加
};
到后面还是出现了各种错误,怎么改也改不完,索性不编译模块了,
其实到STEP2已经编译出内核了,不用step3也是可以的,step3出现的各种错误是在编译各种我并不需要的模块,直接烧写刚刚得到的内核
0.设置地址
setenv serverip 192.168.1.50
1.烧写内核
sf probe 0
mw.b 82000000 ff 400000
tftp 82000000 uImage
sf probe 0
sf erase 100000 400000
sf write 82000000 100000 400000

 

用hisiv100和hisiv200编译出来的内核烧写到板子上启动时一直处于Starting kernel ...状态,用100ntpl编译的干脆无法开机。网上说修改这个很麻烦,前面这些已经折腾了一天了,看来烧写内核是行不通了,再次放弃,选择动态编译GobiNet.ko 模块试试。

海思3531添加移远EC20 4g模块_第10张图片

驱动厂家给出的动态编译流程:

编译驱动源码:注意修改你的内核路径和交叉编译器,编译好后是GobiNet.ko,拷贝到板子上 insmod GobiNet.ko 就好
 编译拨号联网程序,注意修改makefile里得交叉编译器,编译好后 quectel-CM,拷贝到板子上运行即可 ./quectel-CM&
然后ping www.baidu.com ping通证明就成功了

Linux Kernel 2.6要求你编译模块之前,必须先在内核源代码目录下执行make,换言之,你必须先配置过内核,执行过make,然后才能make你自己的模块。(一开始指明的路径是内核源代码目录,结果出现了许多错误),经过层层苦难终于出现了GobiNet.ko, insmod GobiNet.ko时出现了错误:

GobiNet: version magic '3.0.8 mod_unload ARMv5 ' should be '3.0.8 SMP mod_unload ARMv7 '
insmod: can't insert 'GobiNet.ko': invalid module format

出现这种问题一般是  开发板的内核版本号跟   要加载的编译驱动模块内核模块版本号 不一致,内核文件与模块两者有很多东西必须匹配,编译器版本、源码版本、编译时的配置等,所以当内核文件修改了,譬如修改了驱动的编译选项(Y、M、N),那么就必须重新编译和下载内核,否则会出错。

静态加载无法开机,动态加载版本号不一致,网上也有一些解决版本号不一致问题的方法,尝试多次无果。

这个过程也没有走很多弯路,只是一开始接到这个任务的时候只是去网上找方法,没有好好看厂家提供的资料。在改动的过程中,没有注意到指导书给的修改示例和源代码使用的变量名是不一样的,一开始仅仅按照指导书里说的去改,增加了自己的工作量。

补充:Makefile,Kconfig和配置工具组成了Linux2.6内核的配置系统。
     其中Makefile定义了Linux内核的编译规则,它是大型项目开发的产物。Linux环境下的大型项目开发中,系统被分为很多模块,而这些模块一般会经历几次修改,而在修改后的编译过程中,由于某些文件中存在依赖关系,人工编译效率低(有些文件不需要重新编译)且易出错,Makefile文件便应运而生。Makefile文件定义了模块间的依赖关系,指定文件的编译顺序,以及编译所使用的命令。它和make命令使得项目的源程序文件可以自动编译,提高了软件开发效率。到此,再谈一下make,它是用来维护程序模块关系和生成可执行程序的工具,它可以根据程序模块的修改情况重新编译链接生成中间代码或最终的可执行程序,省去那些重复的不必要的编译工作,提高编译效率。
     Kconfig给用户提供配置选择的功能。通常配置内核会有四种方法,makeconfig(字符界面配置),makemenuconfig(菜单界面配置),makexconfig(依赖QT),makegconfig(依赖GTK+)。makeconfig比较适合专业人员,像初学者比较适合makemenuconfig,让我们重点关注一下它。当我们运行makemenuconfig时,配置工具会首先分析与体系结构相对应的/arch/xxx/Kconfig文件(xxx为传入的arch参数),它里面包含了除一些与体系结构相关的配置项和配置菜单外,还通过source语句引入了一系列Kconfig,配置工具依据这些Kconfig包含的菜单和项目就可以描绘出一个分层结构。
例如当我们运行makezImagine、makebzImagine等生成映像的命令时,会先检索顶层的Makefile(在arch/xxx/目录下的Makefile为顶层Makefile补充体系结构相关的信息),顶层Makefile的两个主要任务是:产生内核映像文件和内核模块。接着顶层Makefile会去递归地进入内核的各个子目录,然后分别调用子目录中的Makefile(这些Makefile记录编译目标),而进入哪些子目录取决于内核的配置。
        当使用makemenuconfig,makeconfig命令时,生成的.config会在源码目录下记录哪些部分被编译入内核,哪些部分被编译为内核模块。简而言之,它是保存内核配置结果的文件。当我们装上Linux系统时,第一次查看源码下的所有文件,会发现没有.config文件,那是因为从来没配置过内核。当你运行makemenuconfig保存并退出时,再次查看就有这个文件了。
        配置工具,包括配置命令解释器(对配置脚本中使用的命令进行解释)和配置用户界面(提供字符界面和图形界面),配置工具都是用脚本语言编写的。

你可能感兴趣的:(hisiv3531)