《驱动学习 - 驱动程序框架简单介绍》

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可以看到已经注册的设备
 
 
 
posted @ 2019-09-24 10:45  一个不知道干嘛的小萌新  阅读(936)  评论(0编辑  收藏  举报