zoukankan      html  css  js  c++  java
  • 第三方驱动移植 —— 黑盒移植

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

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

     一、黑盒移植

    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

  • 相关阅读:
    guaguia
    webapp手机移动端开发技巧
    两个数组对象对比
    json 根据某个子,寻找父节点的算法
    递归写法
    数组归类
    视频点击按钮下载
    微信小程序 直接跳转到首页
    iframe 跨域传值
    判断对象是否为空
  • 原文地址:https://www.cnblogs.com/y4247464/p/12359830.html
Copyright © 2011-2022 走看看