Linux内核之字符设备驱动

 

学习计划:
 1.vfs:虚拟文件系统
   VFS的作用就是采用标准的Unix系统调用读写位于不同物理介质上的不同文件系统。VFS是一个可
   以让open()、read()、write()等系统调用不用关心底层的存储介质和文件系统类型就可以工作的
   粘合层。在古老的DOS操作系统中,要访问本地文件系统之外的文件系统需要使用特殊的工具才能
   进行。而在Linux下,通过VFS,一个抽象的通用访问接口屏蔽了底层文件系统和物理介质的差异性。
   这是Linux文件系统对外的接口。任何要使用文件系统的程序都必须经由这层接口来使用它。

 2.字符设备驱动
作业:
 memmove与memcopy的区别
    void *memcpy(void *dst, const void *src, size_t count);
 void *memmove(void *dst, const void *src, size_t count);
 memcpy与memmove的目的都是将N个字节的源内存地址的内容拷贝到目标内存地址中。

 但当源内存和目标内存存在重叠时,memcpy会出现错误,而memmove能正确地实施拷贝,但这也增加了一点点开销。
 memmove的处理措施:
 (1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝
 (2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝
 (3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝

内容:
 0.设备驱动分类:
   块设备驱动、字符设备驱动、网络设备驱动。
   块设备、字符设备都有设备文件,而网络设备则是以网络套接字来实现的,如:eth0 eth1等

 1.inode号:设备编号,用户态都是通过设备编号来访问设备文件,一个文件至少占用一个逻辑块,
   一般都是一个文件对应多个逻辑块
   1).通过 ln -s xxx xxx 可在两个文件之间实现软链接

 2.字符设备驱动
   定义:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先
   后数据。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。:
 
   查看已有设备:cat /proc/devices
   
   字符设备编写步骤:
   1).实例化一个cdev设备对象结构体
   2).分配设备号,注册字符设备(静态分配和动态分配)
   3).初始化字符设备
   4).将字符设备加入到系统文件当中

 3.重要的数据结构:
   file_operations, file,和 inode.

   (1).inode结构体:
   dev_t:字符设备,i_rdev:设备号;设备号一共占32位;
   一个字符设备必然会对应一个设备,*i_cdev,void * i_private

   inode包含文件访问权限,属主,属组,大小,生成时间,访问时间,最后修改时间等信息,结构体如下:

   struct inode {
    struct hlist_node i_hash;

   (有删减)
    
    uid_t   i_uid;//inode拥有者id
   
    gid_t   i_gid;//inode所属群组id
   
    dev_t   i_rdev;//若是设备文件,表示记录设备的设备号
    u64   i_version;
   
    loff_t   i_size;//inode所代表大少
#ifdef __NEED_I_SIZE_ORDERED
    seqcount_t  i_size_seqcount;
#endif
    struct timespec  i_atime;//inode最近一次的存取时间
    struct timespec  i_mtime;//inode最近一次修改时间
    struct timespec  i_ctime;//inode的生成时间
   
      (有删减)

    struct list_head i_devices;
    union {
     struct pipe_inode_info *i_pipe;
     struct block_device *i_bdev;
     struct cdev *i_cdev;//若是字符设备,对应的为cdev结构体
    };

    1.1字符设备结构体描述:cdev

    struct cdev{

      struct kobject kobj;/*内嵌的kobject对象*/

      strcut module *owner;/*所属模块*/

      struct file_operations *ops;/*文件操作结构体*/

      struct list_head list;

      dev_t dev;/*设备号,dev_t实质是一个32位整,12位为主设备号,20位为次设备号,

                提取主次设备号的方法:MAJOR(dev_t dev),MINOR(dev_t dev),
                生成dev_t的方法:MKDEV(int major,int minor)*/

      unsigned int count;

      };

 

     1.2.linux2.6内核提供了一组函数来操作cdev结构体

    void cdev_init(struct cdev *,struct file_operations *);/*初始化cdev的成员,
                                                          *并且建立cdev与file_operation的连接*/
      struct cdev *cdev_alloc(void);/*动态申请一个cdev的内存空间*/
                void cdev_put(struct cdev *p);
    int cdev_add(struct cdev*,dev_t,unsigned);/*添加一个cdev,完成字符的注册*/
     void cdev_del(struct cdev*);/*删除一个cdev,完成字符的注销*/
    
   在调用cdev_add函数向系统注册字符设备之前,应该先调用register_chrdev_region()
   函数或是alloc_chrdev_region()函数向系统申请设备号;模型为:
   
   int register_chrdev_region(dev_t from,unsigned count,constchar *name);
   int alloc_chrdev_region(dev_t *dev,unsignedbaseminor,unsigned count,const char *name)

   在系统调用cdev_del函数从系统注销字符设备后,unregister_chrdev_region()应该释放之前申请的设备号
      该函数原型为:
   unregister_chrdev_region(dev_t from,unsigned count)

   (2).file结构体:
      系统中每个打开的文件在内核空间都会有一个关联的struct file结构体,它由内核打开文件
   创建,在文件所有实例都关闭后,内核释放这个数据结构。在内核源代码中struct file结
   构体的指针通常被命名为file或filp。这个结构体在内核中如下:

   struct file {

    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;//和文件关联的操作,file_operations结构体是字符设备核心
                                       //函数操作集
 
    spinlock_t  f_lock;
    atomic_long_t  f_count;
  
    unsigned int f_flags;//文件标志,也就是文件打开方式O_RDONLY,O_WRONLY,ORDWR等
   
    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

    void   *private_data;//文件私有数据

       #ifdef CONFIG_EPOLL

    struct list_head f_ep_links;
          #endif
    struct address_space *f_mapping;
          #ifdef CONFIG_DEBUG_WRITECOUNT
    unsigned long f_mnt_write_state;
          #endif
   };

      文件读写模式f_mode,标志f_flags都是设备驱动关心的内容,而私有数据指针*private_data在设备驱动中广泛
   应用,大多数指向设备驱动自定义用于描述设备的结构体。

      if(file->f_mode & FMODE_WRITE)//用户要求可写
      if(file->f_flags & O_RDWR)//用于检查设备是否使用可读写方式打开

 4.测试驱动程序
   1).加载驱动程序:insomd xxxx.ko
   2).查看是否加载成功:cat /proc/devices
   3).创建设备文件:mknod demo3 c 11 xx;
      demo0:文件名,c:字符设备文件,11:主设备号,xx:次设备号(0-255)之间
   4).运行设备文件:cat demo3
   5).使用测试文件测试驱动程序
   6).写入命令:echo 12568585 >> demo3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值