zoukankan      html  css  js  c++  java
  • Linux 字符设备驱动模型

    一。使用字符设备驱动程序

      1. 编译/安装驱动

        在Linux系统中,驱动程序通常采用内核模块的程序结构来进行编码。因此,编译/安装一个驱动程序,其实质就是编译/安装一个内核模块

      2. 创建设备文件

        通过字符设备文件,应用程序可以使用相应的字符设备驱动程序来控制字符设备。

        创建字符设备文件的方法一般有两种:

        1.使用mknod命令mknod/dev/文件名c 主设备号  次设备号

           查询设备号的命令  cat /proc/devices

        2. 使用函数在驱动程序中创建(后续课程介绍)

      编写应用程序时,使用命令 arm-linux-readelf  -d write_mem

      3. 访问设备

        编写应用程序访问设备。

        编写了write_mem.c 和read_mem.c 访问文件为  /dev/memdev0  驱动为memdev

        write_mem.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main()
    {
        int fd = 0;
        int src = 2013;
        fd = open("/dev/memdev0",O_RDWR);
        
        write(fd,&src,sizeof(int));
        close(fd);
    
        return 0;    
    
    }

      read_mem.c

    int main()
    { 
        int fd = 0; 
        int dst = 0;
    
       fd =  open("dev/memdev0",O_RDWR);
    
        read(fd,&dst,sizeof(int));
    
        printf("dst is %d
    ",dst);
    
    }

     二。 字符设备驱动模型

      1. 设备描述结构 cdev

        在任何一种驱动模型中,设备都会用内核中的一种结构来描述。

        我们的字符设备在内核中使用struct  cdev来描述。

        struct  cdev

        {

           structkobjectkobj;

           structmodule *owner;

           const structfile_operations*ops;   //设备操作集

           structlist_headlist;

           dev_tdev;  //设备号

           unsigned intcount; //设备数

        };

        (1).字符设备文件与字符驱动程序如何建立起对应关系??

            答案:主设备号

            驱动程序什么来区分串口1和串2

            答案:次设备号

        (2).Linux内核中使用dev_t类型来定义设备号,dev_t这种类型其实质为32位的unsigned int,

            其中高12位为主设备号,低20位为次设备号.

            问1:如果知道主设备号,次设备号,怎么组合成dev_t类型

            答:dev_t dev = MKDEV(主设备号,次设备号)

            问2: 如何从dev_t中分解出主设备号?

            答: 主设备号= MAJOR(dev_t dev)

            问3: 如何从dev_t中分解出次设备号?

            答: 次设备号=MINOR(dev_t dev)

        (3).如何为设备分配一个主设备号?

            #静态申请开发者自己选择一个数字作为主设备号,然后通过函数register_chrdev_region向内核申请使用。

            缺点:如果申请使用的设备号已经被内核中的其他驱动使用了,则申请失败。使用的设备号已经被内核中的其他驱动使用了,则申请失败。

            #动态分配使用alloc_chrdev_region由内核分配一个可用的主设备号。优点:因为内核知道哪些号已经被使用了,所以不会导致分配到已经被使用的号。

        (4).不论使用何种方法分配设备号,都应该在驱动退出时,使用unregister_chrdev_region函数释放这些设备号

         (5). Struct file_operations是一个函数指针的集合,定义能在设备上进行的操作。

           结构中的函数指针指向驱动中的函数, 这些函数实现一个针对设备的操作, 对于不支持的操作则设置函数指针为NULL。

           例如:struct file_operations dev_fops =

              {

                .llseek= NULL,

                .read= dev_read,

                .write= dev_write,

                .ioctl= dev_ioctl,

                .open= dev_open,

                .release= dev_release,

              };

      2. 字符设备驱动模型

        1. 驱动初始化

          2.1.1 分配设备描述结构

             cdev变量的定义可以采用静态和动态两种办法

             •静态分配struct cdev mdev;

             •动态分配struct cdev *pdev = cdev_alloc();

          2.1.2 初始化设备描述结构

             struct cdev的初始化使用cdev_init函数来完成。

             cdev_init(struct cdev *cdev, const struct file_operations *fops)  

             参数:cdev: 待初始化的cdev结构

                fops: 设备对应的操作函数集

          2.1.3 注册设备描述结构

             字符设备的注册使用cdev_add函数来完成。

             cdev_add(struct cdev *p, dev_t dev, unsigned count)

             参数:p: 待添加到内核的字符设备结构

                dev: 设备号

                count: 该类设备的设备个数

          2.1.4 硬件初始化

        2. 实现设备操作

          1. open

            int (*open) (struct inode *, struct file *)打开设备,响应open系统

            open设备方法是驱动程序用来为以后的操作完成初始化准备工作的。

            在大部分驱动程序中,open完成如下工作:

            #标明次设备号

            #启动设备

          2. read

            ssize_t (*read) (struct file *, char __user *, size_t, loff_t *)从设备读取数据,响应read系统调用

            read设备方法通常完成2件事情:

            #从设备中读取数据(属于硬件访问类操作)

            #将读取到的数据返回给应用程序

            ssize_t (*read) (struct file *filp, char __user *buff, size_t count, loff_t *offp)

            参数分析:filp:与字符设备文件关联的file结构指针, 由内核创建.

                 buff : 从设备读取到的数据,需要保存到的位置。由read系统调用提供该参数。

                 count: 请求传输的数据量,由read系统调用提供该参数。

                 offp: 文件的读写位置,由内核从file结构中取出后,传递进来。

          3. write

            ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *)向设备写入数据,响应write系统调用

            write设备方法通常完成2件事情:

            #从应用程序提供的地址中取出数据

            #将数据写入设备(属于硬件访问类操作)

          4. lseek

            loff_t (*llseek) (struct file *, loff_t, int)重定位读写指针,响应lseek系统调用

          5. close 

            int (*release) (struct inode *, struct file *);关闭设备,响应close系统调用

            release方法的作用正好与open相反。

            这个设备方法有时也称为close,它应该:

            #关闭设备

        3. 驱动注销

          当我们从内核中卸载驱动程序的时候,需要使用cdev_del函数来完成字符设备的注销。

      3. 范例驱动分析

        

  • 相关阅读:
    抓包工具 Fiddler 使用介绍
    HTTP 协议常见首部字段
    HTTP 协议服务器相关概念
    HTTP 协议常见的状态码
    HTTP 协议中 GET 和 POST 方法详解
    设置html title标题左侧的小图标
    HTML页面如何判断是手机访问还是电脑访问
    使用Java的Frame类编写的QQ登录界面
    swing中JTable的使用方法
    采用MVC模式JDBC演示案例
  • 原文地址:https://www.cnblogs.com/lvxiaoning/p/5063042.html
Copyright © 2011-2022 走看看