驱动-字符设备驱动程序开发(第二天)

一:字符设备开发的基本步骤

    1.确定主设备号和次设备号

  • 主设备和号是内核识别一类设备的标识。整数(占12位)一般1-255
  • 次设备号由内核使用,用于正确确定设备文件所指的设备。整数(20位)一般0-255
  • 设备编号的内部表示
  • dev_t类型(32位)

用来保存设备编号(包括主设备号(12位)和次设备号(20位))

  • 从dev_t获得主设备号和次设备号:
    • MAJOR(dev_t);
    • MINOR(dev_t);
  • 将主设备号和次设备号转换成dev_t类型:
    • MKDEV(int major,int minor);    
  • 分配主设备号
    • 手工分配主设备号:找一个内核没有使用的主设备号来使用
      • #include<linux/fs.h>
      • int register_chrdev_region(dev_t first,unsigned int count,char*name);  
    • 自动分配
      • #include<linux/fs.h>
      • int alloc_chrdev_region(dev_t*dev,unsigned int firstminor,unsigned int count,char*name);

                     注意:dev是一个输出指针,firstminor是要使用的被请求的第一个次设备号

  • 释放设备号
  • void unregister_chrdev_region(dev_t dev,unsigned int count);通常在模块的清除函数中调用。            

    2.实现字符驱动程序

  •        实现file_operations结构体
  • 实现初始化函数,注册字符设备
  • 实现销毁函数,释放字符设备
  • 实现字符设备其他基本成员函数
  • 实现字符驱动程序
    • cdev结构体

                 struct cdev
                  {

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

               struct module *owner; //所属模块,通常是自己

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

               struct list_head list;

               dev_t dev;   //设备号

               unsigned int count;

                    }

    • 操作cdev的函数

 void cdev_init(struct cdev*cdev,struct file_operations *fops);   //cdv与file_operations建立联系

struct cdev *cdev_alloc(void);   // 动态建立cdev

int cdev_add(struct cdev*dev,dev_t num,unsigned count);//把字符设备添加进内核

void cdev_del(struct cdev*cdev);   //删除设备

    • file_operations结构体
      • 字符驱动和内核的接口在include/linux/fs.h中定义
      • 字符驱动只要实现一个file_operations结构体
      • 当注册到内核中内核就有了操作此设备的能力。
    • file_operations的主要成员:

struct module *owner: 指向模块自身:THIS_MODULE

open:打开设备

release:关闭设备

read:从设备上读数据

write:向设备上写数据

llseek:定位当前读写位置指针

mmap:映射设备空间到进程的地址空间

    • file结构体
      • file结构:
        • file_operation结构体相关的一个结构体
        • 描述一个正在打开的设备文件
      • 成员:
      • loff_t f_ops:
        • 当前读写位置
      • unsigned int f_flags
        • 标识文件打开时,是否可读或可写
        • 0_RDONLY
        • O_NONBLOCK
        • O_SYNC
      • struct file_operation *f_op
        • 文件相关的操作,指向所实现的struct file_operations
      • void *private_data:
        • 私有数据指针。驱动程序可以将这个字段拥有任何目的或者忽略这个字段。
    • inode结构体
      • 内核用inode结构体在内部表示文件
      • inode与file区别
      • file表示打开的文件描述符
      • 多个表示打开的文件描述符的file结构,可以指向单个inode结构
    • inode结构中的两个主要字段:
      • dev_t i_rdev;
      • 对表示设备文件的inode结构,该字段包含了真正的设备编号
      • struct cdev *i_cdev;
      • struct cdev是表示字符设备的内核的内部结构
      • 当inode指向一个字符设备文件时,该字段包含了指向struct cdev结构的指针。
    • 从一个inode中获得主设备号和次设备号
      • unsigned int iminor(struct inode *inode);
      • unsigned int imajor(struct inode *inode);
  • 注册设备,在模块或驱动初始化时调用
    • linux-2.4及以前
      • int register_chrdev(unsigned int major,const char *name ,struct file_operations *fops);
    • linux-2.6
      • void cdev_init(struct cdev *dev,struct file_operations *fops);
      • int cdev_add(struct cdev *dev,dev_t num,unsigned count);
  • 注销设备:在模块卸载时调用
    • linux-2.4及以前
      • int unregister_chrdev(unsigned int major,const char *name);
    • linux-2.6
      • void cdev_del(struct cdev *dev);
  • 设备驱动模块加载模板

static int __init xxx_init(void)

{

  ----

     cdev_init(&xxx.dev.cdv,&xxx_fops);

     xxx_dev.cdev.owner=THIS_MODULE;

//获取字符设备号

if(xxx_major)

{

      register_chrdev_region(xxx_dev_no,1,DEV_NAME);

}

else

{

     alloc_chrdev_region(&xxx_dev_no,0,1,DEV_NAME);

}

ret=cdev_add(&xxx_dev.cdev,xxx_dev_no,1);//注册设备

}

static void __ exit xxx_exit(void)

{

  unregister_chrdev_region(xxx_dev_no,1);//释放设备号

      cdev_del(&xxx_dev.cdev);注销设备

}

    3.创建设备文件节点

 

posted @ 2012-12-02 16:59  黑-色-柳—丁  阅读(209)  评论(0编辑  收藏  举报