好久没有写过这些东西了,自己也是无聊的很,也不知道这几个月我在干些什么。。。
哦,对了,貌似一直在玩坦克世界,表示很蛋疼。。
好几个月没哟接触过这些东西,毕竟忘记很多,所以决定从新复习一遍吧,我是借的学校的《Linux Device Driver》这本书,由于是全英文版的,所以好多东西都不是很懂,尤其是其中的好多单词,但是大体还是可以分析一下的,所以决定记录一下这个学习过程吧。
在这里我只是简单的介绍一下重要的信息来方便于自己以后可以参阅吧!
字符设备驱动
字符设备是一种按照字节来访问的设备,字符设备驱动则负责驱动字符设备,这样的驱动通常实现 open, read, write, close 等系统调用。
1、主/次设备号
主设备号:用来反映设备文件类型,即用来标识与设备文件相连的驱动程序。
此设备号:用来区分同类型的设备。
#include <linux/types.h>
dev_t;
int MAJOR(dev_t dev);
int MINOR(dev_t dev);
dev_t MKDEV(unsigned int major, unsigned int minor);
#include <linux/fs.h>
int register_chrdev_region(dev_t first, unsigned count, const char *name);
int alloc_chrdev_region(dev_t *dev, unsigned firstminor, unsigned count, const char *name); 这两个家伙中的设备名(name)主要体现在 /proc/devices 中!
2、重要数据结构
2.1、struct file
代表一个打开的文件,系统中每个打开的文件在内核空间都有一个相关联的 struct file,它有内核在打开文件时创建,在文件关闭后释放。
struct file {
/*
* fu_list becomes invalid after file_free is called and queued via
* fu_rcuhead for RCU freeing
*/
union {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
#define f_dentry f_path.dentry
#define f_vfsmnt f_path.mnt
const struct file_operations *f_op;
spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ */
#ifdef CONFIG_SMP
int f_sb_list_cpu;
#endif
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
loff_t f_pos;
struct fown_struct f_owner;
const struct cred *f_cred;
struct file_ra_state f_ra;
u64 f_version;
#ifdef CONFIG_SECURITY
void *f_security;
#endif
/* needed for tty driver, and maybe others */
void *private_data;
#ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
#ifdef CONFIG_DEBUG_WRITECOUNT
unsigned long f_mnt_write_state;
#endif
};
上面的是完整结构,其重要成员是:
loff_t f_pos; /* 文件读写位置 */
const struct file_operations f_ops; /* file_operations 结构 */
2.2、strict inode
由于 inode 里边的结构太多,主要记住:在内核中,对于一个文件,可以有多个 file 结构,但是只有一个 inode 结构!
还有就是两个重要成员!
dev_t i_rdev; /* 也就是当前设备号 */
struct cdev i_cdev; /* 当前字符设备 */
2.3、struct file_operations
struct file_operations {
struct module *owner;
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 *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
};
这个就不用多少了吧,一看就该明白了!
3、注册字符设备
#include <linux/fs.h>
int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops);
void unregister_chrdev(unsigned int major, const char *name);
我这里进行一下简单的更改吧,因为昨天写的时候没有在意,今天突然发现写的这个注册字符设备在 2.6.38 用的已经开始少了。。估计要退出历史的舞台了。。
现在介绍下最新的吧。。。
#include <linux/cdev.h>
struct cdev *cdev_alloc(void);
void cdev_init(struct cdev *, const struct file_operations *);
int cdev_add(struct cdev *, dev_t, unsigned);
void cdev_del(struct cdev *);
4、创建设备节点
4.1、手工创建
mknod filename type major minor
4.2、自动创建
#include <linux/device.h>
#define class_create(owner, name) \
({ \
static struct lock_class_key __key; \
__class_create(owner, name, &__key); \
});
void class_destroy(struct class *cls);
struct device *device_create(struct class *cls, struct device *parent,
dev_t devt, void *drvdata,
const char *fmt, ...)
__attribute__((format(printf, 5, 6)));
void device_destroy(struct class *cls, dev_t devt);
5、内核和用户交互传递
#include <asm/uaccess.h>
static inline long copy_from_user(void *to,
const void __user * from, unsigned long n);
static inline long copy_to_user(void __user *to,
const void *from, unsigned long n);
好了,基本上就这么点吧。。
这里我主要是从 Linux 2.6.38 源码找的相关的函数信息。。。
#include <linux/fs.h>
int register_chrdev_region(dev_t first, unsigned count, const char *name);
int alloc_chrdev_region(dev_t *dev, unsigned firstminor, unsigned count, const char *name);