Linux驱动程序刚接触,虽然不是很清楚,但是总归是慢慢学习的过程。我的环境是Fedora14虚拟机。内核版本是2.6.38.1,其中的实现过程存在很多的问题,主要是因为很多的内核函数发生了较大的差别.其中最大的可能是ioctl以及互信息量的实现。这两个的问题也使得我们在驱动设计过程中出现很多的疑惑和问题。
 
接上一部分,继续总结:
主要包括几个重要的结构体、并发控制、以及ioctl的实现。在驱动的设计过程主要涉及3个重要的结构体。struct file_operations,struct inode,struct file.
struct file_operations主要是涉及一些文件操作的函数,其本质上就是一个函数指针的集合,包含了文件操作的各种函数声明,可能与应用程序设计中的相应函数只在参数上存在一定的差别。但是在2.6.36版本以后,其中的内容发生了较大的变化,主要设计了ioctl的相关操作。
  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 (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
  7.     ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
  8.     int (*readdir) (struct file *, void *, filldir_t);
  9.     unsigned int (*poll) (struct file *, struct poll_table_struct *);
  10.     /*新添加的函数,同时去掉了ioctl的函数,同时返回值也发生了变化*/
  11.     long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
  12.     long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
  13.     int (*mmap) (struct file *, struct vm_area_struct *);
  14.     int (*open) (struct inode *, struct file *);
  15.     int (*flush) (struct file *, fl_owner_t id);
  16.     int (*release) (struct inode *, struct file *);
  17.     int (*fsync) (struct file *, int datasync);
  18.     int (*aio_fsync) (struct kiocb *, int datasync);
  19.     int (*fasync) (int, struct file *, int);
  20.     int (*lock) (struct file *, int, struct file_lock *);
  21.     ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
  22.     unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
  23.     int (*check_flags)(int);
  24.     int (*flock) (struct file *, int, struct file_lock *);
  25.     ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
  26.     ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
  27.     int (*setlease)(struct file *, long, struct file_lock **);
  28.     long (*fallocate)(struct file *file, int mode, loff_t offset,
  29.              loff_t len);
  30. };
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
是最近添加进来的函数,为了实现原来的ioctl函数,同时参数以及返回值都发生了较大的变化,这也是为什么在2.6.36版本以后的内核中使用ioctl函数会报错的原因。unlocked_ioctl函数通常用来实现原来的ioctl函数,而compat_ioctl函数则用来实现一些兼容版本的ioctl问题。返回值由原来的int变为long型,也是需要注意的。在ioctl中,第一个参数是struct inode,2.6.36以后的版本将不能直接访问到inode参数,只能间接的访问,具体的访问方法后面在总结。
在驱动实现过程中主要包括对各个需要实现函数的赋值,但是open函数不能赋值与否,都会默认打开,如果不赋值,则默认该设备一直打开。其他的函数不赋值,即表示不实现该方法。常用的复制方法如下:
  1. /*添加该模块的基本文件操作支持*/
  2. static const struct file_operations mem_fops =
  3. {
  4.         /*结尾不是分号,注意其中的差别*/
  5.         .owner = THIS_MODULE,
  6.         .llseek = mem_llseek,
  7.         .read = mem_read,
  8.         .write = mem_write,
  9.         .open = mem_open,
  10.         .release = mem_release,
  11.         /*添加新的操作支持*/
  12.         .unlocked_ioctl = mem_ioctl,
  13. };
需要注意的是后面不再是分号,而是逗号。其中的mem_read、mem_write等是函数的具体实现过程。.owner表示该结构体属于那个,当然就是THIS_MODULE,表示这个模块。
 
struct inode表示的是一个文件的索引,该结构是每一个具体的物理文件(保存在存储器中的实体文件)的索引,一个文件对应一个唯一的struct inode,其中表明了文件的大小,文件的类型,文件的时间等参数,结构体中每一个参数都能表示某一个文件的特性,通过inode就能表示文件的所有信息。
 
  1. struct inode {
  2.     /* RCU path lookup touches following: */
  3.     umode_t            i_mode;
  4.     /*使用者的id*/
  5.     uid_t            i_uid;
  6.     /*使用者的组的id*/         
  7.     gid_t            i_gid;

  8.     const struct inode_operations    *i_op;
  9.     struct super_block    *i_sb;

  10.     spinlock_t        i_lock;    /* i_blocks, i_bytes, maybe i_size */
  11.     unsigned int        i_flags;
  12.     struct mutex        i_mutex;
  13.     /*状态标志*/
  14.     unsigned long        i_state;
  15.     unsigned long        dirtied_when;    /* jiffies of first dirtying */

  16.     struct hlist_node    i_hash;
  17.     struct list_head    i_wb_list;    /* backing dev IO list */
  18.     struct list_head    i_lru;        /* inode LRU list */
  19.     struct list_head    i_sb_list;
  20.    
  21.     union {
  22.         struct list_head    i_dentry;
  23.         struct rcu_head        i_rcu;
  24.     };

  25.     unsigned long        i_ino;
  26.    
  27.     /*引用次数,当这个数为0时,release函数才能完成*/
  28.     atomic_t        i_count;

  29.     unsigned int        i_nlink;
  30.     /*设备文件的设备号*/
  31.     dev_t            i_rdev;

  32.     unsigned int        i_blkbits;
  33.     u64            i_version;
  34.     /*文件偏移量*/
  35.     loff_t            i_size;

  36. #ifdef __NEED_I_SIZE_ORDERED
  37.     seqcount_t        i_size_seqcount;
  38. #endif
  39.     /*文件的时间参数,包括三种时间*/
  40.     struct timespec        i_atime;
  41.     struct timespec        i_mtime;
  42.     struct timespec        i_ctime;
  43.     blkcnt_t        i_blocks;
  44.     unsigned short i_bytes;
  45.     struct rw_semaphore    i_alloc_sem;
  46.     const struct file_operations    *i_fop;    /* former ->i_op->default_file_ops */
  47.     struct file_lock    *i_flock;
  48.    
  49.     /*文件的备份地址空间*/
  50.     struct address_space    *i_mapping;
  51.     /*设备地址空间*/
  52.     struct address_space    i_data;

  53. #ifdef CONFIG_QUOTA
  54.     struct dquot        *i_dquot[MAXQUOTAS];
  55. #endif
  56.     struct list_head    i_devices;
  57.    
  58.     /*说明了三种不同的驱动类型*/
  59.     union {
  60.         struct pipe_inode_info    *i_pipe;
  61.         struct block_device    *i_bdev;
  62.         struct cdev        *i_cdev;
  63.     };

  64.     __u32            i_generation;

  65. #ifdef CONFIG_FSNOTIFY
  66.     __u32            i_fsnotify_mask; /* all events this inode cares about */
  67.     struct hlist_head    i_fsnotify_marks;
  68. #endif

  69. #ifdef CONFIG_IMA
  70.     /* protected by i_lock */
  71.     unsigned int        i_readcount; /* struct files open RO */
  72. #endif
  73.    /*写者使用次数*/
  74.     atomic_t        i_writecount;
  75. #ifdef CONFIG_SECURITY
  76.     void            *i_security;
  77. #endif
  78. #ifdef CONFIG_FS_POSIX_ACL
  79.     struct posix_acl    *i_acl;
  80.     struct posix_acl    *i_default_acl;
  81. #endif
  82.     void            *i_private; /* fs or device private pointer */
  83. };
驱动程序设计过程中通常 采用i_rdev判断设备文件的设备号。
 
struct file是指文件对象,表示进程中打开的文件,一个物理文件只有一个inode,但是可以被打开很多次,因此可以存在很多struct file结构体。
  1. struct file {
  2.     /*
  3.      * fu_list becomes invalid after file_free is called and queued via
  4.      * fu_rcuhead for RCU freeing
  5.      */
  6.     union {
  7.         struct list_head    fu_list;
  8.         struct rcu_head     fu_rcuhead;
  9.     } f_u;
  10.    
  11.     /*文件的路径*/
  12.     struct path        f_path;
  13. #define f_dentry    f_path.dentry
  14. #define f_vfsmnt    f_path.mnt
  15.     /*该文件支持的操作集合*/
  16.     const struct file_operations    *f_op;
  17.     spinlock_t        f_lock; /* f_ep_links, f_flags, no IRQ */
  18. #ifdef CONFIG_SMP
  19.     int            f_sb_list_cpu;
  20. #endif
  21.     /*文件对象的使用次数*/
  22.     atomic_long_t        f_count;

  23.     unsigned int         f_flags;
  24.     fmode_t            f_mode;
  25.     loff_t            f_pos;
  26.     struct fown_struct    f_owner;
  27.     const struct cred    *f_cred;
  28.     struct file_ra_state    f_ra;

  29.     u64            f_version;
  30. #ifdef CONFIG_SECURITY
  31.     void            *f_security;
  32. #endif

  33.     /* needed for tty driver, and maybe others */
  34.     /*通常用来指向具体的数据或者设备文件,实现操作*/
  35.     void            *private_data;

  36. #ifdef CONFIG_EPOLL
  37.     /* Used by fs/eventpoll.to link all the hooks to this file */
  38.     struct list_head    f_ep_links;
  39. #endif /* #ifdef CONFIG_EPOLL */
  40.     struct address_space    *f_mapping;
  41. #ifdef CONFIG_DEBUG_WRITECOUNT
  42.     unsigned long f_mnt_write_state;
  43. #endif
  44. };
  1.  访问inode主要是通过这两个机构体之间的管理型。
  2. struct path {
     struct vfsmount *mnt;
     struct dentry *dentry;
    };
  3. struct dentry {
  4.     /* RCU lookup touched fields */
  5.     unsigned int d_flags;        /* protected by d_lock */
  6.     seqcount_t d_seq;        /* per dentry seqlock */
  7.     struct hlist_bl_node d_hash;    /* lookup hash list */
  8.     struct dentry *d_parent;    /* parent directory */
  9.     struct qstr d_name;
  10.     struct inode *d_inode;        /* Where the name belongs to - NULL is
  11.                      * negative */
  12.     unsigned char d_iname[DNAME_INLINE_LEN];    /* small names */

  13.     /* Ref lookup also touches following */
  14.     unsigned int d_count;        /* protected by d_lock */
  15.     spinlock_t d_lock;        /* per dentry lock */
  16.     const struct dentry_operations *d_op;
  17.     struct super_block *d_sb;    /* The root of the dentry tree */
  18.     unsigned long d_time;        /* used by d_revalidate */
  19.     void *d_fsdata;            /* fs-specific data */

  20.     struct list_head d_lru;        /* LRU list */
  21.     /*
  22.      * d_child and d_rcu can share memory
  23.      */
  24.     union {
  25.         struct list_head d_child;    /* child of parent list */
  26.          struct rcu_head d_rcu;
  27.     } d_u;
  28.     struct list_head d_subdirs;    /* our children */
  29.     struct list_head d_alias;    /* inode alias list */
  30. };
其中的可以通过struct file间接的访问物理文件的struct inode,具体的实现是filp->f_path.entry->d_inode,这个过程也就实现了将inode和file结构体之间的联系。
上面的几个主要的结构体是驱动实现过程中最重要的几个。具体的意义还要联系起来分析。
 
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐