字符设备驱动程序

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

假设何操作字符 装备的接口
void cdev_init( struct cdev *, struc t file_operations *);
Linux-2.6
int cdev_add(st ruct cdev *, dev_t, unsigned) ;
字符装备驱动法式根底布局
刊出装备:在模块卸载时挪用 Linux-2.4及之前
unsigned int count;
};
cdev的kobj、 list 、 count字段不消我们关系和保护〔内核代 办〕,我们只需将其ops字段指向为我们本身的file operations 布局。
对cdev布d cdev_init( struct cdev *, struc t file_operations *);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); // ……………………… };
int unregister_chrdev(unsigned int major, const char *name);
Linvuoxid-2c.d6ev_del (struct cdev *);
字符装备驱动法式根底布局
/ /装备驱动模块加载函数 static int __init xxx_init(void) {
struct cdev *cdev_alloc(void) ;
用于初始化cdev的成员, 并创立cdev和
函数用于动态申请一个fcildee_vop内e存rations之间的毗连
int cdev_add(st ruct cdev *, dev_t, unsigned) ; 划分向系统删除一个cdev,
};
file布局体
file布局代表一个掀开的文件,它由内核在利用法式 open时创建,并将该文件所对应的file operations纪 录在file布局中。
在利用法式挪用close函数,内核会释放该数据布局。
struct file {
struct file_operations
*f_op;
unsigned int
装备号的内部表达
装备编号的内部表达 dev_t类型(32位〕: 用来保存装备编号(包孕主装备号(12位)和 次装备号(20位)) 从dev_t取得主装备号和次装备号: MAJOR(dev_t); MINOR(dev_t); 将主装备号和次装备号转换成dev_t类型: MKDEV(int major,int minor);
Linux字符装备驱动法式
Linux驱动法式的分类
字符装备驱动:用于驱动可以或许像字撙节〔文件〕一样被 会见的装备。利用法式凡是可以使用open、close、read、 write等系统挪用会见字符装备驱动。
块装备驱动:块装备和字符装备只在系统内核内部的办理上 有所区分。利用法式对字符装备的每一个I/O操作城市被内 核直接传递给对应的驱动法式;而利用法式对块装备的操作 要经由虚拟文件系统〔VFS〕懈弛冲区办理系统间接地传递 给驱动法式措置。
inode布局体
内核用inode布局在内部暗示文件,用于存储文件会见权限、 属主、组、大年夜小、临盆时候等VFS关心的信息。
其字段中我们只关心i_rdev(装备号),和i_cdev〔和该文件所 对应的cdev布局〕
我们在创建立备文件时,内核会主动创建一个对应的inode布 局体,并将其i_cdev字段指向对应的字符装备布局体cdev(事 前已在内核中注册过)。
字符装备驱动法式根底布局
/*装备驱动模块卸载函数*/ static void __exit xxx_exit(void) {
unregister_chrdev_region(xxx_dev_no, 1); / /释放占用的装备号
unsigned int imajor(struct inode *inode);
从一个inode中取得主装备号和次装备号:
字符装备驱动法式根底布局
注册装备 ,在模块或驱动初始化时挪用 Linux-2.4 及之前
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops)
所要求的一连装 备编号的个数
和该编号局限关 联的装备名称
主装备号与次装备号
动态分派主装备号:
输出的装备号 #include <linux/fs.h> int alloc_chrdev_resion(dev_t *dev,unsigned int firstminor,
unsigned int count,char *name);
{
struct kobject kobj; struct module *owner;
/* 内嵌的kobject 对象 */ /*所属模块*/
struct file_operations *ops; /*文件操作布局体*/
struct list_head list;
dev_t dev;
/*装备号*/
装备文件与装备号
为了体现“一切都是文件”的设计思惟,linux将每一个已安 装的装备都暗示为一个装备文件。
装备文件凡是位于/dev子目录。 对字符装备,利用法式可以使用open、close、read、write
等系统挪用会见其装备文件,这些I/O操作都被直接传递给该 装备文件所对应的装备。 每一个装备文件中都存储了该装备的“主装备号”和“次装 备号”。 一般由同一个内核模块办理的多个装备占用同一个主装备号, 具体装备用次装备号标识。 用mknod filename c major minor号令创建立备文件 用rm filename号令删除装备文件。正视删除装备文件其实不 会影响驱动模块。
f_flags;
fmode_t
f_mode;
loff_t
f_pos;
struct dentry
*f_dentry
void*
private_data;
};
file布局体
file 布局体 file布局: file_operations布局相关的一个布局体。 描写一个正在掀开的装备文件。 成员: loff_t f_pos: 当前读/写位置 unsigned int f_flags 标识文件掀开时,是不是可读或可写 O_RDONLY O_NONBLOCK O_SYNC struct file_operations *f_op
file_operations 布局体
file_operations的重要成员: struct module *owner: 指向模块本身 open:掀开装备 release:关闭装备 read:从装备上读数据 write:向装备上写数据 ioctl:I/O控制函数 llseek:定位读写指针 mmap:映照装备空间到历程的地址空间
利用法式假设何会见装备
fd1 = open(“/dev/ttyS1”, O_RDWR); // 壅塞 fd2 = open(“/dev/ttyS1”, O_RDWR | O_NONBLOCK); // 非壅塞 int read(int fd, const void *buf, size_t length); int write(int fd, const void *buf, size_t length); int lseek(int fd, offset_t offset, int whence); int ioctl( int fd, int cmd, void *arg); int close(int fd);
... cdev_init(&xxx_dev.cdev, &xxx_fops); / /初始化cdev
/ /取得字符装备号 if (xxx_major) {
register_chrdev_region(xxx_dev_no, 1, DEV_NAME); } else {
alloc_chrdev_region(&xxx_dev_no, 0, 1, DEV_NAME); } ret = cdev_add(&xxx_dev.cdev, xxx_dev_no, 1 ) ; / /注册装备 ... }
完成字符装备的刊出,凡是
在模块的卸载函数中挪用 划分向系统添加一个cdev,
void cdev_del(struct cdev *); 完成字符装备的注册,凡是
在模块加载函数中挪用
file_operations 布局体
file_operations 布局体 字符驱动和内核的接口:
在include/linux/fs.h定义 字符驱动只要实现一个file_operations structs布ftirlue_局cot pme体oradtu并iolen*s注o{wn册er; 到内核中,内核就有了操 作此装备的能力。 loff_t (*llseek) (struct file *, loff_t, int);
收集装备驱动:利用法式必需使用套接字(socket)接口会见 收集装备。
收集装备驱动法式
字符装备驱动法式根底布局
字符装备启示的根底步调 一定主装备号和次装备号 实现字符驱动法式 实现file_operations布局体 机关字符装备布局体cdev 在模块加载函数中注册字符装备 在模块卸载函数中刊出字符装备 创建立备文件节点
主装备号与次装备号
分派主装备号
手工分派主装备号:找一个内核没有使用的主装备 #号incl来ude 使<lin用ux/fs。.h>
int register_chrdev_region( dev_t first, unsigned int count, char *name );
要分派的装备编 号局限的肇端值, 次装备号常常为0
Inode与file的区分:file暗示掀开的文件描写符,多个file布局, 可以指向单个inode布局。
struct inode { dev_t i_rdev; struct cdev *i_cdev; // ………………………
};
Inode布局体
Inode布局中的两个重要字段: dev_t i_rdev; 对暗示装备文件的inode布局,该字段包孕了真实的装备 编号。 struct cdev *i_cdev; struct cdev是暗示字符装备的内核的内部布局。 当inode指向一个字符装备文件时,该字段包孕了指向 struuncstigcndeedvin布t im局in的or指(str针uct inode *inode);
file operations的初始化
struct file_operations my_fops = { .owner = THIS_MODULE, .llseek = my_llseek, .read = my_read, .write = my_write, .ioctl = my_ioctl, .open = my_open, .release = my_release,
要使用的被要求的 第一个次装备号
主装备号与次装备号
释放装备号
void unregister_chrdev_region(dev_t first, unsigned int count);
凡是在模块的去 除函数中挪用。
纪录字符装备的布局体cdev
实现字符驱动法式
cdev 布局体
struct cdev
相关文档
最新文档