最近被问到Linux的驱动如何写,想起以前在树莓派上安装无线网卡驱动编译了很久最后加载Module。NuttX也是支持Module加载的。这样我就可以不用烧录固件使它打开某个串口或者SPI啥的。
首先,example里有模块的例子。menuconfig中开启:
> RTOS Features > [Y] Enable loadable OS modules
> File Systems > [Y] ROMFS file system
> Binary Loader > [Y] Enable the ELF Binary Format
> Application Configuration > Examples > [Y] Module Example
> Application Configuration > Examples > [Y] Built-in File System
编译运行,发现报错
chardev.c:40:26: fatal error: nuttx/config.h: No such file or directory
顺便,报错之后再用单线程编译,这样好找错误源头。
make[5]: Entering directory ‘/home/godenfreemans/NuttX/apps/examples/module/drivers/chardev’
CC: chardev.c
chardev.c:40:26: fatal error: nuttx/config.h: No such file or directory
#include <nuttx/config.h>
^
compilation terminated.
这个文件就是Module例子中的。明显是找不到配置文件。说明它的makefile里没有包含配置文件,设置-D后编译依旧出错。询问了Nutt后,得到解决方法:
在apps/examples/module/drivers/chardev
下创建文件Make.defs 写入内容:
# ELF kernael module definitions
CMODULEFLAGS = $(CFLAGS) -mlong-calls # --target1-abs
LDMODULEFLAGS = -r -e module_initialize
ifeq ($(WINTOOL),y)
LDMODULEFLAGS += -T "${shell cygpath -w
$(TOPDIR)/libs/libc/modlib/gnu-elf.ld}"
else
LDMODULEFLAGS += -T $(TOPDIR)/libs/libc/modlib/gnu-elf.ld
endif
在Make file开头添加
include Make.defs
再编译就通过了。
再次运行,出错。
ERROR: insmod(/mnt/romfs/chardev, chardev) failed: 22
追溯一下,
apps\examples\module\module_main.c:295
handle = insmod(BINDIR "/chardev", "chardev");
是在调用这个函数的时候出现了问题,再往里发现了一个类似调试输出的东西
berr("ERROR: Failed to initialize to load module: %d\n", ret);
查找定义,发现是这么个东西:
#ifdef CONFIG_DEBUG_BINFMT_ERROR
# define berr _err
#else
# define berr (void)
#endif
看起来需要我定义CONFIG_DEBUG_BINFMT_ERROR
了。
menuconfig中查找一下,按照顺序开启
> Build Setup > Debug Options > [Y] Enable Debug Features
> Build Setup > Debug Options > [Y] Enable Error Output
> Build Setup > Debug Options > [Y] Enable Warnings Output
> Build Setup > Debug Options > [Y] Enable Informational Debug Output
> Build Setup > Debug Options > [Y] Binary Loader Debug Features
> Build Setup > Debug Options > [Y] Binary Loader Error Output
> Build Setup > Debug Options > [Y] Binary Loader Warnings Output
再次编译运行。依然是错误,不过这回显示了最初生成错误的地方。对代码分析半天无果。
感觉代码有问题,git checkout .
后,居然正常了。。。
nsh>module
main: Registering romdisk at /dev/ram0
main: Mounting ROMFS filesystem at target=/mnt/romfs with source=/dev/ram0
insmod: Loading file: /mnt/romfs/chardev
modlib_initialize: filename: /mnt/romfs/chardev loadinfo: 200040ec
modlib_read: Read 52 bytes from offset 0
mod_dumploadinfo: LOAD_INFO:
mod_dumploadinfo: textalloc: 00000000
mod_dumploadinfo: datastart: 00000000
mod_dumploadinfo: textsize: 0
mod_dumploadinfo: datasize: 0
mod_dumploadinfo: filelen: 2204
mod_dumploadinfo: filfd: 3
mod_dumploadinfo: symtabidx: 0
mod_dumploadinfo: strtabidx: 0
mod_dumploadinfo: ELF Header:
mod_dumploadinfo: e_ident: 7f 45 4c 46
mod_dumploadinfo: e_type: 0001
mod_dumploadinfo: e_machine: 0028
mod_dumploadinfo: e_version: 00000001
mod_dumploadinfo: e_entry: 000000a9
mod_dumploadinfo: e_phoff: 0
mod_dumploadinfo: e_shoff: 1724
mod_dumploadinfo: e_flags: 05000000
mod_dumploadinfo: e_ehsize: 52
mod_dumploadinfo: e_phentsize: 0
mod_dumploadinfo: e_phnum: 0
mod_dumploadinfo: e_shentsize: 40
mod_dumploadinfo: e_shnum: 12
mod_dumploadinfo: e_shstrndx: 9
modlib_load: loadinfo: 200040ec
modlib_read: Read 480 bytes from offset 1724
modlib_loadfile: Loaded sections:
modlib_read: Read 236 bytes from offset 52
modlib_loadfile: 1. 00000000->20004570
modlib_read: Read 244 bytes from offset 288
modlib_loadfile: 3. 000000ec->2000465c
modlib_read: Read 0 bytes from offset 532
modlib_loadfile: 5. 000001e0->20004750
modlib_loadfile: 6. 000001e0->20004750
mod_dumploadinfo: LOAD_INFO:
mod_dumploadinfo: textalloc: 20004570
mod_dumploadinfo: datastart: 20004750
mod_dumploadinfo: textsize: 480
mod_dumploadinfo: datasize: 0
mod_dumploadinfo: filelen: 2204
mod_dumploadinfo: filfd: 3
mod_dumploadinfo: symtabidx: 0
mod_dumploadinfo: strtabidx: 0
mod_dumploadinfo: ELF Header:
mod_dumploadinfo: e_ident: 7f 45 4c 46
mod_dumploadinfo: e_type: 0001
mod_dumploadinfo: e_machine: 0028
mod_dumploadinfo: e_version: 00000001
mod_dumploadinfo: e_entry: 000000a9
mod_dumploadinfo: e_phoff: 0
mod_dumploadinfo: e_shoff: 1724
mod_dumploadinfo: e_flags: 05000000
mod_dumploadinfo: e_ehsize: 52
mod_dumploadinfo: e_phentsize: 0
mod_dumploadinfo: e_phnum: 0
mod_dumploadinfo: e_shentsize: 40
mod_dumploadinfo: e_shnum: 12
mod_dumploadinfo: e_shstrndx: 9
mod_dumploadinfo: Sections 0:
mod_dumploadinfo: sh_name: 00000000
mod_dumploadinfo: sh_type: 00000000
mod_dumploadinfo: sh_flags: 00000000
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 0
mod_dumploadinfo: sh_size: 0
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 0
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 1:
mod_dumploadinfo: sh_name: 0000001f
mod_dumploadinfo: sh_type: 00000001
mod_dumploadinfo: sh_flags: 00000006
mod_dumploadinfo: sh_addr: 20004570
mod_dumploadinfo: sh_offset: 52
mod_dumploadinfo: sh_size: 236
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 4
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 2:
mod_dumploadinfo: sh_name: 0000001b
mod_dumploadinfo: sh_type: 00000009
mod_dumploadinfo: sh_flags: 00000040
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 1452
mod_dumploadinfo: sh_size: 168
mod_dumploadinfo: sh_link: 10
mod_dumploadinfo: sh_info: 1
mod_dumploadinfo: sh_addralign: 4
mod_dumploadinfo: sh_entsize: 8
mod_dumploadinfo: Sections 3:
mod_dumploadinfo: sh_name: 00000029
mod_dumploadinfo: sh_type: 00000001
mod_dumploadinfo: sh_flags: 00000002
mod_dumploadinfo: sh_addr: 2000465c
mod_dumploadinfo: sh_offset: 288
mod_dumploadinfo: sh_size: 244
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 4
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 4:
mod_dumploadinfo: sh_name: 00000025
mod_dumploadinfo: sh_type: 00000009
mod_dumploadinfo: sh_flags: 00000040
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 1620
mod_dumploadinfo: sh_size: 16
mod_dumploadinfo: sh_link: 10
mod_dumploadinfo: sh_info: 3
mod_dumploadinfo: sh_addralign: 4
mod_dumploadinfo: sh_entsize: 8
mod_dumploadinfo: Sections 5:
mod_dumploadinfo: sh_name: 00000031
mod_dumploadinfo: sh_type: 00000001
mod_dumploadinfo: sh_flags: 00000003
mod_dumploadinfo: sh_addr: 20004750
mod_dumploadinfo: sh_offset: 532
mod_dumploadinfo: sh_size: 0
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 1
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 6:
mod_dumploadinfo: sh_name: 00000037
mod_dumploadinfo: sh_type: 00000008
mod_dumploadinfo: sh_flags: 00000003
mod_dumploadinfo: sh_addr: 20004750
mod_dumploadinfo: sh_offset: 532
mod_dumploadinfo: sh_size: 0
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 1
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 7:
mod_dumploadinfo: sh_name: 0000003c
mod_dumploadinfo: sh_type: 00000001
mod_dumploadinfo: sh_flags: 00000030
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 532
mod_dumploadinfo: sh_size: 50
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 1
mod_dumploadinfo: sh_entsize: 1
mod_dumploadinfo: Sections 8:
mod_dumploadinfo: sh_name: 00000045
mod_dumploadinfo: sh_type: 70000003
mod_dumploadinfo: sh_flags: 00000000
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 582
mod_dumploadinfo: sh_size: 57
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 1
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 9:
mod_dumploadinfo: sh_name: 00000011
mod_dumploadinfo: sh_type: 00000003
mod_dumploadinfo: sh_flags: 00000000
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 1636
mod_dumploadinfo: sh_size: 85
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 1
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 10:
mod_dumploadinfo: sh_name: 00000001
mod_dumploadinfo: sh_type: 00000002
mod_dumploadinfo: sh_flags: 00000000
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 640
mod_dumploadinfo: sh_size: 592
mod_dumploadinfo: sh_link: 11
mod_dumploadinfo: sh_info: 20
mod_dumploadinfo: sh_addralign: 4
mod_dumploadinfo: sh_entsize: 16
mod_dumploadinfo: Sections 11:
mod_dumploadinfo: sh_name: 00000009
mod_dumploadinfo: sh_type: 00000003
mod_dumploadinfo: sh_flags: 00000000
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 1232
mod_dumploadinfo: sh_size: 218
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 1
mod_dumploadinfo: sh_entsize: 0
modlib_bind: INFO: modlib_relocate(modp, loadinfo, 2)
modlib_read: Read 8 bytes from offset 1452
modlib_read: Read 16 bytes from offset 1136
modlib_read: Read 128 bytes from offset 1395
modlib_symvalue: SHN_ABS: name=syslog 00000000+08003219=08003219
up_relocate: Performing ABS32 link at addr=2000458c [00000000] to sym=200040b0 st_value=08003219
modlib_read: Read 8 bytes from offset 1460
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=20004590 [00000044] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1468
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=20004594 [00000065] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1476
modlib_read: Read 16 bytes from offset 976
modlib_read: Read 128 bytes from offset 1286
modlib_symvalue: SHN_ABS: name=lib_dumpbuffer 00000000+0800f2b1=0800f2b1
up_relocate: Performing ABS32 link at addr=20004598 [00000000] to sym=200040b0 st_value=0800f2b1
modlib_read: Read 8 bytes from offset 1484
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=200045d4 [00000000] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1492
modlib_read: Read 16 bytes from offset 1200
modlib_read: Read 128 bytes from offset 1434
modlib_symvalue: SHN_ABS: name=strlen 00000000+080031cd=080031cd
up_relocate: Performing ABS32 link at addr=200045d8 [00000000] to sym=200040b0 st_value=080031cd
modlib_read: Read 8 bytes from offset 1500
modlib_read: Read 16 bytes from offset 1040
modlib_read: Read 128 bytes from offset 1330
modlib_symvalue: SHN_ABS: name=memcpy 00000000+080031dd=080031dd
up_relocate: Performing ABS32 link at addr=200045dc [00000000] to sym=200040b0 st_value=080031dd
modlib_read: Read 8 bytes from offset 1508
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=200045e0 [0000007c] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1516
modlib_read: Read 16 bytes from offset 1136
modlib_read: Read 128 bytes from offset 1395
modlib_symvalue: SHN_ABS: name=syslog 00000000+08003219=08003219
up_relocate: Performing ABS32 link at addr=200045e4 [00000000] to sym=200040b0 st_value=08003219
modlib_read: Read 8 bytes from offset 1524
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=200045e8 [0000009e] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1532
modlib_read: Read 16 bytes from offset 976
modlib_read: Read 128 bytes from offset 1286
modlib_symvalue: SHN_ABS: name=lib_dumpbuffer 00000000+0800f2b1=0800f2b1
up_relocate: Performing ABS32 link at addr=200045ec [00000000] to sym=200040b0 st_value=0800f2b1
modlib_read: Read 8 bytes from offset 1540
modlib_read: Read 16 bytes from offset 1136
modlib_read: Read 128 bytes from offset 1395
modlib_symvalue: SHN_ABS: name=syslog 00000000+08003219=08003219
up_relocate: Performing ABS32 link at addr=20004608 [00000000] to sym=200040b0 st_value=08003219
modlib_read: Read 8 bytes from offset 1548
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=2000460c [000000b6] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1556
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=20004610 [000000d3] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1564
modlib_read: Read 16 bytes from offset 1088
modlib_read: Read 128 bytes from offset 1353
modlib_symvalue: SHN_ABS: name=unregister_driver 00000000+08009363=08009363
up_relocate: Performing ABS32 link at addr=20004614 [00000000] to sym=200040b0 st_value=08009363
modlib_read: Read 8 bytes from offset 1572
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=20004644 [000000e0] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1580
modlib_read: Read 16 bytes from offset 1136
modlib_read: Read 128 bytes from offset 1395
modlib_symvalue: SHN_ABS: name=syslog 00000000+08003219=08003219
up_relocate: Performing ABS32 link at addr=20004648 [00000000] to sym=200040b0 st_value=08003219
modlib_read: Read 8 bytes from offset 1588
modlib_read: Read 16 bytes from offset 784
modlib_symvalue: Other: 00000081+20004570=200045f1
up_relocate: Performing ABS32 link at addr=2000464c [00000000] to sym=200040b0 st_value=200045f1
modlib_read: Read 8 bytes from offset 1596
modlib_read: Read 16 bytes from offset 960
modlib_read: Read 128 bytes from offset 1355
modlib_symvalue: SHN_ABS: name=register_driver 00000000+08009331=08009331
up_relocate: Performing ABS32 link at addr=20004650 [00000000] to sym=200040b0 st_value=08009331
modlib_read: Read 8 bytes from offset 1604
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=20004654 [00000028] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1612
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=20004658 [000000d3] to sym=200040b0 st_value=2000465c
modlib_bind: INFO: modlib_relocate(modp, loadinfo, 4)
modlib_read: Read 8 bytes from offset 1620
modlib_read: Read 16 bytes from offset 736
modlib_symvalue: Other: 0000002d+20004570=2000459d
up_relocate: Performing ABS32 link at addr=2000468c [00000000] to sym=200040b0 st_value=2000459d
modlib_read: Read 8 bytes from offset 1628
modlib_read: Read 16 bytes from offset 688
modlib_symvalue: Other: 00000001+20004570=20004571
up_relocate: Performing ABS32 link at addr=20004690 [00000000] to sym=200040b0 st_value=20004571
module_initialize:
chardev_read: Returning 36 bytes
chardev_read: Returning (20004168):
0000: 48692074686572652c20617070732f65 78616d706c65732f6d6f64756c652074 Hi there, apps/e xamples/module t
0020: 6573740a est.
main: Read 36 bytes: 196
main: Bytes read (20004168):
0000: 48692074686572652c20617070732f65 78616d706c65732f6d6f64756c652074 Hi there, apps/e xamples/module t
0020: 6573740a est.
chardev_write: Writing 27 bytes
chardev_write: Writing (801400f):
0000: 48692074686572652c20696e7374616c 6c6564206472697665720a Hi there, instal led driver.
main: Wrote 27 bytes: 102
main: Bytes written (801400f):
0000: 48692074686572652c20696e7374616c 6c6564206472697665720a Hi there, instal led driver.
module_uninitialize: arg=0
可以看到,这个例子先挂载了一个ramdisk,这个ramdisk里的内容就是chardev的模块文件,接下来挂载了名为chardev
的设备。但是在测试完成后居然卸载了模块!这怎么能行,我要用lsmod
查看模块啊。下面手动挂载模块。
insmod /mnt/romfs/chardev chardev
注意。这里使用的是绝对路径,如果使用相对路径的话会出错。或许是有什么参数没有开启吧。
经过一长串的调试信息后,没有报错。应该是成功了。
nsh>ls /dev
/dev:
chardev
console
null
ram0
timer1
timer2
timer3
timer4
timer5
ttyS0
zero
nsh>lsmod
NAME INIT UNINIT ARG NEXPORTS TEXT SIZE DATA SIZE
chardev 200038c9 200038a1 0 0 20003820 480 20003a00 0
nsh>rmmod chardev
module_uninitialize: arg=0
nsh>ls /dev
/dev:
console
null
ram0
timer1
timer2
timer3
timer4
timer5
ttyS0
zero
nsh>lsmod
NAME INIT UNINIT ARG NEXPORTS TEXT SIZE DATA SIZE
nsh>
完全可以。没有问题。
下来分析这个模块的写法。