基本驱动模型

应用程序使用驱动:

一个设备驱动其实就是一个内核模块

应用程序使用一个字符设备是通过使用其设备文件来完成的,通过对其设备文件的读写来完成对设备的交互:

 

那么,想要使用字符设备驱动就首先得有一个字符设备文件,创建一个字符设备文件的方式有两种:

 

 

驱动初始化

因为驱动程序是一个内核模块,所以驱动的初始化操作是放在内核模块的初始化函数里:

 

   主要流程如下:

 

下面展示一段示例代码:

 

 

 

 

 

下面来解释一下这段初始化代码中的函数和数据结构:

Struct cdev是用来表示设备的结构体,具体实现如下:

 

其中比较重要的就是其中特殊颜色的几个属性,设备操作集是指一些操作函数。设备号是用来标示设备的。设备数是用来表示同类型的设备一共有几个,这几个设备的主设备号相同,次设备号不同。比如串口1,串口2,它们的主设备号相同,次设备号不同

Cdev有两种分配方式:

 

 

Det_t类型,指的是设备号。实际为32位的无符号整型。这个32位无符号整型包含了两部分,分别是主设备号,和次设备号,它们相互转化的方式为:

 

分配一个设备号的方式有两种:

 

因为设备号是一种资源,所以当驱动退出的时候,应该使用unregister_chrdev_region函数释放掉这个设备号

 

Struct file_operations是一个函数指针的集合,定义的是能在设备上进行的操作,这个结构体里就是各种函数指针,你需要重新给这些函数指针赋值,来重定向各种文件操作。下面是给这个结构体赋值的语句。

 

关于上面那种赋值方式只说明两点:1.无所谓顺序。2.注意下面:

 

  

Cedv_init函数使用来初始化cdev结构体的,主要是为了将操作函数集加入到cdev中。

   

 

  Cdev_add用来向内核注册一个设备:

 

 

实现设备操作:

一般来说:常用的设备操作有以下几个:

v int (*open) (struct inode *, struct file *)打开设备,响应open系统

Open设备方法是驱动程序用来为以后的操作完成初始化准备工作的,在绝大部分驱动程序中,open完成如下工作:

1. 标明设备号。

2. 启动设备

      解释一下其中的比较重要的结构体:

  Struct file,在linux系统中,每一个打开的文件关联一个struct file结构,在内核打开文件的时候创建,在文件关闭后释放。他的重要成员如下:

  

 

      Struct inode,在linux中,每一个存在于文件系统里的文件都会关联一个inode结构(不论有没有打开),该结构主要记录物理信息,主要数据结构如下:

  

  例子程序如下:

  

v int (*release) (struct inode *, struct file *);关闭设备,响应close系统调用

Release方法要做的就是关闭设备。

下面是示例代码:

    

v loff_t (*llseek) (struct file *, loff_t, int)重定位读写指针,响应lseek系统调用

文件当前读写指针重定位:

示例代码:

 

 

v ssize_t (*read) (struct file *, char __user *, size_t, loff_t *)从设备读取数据,响应read系统调用

参数意义如下:

 

 

Read设备方法通常完成两件事情:

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

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

 

示例代码:

 

 

 

 

用一张图说明read函数的工作流程:

 

 

v ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *)向设备写入数据,响应write系统调用

Write设备方法通常完成两件事:

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

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

 

驱动注销:

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

示例代码:





posted @ 2015-11-24 23:38  DChipNau  阅读(422)  评论(0编辑  收藏  举报