黑盒移植,即在不用理解驱动程序的细节基础上进行移植
驱动移植的主要流程如下:
一、黑盒移植
1、将驱动编译进内核
如果内核中已经有了已经支持的驱动,那直接在menu上选配即可。若没有,则需要第三方的驱动或者自己写一个驱动,移植进内核。
1)将第三方驱动放到linux源码的driver目录中
拷贝LED驱动程序至drivers目录
LED属于字符设备,所以放在drivers/char/
目录下
2)修改Makefile让驱动编译进内核(对应目录下的Makefile)
make uImage编译内核
3)测试·驱动
烧写镜像到开发板
在ubuntu上编译驱动程序测试代码, 并拷贝到根文件系统
1 #include <stdio.h> 2 #include <fcntl.h> 3 #include <unistd.h> 4 #include <stdlib.h> 5 #include <sys/ioctl.h> 6 7 #define LED_MAGIC ‘L‘ 8 #define LED_ON _IOW(LED_MAGIC, 1, int) 9 #define LED_OFF _IOW(LED_MAGIC, 2, int) 10 11 int main(int argc, char **argv) 12 { 13 int fd; 14 15 fd = open("/dev/led", O_RDWR); 16 if (fd < 0) { 17 perror("open"); 18 exit(1); 19 } 20 21 printf("open led ok\n"); 22 23 //实现LED灯闪烁 24 while(1) 25 { 26 ioctl(fd, LED_ON); //点亮灯 27 usleep(100000); 28 ioctl(fd, LED_OFF); //灭灯 29 usleep(100000); 30 } 31 32 return 0; 33 }
fs4412_app.c
在板子上运行app.c,测试驱动
报错,看到app.c
得知,需要创建设备文件
4)创建设备文件
在fs4412_led_drv.c中,获取设备号
501为主设备号,0为次设备号
在板子上创建设备文件
mknod /dev/led c 501 0
再次执行,可以发现LED灯闪烁并相应输出打印信息
二、通过配置Kconfig来添加驱动
如果在实际开发中都像以上方法一样,手动添加驱动到文件夹,修改Makefile,不想加载驱动的时候又从相应文件中删除,那么当驱动数量很多时,会十分的繁杂。所以可以通过在配置Kconfig在图形界面中,添减驱动。
1)在Kconfig中添加一个led设备驱动
进入对于子目录下的Kconfig
make menuconfig
打开帮助信息
可以看到相关驱动已经在图形界面里了
2)修改Makefile
将原来的信息注释,添加配置项
3)在图形界面选择不编译进内核,测试一下
4)编译测试
make menuconfig
在编译界面没有看到fs4412_led_drv.o编译进来,再到板子上看看
led驱动确实没有编译进内核。
3、编译驱动为独立模块
在前面使用了两者方法来加载驱动,但是这两种方法都是通过在内核目录里添加文件,在对应目录下修改Makefile和Kconfig。这样对于新增的驱动并不好管理。因此我们可以单独创建一个目录,目录可以在任意位置,内核外,把要载入的驱动独立出来。如何实现?
1)配置为模块方法
在内核外单独编译驱动模块
创建目录,
1 #include <linux/kernel.h> 2 #include <linux/module.h> 3 #include <linux/fs.h> 4 #include <linux/cdev.h> 5 #include <asm/io.h> 6 7 8 #define LED_MAGIC ‘L‘ 9 #define LED_ON _IOW(LED_MAGIC, 1, int) 10 #define LED_OFF _IOW(LED_MAGIC, 2, int) 11 12 #define LED_MA 501 13 #define LED_MI 0 14 #define LED_NUM 1 15 16 #define LED_CON 0x11000C20 17 #define LED_DAT 0x11000C24 18 19 20 struct cdev cdev; 21 22 unsigned int *ledcon; 23 unsigned int *leddat; 24 25 int led_open (struct inode *inode, struct file *file) 26 { 27 printk("led_open\n"); 28 29 30 ledcon = ioremap(LED_CON, 4); 31 if(ledcon == NULL) { 32 printk("ioremap LED_CON error\n"); 33 return -1; 34 } 35 writel(0x01, ledcon); //设置LED3 GPX1_0 为输出模式 36 37 38 leddat = ioremap(LED_DAT, 4); 39 if(leddat == NULL) { 40 printk("ioremap LED_DAT error\n"); 41 return -1; 42 } 43 writel(1, leddat); //设置LED3 GPX1_0 输出高电平 44 45 return 0; 46 } 47 48 int led_release(struct inode *inode, struct file *file) 49 { 50 printk("led_close\n"); 51 return 0; 52 } 53 54 long led_ioctl(struct file *file, unsigned int cmd, unsigned long args) 55 { 56 switch(cmd) 57 { 58 case LED_ON: 59 printk("led on ..\n"); 60 writel(1, leddat); //设置LED3 GPX1_0 输出高电平 61 break; 62 case LED_OFF: 63 printk("led off ..\n"); 64 writel(0, leddat); //设置LED3 GPX1_0 输出高电平 65 break; 66 default: 67 printk("no command\n"); 68 break; 69 } 70 return 0; 71 } 72 73 74 struct file_operations led_fops = { //文件操作 75 .owner = THIS_MODULE, 76 .open = led_open, 77 .release =led_release, 78 .unlocked_ioctl = led_ioctl, 79 }; 80 81 static led_init(void) 82 { 83 int ret; 84 dev_t devno = MKDEV(LED_MA, LED_MI); 85 ret= register_chrdev_region(devno, LED_NUM, "newled"); //注册设备号 86 if(ret) { 87 printk("register_chrdev_region error\n"); 88 return -1; 89 } 90 91 cdev_init(&cdev, &led_fops); //初始化字符设备 92 ret = cdev_add(&cdev, devno, LED_NUM); //添加字符设备到系统中 93 if (ret < 0) { 94 printk("cdev_add error\n"); 95 return -1; 96 } 97 98 printk("Led init 5 \n"); 99 return 0; 100 } 101 102 static void led_exit(void) 103 { 104 dev_t devno = MKDEV(LED_MA, LED_MI); 105 cdev_del(&cdev); 106 unregister_chrdev_region(devno, LED_NUM); //取消注册 107 printk("Led exit\n"); 108 } 109 110 module_init(led_init); 111 module_exit(led_exit); 112 MODULE_LICENSE("Dual BSD/GPL");
fs4412_led_drv.c
1 ifeq ($(KERNELRELEASE),) 2 KERNELDIR ?= /home/linux/kernel/linux-3.14-fs4412 3 PWD := $(shell pwd) 4 5 all: 6 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 7 8 clean: 9 $(MAKE) -C $(KERNELDIR) M=$(PWD) clean 10 rm -rf a.out 11 12 else 13 obj-m := fs4412_led_drv.o 14 endif
Makefile
2)make 编译出ko模块
make之后(Makefile里面将module附加到了make命令后,所以直接make就好了),会自动跳到内核里面,借用内核的Makefile把当前驱动程序编译成ko文件,拷贝到根文件系统
在内核中的Kconfig,配置驱动为模块方式编译进内核
将配置项改为tristate后可以选择编译为模块
4)编译所有模块 make modules
编译模块不需要重新编译内核,make module即可。
会生成以上两个文件,这个ko文件和之前单独在led目录里面make出来的ko是相同的,只是编译的环境不一样而已。选择一个拷贝到nfs即可。
5)插入模块
转到ko文件所在目录下
insmod fs4412_led_drv.ko
创建设备节点(应用访问驱动的入口)
mknod /dev/led c 501 0
6)运行测试驱动的应用程序
./a.out
参考博客:
https://blog.csdn.net/m0_37542524/article/details/86476109
原文地址:https://www.cnblogs.com/y4247464/p/12359830.html