作者:韦凯孟强志宪 | 来源:互联网 | 2023-09-13 16:48
篇首语:本文由编程笔记#小编为大家整理,主要介绍了第三方驱动移植——黑盒移植相关的知识,希望对你有一定的参考价值。黑盒移植,即在不用理解驱动程序的细节基础上进行移植
篇首语:本文由编程笔记#小编为大家整理,主要介绍了第三方驱动移植 —— 黑盒移植相关的知识,希望对你有一定的参考价值。
黑盒移植,即在不用理解驱动程序的细节基础上进行移植
驱动移植的主要流程如下:
一、黑盒移植
1、将驱动编译进内核
如果内核中已经有了已经支持的驱动,那直接在menu上选配即可。若没有,则需要第三方的驱动或者自己写一个驱动,移植进内核。
1)将第三方驱动放到linux源码的driver目录中
拷贝LED驱动程序至drivers目录
LED属于字符设备,所以放在drivers/char/
目录下
2)修改Makefile让驱动编译进内核(对应目录下的Makefile)
make uImage编译内核
3)测试·驱动
烧写镜像到开发板
在ubuntu上编译驱动程序测试代码, 并拷贝到根文件系统
1 #include
2 #include
3 #include
4 #include
5 #include
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
");
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
2 #include
3 #include
4 #include
5 #include
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
");
28
29
30 ledcon = ioremap(LED_CON, 4);
31 if(ledcon == NULL) {
32 printk("ioremap LED_CON error
");
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
");
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
");
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 ..
");
60 writel(1, leddat); //设置LED3 GPX1_0 输出高电平
61 break;
62 case LED_OFF:
63 printk("led off ..
");
64 writel(0, leddat); //设置LED3 GPX1_0 输出高电平
65 break;
66 default:
67 printk("no command
");
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
");
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
");
95 return -1;
96 }
97
98 printk("Led init 5
");
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
");
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