linux设备模型的inode,cdev,kobj_map,char_device_struct

Char Device Driver

  相关数据结构:

  

struct cdev {

  struct kobject kobj;

  struct module *owner;

  const struct file_operations *ops;

  struct list_head list;

  dev_t dev;

  unsigned int count;

  };

 

 struct kobj_map {

  struct probe {

  struct probe *next;

  dev_t dev;

  unsigned long range;

  struct module *owner;

  kobj_probe_t *get;

  int (*lock)(dev_t, void *);

  void *data;

  } *probes[255];

  struct mutex *lock;

  };

  

static struct char_device_struct {

  struct char_device_struct *next;

  unsigned int major;

  unsigned int baseminor;

  int minorct;

  char name[64];

  struct file_operations *fops;

  struct cdev*cdev;               

  } *chrdevs[CHRDEV_MAJOR_HASH_SIZE];

  #defineCHRDEV_MAJOR_HASH_SIZE       255

  下面本文通过一下三个方面以及他们的关联来描述字符设备驱动:

  1. 字符驱动模型

  2. 字符设备的设备号

  3. 文件系统中对字符设备文件的访问

  1. 字符驱动模型

  每个字符驱动由一个 cdev 结构来表示.

  在设备驱动模型(device driver model)中, 使用 (kobject mapping domain)来记录字符设备驱动.

  这是由 struct kobj_map 结构来表示的. 它内嵌了255个struct probe指针数组

  kobj_map由全局变量 cdev_map 引用: static struct kobj_map*cdev_map;

点击查看原始尺寸

  相关函数说明:

  cdev_alloc() 用来创建一个cdev的对象

  cdev_add() 用来将cdev对象添加到驱动模型中,其主要是通过kobj_map()来实现的.

  kobj_map()会创建一个probe对象,然后将其插入cdev_map中的某一项中,并关联probe->data 指向cdev

  struct kobject *kobj_lookup(struct kobj_map *domain, dev_tdev, int *index)

  根据设备号,在cdev_map中查找其cdev对象内嵌的kobject.(probe->data->kobj),返回的是cdev的kobject


2. 字符设备的设备号

  字符设备的主,次设备号的分配:

  全局数组 chrdevs 包含了255(CHRDEV_MAJOR_HASH_SIZE 的值)个 structchar_device_struct的元素.

  每一个对应一个相应的主设备号.

  如果分配了一个设备号,就会创建一个 struct char_device_struct 的对象,并将其添加到 chrdevs中.

  这样,通过chrdevs数组,我们就可以知道分配了哪些设备号.

点击查看原始尺寸

  相关函数:

  register_chrdev_region( ) 分配指定的设备号范围

  alloc_chrdev_region( ) 动态分配设备范围

  他们都主要是通过调用函数__register_chrdev_region() 来实现的

  要注意,这两个函数仅仅是注册设备号! 如果要和cdev关联起来(即要将设备添加到字符设备数据库),还要调用cdev_add()

  register_chrdev( ) 申请指定的设备号,并且将其注册到字符设备驱动模型中.

  它所做的事情为:

  1. 注册设备号, 通过调用 __register_chrdev_region() 来实现

  2. 分配一个cdev, 通过调用 cdev_alloc() 来实现

  3. 将cdev添加到驱动模型中, 这一步将设备号和驱动关联了起来. 通过调用 cdev_add() 来实现

  4. 将第一步中创建的 struct char_device_struct 对象的 cdev 指向第二步中分配的cdev.由于register_chrdev()是老的接口,这一步在新的接口中并不需要.

  3. 文件系统中对字符设备文件的访问

  对于一个字符设备文件, 其inode->i_cdev 指向字符驱动对象cdev,如果i_cdev为 NULL ,则说明该设备文件没有被打开.

  由于多个设备可以共用同一个驱动程序.所以,通过字符设备的inode 中的i_devices 和cdev中的list组成一个链表

点击查看原始尺寸

  首先,系统调用open打开一个字符设备的时候, 通过一系列调用,最终会执行到 chrdev_open.

  (最终是通过调用到def_chr_fops中的.open, 而def_chr_fops.open =chrdev_open. 这一系列的调用过程,本文暂不讨论)

  int chrdev_open(struct inode * inode, struct file * filp)

  chrdev_open()所做的事情可以概括如下:

  1. 根据设备号(inode->i_rdev), 在字符设备驱动模型中查找对应的驱动程序,这通过kobj_lookup() 来实现, kobj_lookup()会返回对应驱动程序cdev的kobject.

  2. 设置inode->i_cdev , 指向找到的cdev.

  3. 将inode添加到cdev->list的链表中.

  4. 使用cdev的ops 设置file对象的f_op

  5. 如果ops中定义了open方法,则调用该open方法

  6. 返回.

  执行完 chrdev_open()之后,file对象的f_op指向cdev的ops,因而之后对设备进行的read,write等操作,就会执行cdev的相应操作.


#######################################################################################################################


设备文件并不关联到硬盘或其他存储介质上的数据段,而是建立了与某个设备驱动程序的连接,以支持与扩展设备的通信。

设备并不是通过文件名来标识,而是通过文件的主、从设备号标识。这些号码在文件系统中作为特别的文件属性管理。

在打开一个设备文件时,内核会为块设备或字符设备文件创建一个inode。

假定表示设备文件的inode此前没有打开过。根据给出的设备号,kobject_lookup查询字符设备的数据库(全局数组 chrdevs),并返回与该驱动程序关联的kobject实例。该返回值可用于获取cdev实例。获得了对应设备文件的cdev实例,内核通过cdev-ops还可以访问特定于设备的file_operations。inode->i_cdev指向所选择的cdev实例。在下一次打开该inode时,就不必再查询字符设备的数据库,因为我们可以使用缓存中的值。



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值