zoukankan      html  css  js  c++  java
  • 《驱动学习

    1.驱动简单架构
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/miscdevice.h>
    #include <linux/fs.h>
    #include <linux/types.h>
    #include <linux/moduleparam.h>
    #include <linux/slab.h>
    #include <linux/ioctl.h>
    #include <linux/cdev.h>
    #include <linux/delay.h>
     
    #include <linux/gpio.h>
    #include <mach/gpio.h>
    #include <plat/gpio-cfg.h>
    
    #define major  111   //当major设置为0的时候,就是让系统自动分配
    static struct class *
    static int first_drv_open(struct inode *inode, struct file *file)
    {
     return 0;
    }
    
    static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
    {
     return 0;
    }
    
    static struct file_operations first_drv_fops = {
     .owner   = THIS_MODULE,
     .open   = first_drv_open,
     .write   = first_drv_write,
    };
    static int __init first_drv_init(void)
    {
     //major是主设备号     ,"first_drv"就是注册的名字
     register_chrdev(major, "first_drv", &first_drv_fops);
     return 0;
    }
    
    static void first_drv_exit(void)
    {
     unregister_chrdev(major, "first_drv");
    }
    
    module_init(first_drv_init);
    module_exit(first_drv_exit);
    MODULE_LICENSE("GPL");

    register_chrdev函数解释:

      register_chrdev会在内核中找到一个数组chrdev,然后在这个数组里面,以major为索引,将file_operations填充进去。这样应用程序就可以直接open("/dev/led"),来找到该设备的设备号,然后根据设备号找到对应的file_operations去执行对应的open函数。

     
    应用程序怎么通过open("/dev/xxx","")找到相对应的设备函数?
      应用程序:open("/dev/xxx","")
         获取/dev/xxx的属性,比如字符型c,获取主设备号
            通过C库进入到内核中
               在VFS中(待确认,以及什么是虚拟文件系统)通过c找到chrdev,再通过主设备号找到对应的file_operation
                  通过file_operation找到对应的xxx_open,xxx_write等等
     
    那么驱动程序这边应该怎么做才能让应用程序找到自己?
      在驱动程序中:编写xxx_open,xxx_write等等
        定义一个file_operation结构体变量
          将编写好的xxx_open,xxx_write等等初始化到定义的结构体变量中
            将file_operation结构体通过register_chrdev函数注册到内核中
    通过以上两个就能很直观的理解,应用程序是怎么找到相对应的驱动程序,驱动程序是怎么编写让应用程序可以找到。
     
    主设备号怎么设置?
      1.主设备号可以通过我们register_chrdev(111, "first_drv", &first_drv_fops)这样固定去设置。可以先通过cat /proc/devices查看已经有哪些主设备号被注册,然后选择没有被注册的。
      2.major=register_chrdev(0, "first_drv", &first_drv_fops),将register_chrdev函数的第一个参数设置为0。那么系统会自动帮你分配一个主设备号major。
     
     
    那么就有一个问题/dev/xxx是怎么创建的?
     1.mknod /dev/xxx c 主设备号  次设备号(在开发板中进行mknod,而且这个时候需要知道设置的主设备号,还需要在开发板上面进行查看)
     2.自动创建mkdev(根据系统信息创建设备节点,因为驱动程序加载的时候,就会在/sys里面生成信息
      cd /sys/class
      进入我们创建的比如firstdrv,里面假如有个xyz,
      cd  xyz
         cat dev
      就可以看到主设备号和次设备号,mdev根据这个信息创建设备节点
     
    那么怎么生成系统信息?
      static struct class *firstdrv_class;
      static struct class_device *firstdrv_class_dev;
      int major;
    
    static int first_drv_init(void)
    {
      major = register_chrdev(0, "first_drv", &first_drv_fops); // 注册, 告诉内核
      firstdrv_class = class_create(THIS_MODULE, "firstdrv");
      firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */
      gpbcon = (volatile unsigned long *)ioremap(0x56000010, 16);
      gpbdat = gpbcon + 1;
      return 0;
    }
    
    static void first_drv_exit(void)
    {
      unregister_chrdev(major, "first_drv"); // 卸载
      class_device_unregister(firstdrv_class_dev);
      class_destroy(firstdrv_class);
      iounmap(gpbcon);
    }

      class_create和class_device_create,就会在/sys/class中生成一个firstdrv文件,里面会有一个xyz文件。

      MKDEV会根据这个系统信息去创建一个/dev/xyz的设备节点。

    问题:为什么一旦卸载驱动程序然后再insmod,mdev可以里面又创建新的设备节点
         因为在rcs脚本中我们定义了ech0 /sbin/mdev >/proc/sys/kernel/hotplug

    注意:register_chrdev函数的第二个参数,在后面使用设备树的时候有用。因为设备树通过这个参数一致名字
     
    在开发板中cat /proc/devices可以看到已经注册的设备
     
     
     
  • 相关阅读:
    php json_decode无法处理解决方法
    jquery ajax怎么使用jsonp跨域访问
    jquery ajax怎么使用jsonp跨域访问
    查看xml源码的方法
    php array_push 与 $arr[]=$value 性能比较
    生成个性二维码方法
    PHP匿名函数的写法
    PHP rand和mt_rand 区别
    C++ 顺序表
    线索树的建立与遍历
  • 原文地址:https://www.cnblogs.com/zhuangquan/p/11576995.html
Copyright © 2011-2022 走看看