首先 是一些 写驱动需要包含的头文件
<pre name="code" class="cpp">#include<linux/init.h> //module_init exit
#include<linux/module.h> //MODULE_LISENCE AUTHOR
#include<linux/fs.h> //file_operations
#include<linux/mm.h>
#include<linux/slab.h>
#include<linux/errno.h>
#include<linux/ioctl.h> //ioctl
#include<linux/cdev.h>
#include<asm/io.h>
#include<mach/map.h>
#include<mach/regs-clock.h>
#include<mach/regs-gpio.h>
#include<mach/gpio-bank-k.h>
a、用字符设备写LED的驱动
struct cdev {
struct kobject kobj; /* 内嵌的 kobject 对象 */
struct module *owner; /*所属模块*/
struct file_operations *ops; /*文件操作结构体*/
struct list_head list;
dev_t dev; /*设备号*/
unsigned int count;
};
步骤:
0、定义cdev结构体
定义cdev 时,可以静态定义或者动态分配
动态分配用 cdev_alloc()
struct cdev *cdev_alloc(void)
1、分配设备号
设备号可以动态分配,也可以静态指定
当静态分配时,使用函数 register_chrdev_region
int register_chrdev_region(dev_t from, unsigned count, const char *name) ;
当动态分配时,使用函数 alloc_chrdev_region
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name) ;
2、cdev_init
void cdev_init(struct cdev *, struct file_operations *);
cdev_init 用于连接cdev和fops的关系
fops 结构体中包含操作设备的 open write read ioctl release 等函数
3、cdev_add
int cdev_add(struct cdev *, dev_t, unsigned);
cdev_add用于关联cdev和dev_no
4、收尾工作
动态分配cdev的注销
void cdev_del(struct cdev *);
动态分配设备号的注销
void unregister_chrdev_region(dev_t from, unsigned count) ;
模块卸载函数中对cdev的卸载
void cdev_del(struct cdev *);
相反地,在调用 cdev_del()函数从系统注销字符设备之后,unregister_chrdev_region()应该被调用以释放原先申请的设备号,这个函数的原型为:
void unregister_chrdev_region(dev_t from, unsigned count) ;
b、用miscdevice驱动写LED程序
miscdevice 本质上还是字符型设备,只是在其上增加了一层封装而已
<pre name="code" class="cpp">struct miscdevice {
int minor;
const char *name;
const struct file_operations *fops;
struct list_head list;
struct device *parent;
struct device *this_device;
};
1、定义miscdevice结构体
struct miscdevice {
int minor;
const char *name;
const struct file_operations *fops;
struct list_head list;
struct device *parent;
struct device *this_device;
};
2、用misc_register()注册
int misc_register(struct miscdevice * misc);
3、用misc_deregister()注销
int misc_deregister(struct miscdevice *misc);
用到的函数原型
<span style="font-size:18px;">对主次设备号的操作函数</span>
MAJOR(dev_t dev)
MINOR(dev_t dev)
MKDEV(int major, int minor)
file_operations 结构
struct file_operations {
struct module *owner;
/* 拥有该结构的模块的指针,一般为 THIS_MODULES */
loff_t( *llseek)(struct file *, loff_t, int);
/* 用来修改文件当前的读写位置 */
ssize_t( *read)(struct file *, char _ _user *, size_t, loff_t*);
/* 从设备中同步读取数据 */
ssize_t( *write)(struct file *, const char _ _user *, size_t, loff_t*);
/* 向设备发送数据*/
ssize_t( *aio_read)(struct kiocb *, char _ _user *, size_t, loff_t);
/* 初始化一个异步的读取操作*/
ssize_t( *aio_write)(struct kiocb *, const char _ _user *, size_t, loff_t);
/* 初始化一个异步的写入操作*/
int( *readdir)(struct file *, void *, filldir_t);
/* 仅用于读取目录,对于设备文件,该字段为 NULL */
unsigned int( *poll)(struct file *, struct poll_table_struct*);
/* 轮询函数,判断目前是否可以进行非阻塞的读取或写入*/
int( *ioctl)(struct inode *, struct file *, unsigned int, unsigned long);
/* 执行设备 I/O 控制命令*/
long( *unlocked_ioctl)(struct file *, unsigned int, unsigned long);
/* 不使用 BLK 的文件系统,将使用此种函数指针代替 ioctl */
long( *compat_ioctl)(struct file *, unsigned int, unsigned long);
/* 在 64 位系统上, 32 位的 ioctl 调用,将使用此函数指针代替*/
int( *mmap)(struct file *, struct vm_area_struct*);
/* 用于请求将设备内存映射到进程地址空间*/
int( *open)(struct inode *, struct file*);
/* 打开 */
int( *flush)(struct file*);
int( *release)(struct inode *, struct file*);
/* 关闭*/
int ( *fsync) (struct file *, struct dentry *, int datasync);
/* 刷新待处理的数据*/
int( *aio_fsync)(struct kiocb *, int datasync);
/* 异步 fsync */
int( *fasync)(int, struct file *, int);
/* 通知设备 FASYNC 标志发生变化*/
int( *lock)(struct file *, int, struct file_lock*);
ssize_t( *sendpage)(struct file *, struct page *, int, size_t, loff_t *, int);
/* 通常为 NULL */
unsigned long( *get_unmapped_area)(struct file *,unsigned long, unsigned long,
unsigned long, unsigned long);
/* 在当前进程地址空间找到一个未映射的内存段 */
int( *check_flags)(int);
/* 允许模块检查传递给 fcntl(F_SETEL...) 调用 的标志 */
int( *dir_notify)(struct file *filp, unsigned long arg);
/* 对文件系统有效,驱动程序不必实现*/
int( *flock)(struct file *, int, struct file_lock*);
ssize_t ( *splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t,
unsigned int); /* 由 VFS 调用,将管道数据粘接到文件 */
ssize_t ( *splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t,
unsigned int); /* 由 VFS 调用,将文件数据粘接到管道 */
int ( *setlease)(struct file *, long, struct file_lock **);
};