• linux 设备驱动(一)


      首先,需要明白驱动程序的工作流程。

      正常我们在操作设备时的顺序是这样的。(1)在应用层,直接通过open、read、或者说是write等函数。(2)这些函数都是在C库中实现的,可以肯定的是C库中对其反应是发生异常SWI,触发异常swi val。根据val的不同进入不同的异常处理。(3)进入驱动函数,内核空间()

      然后,需要明白设备如何告知linux内核?即驱动程序的工作流程:1)定义一个file_operation结构体 2)注册(主设备号,名字,file_operation)。就是将file_operation放到file_operation字符数组的主设备号项中。注册函数有registre_chrdev这是注册到字符数组中。 3)谁来调用它??驱动入口函数 module_init 4)修饰module_init(函数指针,指下入口函数),定义一个结构体,这个结构体里有一个函数指针,指向入口函数。当加载或安装一个驱动时(insmod),内核会自动找到一个这样的结构体,调用它指向的函数。

      open("/dev/xxx"),注意这里的"xxx"是怎么来的?也就是我们常说的,生成驱动设备节点文件的方法

      1)手工建立

        mknode /dev/xxx c 主设备号 次设备号

        这里的主设备号是通过cat /proc/device,而次设备号是自己定的

       2)自动创建:udev(对于busybox就是mdev)。mdev会根据系统信息,在/sys/注册一个驱动程序时会在该系统下生成注册信息。而mdev会根据系统信息自动创建设备节点。

    insmod进去加载一驱动之后,肯定会更改信息,为什么一更改信息,mdev就会自动运行生成呢?是因为脚本文件/etc/init.d。“echo /sbin/mdev > /proc/sys/hotplug”。

    方法创建一个类,然后再在这个类下创建一个设备。

      另外,写驱动程序和普通的骒驱有什么区别?

      在单片机里我们直接对物理地址操作,而在驱动程序中我们需要对地址重映射之后才行。

      混杂设备()Linux系统中,存在一类字符设备,它们共享一个主设备号(10),但次设备号不同,我们称这类设备为混杂设备(miscdevice)。所有的混杂设备形成一个链,对设备访问时内核根据次设备号查找到相应的miscdevice设备。

      module_init()和init_module()这两个加载函数有什么区别吗?

      init_module是默认的模块的入口,如果你想指定其他的函数作为模块的入口就需要module_init函数来指定。

      init_module()是真正的入口,module_init是宏,如果在模块中使用,最终还是要转换到init_module()上。如果不是在模块中使用,module_init可以说没有什么作用。总之,使用module_init方便代码在模块和非模块间移植

        linux kernel中有很大一部分代码是设备驱动代码,这些驱动代码都有初始化和反初始化函数,这些代码一般都只执行一次,为了有更有效的利用内存,这些代码所占用的内存可以释放出来。

    linux就是这样做的,对只需要初始化运行一次的函数都加上__init属性。在kernel初始化后期,释放所有这些函数代码所占的内存空间。它是怎么做到的呢?看过module_init和module_exit 的人知道,连接器把带__init属性的函数放在同一个section里,在用完以后,把整个section释放掉。

           口说无凭,我们看源码,init/main.c中start_kernel是进入kernel的第一个c函数,在这个函数的最后一行是

     rest_init();

    static void rest_init(void)
    {
     kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
     unlock_kernel();
     cpu_idle();
    }

    创建了一个内核线程,主函数init,代码如下:

    static int init(void * unused)
    {
     lock_kernel();
     do_basic_setup();

     prepare_namespace();

     /*
      * Ok, we have completed the initial bootup, and
      * we're essentially up and running. Get rid of the
      * initmem segments and start the user-mode stuff..
      */
     free_initmem();
     unlock_kernel();

    红色那行代码就是用来释放初始化代码和数据的。

    void free_initmem(void)
    {
    #ifndef CONFIG_XIP_ROM
        if (!machine_is_integrator()) {
            free_area((unsigned long)(&__init_begin),
                               (unsigned long)(&__init_end),
                               "init");
        }
    #endif
    }

      

      

  • 相关阅读:
    25.C++- 泛型编程之函数模板(详解)
    Windows10 + Visual Studio 2017 + CMake +OpenCV编译、开发环境配置及测试
    终于解决了python 3.x import cv2 “ImportError: DLL load failed: 找不到指定的模块” 及“pycharm关于cv2没有代码提示”的问题
    Python的开源人脸识别库:离线识别率高达99.38%(附源码)
    python获取公网ip的几种方式
    Chrome与chromedriver.exe的版本对应
    Google Gson用法
    idea 报错javax/xml/bind/DatatypeConverter
    org.slf4j:slf4j-api:添加日志管理
    基本使用——OkHttp3详细使用教程
  • 原文地址:https://www.cnblogs.com/dudu1990/p/2953173.html
Copyright © 2020-2023  润新知