Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1255183
  • 博文数量: 404
  • 博客积分: 10011
  • 博客等级: 上将
  • 技术积分: 5382
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-03 16:29
文章存档

2010年(40)

2009年(140)

2008年(224)

我的朋友

分类: LINUX

2008-09-08 12:31:52

字符设备驱动

  

 1. 主设备号和次设备号.

      1.介绍

对字符设备的访问是通过文件系统内的设备文件进行的. 这些文件位于/dev.

设备通过设备号来标识:

主设备号: 标识设备对应的驱动程序.在linux里,允许多个驱动程序共用一个主设备号. 

次设备号:  用于确定设备文所指的设备.

在内核中,用dev_t类型>保存设备号.定义在

2.4 kernel 采用16位设备号(8 bit 主,8 bit 次);

2.6 kernel 采用 32位设备号(12 bit 主,20 bit 次);

在驱动程序中访问设备号应用中的宏:

MAJOR(dev_t dev);

MINOR(dev_t dev);

MKDEV(int major,int minor);

      2. 分配.释放设备编号

在建立设备前,应先获的设备号.

分配:

 #include 

Int register_chrdev_region(dev_t first,unsigned int count,char *name)

First :要分配的设备编号范围的初始值(次设备号常设为0);

Count:连续编号范围.

Name:编号相关联的设备名称. (/proc/devices);

动态分配:

Int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);

Firstminor : 通常为0;

*dev:存放返回的设备号;

释放:

Void unregist_chrdev_region(dev_t first,unsigned int count);

调用Documentation/devices.txt中可以找到已经分配的设备号.

      3. 建立设备文件:

当设备驱动模块申请了主设备号,次设备号,并insmod 加载到内核中后.就可以在/dev下创建     设备了:

Mknod /dev/mychar c major minor

    2. 字符设备的基本数据结构

     3个基本的数据结构file,file_operations,inode 都定义在

1.file_operations 数据结构

结构中包含了若干涵数指针.用户空间调用的open,write 等涵数,最终会调用到结构中的指针所指向的涵数.

2.6内核初始化:

Struct file_operations my_fops = {

.owner  = THIS_MODULE,

.llseek  = my_llseek,

.read   = my_read, .....

    }

2.4内核初始化:

Struct file_operations my_fops = {

Owner: THIS_MODELE,

Llseek:my_llseek,

....

}

2.File 结构 

 File 是一个内核结构体,和用户open一个文件后返回的文件描述符fd相对应.内核在open时 建file结构,并传递给该文件上进行操作的所有涵数,直到close,kernel释放这个结构.

 结构中主要成员有:

 Mode_t f_mode;  通过FMODE_READ,FMODE_WRITE标示文件是否可读可写.

 Loff_t f_pos; 当前读写位置.Loff_t为64位.

 Unsigned int f_flags: 文件标志.如O_RDONLY,O_NONBLOCK..... 

 Struct  file_operations *f_op; 与文件相关的操作.内核在执行open时对指针赋值.可以在驱动  open方法中根据次设备号赋予不同的f_op;

 Void * private; 通常表示硬件设备结构体.

 Struct denty *f_dentry; 文件对应的目录项结构.可通过filp->f_dentry->d_inode访问索引节点.

    3.inode 结构 < linux/fs.h >

 内核用inode结构描述一个实际的文件,可以是普通文件,也可以是设备文件.每个文件只有一 个inode结构,而和文件描述符对应的file结构可以有多个.这些file结构指向同一个inode结 构.

 结构成员有:

 Dev_t i_rdev; 设备文件的inode结构,包含真正的设备编号.

Struct cdev *i_cdev; 字符设备的内核结构.

下面的宏从inode获取设备号:

Unsigned int iminor(struct inode *inode);

Unsigned int imajor(struct inode *inode);

3.字符设备的注册和注销

内核中使用cdev 结构来表示一个字符设备。

注册步骤:

1. 在设备结构中加入cdev 

Struct scull_dev {

 .

 Struct cdev cdev;

   }

2.初始化

  Void cdev_init(strcut cdev *cdev,struct file_operations *fops);

3. 设定cdev中的内容

Dev->cdev.owner = THIS_MODULE;

Dev->cdev.ops = &scull_fops;

向内核中添加设定好的cdev

Int cdev_add(struct cdev *dev,dev_t num,unsigned int count);

Num:设备对应的第一个编号。

Count :和设备关联的设备编号的数量。常取1

一旦cdev_add  返回,内核就认为设备可以用了。所以在调用之前完成设备的硬件初始化。

老式的注册和注销函数

2.4kerner

注册:

Int register_chrdev(unsigned int major,const char *name,struct file_operations *fops)

采用用户指定的主设备号major注册。Major 为0 时,向内核动态分配主设备号。0255 作为次设备号,并为每个设备建立对应的cdev结构。

注销:

Int unregister_chrdev(unsigned int major,const char *name);

4.设备的open and release

 1 open

 驱动在open方法中完成对硬件(设备)的初始化工作,完成后,用户程序就可以通过write访问设备了。

 完成的工作有:

  检查设备的特定错误

  如果设备首次打开,则对其初始化

  如果有必要,更新f_op指针

  分配并填写filp->private_data中的数据

Int (*open) ( struct inode * inode,struct file *filp):

在open 中通过inode 获得dev指针,并将其赋给file->private_data。如:(动态分配)

 Struct scull_dev *dev;

 Dev = contain_of(inode->i_cdev,struct scull_dev,cdev);

 Filp->private_data = dev;

如果是静态分配的,则open or write 可以直接访问dev.

 2 release

  当file的计数器为0时。通过close 调用release ,释放 dev结构。否则用close 关闭。

5. read and write

read and write 是驱动中完成从用户空间copy 数据到内核,或是从内核到用户空间的工作。

Ssize_t read(struct file *filp,char  __user *buff,size_f count,loff_t *offp);

Ssize_t write(struct file *filp,const char __user *buff, size_t count,loff_t *offp);

Buff : 用户空间的缓冲区指针。

Offp: 用户在文件中进行存取操作的位置。

在read and write 中,copy data 后,应更新offp.

内核和用户空间交换数据函数:

内核到用户:

Unsigned long copy_to_user(void __user *to,const void *from,unsigned long count);

用户到内核

Unsigned long copy_from_user(void *to,const void __user *from,unsigned long count);

向用户空间copy data:    字节数由sizeof(*ptr)决定,成功返回0,负为错误。

Int put_user(datum,ptr)

从用户空间获得数据:  字节数由sizeof(*ptr)决定,

Int get_user(local,ptr)

 

阅读(700) | 评论(0) | 转发(0) |
0

上一篇:kernel api(转载)

下一篇:ERROR(转载)

给主人留下些什么吧!~~