LDD读书笔记第三章-字符设备驱动程序(一)

设备号

一、简介

字符设备由在 /dev目录中使用 ls -l 使用来分辨,第一列为c是字符设备d为块设备。
一般同一类设备使用相同的设备号。而同种类型的不同设备用次设备号来表示。
列如对于磁盘:

1
2
3
4
5
brw-rw----  1 root disk    8,   0  714 08:15 sda
brw-rw----  1 root disk    8,   1  714 08:15 sda1
brw-rw----  1 root disk    8,   2  714 08:15 sda2
brw-rw----  1 root disk    8,   3  714 08:15 sda3
brw-rw----  1 root disk    8,   4  714 08:15 sda4

第一列的b表示是块设备,他们的主设备号8表示SCSI disk devices  次设备的 0~4 表示不同的分区。对于硬盘从设备号0~15 为第一块硬盘也就是sda, 16~31为第二块硬盘 sdb以此类推。详细状况查看linux设备号分配表。
Linux 设备分配清单

二、设备号的内部表达

内核使用dev_t 类型表达设备号。 在2.6.0版本中dev_t是32位数,其中12位表示主设备号20位表示从设备号。但是为了兼容性 应该使用相应的宏来操作设备号。

1
2
3
4
5
#include <linux/types.h>          /*dev_t 类型在此定义*/
#include  <linux/kdev_t.h>      /*下面使用的宏在此定义*/
MAJOR(dev_t dev);            /*从dev_t中获取主设备号*/
MINOR(dev_t dev);            /*从dev_t中获取从设备号*/
dev_t dev=MKDEV(int major , int minor);  /*以major 为主设备号 minor为从设备号生成dev_t*/

分配设备号时有动态和静态两种分配方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <linux/fs.h>;  /*包含下面要使用的函数。*/
int register_chrdev_region(dev_t first ,unsigned int count,char *name);
/*
first是用来表示要分配的设备编号起始值。
count  是请求分配的连续设备个数。
name 是设备名称。
运行成功返回0,失败返回负的错误码。
*/
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count,char *name);
/*
dev 用来保存分配的第一个设备编号。
firstminor  表示要申请的第一个从设备号。
其余两个选项和上面相同。
运行成功返回0,失败返回负的错误码。
*/
void unregister_chrdev_region(dev_t first,unsigned int count);
/*
用来释放所分配的设备编号。
参数和上面的解释相同。
*/

静态分配方法:

1
2
dev_t dev = MKDEV(major,minor);
result = register_chrdev_region(dev,count,”devname”);

这样就分配了 主设备号为major,从设备号为minor~minor+count,名称为devname的count个设备号。最后要检查result是否为负,来确认是否分配成功。
动态分配方法:

1
2
3
dev_ t dev;
result =  alloc_chrdev_region(&amp;dev,minor,count,”devname”);
major = MAJOR(dev);

除了dev以外其他参数和上面相同。dev是用来返回分配的设备号。最后用MAJOR宏来取得主设备号。

一些重要的数据结构

文件操作file_operations 结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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 *);
	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
	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 *, struct dentry *, 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 **);
};

文件表示 file 结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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 */
	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
};

inode 结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
struct inode {
	struct hlist_node    i_hash;
	struct list_head    i_list;        /* backing dev IO list */
	struct list_head    i_sb_list;
	struct list_head    i_dentry;
	unsigned long        i_ino;
	atomic_t        i_count;
	unsigned int        i_nlink;
	uid_t            i_uid;
	gid_t            i_gid;
	dev_t            i_rdev;
	unsigned int        i_blkbits;
	u64            i_version;
	loff_t            i_size;
#ifdef __NEED_I_SIZE_ORDERED
	seqcount_t        i_size_seqcount;
#endif
	struct timespec        i_atime;
	struct timespec        i_mtime;
	struct timespec        i_ctime;
	blkcnt_t        i_blocks;
	unsigned short          i_bytes;
	umode_t            i_mode;
	spinlock_t        i_lock;    /* i_blocks, i_bytes, maybe i_size */
	struct mutex        i_mutex;
	struct rw_semaphore    i_alloc_sem;
	const struct inode_operations    *i_op;
	const struct file_operations    *i_fop;    /* former -&gt;i_op-&gt;default_file_ops */
	struct super_block    *i_sb;
	struct file_lock    *i_flock;
	struct address_space    *i_mapping;
	struct address_space    i_data;
#ifdef CONFIG_QUOTA
	struct dquot        *i_dquot[MAXQUOTAS];
#endif
	struct list_head    i_devices;
	union {
		struct pipe_inode_info    *i_pipe;
		struct block_device    *i_bdev;
		struct cdev        *i_cdev;
	};
 
	__u32            i_generation;
 
#ifdef CONFIG_FSNOTIFY
	__u32            i_fsnotify_mask; /* all events this inode cares about */
	struct hlist_head    i_fsnotify_mark_entries; /* fsnotify mark entries */
#endif
 
#ifdef CONFIG_INOTIFY
	struct list_head    inotify_watches; /* watches on this inode */
	struct mutex        inotify_mutex;    /* protects the watches list */
#endif
 
	unsigned long        i_state;
	unsigned long        dirtied_when;    /* jiffies of first dirtying */
	unsigned int        i_flags;
	atomic_t        i_writecount;
#ifdef CONFIG_SECURITY
	void            *i_security;
#endif
#ifdef CONFIG_FS_POSIX_ACL
	struct posix_acl    *i_acl;
	struct posix_acl    *i_default_acl;
#endif
	void            *i_private; /* fs or device private pointer */
};

字符设备的注册:
cdev相关的 头文件为 <linux/cdev.h>
这里用到cdev 结构 原型为

1
2
3
4
5
6
7
8
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};

获取cdev结构

1
2
3
4
5
6
7
8
struct cdev *my_cdev = cdev_alloc();  /*申请cdev结构*/
my_cdev-&gt;ops = &amp;my_fops;     /*初始化file_operations 结构*/
然后需要初始化cdev结构
void cdev_init(struct cdev *cdev , struct file_operations *fops);
通知内核
int cdev_add(struct cdev *dev ,dev_t num,unsigned int count);
移除设备
void cdev_del(struct cdev *dev);
----------------- 全文结束 -----------------
© 该日志作者:Senghoo, 于2010年07月14日发表于分类"Linux Kernel"下;
© 除非另有注明本文采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可。
© 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
© 转载请注明: LDD读书笔记第三章-字符设备驱动程序(一) | 转自: Senghoo's Blog
© Tag: , ,

你可以继续围观

1 条评论

  1. :razz: