嵌入式系统移植之第三方驱动移植

第三方驱动移植流程

  1. 将 fs4412_led_drv.c 保存到 linux-5.4.79/drivers/char 字符驱动文件夹中。
  2. 修改 Makefile
  3. 编译内核,获取uImage文件,
make -j6 ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
mkimage -A arm -O linux -T kernel -C none -a 0x41000000 -e 0x41000040 -n "aaa" -d zImage uImage

观察现象

linux@ubuntu:~/Level10/day6/linux-5.4.79$ make -j6 ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
  CALL    scripts/atomic/check-atomics.sh
  CALL    scripts/checksyscalls.sh
  CHK     include/generated/compile.h
  CC      drivers/char/fs4412_led_drv.o                 //发现已经被编译进去
drivers/char/fs4412_led_drv.c:81:8: warning: return type defaults to 'int' [-Wreturn-type]
  AR      drivers/char/built-in.a
  AR      drivers/built-in.a
  GEN     .version
  CHK     include/generated/compile.h
  UPD     include/generated/compile.h
  CC      init/version.o
  AR      init/built-in.a
  LD      vmlinux.o
  MODPOST vmlinux.o
WARNING: "return_address" [vmlinux] is a static EXPORT_SYMBOL_GPL
  MODINFO modules.builtin.modinfo
  LD      .tmp_vmlinux.kallsyms1
  KSYM    .tmp_vmlinux.kallsyms1.o
  LD      .tmp_vmlinux.kallsyms2
  KSYM    .tmp_vmlinux.kallsyms2.o
  LD      vmlinux
  SORTEX  vmlinux
  SYSMAP  System.map
  Building modules, stage 2.
  MODPOST 105 modules
  OBJCOPY arch/arm/boot/Image
  Kernel: arch/arm/boot/Image is ready
  GZIP    arch/arm/boot/compressed/piggy_data
  AS      arch/arm/boot/compressed/piggy.o
  LD      arch/arm/boot/compressed/vmlinux
  OBJCOPY arch/arm/boot/zImage
  Kernel: arch/arm/boot/zImage is ready

  1. fs4412_led_app.c 交叉编译
arm-none-linux-gnueabi-cc fs4412_led_app.c
  1. 开发板上运行创建字符设备指令
mknod /dev/led c 501 0

  1. 开发板上运行a.out文件,观察结果:
[root@farsight ]# ./a.out
[  301.024579] led_open
[  301.025926] led on ..
open led ok
[  301.127968] led off ..
[  301.228970] led on ..
[  301.329883] led off ..
[  301.430882] led on ..
[  301.531795] led off ..
[  301.632796] led on ..
[  301.733709] led off ..
[  301.834709] led on ..
[  301.935623] led off ..

灯闪烁,运行正常。

图像化配置Kconfig

一般来讲每个文件夹下 都会有一个Makefile 对应一个Kconfig,二者之间必须联动,才能取得想要的效果。

  1. 修改 drivers/char/Kconfig,

  2. 执行命令 ,观察效果

linux@ubuntu:~/Level10/day6/linux-5.4.79$ make menuconfig


发现找到了刚添加进去的led选项,但现在更改此选项内核也不会发生改变,因为没有和Makefile形成联动

  1. 修改 drivers/char/Makefile

  2. 重新编译uImage,观察效果

[root@farsight ]# mknod /dev/led c 501 0
[root@farsight ]# ./a.out
open: No such device or address

取消led选中过后,再次执行,发现led的驱动的确没有编译进内核。

编译驱动为独立的模块

  1. 编译模块 方式1
    独立创建个文件夹,把驱动 和 模块的Makefile复制过去,更改模块的Makefile适配驱动文件。
linux@ubuntu:~/develop/led$ make -j6 ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-

linux@ubuntu:~/develop/led$ ls
fs4412_led_drv.c  fs4412_led_drv.ko  fs4412_led_drv.mod  fs4412_led_drv.mod.c 
fs4412_led_drv.mod.o  fs4412_led_drv.o  Makefile  modules.order  Module.symvers
linux@ubuntu:~/develop/led$ 

fs4412_led_drv.ko文件 就是要的模块文件
  1. 编译模块 方式2
    到linux-5.4.79/drivers/char 目录下,找到 Kconfig 将该驱动模块的属性改成 tristate。
linux@ubuntu:~/Level10/day6/linux-5.4.79/drivers/char$ vim Kconfig

linux@ubuntu:~/Level10/day6/linux-5.4.79$ make modules -j6 ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-

生成.ko模块文件(本方式是驱动放在内核文件夹下的生成.ko文件的方法,也可用 1. 配置为模块方式 中的的形式生成.ko文件)

  1. 加载驱动
[root@farsight ]# insmod fs4412_led_drv.ko
[  140.582962] fs4412_led_drv: loading out-of-tree module taints kernel.
[  140.589011] Led init  5
  1. 运行测试驱动的应用程序
[root@farsight ]# mknod /dev/led c 501 0
[root@farsight ]# ./a.out

黑白盒对比

黑盒移植
  两种方式
    1. 驱动编译进内核
      选则源码目录
      修改Makefile
      修改Kconfig
      
    2. 将驱动编译成独立的模块
      配置为模块方式 通过修改Kconfig
      使用make modules 编译为模块
      装载模块 insmod xxx.ko
      创建设备结点 mknod /dev/xxx c xx xx
      运行测试驱动的应用程序
白盒移植
  需要阅读阅读源码,熟悉驱动框架
  1. 字符设备   2. 平台设备
    字符设备框架

User Mode				||
						    \/
------------------------------------	
				System Call Interface
						      ||
Kernel Mode				\/
			  Virture File System(VFS)
					|      |     |
			  Character Block  Network
					|      |     |
			  Device interface
						      ||
						      \/
--------------------------------------
Hardware		Physical Device (Hardware)
	

字符设备引入

	1.一切设备皆文件
		对设备的操作的就是 对设备文件的 read write
	2. open read write ioctl 
	3. 将设备进行编号 设备号(主次设备号组成)
	字符设备驱动相关
	1. 注册获取设备号
	2. 初始化设备
	3. 操作设备 file_operations		-- open release read write ioctl...
	4. 两个宏定义 module_init  module_exit  两个命令 insmod   rmmod
	5. 注册设备号  register_chrdev_region
	6. cdev_init 初始化字符设备
	7. cdev_add 添加字符设备到系统
	
	驱动是被动调用的,是被应用程序触发的 
	应用程序的 open  调用到驱动的file_operations 的 open
	应用程序的 read  调用到驱动的file_operations 的 read
	应用程序的 write 调用到驱动的file_operations 的 write
	应用程序的 ioctl 调用到驱动的file_operations 的 ioctl
	应用程序的 close 调用到驱动的file_operations 的 release

平台设备引入

	1. 寄存器的地址值是根据芯片手册 和原理图找到的
	2. 对寄存器地址内容操作不能直接使用物理地址,需要ioremap
	3. ioremap 将物理地址 映射到虚拟地址
	4. platform 用于将硬件信息 和驱动代码做分离
	5. 通过名字匹配,匹配成功执行 probe函数
	6. 驱动通过 platform_get_resource 获取硬件设备资源
	7. 作用 容易维护