In order to learn the driver of character devices, we have to understand some related structures... So, open the kernel through Source Insight... I browsed important driver structures.
* User-driver relationship: user space read, write, etc. ---> linux System Call ---> indirectly call the functions in the file_operations structure of the device driver (see the example below)
1. structure required by struct file_operations driver
Struct file_operations {struct module * owner; // driver module pointer loff_t (* llseek) (struct file *, loff_t, INT); // file read/write location ssize_t (* read) (struct file *, char _ User *, size_t, loff_t *); // read data from the device ssize_t (* write) (struct file *, const char _ User *, size_t, loff_t *); // write data to the device 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 *); // whether reading and writing of file descriptors blocks int (* IOCTL) (struct inode *, struct file *, unsigned int, unsigned long ); // command control settings 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 *); // The device memory is mapped to the process space int (* open) (struct inode *, struct file *); // open the INT (* flush) (struct file *, fl_owner_t ID) of the device; int (* release) (struct inode *, struct file *); // disable the 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); 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 **);};
2. File structureRepresents an opened file descriptor, which is not used by the driver. Each opened file in the system has an associated struct file in the kernel. It is created when the kernel is open and passed to any function operated on the file until it is closed. When all instances of the file are closed, the kernel releases the data structure.
Struct file {/** fu_list becomes invalid after file_free is called and queued via * Waiting for RCU freeing */union {struct list_head fu_list; struct rcu_head fu_rcuhead;} f_u; struct path f_path; // file path # define f_dentry f_path.dentry # define paif_path.mnt const struct file_operations * f_op; // file operator structure: spinlock_t f_lock;/* f_ep_links, f_flags, no IRQ */limit f_count; unsigned int f_flags; // File ID, writable, readable fmode_t f_mode; loff_t f_pos; // file read/write location 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 extends unsigned long f_mnt_write_state; # endif };
3. The inode structure is used in the kernel to indicate specific files.
struct inode { struct hlist_node i_hash; struct list_head i_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; 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; unsigned int i_blkbits; 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; }; int i_cindex; __u32 i_generation;#ifdef CONFIG_DNOTIFY unsigned long i_dnotify_mask; /* Directory notify events */ struct dnotify_struct *i_dnotify; /* for directory notifications */#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 void *i_private; /* fs or device private pointer */};
References: http://www.cnblogs.com/QJohnson/archive/2011/06/24/2089414.html
4. cdev Structure
The cdev structure is used to describe a character device in the Linux2.6 kernel. Its definition is as follows:
Struct cdev {struct kobject kobj; struct module * owner; // The const struct file_operations * ops module; // file operation structure. When writing a driver, most of the functions in its structure are implemented by struct list_head list; dev_t dev; // device number, int type, with a height of 12 digits as the primary device number, the second device number is unsigned int count for the lower 20 bits ;};
You can use the following macro call to obtain the master and secondary device numbers:
MAJOR (dev_t dev)
MINOR (dev_t dev)
MKDEV (int major, int minor) // use the Primary and Secondary device numbers to generate dev_t
5. miscdevice structure of hybrid Devices
struct miscdevice { int minor; const char *name; const struct file_operations *fops; struct list_head list; struct device *parent; struct device *this_device;};