精华内容
下载资源
问答
  • Linux设备模型

    2017-12-11 22:40:28
    Linux设备模型 Linux设备模型 Linux设备模型 Linux设备模型
  • Linux设备模型及Platform驱动 目标 理解Linux设备模型的内容和意义 掌握符合设备模型的驱动编写方法 掌握Platform设备驱动编写方法 第一章:Linux设备模型 第二章:Linux设备模型简单例程 第三章:Platform...
  • Linux设备模型三总线、设备、驱动程序Linux设备模型三总线、设备、驱动程序
  • 分linux设备模型浅析之设备篇 与 linux设备模型浅析之驱动篇 两篇 详细分析了linux驱动设备模型架构
  • Linux设备模型浅析之驱动篇.pdf
  • Linux设备模型(总线、设备、驱动程序和类)
  • mtk设备模型之LCM

    千次阅读 2016-04-14 19:21:37
    1、Linux设备模型 站在BSP的角度来看,整个系统可以由三部分组成:设备、总线、驱动。 Linux kernel有一些总线,比如USB、I2C等。对于每一个总线都会有一些设备和驱动挂在上面。驱动服务于匹配的设备,使...

    1、Linux设备模型

    站在BSP的角度来看,整个系统可以由三部分组成:设备、总线、驱动。


    Linux kernel有一些总线,比如USB、I2C等。对于每一个总线都会有一些设备和驱动挂在上面。驱动服务于匹配的设备,使Linux正确的操作硬件设备。当一个设备或者驱动注册到特定的总线上的时候就会触发总线匹配函数,比如一个设备注册到了总线,所有的该总线的驱动都会被枚举,判断是不是可以服务于新添加的设备(一般通过name来匹配),反之亦然。

    如果总线匹配成功,就会调用驱动的probe函数,检查指定的硬件确实存在,然后确定是否所需的资源都能够从系统申请。

    事实上,设备或者驱动能够正确的合作,在probe之后,模块初始化顺序决定于probe的执行顺序,可以由BSP函数中注册设备的顺序控制。MT6572平台,L版本的BSP文件放在kernel/arch/arm/mach-mt6572/mt_devs.c,mt_board_init()函数控制着probe的顺序。


    2、LCM设备模型

    对于方案公司的驱动开发人员来说,对于LCM的工作主要是在Mediatek的代码架构下进行兼容和优化。和其他的所有的模块一样,Mediatek的软件架构尽可能的把所有的无需客制化的代码划分出来,从而减少对下游开发人员的工作量。

    Mediatek封装了一个结构体给开发人员,包含了所有可能需要克制化的函数指针,对于不同的IC,只需要对应实现相应的函数就可以了。

     

    LCM_DRIVER 结构体的各个成员的介绍如下:

    l  在LCM_UTIL_FUNCS这个类型中,主要定义了一些接口函数,这些接口函数是mtk提供给lcm驱动开发者使用的;

    l  lcm_compare_id函数中主要是通过读寄存器获取硬件的id号判断和此驱动支持的硬件lcm是否一致,如果一致就选择这个驱动。实现了驱动和设备正确匹配。在后面分析lcm的设备模型中会讲到。

    l  lcm_get_params函数中主要是一些参数定义,例如屏的分辨率,屏的接口类型等;

    l  下面三个函数主要和上电时序有关

      // for power-onsequence refinement
         void (*init_power)(void);
         void (*suspend_power)(void);  
             void(*resume_power)(void);


    l  下面几个函数和ESD有关

       /ESD_RECOVERY//
        unsigned int(*esd_check)(void);
        unsigned int  (*esd_recover)(void);
        unsigned int(*check_status)(void);
        unsigned int(*ata_check)(unsigned char *buffer);


    言归正传,LCM的设备模型也是遵守设备总线驱动结构的,只不过在这个基础上MTK又做了一些工作,封装出LCM_DRIVER 结构体。

    总线

    platform虚拟总线,关在该总线的设备和驱动通过name来匹配。

    设备

    在文件Mt_devs.c (arch\arm\mach-mt6572)中定义了LCM设备和资源,代码如下:



    驱动

    驱动文件出了MTK抽象出来的具体设备驱动文件外,这里指的是挂在platform上的驱动文件。Mtkfb.c (drivers\misc\mediatek\video\mt6572) 。


    驱动的名字和设备匹配后,调用驱动的probe进行探测设备,并完成资源申请,sysfs文件系统操作等。最终在/dev/下生成设备文件节点。系统通过uevent通知udev,udev会收集在sysfs/class下面的文件信息,自动创建文件节点。

    mtk_fb_probe函数主要做的工作如下:

    /* Called by LDM binding to probe andattach a new device.

     *Initialization sequence:

     *   1.allocate system fb_info structure

     *     select panel type according to machine type

     *   2.init LCD panel

     *   3.init LCD controller and LCD DMA

     *   4.init system fb_info structure

     *   5.init gfx DMA

     *   6.enable LCD panel

     *     start LCD frame transfer

     *   7.register system fb_info structure

     */

    比较关键的函数是mtkfb_find_lcm_driver,这个函数调用具体设备驱动里面的函数和数据(例如:St7796s_hvga_dsi_ivo_txd.c (drivers\misc\mediatek\lcm\st7796s_hvga_dsi_ivo_txd))。

    下面对其进行分析:

    BOOL mtkfb_find_lcm_driver(void)
    {
             p = strstr(saved_command_line, "lcm=");
             if(p== NULL)
             {
                       //we can't find lcm string in the command line, the uboot should be old version
                       returnDISP_SelectDevice(NULL);
             }
             if(DISP_SelectDevice(mtkfb_lcm_name))
                       ret= TRUE;
    done:
             returnret;
    }


    p =strstr(saved_command_line, "lcm=");获取从lk(uboot)传入的cmdline中的"lcm="数据,为LCM设备的名称。众所周知,uboot把控制权交给kernel之后会传入一些参数,其中cmdline为uboot传入kernel参数命令行。可以通过如下指令获得:cat /proc/cmdline .

    << /proc/cmdline >>:

    console=tty0 console=ttyMT0,921600n1 root=/dev/ram vmalloc=496Mslub_max_order=0 slub_debug=O  lcm=1-st7796s_hvga_dsi_ivo_txd fps=5480 vram=4194304bootprof.pl_t=1830 bootprof.lk_t=1628 printk.disable_uart=0ddebug_query="file *mediatek* +p ; file *gpu* =_" boot_reason=0androidboot.serialno=0123456789ABCDEF androidboot.bootreason=power_key

    获得LCM名称以后就会调用if(DISP_SelectDevice(mtkfb_lcm_name)) 函数根据mtkfb_lcm_name 从LCM_DRIVER链表中获取对应的结构体指针,然后就传入了上面介绍的MTK客制化的一些LCM函数。

    问题来了,uboot(LK)是怎么知道LCM的名字的呢?

    在LK中也会有和kernel具体LCM驱动相同的设备驱动文件如

    St7796s_hvga_dsi_ivo_txd.c(dev\lcm\st7796s_hvga_dsi_ivo_txd)。

    LK也会把一系列LCM_DRIVER放入链表中,然后通过调用LCM_DRIVER里面的lcm_compare_id函数进行ID匹配,如果读到硬件的id和此驱动支持的id匹配,则选择此驱动。下面是对LK代码中LCM驱动的选择流程分析。

    首先是LK总体代码执行的流程图:


    在Kmain()函数中会有以下的函数调用流程:


    在函数platform_early_init()函数里进行一系列的硬件初始化,看代码(精简):

    void platform_early_init(void)
    {
       //preloader won't reach max speed. It will done by LK.
       if (g_boot_arg->boot_mode != DOWNLOAD_BOOT)
        {
        mtk_set_arm_clock();//设置时钟
        }
       /* initialize the uart */
       uart_init_early();//串口初始化
       platform_init_interrupts();//中断
       platform_early_init_timer();//时钟
       mt_gpio_set_default();//gpio
       mt_i2c_init();//i2c
       clk_init();//clk
       mtk_wdt_init();//看门狗
       isink0_init();              //turnon PMIC6329 isink0
        mt_disp_init((void *)g_fb_base);//LCM
    #ifdef CONFIG_CFB_CONSOLE
       drv_video_init();
    #endif
    #if defined(TARGET_S4)
       pmic_init();//pmu
    #endif
    }


    mt_disp_init((void *)g_fb_base);函数会调用

      DISP_CHECK_RET(DISP_Init((UINT32)lcdbase, (UINT32)lcdbase, FALSE));

    DISP_Init函数在Disp_drv.c(platform\mt6572)    中定义,然后继续调用disp_drv_init_context()函数--》

     if(!isLCMFound)

           DISP_DetectDevice();

    --》

      lcm_drv = disp_drv_get_lcm_driver(NULL);

    --》判断LCM_DRIVER链表中lcm驱动的数量,如果为1个就直接拿来用给设备,不需要调用compare_id函数,如果多个就需要匹配硬件id号了。

    if(lcm_count ==1)
       {
         // we need to verify whether the lcm is connected
         // even there is only one lcm type defined
         lcm = lcm_driver_list[0];
         lcm->set_util_funcs(&lcm_utils);
         lcm->get_params(&s_lcm_params);
         u4IndexOfLCMList = 0;
         
         lcm_params = &s_lcm_params;
         lcm_drv = lcm;
                       isLCMFound= TRUE;
    }
    for(i = 0;i < lcm_count;i++)
         {
            ……
               if(lcm->compare_id != NULL && lcm->compare_id())
               {
                  printk("\t\t[success]\n");
                   isLCMFound = TRUE;
                   lcm_drv = lcm;
                   u4IndexOfLCMList = i;
                   goto done;
               }
             }


    驱动找到会把LCD_DRIVER结构体指针赋值到全局变量lcm_drv中。通过调用文件Mt_boot.c (app\mt_boot)中的intboot_linux_from_storage(void)函数

       strlen += sprintf(commanline, "%s lcm=%1d-%s", commanline,DISP_IsLcmFound(), mt_disp_get_lcm_id());
       strlen += sprintf(commanline, "%s fps=%1d", commanline,mt_disp_get_lcd_time());
       strlen += sprintf(commanline, "%s vram=%1d", commanline,DISP_GetVRamSize());


    将lcm相关的信息,写到cmdline中,传递给kernel。


    展开全文
  • Zephyr Kernel 设备驱动和设备模型(一)

    千次阅读 2017-04-26 14:13:18
    Zephyr 的设备模型为配置驱动程序提供了一致的设备模型设备模型负责初始化配置到系统中的所有驱动。 每种类型的驱动程序(UAR,SPI,I2C)都有一个通用类型的API。 在这个模型中,当驱动程序初始化时,驱动中会...
    介绍
    

           Zephyr 内核支持大量的设备驱动程序。应用程序板级配置的可用设备驱动集合随着所关联的硬件组件和设备驱动软件的变化而变化。Zephyr 的设备模型为配置驱动程序提供了一致的设备模型。设备模型负责初始化配置到系统中的所有驱动。每种类型的驱动程序(UAR,SPI,I2C)都有一个通用类型的API。在这个模型中,当驱动程序初始化时,驱动中会填充指向包含指向它的API 函数的结构的指针。这些结构体被按照初始化等级放到RAM区。


    标准驱动
    所有的板级配置中都支持的设备驱动包括:
    • 中断控制器:用于内核的中断管理子系统。
    • 定时器:用于内核的系统时钟和硬件时钟子系统。
    • 串行通信:用于内核的系统控制台子系统。
    • 随机数生产器:提供数据数源。

    同步调用

    Zephyr 对多种板子提供了一系列的设备驱动程序。除非硬件不支持,否则每个驱动都应当提供基于中断(而不是轮询)的实现。


    驱动程序API
    device.h中提供了如下关于设备驱动程序的API。这些API只能用于设备驱动程序中,不能应用于应用程
    序中。.
    DEVICE_INIT()
    创建设备对象,并在启动的初始化阶段调用其初始化函数。
    DEVICE_AND_API_INIT()
    创建设备对象,并在启动的初始化阶段调用其初始化函数。此外,它还用一个指针指向驱动程
    序的API。
    DEVICE_NAME_GET()
    获得一个全局设别对象的全名。
    DEVICE_GET()
    通过名字获取一个执行设备对象的指针。
    DEVICE_DECLARE()
    声明一个设备对象。


    驱动的数据结构
    设备驱动宏中的某些数据结构分为只读部分和运行时可变部分。在最顶层包括:
    struct device {
    struct device_config *config;
    void *driver_api;
    void *driver_data;
    };
    成员config 是只读配置数据的集合,它在编译时就确定了,例如IO 地址映射的内存、IRQ 号或者设备的其
    它固定物理特性。这是传递给宏DEVICE_*INIT()的config_info结构体。
    driver_data 结构被置于ARM 中,它是每个实例在运行时的驱动程序所使用的数据。例如,引用计数、信号
    量、scratch 缓冲等。
    driver_api 结构是驱动程序中实现的设备相关的通用子系统API。它通常是只读的,并在编译时就确定了。
    在下一节中将详细描述这一点。
    子系统以及API 结构
    大多数驱动程序的主要目标是提供一个与设备独立的子系统API。应用程序只需要简单地使用这些通用
    API,而不需要了解驱动实现的细节。
    子系统API的定义通常是这样的:
    typedef int (*subsystem_do_this_t)(struct device *device, int foo, int bar);
    typedef void (*subsystem_do_that_t)(struct device *device, void *baz);
    struct subsystem_api {
    subsystem_do_this_t do_this;
    subsystem_do_that_t do_that;
    };
    static inline int subsystem_do_this(struct device *device, int foo, int bar)
    {
    struct subsystem_api *api;
    api = (struct subsystem_api *)device->driver_api;
    return api->do_this(device, foo, bar);
    }
    static inline void subsystem_do_that(struct device *device, void *baz)
    {
    struct subsystem_api *api;
    api = (struct subsystem_api *)device->driver_api;
    api->do_that(device, foo, bar);
    }
    通常,在遇到错误时,除非在某个常规操作中需要返回值(例如存储设备满了),否则最好使用宏
    __ASSERT() 进行断言。参数错误、编程错误、一致性检查、不可恢复的错误等都需要使用断言进行处理。
    当需要返回错误状态给调用者检查时,如果成功则返回0,如果失败则返回POSIX errno.h 代码。更多细节
    请参考https://wiki.zephyrproject.org/view/Coding_conventions#Return_Codes。
    当实现一个具体的子系统时,驱动程序需要定义这些API,并将它与子系统API 结构绑定在一起:

    static int my_driver_do_this(struct device *device, int foo, int bar)
    {
    ...
    }
    static void my_driver_do_that(struct device *device, void *baz)
    {
    ...
    }
    static struct subsystem_api my_driver_api_funcs = {
    .do_this = my_driver_do_this,
    .do_that = my_driver_do_that
    };
    然后,驱动程序需要将my_driver_api_funcs 作为api 参数传递给宏DEVICE_AND_API_INIT(),或者在驱动
    的初始化函数中手动地将其赋值给device->driver_api。
    注解: 由于指向API 函数的指针是通过driver_api 结构引用的,这些指针将始终被包含到二进制文件中(即
    使未使用)。链接选项gc-sections 至少能看到对它们的一个引用。Providing for link-time size optimizations
    with driver APIs in most cases requires that the optional feature be controlled by a Kconfig option.

    初始化等级
    驱动程序可能会依赖其它先初始化的驱动或者需要使用内核服务。DEVICE_INIT() 允许用户指定在系统
    启动的哪个时间段执行设备驱动的初始化函数。所有的驱动程序都需要在如下的五个初始化等级中指定一
    个:
    PRE_KERNEL_1
    用于那些没有任何依赖的设备,例如那些纯粹只需要处理器/SoC 上的硬件的设备。这些设备在
    配置期间不需要使用任何内内核服务,因此此时内核服务还未启动。不过,中断子系统会被配
    置,因此可以设置中断。在这个等级上的初始化函数运行在中断栈上面。
    PRE_KERNEL_2
    用于那些依赖于已被初始化的PRE_KERNEL_1 等级的设备的设备。这些设备在配置期间不使用
    任何内核服务,因此此时内核服务还未启动。在这个等级上的初始化函数运行在中断栈上面。
    POST_KERNEL
    用于那些在配置期间需要依赖内核服务的设备。在这个等级上的初始化函数运行在内核主栈的
    上下文中。
    APPLICATION


    用于需要自动配置的应用程序组件(即非内核组件)。这些设别在配置期间可以使用内核提供
    的所有服务。在这个等级上的初始化函数运行在内核主栈的上下文中。
    在每个初始化等级,您还需要指定一个优先级,用于区分相同初始化等级的其它设备。这个优先级是0 到
    99 之间的整数值。优先级越低表示越早被初始化。优先级必须是一个前面没有补零的或者没有符号的十
    进制整数字面量或者一个对等的符号(例如#define MY_INIT_PRIO 32)。符号表达式是不被允许的(例如
    CONFIG_KERNEL_INIT_PRIORITY_DEFAULT + 5)。
    系统驱动
    在某些情况下,您可以只需要在启动时运行某个函数。宏SYS_INIT 被映射为DEVICE_INIT() 或DEVICE_
    INIT_PM()。对于SYS_INIT(),它不存在配置或者运行时的数据结构,因此也不能再随后通过名字获
    取到设备指针。它的初始化等级和优先级与普通设备是一样的。
    对于SYS_INIT_PM(),您可以通过名字获得指针。参考power management 一节。
    SYS_INIT()
    SYS_INIT_PM()

    展开全文
  • Linux设备模型 (2)

    千次阅读 2014-09-02 13:58:22
    上一篇文章《Linux设备模型 (1)》主要介绍了Linux设备模型在用户空间的接口sysfs,用户通过这个接口可以一览内核设备的全貌。本文将从Linux内核的角度来看一看这个设备模型是如何构建的。 在Linux内核里,kobject...

    转载:http://www.cnblogs.com/wwang/archive/2010/12/16/1902721.html

    上一篇文章《Linux设备模型 (1)》主要介绍了Linux设备模型在用户空间的接口sysfs,用户通过这个接口可以一览内核设备的全貌。本文将从Linux内核的角度来看一看这个设备模型是如何构建的。

    在Linux内核里,kobject是组成Linux设备模型的基础,一个kobject对应sysfs里的一个目录。从面向对象的角度来说,kobject可以看作是所有设备对象的基类,因为C语言并没有面向对象的语法,所以一般是把kobject内嵌到其他结构体里来实现类似的作用,这里的其他结构体可以看作是kobject的派生类。Kobject为Linux设备模型提供了很多有用的功能,比如引用计数,接口抽象,父子关系等等。引用计数本质上就是利用kref实现的,至于kref的细节可以参考我之前的文章《Linux内核里的“智能指针”》。

    另外,Linux设备模型还有一个重要的数据结构kset。Kset本身也是一个kobject,所以它在sysfs里同样表现为一个目录,但它和kobject的不同之处在于kset可以看作是一个容器,如果你把它类比为C++里的容器类如list也无不可。Kset之所以能作为容器来使用,其内部正是内嵌了一个双向链表结构struct list_head。对于list_head的细节可以参考《玩转C链表》一文。

    下面这幅图可以用来表示kobject和kset在内核里关系。

    在接下来的篇幅里我们会逐步看到这个关系图在内核里是如何建立的。本文的示例代码可以从这里下载,下文中的两个实作都在这个示例代码里。

     

    Kobject

    Kobject在Linux内核里的定义如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    struct  kobject {
         const  char       *name;
         struct  list_head    entry;
         struct  kobject      *parent;
         struct  kset     *kset;
         struct  kobj_type    *ktype;
         struct  sysfs_dirent *sd;
         struct  kref     kref;
         unsigned int  state_initialized:1;
         unsigned int  state_in_sysfs:1;
         unsigned int  state_add_uevent_sent:1;
         unsigned int  state_remove_uevent_sent:1;
         unsigned int  uevent_suppress:1;
    };

    在《Linux设备模型 (1)》里面我们介绍到内核里的设备之间是以树状形式组织的,在这种组织架构里比较靠上层的节点可以看作是下层节点的父节点,反映到sysfs里就是上级目录和下级目录之间的关系,在内核里,正是kobject帮助我们实现这种父子关系。在kobject的定义里,name表示的是kobject在sysfs中的名字;指针parent用来指向kobject的父对象;Kref大家应该比较熟悉了,kobject通过它来实现引用计数;Kset指针用来指向这个kobject所属的kset,下文会再详细描述kset的用法;对于ktype,如果只是望文生义的话,应该是用来描述kobject的类型信息。Ktype的定义如下:

    1
    2
    3
    4
    5
    struct  kobj_type {
         void  (*release)( struct  kobject *kobj);
         const  struct  sysfs_ops *sysfs_ops;
         struct  attribute **default_attrs;
    };

    函数指针release是给kref使用的,当引用计数为0这个指针指向的函数会被调用来释放内存。sysfs_ops和attribute是做什么用的呢?前文里提到,一个kobject对应sysfs里的一个目录,而目录下的文件就是由sysfs_ops和attribute来实现的,其中,attribute定义了kobject的属性,在sysfs里对应一个文件,sysfs_ops用来定义读写这个文件的方法。Ktype里的attribute是默认的属性,另外也可以使用更加灵活的手段,本文的重点还是放在default attribute。

     

    下面看一个实作。在这个实作里,我们定义一个内嵌kobject的结构。

    1
    2
    3
    4
    struct  my_kobj {
         int  val;
         struct  kobject kobj;
    };

    最终我们的目的是在内核里构建这样的架构。

    对应sysfs里的目录关系是:

    mykobj1/
    |-- mykobj2
    | |-- name
    | `-- val
    |-- name
    `-- val

    这是module_init代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    static  int  __init mykobj_init( void )
    {
         printk(KERN_INFO "mykobj_init\n" );
     
         obj1 = kzalloc( sizeof ( struct  my_kobj), GFP_KERNEL);
         if  (!obj1) {
             return  -ENOMEM;
         }
         obj1->val = 1;
     
         obj2 = kzalloc( sizeof ( struct  my_kobj), GFP_KERNEL);
         if  (!obj2) {
             kfree(obj1);
             return  -ENOMEM;
         }
         obj2->val = 2;
     
         my_type.release = obj_release;
         my_type.default_attrs = my_attrs;
         my_type.sysfs_ops = &my_sysfsops;
     
         kobject_init_and_add(&obj1->kobj, &my_type, NULL, "mykobj1" );
         kobject_init_and_add(&obj2->kobj, &my_type, &obj1->kobj, "mykobj2" );
     
         return  0;
    }

    这段代码可以分作三个部分。第一部分是分配obj1和obj2并赋值;第二部分是初始化kobj_type变量my_type;第三部分是调用kobject_init_and_add函数来初始化kobject并把它加入到设备模型的体系架构(也就是上文中提到的内核中的那棵树)中。kobject_init_and_add是简化的写法,这个函数也可以分两步完成:kobject_init和kobject_add。

    int  kobject_init_and_add( struct  kobject *kobj, struct  kobj_type *ktype,
                  struct  kobject *parent, const  char  *fmt, ...);
     
    void  kobject_init( struct  kobject *kobj, struct  kobj_type *ktype);
    int  kobject_add( struct  kobject *kobj, struct  kobject *parent,
             const  char  *fmt, ...);

    kobject_init用来初始化kobject结构,kobject_add用来把kobj加入到设备模型之中。在实作中,我们先对obj1进行初始化和添加的动作,调用参数里,parent被赋为NULL,表示obj1没有父对象,反映到sysfs里,my_kobj1的目录会出现在/sys下,obj2的父对象设定为obj1,那么my_kobj2的目录会出现在/sys/my_kobj1下面。

    前面提到,kobject也提供了引用计数的功能,虽然本质上是利用kref,但也提供了另外的接口供用户使用。

    1
    2
    struct  kobject *kobject_get( struct  kobject *kobj);
    void  kobject_put( struct  kobject *kobj);

    kobject_init_and_add和kobject_init这两个函数被调用后,kobj的引用计数会初始化为1,所以在module_exit时要记得用kobject_put来释放引用计数。

    我们再回到实作中,看看如何使用ktype。代码里,my_attrs是这样定义的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    struct  attribute name_attr = {
         .name = "name" ,
         .mode = 0444,
    };
     
    struct  attribute val_attr = {
         .name = "val" ,
         .mode = 0666,
    };
     
    struct  attribute *my_attrs[] = {
         &name_attr,
         &val_attr,
         NULL,
    };

    结构体struct attribute里的name变量用来指定文件名,mode变量用来指定文件的访问权限。这里需要着重指出的是,数组my_attrs的最后一项一定要赋为NULL,否则会造成内核oops。

    sysfs_ops的代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    ssize_t my_show( struct  kobject *kobj, struct  attribute *attr, char  *buffer)
    {
         struct  my_kobj *obj = container_of(kobj, struct  my_kobj, kobj);
         ssize_t count = 0;
     
         if  ( strcmp (attr->name, "name" ) == 0) {
             count = sprintf (buffer, "%s\n" , kobject_name(kobj));
         } else  if  ( strcmp (attr->name, "val" ) == 0) {
             count = sprintf (buffer, "%d\n" , obj->val);
         }
     
         return  count;
    }
     
    ssize_t my_store( struct  kobject *kobj, struct  attribute *attr, const  char  *buffer, size_t  size)
    {
         struct  my_kobj *obj = container_of(kobj, struct  my_kobj, kobj);
     
         if  ( strcmp (attr->name, "val" ) == 0) {
             sscanf (buffer, "%d" , &obj->val);
         }
     
         return  size;
    }
     
    struct  sysfs_ops my_sysfsops = {
         .show = my_show,
         .store = my_store,
    };

    读文件会调用my_show,写文件会调用my_store。

    最后是module_exit:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    static  void  __exit mykobj_exit( void )
    {
         printk(KERN_INFO "mykobj_exit\n" );
     
         kobject_del(&obj2->kobj);
         kobject_put(&obj2->kobj);
         
         kobject_del(&obj1->kobj);
         kobject_put(&obj1->kobj);
     
         return ;
    }

    kobject_del的作用是把kobject从设备模型的那棵树里摘掉,同时sysfs里相应的目录也会删除。这里需要指出的是,释放的顺序应该是先子对象,后父对象。因为kobject_init_and_add和kobject_add这两个函数会调用kobject_get来增加父对象的引用计数,所以kobject_del需要调用kobject_put来减少父对象的引用计数。在本例中,如果先通过kobject_put来释放obj1,那kobject_del(&obj2->kobj)就会出现内存错误。

    在这个实作中,我们建立了两个对象obj1和obj2,obj1是obj2的父对象,如果推广开来,obj1可以有更多的子对象。在Linux内核中,这种架构方式其实并无太大的实际价值,有限的用处之一是在sysfs里创建子目录(Linux内核里有这种用法,这种情况下,直接调用内核提供的kobject_create来实现,不需要自定义数据结构并内嵌kobject),而且,创建子目录也是有其他的办法的。我们知道,Linux设备模型最初的目的是为了方便电源管理,这就需要从上到下的遍历,在这种架构里,通过obj1并无法访问其所有的子对象。这个实作最大的意义在于可以让我们比较清晰的理解kobject如何使用。通常情况下,kobject只需要在叶节点里使用,上层的节点要使用kset。

     

    Kset

    Kset的定义如下:

    1
    2
    3
    4
    5
    6
    struct  kset {
         struct  list_head list;
         spinlock_t list_lock;
         struct  kobject kobj;
         const  struct  kset_uevent_ops *uevent_ops;
    };

    Kset结构里的kobj表明它也是一个kobject,list变量用来组织它所有的子对象。

     

    我们直接看一个实作。在这个实作里,我们将构建如下的架构。

    对应sysfs里的目录关系是:

    my_kset/
    |-- mykobj1
    |   |-- name
    |   `-- val
    `-- mykobj2
        |-- name
        `-- val

    这个实作和前一个差别很小,下面只简略的引用一些代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    static  int  __init mykset_init( void )
    {
         printk(KERN_INFO "mykset_init\n" );
     
         my_kset = kset_create_and_add( "my_kset" , NULL, NULL);
         if  (!my_kset) {
             return  -ENOMEM;
         }
     
         // Allocate obj1 and obj2
         // ...
     
         obj1->kobj.kset = my_kset;
         obj2->kobj.kset = my_kset;
     
         // Init my_type
         // ...
     
         kobject_init_and_add(&obj1->kobj, &my_type, NULL, "mykobj1" );
         kobject_init_and_add(&obj2->kobj, &my_type, NULL, "mykobj2" );
     
         return  0;
    }
     
    static  void  __exit mykset_exit( void )
    {
         printk(KERN_INFO "mykset_exit\n" );
     
         // Release obj1 and obj2
         // ...
     
         kset_unregister(my_kset);
     
         return ;
    }

    在module_init里,我们首先调用kset_create_and_add创建my_kset,接下来把my_kset赋给obj1和obj2,最后调用kobject_init_and_add来添加obj1和obj2。这里需要注意的是,kobject_init_and_add参数里的parent都是NULL,在这种情况下,obj1和obj2的父对象由kobject结构里的kset指针决定,在这个实作里就是my_kset。在module_exit里,我们还需要额外调用kset_unregister来释放之前创建的my_kset。

     

    注:看过LDD3的读者应该对Linux Device Model一章中的subsystem还有印象,我在这里注明一下,从2.6.23开始Linux内核就抛弃了subsystem,subsystem其实只是kset的一个马甲,所以抛弃它对Linux设备模型并没什么影响。

    展开全文
  • 提到 sysfs 文件系统 ,必须先需要了解的是Linux设备模型,什么事Linux设备模型呢? 一、Linux 设备模型 1、设备模型概述  从2.6版本开始,Linux开发团队便为内核建立起一个统一的设备模型。在以前的内核中没有...

          提到 sysfs 文件系统 ,必须先需要了解的是Linux设备模型,什么是Linux设备模型呢?

    一、Linux 设备模型

    1、设备模型概述

         从2.6版本开始,Linux开发团队便为内核建立起一个统一的设备模型。在以前的内核中没有独立的数据结构用来让内核获得系统整体配合的信息。尽管缺乏这些信息,在多数情况下内核还是能正常工作的。然而,随着拓扑结构越来越复杂,以及要支持诸如电源管理等新特性的需求,向新版本的内核明确提出了这样的要求:需要有一个对系统结构的一般性抽象描述,即设备模型。

    目的

    I     设备、驱动、总线等彼此之间关系错综复杂。如果想让内核运行流畅,那就必须为每个模块编码实现这些功能。如此一来,内核将变得非常臃肿、冗余。而设备模型的理念即是将这些代码抽象成各模块共用的框架,这样不但代码简洁了,也可让设备驱动开发者摆脱这本让人头痛但又必不可少的一劫,将有限的精力放于设备差异性的实现。

    II    设备模型用类的思想将具有相似功能的设备放到一起管理,并将相似部分萃取出来,使用一份代码实现。从而使结构更加清晰,简洁。

    III   动态分配主从设备号,有效解决设备号的不足。设备模型实现了只有设备在位时才为其分配主从设备号,这与之前版本为每个设备分配一个主从设备号不同,使得有限的资源得到合理利用。

    IV   设备模型提供sysfs文件系统,以文件的方式让本是抽象复杂而又无法捉摸的结构清晰可视起来。同时也给用户空间程序配置处于内核空间的设备驱动提供了一个友善的通道。

    V   程序具有随意性,同一个功能,不同的人实现的方法和风格各不相同,设备驱动亦是如此。大量的设备亦若实现方法流程均不相同,对以后的管理、重构将是难以想象的工作量。设备模型恰是提供了一个模板,一个被证明过的最优的思路和流程,这减少了开发者设计过程中不必要的错误,也给以后的维护扫除了障碍。


    2、设备模型结构

           如表,Linux设备模型包含以下四个基本结构:

    类型

    所包含的内容

    内核数据结构

    对应/sys

    设备(Devices)

    设备是此模型中最基本的类型,以设备本身的连接按层次组织

    struct device

    /sys/devices/*/*/.../

    驱动

    (Drivers)

    在一个系统中安装多个相同设备,只需要一份驱动程序的支持

    struct device_driver

    /sys/bus/pci/drivers/*/

    总线

    (Bus)

    在整个总线级别对此总线上连接的所有设备进行管理

    struct bus_type

    /sys/bus/*/

    类别(Classes)

    这是按照功能进行分类组织的设备层次树;如 USB 接口和 PS/2 接口的鼠标都是输入设备,都会出现在/sys/class/input/下

    struct class

    /sys/class/*/



           device、driver、bus、class是组成设备模型的基本数据结构。kobject是构成这些基本结构的核心,kset又是相同类型结构kobject的集合。kobject和kset共同组成了sysfs的底层数据体系。本节采用从最小数据结构到最终组成一个大的模型的思路来介绍。当然,阅读时也可先从Device、Driver、Bus、Class的介绍开始,先总体了解设备模型的构成,然后再回到kobject和kset,弄清它们是如何将Device、Driver、Bus、Class穿插链接在一起的,以及如何将这些映像成文件并最终形成一个sysfs文件系统。


    二、sys 文件系统

            sysfs是一个基于内存的文件系统,它的作用是将内核信息以文件的方式提供给用户程序使用

            sysfs可以看成与proc,devfs和devpty同类别的文件系统,该文件系统是虚拟的文件系统,可以更方便对系统设备进行管理。它可以产生一个包含所有系统硬件层次视图,与提供进程和状态信息的proc文件系统十分类似。

           sysfs把连接在系统上的设备和总线组织成为一个分级的文件,它们可以由用户空间存取,向用户空间导出内核的数据结构以及它们的属性。sysfs的一个目的就是展示设备驱动模型中各组件的层次关系,其顶级目录包括block,bus,drivers,class,power和firmware等.

          sysfs提供一种机制,使得可以显式的描述内核对象、对象属性及对象间关系。sysfs有两组接口,一组针对内核,用于将设备映射到文件系统中,另一组针对用户程序,用于读取或操作这些设备。表2描述了内核中的sysfs要素及其在用户空间的表现:

              sysfs在内核中的组成要素              

                   在用户空间的显示         

    内核对象(kobject)

    目录

    对象属性(attribute)

    文件

    对象关系(relationship)

       链接(Symbolic Link)


         sysfs目录结构:

    /sys 下的子目录                   

    所包含的内容

    /sys/devices

    这是内核对系统中所有设备的分层次表达模型,也是/sys文件系统管理设备的最重要的目录结构;

    /sys/dev

    这个目录下维护一个按字符设备和块设备的主次号码(major:minor)链接到真实的设备(/sys/devices下)的符号链接文件;

    /sys/bus

    这是内核设备按总线类型分层放置的目录结构, devices 中的所有设备都是连接于某种总线之下,在这里的每一种具体总线之下可以找到每一个具体设备的符号链接,它也是构成 Linux 统一设备模型的一部分;

    /sys/class

    这是按照设备功能分类的设备模型,如系统所有输入设备都会出现在/sys/class/input 之下,而不论它们是以何种总线连接到系统。它也是构成 Linux 统一设备模型的一部分;

    /sys/kernel

    这里是内核所有可调整参数的位置,目前只有 uevent_helper, kexec_loaded, mm, 和新式的slab 分配器等几项较新的设计在使用它,其它内核可调整参数仍然位于sysctl(/proc/sys/kernel) 接口中;

    /sys/module

    这里有系统中所有模块的信息,不论这些模块是以内联(inlined)方式编译到内核映像文件(vmlinuz)中还是编译为外部模块(ko文件),都可能会出现在/sys/module 中:

    • 编译为外部模块(ko文件)在加载后会出现对应的/sys/module/<module_name>/,并且在这个目录下会出现一些属性文件和属性目录来表示此外部模块的一些信息,如版本号、加载状态、所提供的驱动程序等;
    • 编译为内联方式的模块则只在当它有非0属性的模块参数时会出现对应的/sys/module/<module_name>,这些模块的可用参数会出现在/sys/modules/<modname>/parameters/<param_name> 中,
      • 如/sys/module/printk/parameters/time这个可读写参数控制着内联模块printk在打印内核消息时是否加上时间前缀;
      • 所有内联模块的参数也可以由"<module_name>.<param_name>=<value>"的形式写在内核启动参数上,如启动内核时加上参数"printk.time=1"与向"/sys/module/printk/parameters/time"写入1的效果相同;
    • 没有非0属性参数的内联模块不会出现于此。

    /sys/power

    这里是系统中电源选项,这个目录下有几个属性文件可以用于控制整个机器的电源状态,如可以向其中写入控制命令让机器关机、重启等。

    表3:sysfs目录结构

     

    三、深入理解 sysfs 文件系统

            sysfs是一个特殊文件系统,并没有一个实际存放文件的介质。

    1、kobject结构

            sysfs的信息来源是kobject层次结构,读一个sysfs文件,就是动态的从kobject结构提取信息,生成文件。重启后里面的信息当然就没了

            sysfs文件系统与kobject结构紧密关联,每个在内核中注册的kobject对象都对应于sysfs文件系统中的一个目录。

            Kobject 是Linux 2.6引入的新的设备管理机制,在内核中由struct kobject表示。通过这个数据结构使所有设备在底层都具有统一的接口,kobject提供基本的对象管理,是构成Linux2.6设备模型的核心结构,Kobject是组成设备模型的基本结构。类似于C++中的基类,它嵌入于更大的对象的对象中,用来描述设备模型的组件。如bus,devices, drivers 等。都是通过kobject连接起来了,形成了一个树状结构。这个树状结构就与/sys向对应


    2、sysfs 如何读写kobject 结构

          sysfs就是利用VFS的接口去读写kobject的层次结构,建立起来的文件系统。 kobject的层次结构的注册与注销XX_register()形成的。文件系统是个很模糊广泛的概念, linux把所有的资源都看成是文件,让用户通过一个统一的文件系统操作界面,也就是同一组系统调用,对属于不同文件系统的文件进行操作。这样,就可以对用户程序隐藏各种不同文件系统的实现细节,为用户程序提供了一个统一的,抽象的,虚拟的文件系统界面,这就是所谓"VFS(Virtual Filesystem Switch)"。这个抽象出来的接口就是一组函数操作。
         我们要实现一种文件系统就是要实现VFS所定义的一系列接口,file_operations, dentry_operations, inode_operations等,供上层调用。

    file_operations是描述对每个具体文件的操作方法(如:读,写);

    dentry_operations结构体指明了VFS所有目录的操作方法;

    inode_operations提供所有结点的操作方法


    举个例子,我们写C程序,open(“hello.c”, O_RDONLY),它通过系统调用的流程是这样的

    open() -> 系统调用->  sys_open() -> filp_open()-> dentry_open() -> file_operations->open()          

          不同的文件系统,调用不同的file_operations->open(),在sysfs下就是sysfs_open_file()。我们使用不同的文件系统,就是将它们各自的文件信息都抽象到dentry和inode中去。这样对于高层来说,我们就可以不关心底层的实现,我们使用的都是一系列标准的函数调用。这就是VFS的精髓,实际上就是面向对象。

         注意sysfs是典型的特殊文件。它存储的信息都是由系统动态的生成的,它动态的包含了整个机器的硬件资源情况。从sysfs读写就相当于向 kobject层次结构提取数据


    下面是详细分析:

    a -- sysfs_dirent是组成sysfs单元的基本数据结构,它是sysfs文件夹或文件在内存中的代表。sysfs_dirent只表示文件类型(文件夹/普通文件/二进制文件/链接文件)及层级关系,其它信息都保存在对应的inode中。我们创建或删除一个sysfs文件或文件夹事实上只是对以sysfs_dirent为节点的树的节点的添加或删除。sysfs_dirent数据结构如下:

    struct sysfs_dirent {
           atomic_t                s_count;
           atomic_t                s_active;
           struct sysfs_dirent  *s_parent;  /* 指向父节点 */
           struct sysfs_dirent  *s_sibling;  /* 指向兄弟节点,兄弟节点是按照inode索引s_ino的大小顺序链接在一起的。*/
           const char             *s_name;    /* 节点名称 */
     
           union {
                  struct sysfs_elem_dir            s_dir;      /* 文件夹,s_dir->kobj指向sysfs对象 */
                  struct sysfs_elem_symlink    s_symlink;  /* 链接 */
                  struct sysfs_elem_attr           s_attr;     /* 普通文件 */
                  struct sysfs_elem_bin_attr     s_bin_attr;  /* 二进制文件 */
           };
     
           unsigned int           s_flags;
    ino_t          s_ino;     /* inode索引,创建节点时被动态申请,通过此值和sysfs_dirent地址可以到inode散列表中获取inode结构 */
           umode_t                s_mode;
           struct iattr             *s_iattr;
    };


    b -- inode(index node)中保存了设备的主从设备号、一组文件操作函数和一组inode操作函数。

         文件操作比较常见:open、read、write等。inode操作在sysfs文件系统中只针对文件夹实现了两个函数一个是目录下查找inode函数(.lookup=sysfs_lookup),该函数在找不到inode时会创建一个,并用sysfs_init_inode为其赋值;另一个是设置inode属性函数(.setattr=sysfs_setattr),该函数用于修改用户的权限等。inode结构如下:

    struct inode {
           struct hlist_node     i_hash;    /* 散列表链节 */
           struct list_head       i_list;
           struct list_head       i_sb_list;
           struct list_head       i_dentry;  /* dentry链节 */
           unsigned long         i_ino;   /* inode索引 */
           atomic_t             i_count;
           unsigned int           i_nlink;
           uid_t                     i_uid;
           gid_t                     i_gid;
           dev_t                    i_rdev; /* 主从设备号 */
    const struct inode_operations *i_op; /* 一组inode操作函数,可用其中lookup查找目录下的inode,对应sysfs为sysfs_lookup函数 */
    const struct file_operations  *i_fop;    /* 一组文件操作函数,对于sysfs为sysfs的open/read/write等函数 */
           struct super_block  *i_sb;
           struct list_head       i_devices;
           union {
                  struct pipe_inode_info    *i_pipe;
                  struct block_device       *i_bdev;
                  struct cdev            *i_cdev;
           };
    };

    c -- dentry(directory entry)的中文名称是目录项,是Linux文件系统中某个索引节点(inode)的链接。

          这个索引节点可以是文件,也可以是目录。引入dentry的目的是加快文件的访问。dentry数据结构如下:

    struct dentry {
           atomic_t d_count;         /* 目录项对象使用的计数器 */
           unsigned int d_flags;             /* 目录项标志 */
           spinlock_t d_lock;              /* 目录项自旋锁 */
           int d_mounted;                     /* 对于安装点而言,表示被安装文件系统根项 */
           struct inode *d_inode;           /* 文件索引节点(inode) */
           /*
            * The next three fields are touched by __d_lookup.  Place them here
            * so they all fit in a cache line.
            */
           struct hlist_node d_hash;       /* lookup hash list */
           struct dentry *d_parent; /* parent directory */
           struct qstr d_name;              /* 文件名 */
     
           /*
            * d_child and d_rcu can share memory
            */
           union {
                  struct list_head d_child; /* child of parent list */
                 struct rcu_head d_rcu;
           } d_u;
          
           void *d_fsdata;                    /* 与文件系统相关的数据,在sysfs中指向sysfs_dirent */
           unsigned char d_iname[DNAME_INLINE_LEN_MIN];      /* 存放短文件名 */
    };

    sysfs_dirent、inode、dentry三者关系:


           如上图sysfs超级块sysfs_sb、dentry根目录root、sysfs_direct根目录sysfs_root都是在sysfs初始化时创建。

          sysfs_root下的子节点是添加设备对象或对象属性时调用sysfs_create_dir/ sysfs_create_file创建的,同时会申请对应的inode的索引号s_ino。注意此时并未创建inode。

          inode是在用到的时候调用sysfs_get_inode函数创建并依据sysfs_sb地址和申请到的s_ino索引计算散列表位置放入其中。

          dentry的子节点也是需要用的时候才会创建。比如open文件时,会调用path_walk根据路径一层层的查找指定dentry,如果找不到,则创建一个,并调用父dentry的inodelookup函数(sysfs文件系统的为sysfs_lookup)查找对应的子inode填充指定的dentry。


           这里有必要介绍一下sysfs_lookup的实现,以保证我们更加清晰地了解这个过程,函数主体如下:

    static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
    {
           struct dentry *ret = NULL;
           struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata; //获取父sysfs_direct
           struct sysfs_dirent *sd;
           struct inode *inode;
     
           mutex_lock(&sysfs_mutex);
          
           /* 在父sysfs_direct查找名为dentry->d_name.name的节点 */
           sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);
     
           /* no such entry */
           if (!sd) {
                  ret = ERR_PTR(-ENOENT);
                  goto out_unlock;
           }
          
           /* 这儿就是通过sysfs_direct获取对应的inode,sysfs_get_inode实现原理上面已经介绍过了 */
           /* attach dentry and inode */
           inode = sysfs_get_inode(sd);
           if (!inode) {
                  ret = ERR_PTR(-ENOMEM);
                  goto out_unlock;
           }
          
           /* 填充目录项,至此一个目录项创建完毕 */
           /* instantiate and hash dentry */
    dentry->d_op = &sysfs_dentry_ops;   /* 填充目录项的操作方法,该方法只提供一释放inode函数sysfs_d_iput */
           dentry->d_fsdata = sysfs_get(sd);        //填充sysfs_direct
           d_instantiate(dentry, inode);                 //填充inode
           d_rehash(dentry);                               //将dentry加入hash表
     
     out_unlock:
           mutex_unlock(&sysfs_mutex);
           return ret;
    }


    四、实例分析

    a -- sysfs文件open流程

            open的主要过程是通过指定的路径找到对应的dentry,并从中获取inode,然后获取一个空的file结构,将inode中相关内容赋值给file,这其中包括将inode的fop赋给file的fop。因此接下来调用的filp->fop->open其实就是inode里的fop->open。新的file结构对应一个文件句柄fd,这会作为整个open函数的返回值。之后的read/write操作就靠这个fd找到对应的file结构了。

    图3-2是从网上找到的,清晰地描述了file和dentry以及inode之间的关系


                                                      图3-2:file、dentry、inode关系


            进程每打开一个文件,就会有一个file结构与之对应。同一个进程可以多次打开同一个文件而得到多个不同的file结构,file结构描述了被打开文件的属性,读写的偏移指针等等当前信息。

            两个不同的file结构可以对应同一个dentry结构。进程多次打开同一个文件时,对应的只有一个dentry结构。dentry结构存储目录项和对应文件(inode)的信息。

           在存储介质中,每个文件对应唯一的inode结点,但是,每个文件又可以有多个文件名。即可以通过不同的文件名访问同一个文件。这里多个文件名对应一个文件的关系在数据结构中表示就是dentry和inode的关系。

          inode中不存储文件的名字,它只存储节点号;而dentry则保存有名字和与其对应的节点号,所以就可以通过不同的dentry访问同一个inode。


    b -- sysfs文件read/write流程

          sysfs与普通文件系统的最大差异是,sysfs不会申请任何内存空间来保存文件的内容。事实上再不对文件操作时,文件是不存在的。只有用户读或写文件时,sysfs才会申请一页内存(只有一页),用于保存将要读取的文件信息。如果作读操作,sysfs就会调用文件的父对象(文件夹kobject)的属性处理函数kobject->ktype->sysfs_ops->show,然后通过show函数来调用包含该对象的外层设备(或驱动、总线等)的属性的show函数来获取硬件设备的对应属性值,然后将该值拷贝到用户空间的buff,这样就完成了读操作。写操作也类似,都要进行内核空间ßà用户空间内存的拷贝,以保护内核代码的安全运行。

    图为用户空间程序读sysfs文件的处理流程,其他操作类似:





     



    展开全文
  • Linux设备模型之device_add

    千次阅读 2014-10-25 23:24:48
    前言 linux设备模型是学习linux驱动的很重要的内容。了解这些
  • linux设备模型详解

    千次阅读 2011-11-18 18:20:02
    Linux 2.6内核的一个重要特色是提供了统一的内核设备模型。随着技术的不断进步,系统的拓扑结构越来越复杂,对智能电源管理、热插拔以及plug and play的支持要求也越来越高,2.4内核已经难以满足这些需求。为适应...
  • Linux2.6以后的设备驱动,都是在设备模型的基础上构建的,因此,要编写linux下的设备驱动程序,不论是usb设备,pci设备等, 都需要了解设备模型设备模型的基础结构体主要是kobject,kset这两个结构体: ...
  • 1. 前言 device和device driver是Linux驱动开发的基本概念。Linux kernel的思路很简单:驱动开发,就是要开发指定的软件(driver...因此本文将会围绕这两个数据结构,介绍Linux设备模型的核心逻辑,包括: 设备及...
  • linux设备驱动--字符设备模型

    千次阅读 2011-12-02 16:03:56
    linux设备驱动--字符设备模型 最近正在学习设备驱动开发,因此打算写一个系列博客,即是对自己学习的一个总结,也是对自己的一个督促,有不对,不足,需要改正的地方还望大家指出,而且希望结识志同道合的朋友...
  • 恰好今天又在看Linux设备模型,找了很多资料。总结如下: 1、linux设备模型总结:点击打开链接 这篇文章对设备模型的讲解比较到位,但是没有图示清楚,如果需要形象理解,则可以参考我的前一篇文章:linux对象系统。...
  • Linux 设备模型基本概念 (一)

    千次阅读 2015-06-04 10:37:37
    1、设备模型引入 Linux 2.6内核最初为了应付电源管理的需要,提出了一个设备模型来管理所有的设备。在物理上,外设之间是有一种层次关系的,比如把一个U盘插到笔记本上,实际上这个U盘是接在一个USB Hub上,USB Hub...
  • Linux设备模型(上)之底层模型

    千次阅读 2011-11-21 21:22:40
    以《LDD3》的说法:Linux设备模型这部分内容可以认为是高级教材,对于多数程序作者来说是不必要的。但是我个人认为:对于一个嵌入式Linux的底层程序员来说,这部分内容是很重要的。以我学习的ARM9为例,有很多总线...
  • Linux2.6.29设备模型分析-概述

    千次阅读 2010-07-12 22:01:00
    设备模型功能概述
  • 设备模型一(基本概念)

    千次阅读 2017-03-08 10:30:21
    设备驱动模型研究好一阵子了,但是很快就忘了,不得不重新再研究,打算记录下来,设备驱动模型系列打算参考wowo科技系列的文章(http://www.wowotech.net/linux_kenrel/13.html)以及自己的理解讲诉一下,开篇的话引入wowo...
  • Linux 2.6内核的设备模型

    千次阅读 2009-12-10 16:23:00
    Linux 2.6内核的一个重要特色是提供了统一的内核设备模型。随着技术的不断进步,系统的拓扑结构越来越复杂,对智能电源管理、热插拔以及plug and play的支持要求也越来越高,2.4内核已经难以满足这些需求。为适应...
  • Linux驱动之设备模型(1)

    千次阅读 2011-11-30 20:10:20
    设备模型是2.6内核引入的新特性,提供了一个独立的机制专门来表示设备,并描述其在系统中的拓扑结构,使得系统具有以下优点: n 代码重复最小化 n 提供诸如引用计数这样的统一机制 n 可以列举系统中所有的...
  • Linux设备模型(中)之上层容器

    千次阅读 2012-01-18 16:13:50
    设备模型中, 所有的设备都通过总线相连, 甚至是内部的虚拟“platform”总线(下一篇介绍),注意,这里设备模型中只是为个更好方便管理,所以有些总线是pic,i2c,usb等,但都只是一个分类的名字
  • linux设备模型一(基础知识)

    千次阅读 多人点赞 2018-08-02 22:02:40
    在上一节中,蜗蜗大神有提到,由于Linux支持世界上几乎所有的、不同功能的硬件设备(这是Linux的优点),导致Linux内核中有一半的代码是设备驱动,而且随着硬件的快速升级换代,设备驱动的代码量也在快速增长。...
  • Linux平台总线驱动设备模型

    万次阅读 2014-01-07 21:09:07
    platform总线是一种虚拟的总线,相应的设备成为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。
  • 总线是处理器和一个或多个设备之间的通道,在设备模型中,所有的设备都通过总线相连,甚至是内部的虚拟"platform"总线。可以通过ls -l /sys/bus看到系统加载的所有总线。drwxr-xr-x root root 1970-01-01 00:02 ...
  • Camera驱动详细分析Linux设备模型介绍

    热门讨论 2012-11-05 13:28:39
    Camera Ov5640 Linux driver device
  • 推荐博文: Linux内核“问题门”——学习问题、经验集锦推荐下载:《Linux内核修炼之道》精华版之方法论 对于驱动开发来说,设备模型的理解是根本,毫不夸张得说,理解了设备模型,再去看那些五花八门的驱动程序,...
  • 推荐博文: Linux内核“问题门”——学习问题、经验集锦推荐下载:《Linux内核修炼之道》精华版之方法论 设备模型拍得再玄幻,它也只是个模型,必须得落实在具体的子系统,否则就只能抱着个最佳技术奖空遗恨。...
  • 前面分析了这么多,是因为设备模型和文件系统的联系很紧密,了解sysfs是为了更好的理解设备模型。  在分析sysfs的时候,我们也看到了sysfs_dirent与kobject的紧密联系。这一次我们分析下kobject kest和ktype。在...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 404,574
精华内容 161,829
关键字:

设备模型