////////字符设备驱动//////////
1. 申请设备号
2. 定义一个cdev的设备驱动对象
| struct cdev mycdev; //定义一个file_operations的文件操作对象 struct file_operations fops = { .owner = THIS_MODULE, .read = 读函数 .... }; |
3. 把fops对象与mycdev关联起来
| cdev_init(&mycdev, &fops); //mycdev.ops = &fops; mycdev.owner = THIS_MODULE; |
4. 把设备驱动加入内核里, 并指定该驱动对应的设备号
cdev_add(&mycdev, 设备号, 次设备号的个数);
5. 卸载模块时, 要把设备驱动从内核里移除, 并把设备号反注册
| cdev_del(&mycdev); ///////////创建设备文件 mknod /dev/设备文件名 c 主设备号 次设备号 ////////inode节点对象描述一个文件/设备文件, 包括权限,设备号等信息 struct inode { ... dev_t i_rdev; //设备文件对应的设备号 struct cdev *i_cdev; //指向对应的设备驱动对象的地址 ... }; ////file对象描述文件描述符, 在文件打开时创建, 关闭时销毁 struct file { ... const struct file_operations *f_op; //对应的文件操作对象的地址 unsigned int f_flags; //文件打开的标志 fmode_t f_mode; //权限 loff_t f_pos; //文件描述符的偏移 struct fown_struct f_owner; //属于哪个进程 unsigned int f_uid, f_gid; void *private_data; //给驱动程序员使用 ... }; |
通file里的成员f_path.dentry->d_inode->i_rdev可以获取到设备文件的设备号
///错误码在<asm/errno.h> ////
/////////struct file_operations ////
inode表示应用程序打开的文件的节点对象, file表示打开文件获取到的文件描述符
成功返回0, 失败返回错误码
int (*open) (struct inode *, struct file *);
buf指向用户进程里的缓冲区, len表示buf的大小(由用户调用read时传进来的)
off表示fl文件描述符的操作偏移, 返回值为实际给用户的数据字节数.
ssize_t (*read) (struct file *fl, char __user *buf, size_t len, loff_t *off);
用户进程把数据给驱动
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
to指用户进程的缓冲区, from指驱动里装数据的缓冲区, n多少字节, 返回值是0
extern inline long copy_to_user(void __user *to, const void *from, long n)
to指驱动的... from用户... n多少字节, ....
|
static inline unsigned long __must_check copy_to_user(void __user *to, const
void *from, unsigned long n)
{
if (access_ok(VERIFY_WRITE, to, n))
n = __copy_to_user(to, from, n);
return n; //返回值为剩下多少字节没拷贝
} |








