一、前言
在调用了alloc_chrdev_region函数或register_chrdev_region函数之后可以在/proc/devices中看到该设备的主设备号,比如我注册的hello模块的主设备号为1024,如下图:
现在使用lsmod能看到驱动名,使用cat /proc/devices能看到设备名,那怎么来使用这个设备呢,这个时候我们还需要一个设备文件,这个设备文件就是在应用程序中用open函数打开的文件。
二、创建设备文件
方法一:手动创建
使用mknod指令,mknod用法:mknod <filename> <type> <major> <minor>
filename:设备文件名
type:设备类型
major:主设备号
minor:次设备号
如:mknod /dev/haha c 1024 0
这就是说创建了一个/dev/haha的文件,类型是字符设备,主设备号为1024,次设备号为0
方法二:自动创建
三、struct file
有了设备文件之后,便可以用open打开这个设备文件,然后用read,write等函数来操作这个文件,但是在用户态中怎么调用到内核的东西呢。
系统每打开一个文件在内核空间都有一个相关联的struct file,它由内核在打开文件时创建,在关闭文件后释放。
struct file的定义如下:
1 struct file { 2 union { 3 struct llist_node fu_llist; 4 struct rcu_head fu_rcuhead; 5 } f_u; 6 struct path f_path; 7 struct inode *f_inode; /* cached value */ 8 const struct file_operations *f_op; 9 10 /* 11 * Protects f_ep_links, f_flags. 12 * Must not be taken from IRQ context. 13 */ 14 spinlock_t f_lock; 15 atomic_long_t f_count; 16 unsigned int f_flags; 17 fmode_t f_mode; 18 struct mutex f_pos_lock; 19 loff_t f_pos; 20 struct fown_struct f_owner; 21 const struct cred *f_cred; 22 struct file_ra_state f_ra; 23 24 u64 f_version; 25 #ifdef CONFIG_SECURITY 26 void *f_security; 27 #endif 28 /* needed for tty driver, and maybe others */ 29 void *private_data; 30 31 #ifdef CONFIG_EPOLL 32 /* Used by fs/eventpoll.c to link all the hooks to this file */ 33 struct list_head f_ep_links; 34 struct list_head f_tfile_llink; 35 #endif /* #ifdef CONFIG_EPOLL */ 36 struct address_space *f_mapping; 37 } __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
其中有一个重要成员就是 const struct file_operations *f_op;
struct file_operations的定义如下:
1 struct file_operations { 2 struct module *owner; 3 loff_t (*llseek) (struct file *, loff_t, int); 4 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 5 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 6 ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); 7 ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); 8 int (*iterate) (struct file *, struct dir_context *); 9 unsigned int (*poll) (struct file *, struct poll_table_struct *); 10 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); 11 long (*compat_ioctl) (struct file *, unsigned int, unsigned long); 12 int (*mmap) (struct file *, struct vm_area_struct *); 13 int (*open) (struct inode *, struct file *); 14 int (*flush) (struct file *, fl_owner_t id); 15 int (*release) (struct inode *, struct file *); 16 int (*fsync) (struct file *, loff_t, loff_t, int datasync); 17 int (*aio_fsync) (struct kiocb *, int datasync); 18 int (*fasync) (int, struct file *, int); 19 int (*lock) (struct file *, int, struct file_lock *); 20 ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); 21 unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); 22 int (*check_flags)(int); 23 int (*flock) (struct file *, int, struct file_lock *); 24 ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); 25 ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); 26 int (*setlease)(struct file *, long, struct file_lock **, void **); 27 long (*fallocate)(struct file *file, int mode, loff_t offset, 28 loff_t len); 29 void (*show_fdinfo)(struct seq_file *m, struct file *f); 30 #ifndef CONFIG_MMU 31 unsigned (*mmap_capabilities)(struct file *); 32 #endif 33 };
这里面就包含了打开文件之后可以对文件的操作,在用open打开一个文件之后获得一个文件描述符fd,比如要对该文件进行写操作,则调用write函数,实际上会调用到 file_operations中的read函数,而在内核驱动中是需要自己编写read函数的,这样就能实现应用和内核之间的交互。
原文地址:https://www.cnblogs.com/Suzkfly/p/11768444.html