第三方驱动移植 —— 黑盒移植

Posted y4247464

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第三方驱动移植 —— 黑盒移植相关的知识,希望对你有一定的参考价值。

黑盒移植,即在不用理解驱动程序的细节基础上进行移植

驱动移植的主要流程如下:

技术图片

 一、黑盒移植

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
");
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
");
 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

 

以上是关于第三方驱动移植 —— 黑盒移植的主要内容,如果未能解决你的问题,请参考以下文章

安卓rom移植到底是啥意思?

X210开发板(S5PV210芯片)uboot移植DM9000驱动移植

如何使用片段反向移植?

Linux-2.6.39在Tiny6410上的移植 - 外设驱动移植

卡住了从活动到片段的移植

INA219驱动,基于STM32(STM8移植可用)