【11】Linux-字符驱动编程模型

来源:互联网 发布:织梦cms 首页轮播 编辑:程序博客网 时间:2024/04/30 01:40

Linux-字符驱动编程模型

内核驱动,实际上就是如何去通过内核模块使得设备工作起来的过程。

驱动设备的基础知识介绍

1.在任何一种驱动模型中,设备都会用内核中的一种结构来描述,字符设备在内核中使用struct cdev来描述 。

struct cdev {

struct kobject kobj;

struct module *owner;

const struct file_operations *ops; //字符设备的函数映射

struct list_head list;

dev_t dev; //设备号包括主设备号和次设备号

unsigned int count; //设备数目

};

2.描述结构的分配

a) 静态分配:struct cdev mdev;

b) 动态分配:struct cdev *pdev = cdev_alloc();

3.字符设备文件是通过主设备号来与驱动程序建立对应关系的

4.驱动程序是通过设备的次设备号来区分不同设备的

5.Linux内核中使用dev_t【unsigned int】类型来定义设备号,其中高12位主设备号低20位次设备号

5-1.dev_t dev = MKDEV(主设备号, 次设备号),将主设备号和次设备号组合成dev_t

5-2.主设备号 = MAJOR(dev_t dev),从dev_t中分解出主设备号

5-3.次设备号 = MINOR(dev_t dev),从dev_t中分解出次设备号

6.分配主设备号

6-1.静态申请,选择一个数字作为主设备号,之后通过函数register_chrdev_region 向内核申请使用。缺点:如果申请使用的设备号已经被内核中的其他驱动使用了,则申 请失败

6-2.动态分配,使用alloc_chrdev_region由内核分配一个可用的主设备号。优点:因 为内核知道哪些号已经被使用了,所以不会导致分配到已经被使用的号。

7.注销设备号

在驱动退出时,使用unregister_chrdev_region函数来释放这些设备号。

8.函数操作集(file_operations)

使用struct file_opertations来表示能在设备上进行的操作,结构中的函数指针指向驱动中的函数,这些函数实现一个针对设备的操作,对于不支持的操作则设置函数指针为NULL。

eg:

static const struct file_operations mem_fops =

{

  .llseek = mem_llseek,

  .read = mem_read,

  .write = mem_write,

  .open = mem_open,

  .release = mem_release,

};

9.每一个打开的文件,在内核中都会关联一个struct file,由内核在打开文件时创建,在文件关闭后释放。

重要成员:

loff_t f_ops /*文件读写指针*/

struct file_operations *f_op /*该文件所对应的操作*/

10.每一个存在于文件系统里面的文件都会关联一个inode结构,该结构主要用来记录文件物理上的信息。一个文件没有被打开时不会关联file结构,但是却会关联一个inode结构

重要成员:

dev_t i_rdev :设备号

11.源于用户空间的指针,不能被内核代码直接饮用,必须使用专门的函数

int copy_from_user(void *to, const void __user *from, int n)

int copy_to_user(void __user *to, const void *from, int n)

1.驱动初始化

a)分配设备描述结构

i. 静态分配:struct cdev mdev;

动态分配:struct cdev *pdev = cdev_alloc();

b)初始化设备描述结构

i. cdev_init(struct cdev *cdev, const struct file_operation *fops)

参数:

cdev:待初始化的cdev结构

fops:设备对应的操作函数集

c)注册设备描述结构

i. cdev_add(struct cdev *p, dev_t dev, unsigned count)

参数:

p:待添加到内核的字符设备结构

dev:设备号

count:该类设备的设备个数

d)硬件初始化

2.实现设备操作

实际上就是应用程序对设备进行操作时,设备所对应的操作。

1.int (*open) (struct inode *, struct file *);

打开设备,对应open函数,完成如下工作:

标明次设备号

启动设备

2.int (*release) (struct inode *, struct file *);

关闭设备,相应close系统调用,完成如下工作:

关闭设备

3.loff_t (*llseek)(struct file*, loff_t, int);

重定位读写指针,相应lseek系统调用

4.ssize_t (*read)(struct file *, char __user*, size_t, loff_t *);

从设备读取数据,相应read系统调用,完成如下工作:

从设备中读取数据(属于硬件访问类操作)

将读取到的数据返回给应用程序

参数分析:

struct file *:与字符设备文件关联的file结构指针,由内核创建

char __user*:从设备读取到的数据,需要保存到的位置。由read系统调用提供该参数。处于用户空间

count:请求传输的数据量,由read系统调用提供该参数,属于用户空间

offp:文件的读写位置,由内核从file结构中取出后,传递进来

 

5.ssize_t (*write)(struct file *, const char __user*, size_t, loff_t *);

向设备写入数据,相应write系统调用,完成工作如下

从应用程序提供的地址中取出数据

将数据写入设备(属于硬件访问类操作)

6.当从内核中卸载驱动程序时,需要用cdev_del函数来完成字符设备的注销

0 0
原创粉丝点击