LDD读书笔记第三章-字符设备驱动程序(一)
设备号
一、简介
字符设备由在 /dev目录中使用 ls -l 使用来分辨,第一列为c是字符设备d为块设备。
一般同一类设备使用相同的设备号。而同种类型的不同设备用次设备号来表示。
列如对于磁盘:
1 2 3 4 5 | brw-rw---- 1 root disk 8, 0 7月 14 08:15 sda brw-rw---- 1 root disk 8, 1 7月 14 08:15 sda1 brw-rw---- 1 root disk 8, 2 7月 14 08:15 sda2 brw-rw---- 1 root disk 8, 3 7月 14 08:15 sda3 brw-rw---- 1 root disk 8, 4 7月 14 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(&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 ->i_op->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->ops = &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: ldd , 字符设备 , 驱动
© 除非另有注明本文采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可。
© 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
© 转载请注明: LDD读书笔记第三章-字符设备驱动程序(一) | 转自: Senghoo's Blog
© Tag: ldd , 字符设备 , 驱动