精华内容
下载资源
问答
  • linux内核驱动模型

    2008-08-29 16:31:55
    linux内核驱动模型linux内核驱动模型linux内核驱动模型
  • 若你发现有需要改正的地方欢迎指出本文与原文档采用相同许可协议发布综述Linux内核驱动模型是一种以前在用的所有模型的统一。它目的在于通过增加一组数据和方法到全局的数据结构上为桥和设备增加总线驱动。...
    翻译自Linux Kernel的文档,
    Documentation/driver-model/overview.txt
    
    该翻译源于译者个人兴趣,其中某些地方可能含糊不清、歧义、甚至错误,请参考原始文档阅读文。
    若你发现有需要改正的地方欢迎指出
    本文与原文档采用相同许可协议发布


    综述


    Linux内核驱动模型是一种以前在用的所有模型的统一。它目的在于通过增加一组数据和
    方法到全局的数据结构上为桥和设备增加总线驱动。

    传统的驱动模型为他们要控制的设备实现了一个有序的类树结构(有时只是一个链表),
    在不同的总线类型间他们并不是统一的。

    现在的驱动模型提供了一个公共的、统一的数据模型来描述总线和可被总线发现的设备。
    统一的总线模型包含了一组公共的属性和一组公共的回调,用来总线发现,总线关闭,
    总线电源管理等等。

    设备与桥接口反应了现代计算机的目标:也就是“即插即用”的能力,可电源管理,可热插拔。
    特别的,这个模型被Intel和Microsoft使用(即ACPI),确保每个设备几乎都挂在总线上,
    x86兼容系统则可在这个范式下运行。当然,不是所有总线都完全支持以这些操作,但是大
    部分总线是支持大部分的这些操作。


    下游开发


    公共的数据成员已经从单独的总线层移动到公共的数据结构中了。这些成员必须总是能够
    被总线层访问,有时需要被特定设备驱动访问。

    其它总线驱动层最好是像PCI总线驱动层做的那样
    struct pci_dev 现在大概长这个样子:

    struct pci_dev {
        ...

        struct device dev;     /* Generic device interface */
        ...
    };

    首先要注意的是struct device dev在struct pci_dev中是被静态申请的。意思是在
    设备发现的过程中,说只为设备申请一次内存。

    然后要注意的是struct device dev并不必被定义在pci_dev结构体的头部。这是为了
    使开发者思考在切换总线驱动和全局驱动时他们做了什么,并且阻止他们在这两者之
    间做没有意义和不正确的转换。

    PCI总线驱动层自由地访问struct device的成员,这是因为它知道这个结构体在
    struct pci_dev中。通常单独的PCI设备驱动已经被转换到当前驱动模型下了,不要去动
    struct device下的成员,除非有什么迫不得已的理由需要这么做。

    以上说明防止你在过渡期间不必要的痛苦。如果不这样做,那么所有的数据成员将会被
    重命名或者被移除,所有的下游驱动都会坏掉。另一方面,如果只是总线层(不是设备层)
    访问struct device,那么仅仅只是总线层需要被修改。


    用户接口


    通过系统中所有设备的完全分层的结构所带来的优点,内核将完全分层的结构导出到
    用户空间变得相对简单。这些的实现是通过一个名为sysfs的虚拟文件系统来完成的。

    几乎所有的主流Linux发行版会自动挂载这个文件系统;你可以输入“mount”命令来看到
    类似于以下内容的输出

    $ mount
    ...
    none on /sys type sysfs (rw,noexec,nosuid,nodev)
    ...
    $

    自动挂载sysfs文件系统通常是通过/etc/fstab文件中的一条记录实现的,大概如下所示

    none         /sys    sysfs    defaults          0 0

    或者在基于debian的系统中,在/lib/init/fstab下有着类似于以下内容的记录

    none            /sys    sysfs    nodev,noexec,nosuid    0 0

    如果sysfs没有被自动挂载,你可以通过以下命令手动挂载

    # mount -t sysfs sysfs /sys

    每当设备被加入到设备树上时,sysfs中会为它创建一个目录。这个目录可以会出现在以下
    每个层的目录中 —— 全局层、总线层、设备层。

    全局层目前创建两个文件 - ‘name’ 和 ‘power’。前者只报告这个设备的名字,后者报告
    该设备当前的电源状态。它通常被用来设置设备当前的电源状态

    总线层在探测总线时可能也会为设备创建一些文件,比如说 PCI层会为每个设备都创建
    ‘irq’和‘resource’文件

    一个特定设备驱动在设备自己的目录瞎导出一些与设备相关的数据文件或者操作接口

    更多与sysfs目录相关的信息在在当前目录下别的文档中,还有Documentation/filesystems/sysfs.txt
    展开全文
  • struct device_driver { const char *name; struct bus_type *bus; struct driver_private *p; int (*probe) (struct device *dev); } struct driver_private { struct kobject kobj; ...
  • 上来就有两句话没看懂:在2.4版本的内核中,每一个设备的物理部分都由一段总线特定的代码来控制。总线代码负责各种不同类型的任务,而每一种具体总线的代码之间则没有交互。后一句的原文是:This bus code was ...

    这章篇幅不大,可读得费劲。

    上来就有两句话没看懂:在2.4版本的内核中,每一个设备的物理部分都由一段总线特定的代码来控制。总线代码负责各种不同类型的任务,而每一种具体总线的代码之间则没有交互。

    后一句的原文是:This bus code was responsible for a wide range of different tasks, and each individual bus code had no interaction with any other bus code.

    这里,总线特定代码(bus-specific code)是什么意思?

    然后,Greg Kroah-Hartman提出两个问题,1是在解决电源管理问题时,内核需要知道不同设备的连接关系;2是不论哪一台USB打印机先启动,两台打印机的名字永不变。

    其他系统的一般解决方法,1是内核中放一个处理设备名的小数据库,2是通过文件系统中可以直接访问设备的devfs类型来导出设备的所有信息。

    对Linux来说,内核里放数据库是不能接受的,同时,Linux的devfs文件系统实现中“存在一些众所周知的且难以消除的竞争条件,导致几乎所有的Linux发布的版本中都不能依赖它。”这句话怎么理解?

    再然后,作者用一个“简单”的例子展现了,展现了什么呢,我觉得是展现了C语言的复杂用法。如作者所说:是的,非常强大,只要你清楚地知道你正在做什么。

    不信就看看这个宏吧: 

    1. #define container_of(ptr, type, member)    ({    /
    2.     const typeof( ((type *)0) ->member ) * _mptr = (ptr);    /
    3.     (type *)( (char *)_mptr - offsetof(type, member) );})

    作者通过介绍Linux内核中解决前面提到的两个问题所需的数据结构和支持函数的演变,来说明协作给Linux带来的好处,还好文末有个总结,否则我又要忘了他要说什么。

    展开全文
  • Linux内核设备模型与总线 - 内核版本 Linux Kernel 2.6.34, 与 Robert.Love的《Linux Kernel Development》(第三版)所讲述的内核版本一样 - 源代码下载路径: ...

    Linux内核设备模型与总线

    -         内核版本 Linux Kernel 2.6.34, 与 Robert.Love的《Linux Kernel Development》(第三版)所讲述的内核版本一样

    -         源代码下载路径: https://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.34.tar.bz2


     

    1.      Linux内核设备模型分析

    1)     kobject对象的设计思想

    -         对于没有接触过JAVA、Python等高级面向对象编程语言工程师,第一次看到struct  kobject对象,都会对它的作用感到困惑,不知道为什么这么多Linux内核对象结构体中,都要有一个看起来没什么用的struct  kobject。

    -         对于接触过JAVA、Python等面向对象编程语言的工程师,对object对象肯定不陌生。在JAVA、Python中,object对象是所有对象的基类,所有的对象最终都会继承到object对象。关于JAVA中object对象及其相关方法的描述,可以参阅JDK在线文档

    -         在Linux内核设备模型中,也是借鉴了JAVA、Python中的做法,让struct kobject对象作为所有内核设备的基类,kobject是一个最高层次的抽象基类,这样Linux内核才能够通过一个继承树体系,管理到系统里的每一个设备。

    -         在Linux内核中,虽然kobject对象可以作为所有设备对象的基类,但是类比于JAVA、Python,我们一般不直接使用kobject这种最高抽象层次的基类作为实际需要开发的设备程序的的直接基类,原因见图1。kobject类比于物质在自然界继承体系里的概念,物质是一个抽象的概念,所有的生物和非生物都继承自物质,即他们和物质都是IS-A的关系。狗 IS-A 物质,水IS-A 物质。但是我们真正研究狗的时候,一般是从其犬科动物或者动物等比较具体的基类开始研究,研究它动物属性,研究它发出叫声的特性,很少研究狗的物质属性(除非是唯物主义哲学家),但是狗确实是物质。

    -         同理,在研究一般具体的Linux设备驱动,如视频设备V4L2驱动的代码,一般都从其上层基类struct  video_device研究起,或者再抽血一些,研究struct  video_device 的基类struct  cdev, 很少直接使用最上层的kobject基类。但是V4L2设备驱动,确实 IS-A kobject。


    Figure 1 自然界继承体系,所有对象都继承自物质

    2)     kobject对象的特性

    -         kobjet对象的声明在与相关的API在include/linux/kobject.h文件中。

    -         kobject 对象有对象引用计数(kref),父子object索引(parent)等基本属性。

    -         kobject提供了sysfs文件系统相关的节点描述,属性与函数,使得Linux系统可以通过特殊的sysfs文件系统,以树形继承的关系来访问Linux内核中的每个具体的kobject对象。实际上,kobject最初的设计目的就是为了在sysfs中模仿windows的设备管理器,提供一个类似树形的,可以管理额访问系统所有设备的接口。

    -         kobject对象还提供了Linux系统设备中hotplug热插拔相关的事件与函数方法,使得内核设备可以支持热插拔机制。

    -         每个继承了object的Linux设备对象,在调用者获得kobject基类对象实例之后,可以通过container_of()函数,一层一层转换,最终获得具体子类对象。有了kobject,就可以实现通过基类来访问子类对象的机制

    3)     Linux内核中继承kobject的主要基础类设备模型

    -         Kobject类似于JAVA中的object类,一般不作为内核设备对象的直接基类。但是类似于JDK中有不少对象直接继承自object对象,JDK中直接继承自object的对象,一般都是最为基础类对象,提供给开发者使用。同样,Linux内核中也有不少继承自kobject的基础类对象,Linux内核驱动开发者可以使用这些直接继承自kobject的基础类设备,来构建实际的Linux设备驱动。

    -         kset是一个集合容器,用于管理一类object子类对象的集合,继承自某个基类kobject的所有基类的kobject对象都可以用一个kset容器来管理。

    -         Linux内核在继承自kobject的重要基础类对象如图2所示。



    Figure 2  Linux内核中直接继承kobject的重要基础类对象

    -         device类对象一般用于Linux各种总线设备(platform虚拟平台总线、USB总线等)的基类,下一节详细介绍。

    -         module对象是用于模块管理接口(就是上一篇文章中单继承与接口一节的接口),接口本身也是一个对象(JAVA中的interface也是对象,继承object),实现了module接口的对象,可以通过模块的方式,动态装载、卸载代码块。

    -         class对象是用于设备分类管理的相关接口,通过class接口可以将内核中各种设备类型的信息导出到用户态。

    -         cdev对象就是典型的字符设备基类对象,所有的字符设备最终都会继承到cdev对象。cdev对象同时制定了字符设备标准的访问接口函数方法。

    -         总之,拥有了以上这些基础类,内核开发者就能开发自己特殊的设备驱动,并且通过这些类和接口,将驱动程序集成到Linux内核中。


    3). Linux内核中是怎么管理维护这些继承类对象

    -         之前的内容讲了一堆面向对象的概念,描述了一堆与Linux设备驱动有关的对象之间的关系,可Linux内核毕竟是C语言写的,内核中如何维护这些基础类对象呢?

    -         在Linux内核drivers/base/ 目录下,有很多重要的代码,目录命名为base/,可见基础类对象这个 名词还是有来源依据的,Linux设备驱动里的对象基本都是继承自drivers/base/里面的对象。

    -         drivers/base/base.h中声明了base的一些私有对象属性,以及API,其中很多API如devices_init(),buses_init(),classes_init(),platform_bus_init()等初始化函数都会在Linux内核init函数的driver_init()中被调用,因此可见,Linux内核在启动时通过base.h中的这些初始化*_init()函数使得Linux内核中整个驱动系统相关的基础类组件对象都能进入工作状态。

    -         查看devices_init()函数实现代码如下,我们发现实际上,内核在初始化devices的时候,使用kobject对象创建了dev_kobj作为所有device子类对象的基类。并且创建了相应的devices_kset来管理这些子类。

    int __init devices_init(void)
    {
    	devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
    	if (!devices_kset)
    		return -ENOMEM;
    	dev_kobj = kobject_create_and_add("dev", NULL);
    	if (!dev_kobj)
    		goto dev_kobj_err;
    	sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
    	if (!sysfs_dev_block_kobj)
    		goto block_kobj_err;
    	sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
    	if (!sysfs_dev_char_kobj)
    		goto char_kobj_err;
    
    	return 0;
    
     char_kobj_err:
    	kobject_put(sysfs_dev_block_kobj);
     block_kobj_err:
    	kobject_put(dev_kobj);
     dev_kobj_err:
    	kset_unregister(devices_kset);
    	return -ENOMEM;
    }



    -         最后,我们实现device的子类对象,并通过device_register()函数将其注册的时候(Linux内核还有很多类似的register函数,例如register_chrdev_region,注册函数意图大同小异,都是让基类能够获取注册后的子类对象),用户就可以通过基类访问注册后的子类对象了。

    -         在device_register()函数中,我们看到注册的device子类会和基类的kset容器以及关联起来,最终系统可以通过基类device对象实例dev_kobj所关联的kset容器来访问deivce的子类对象(一般会通过container_of()函数获取子类对象)。

    -         实际上,Linux内核中,cdev,device等基础类对象,都会在初始化时init()相关的全局变量,Linux内核需要维护这些全局变量以及相关的容器(kset、数组、list都可以看成容器)。

    -         由此可见,面向对象思想里面,继承,多态,虚函数的实现并不神秘,还是通过精巧的设计,用全部变量加容易的方法来管理这些关系。由于有这些由Linux内核维护的全局变量和相关容器,所以在开发设备驱动模块子类时,需要通过注册函数(register)才能让基类能够关联到子类的对象。当有了面向对象的观点,我们可以在更高层次理解Linux内核这些对象的关系,从而设计并改进我们的系统。




    2.      Linux内核总线、设备与驱动

    1). 计算机系统总线模型

    - Linux内核总线的思想来源于如图3所示的计算机系统总线模型。

    - 计算机系统总线控制着外部设备与计算机CPU的通信,任意CPU N都可以通过总线访问到任意外部设备。

    - 一般情况下,外部设备数量都会大于CPU的数量,有了总线,无需为每个外部设备都配备一个CPU。只有外部设备需要CPU来访问读取处理数据,发送控制信号时,一个空闲的CPU才会通过总线控制器与某个外部设备建立通信连接。

    - 一旦CPU处理完某个外部设备的数据之后,CPU可以通过总线控制器,断开和某个外部设备的连接,去处理其它外部设备的访问需求。

    - 总之,计算机系统中的总线模型为数量较多的外部设备提供了一种共享数量较少的CPU的控制访问机制。



    Figure 3 计算机系统中的总线

    2). Linux内核中的与总线

    - Linux内核之后有各种各样的软件总线,系统中所支持的所有总线型驱动设备在/sys/bus/ 目录下可以看到。主要的总线型设备驱动有USB、platform、I2C、SPI、SCSI、mmc等。

    - Linux内核中所有总线接口的的基类以及相关的API都是在include/linux/device.h中声明。其中一个总线接口包括三个核心的基类对象:struct bus_type、struct device 与struct device_driver。这些基类对象与Linux内核中实际的USB、platform、I2C总线接口的继承关系如图4所示。



    Figure 4 Linux内核中,各种总线设备与总线接口基类的对应关系

     

    - Linux 内核总线驱动实际上是模仿计算机系统总线的机制,在一个具体类型的总线上(例如I2C、USB、platform)多数的device设备共享少数的device_driver提供了一种管理机制

    - 通过总线,将一个设备驱动中,逻辑功能部分(device_driver)与硬件具体资源bsp相关的部分(device)分隔开来,使得同一种类型的多数设备实例(device),能够共享同一个驱动程序逻辑代码(device_driver)。

    - struct  bus_type 对象与struct device 对象、structdevice_driver对象构成了一个设备实例化管理接口,对象之间的行为模式如图5所示,类似于抽象共产,将每个device与device_driver装配起来,构造出真正的设备实例。

    - struct bus_type对象在 match()函数方法中,通过对比新发现的device 与 device_driver 的 Id(Id可以是name也可以是dts的描述节点或者实际总线自己定义的匹配Id号都可以匹配),为新加入的device设备找到合适的Id匹配的device_driver,然后调用device_driver的probe()函数方法,进行构造实例化,最终产生实例化的设备驱动并且作为节点挂载在/dev目录下。

    - struct bus_type对象的 remove()函数则处理设备卸载析构的行为

    - bus_type对象与device对象、device_driver对象除了用于实例化的函数方法,还有suspend()、resume()、shutdown()等函数方法,用于实现设备的休眠、唤醒等电源管理相关的功能。

    - struct bus_type对象的uevent()函数方法提供了热插拔事件的相关通信机制,通过该函数接口,可以给用户态发送热插拔相关的异步事件。



    Figure 5 bus_type 与 device、device_driver对象的行为模式

    3).platform总线与设备简介

    - 在Linux 内核中,USB、I2C、SPI等总线都是实际存在的总线,都有对应的相关的外部硬件电路以及相关的标准化通信协议最终以电信号为载体与实际的I2C、USB等实际硬件设备通信。

    - USB、I2C等总线设备,可以通过真正的硬件热插拔,从而触发具体的bus_type总线进行driver与device匹配,最终在/dev/*目录下构造实例化设备驱动。

    - 而struct platform_bus_type对象在Linux内核中代表一个虚拟的平台设备总线。即在系统硬件中,不存在与platform_bus_type对应的硬件电路,在SOC中也不存在对应的总线控制器(USB、I2C等模组在SOC芯片中都有相关的硬件控制器)。

    - 虽然struct platform_bus_type不存在真正的总线,但是我们在处理各种杂七杂八的驱动时(比如LED、智能卡、杂项设备、framebuffer等),也有把device_driver的驱动实现逻辑代码和device硬件bsp相关的代码分离出来的需求, 这样使得同样类型但是占用不同端口或者资源(比如 LED1、 LED2都是LED设备,但是一般会占用不同的GPIO口)的device能够共享同一份device_driver的逻辑代码,不需要为每一个LED设备都写一份驱动(维护量无比巨大)。

    - 因而Linux内核采用 struct platform_bus_type、structplatform_device 与struct platform_driver三个对象继承了总线设备相关的基类对象,模仿系统总线的行为模式,通过struct platform_bus_type来管理 structplatform_driver与struct platform_device的设备匹配与设备构造实例化

    - 虽然platform虚拟平台总线不像usb、I2C等总线接口有真正的硬件设备插拔事件。但是struct platform_driver与struct platform_device对象都实现了module接口,可以编译成module进行insmod/rmmod等动态装载于卸载。那么struct platform_driver与struct platform_device对象在在作为module动态地装载与卸载时,相当于模拟了总线的热插拔事件,那么可以通过insmod/rmmod模拟总线设备的热插拔,来触发struct platform_bus_type对象进行driver与device匹配,并在/dev/*目录下构造实例化真正的设备驱动。

    展开全文
  • Linux platform设备驱动模型 文章目录Linux platform设备驱动模型前言框架设备与驱动的分离设备(device)驱动(driver)匹配(match)参考 前言 为什么要往平台设备驱动迁移?这里需要引入设备,总线,驱动这三个...

    Linux platform设备驱动模型

    前言

    为什么要往平台设备驱动迁移?这里需要引入设备,总线,驱动这三个概念。上一篇字符型设备驱动的实现实际将设备和驱动集成到同一个文件中实现,如果这里有硬件A的驱动硬件B的驱动硬件C的驱动,然后有三类用户接口E接口F接口G,这里用户接口是提供给用户层调用的接口,每一种接口又必须兼容这三种硬件,按照原来的实现方式,为了适配所有的使用需求,理论上会出现A+EA+FA+GB+EB+FB+GC+EC+FC+G,这几种实现方式,而表现在代码中的则是

    #if A
    #elif B
    #elif C
    #endif
    

    当然,目前接口数量和硬件数量不是很庞大的时候,维护上暂时不会造成太大的问题,所以,这里引入了设备/总线/驱动的机制,实现了驱动和设备之间的解耦,这里我的理解是和设计模式中的中介者模式比较相似。
    在这里插入图片描述

    框架

    大致地整理了一下platform设备驱动模型的整体框架。
    在这里插入图片描述

    设备与驱动的分离

    设备(device)

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/cdev.h>
    #include <linux/fs.h>
    #include <linux/slab.h>
    #include <linux/platform_device.h>
    
    static struct platform_device *character_dev;
    
    static int __init cnc_platform_character_init(void){
    
    	int ret = 0;	
    	character_dev = platform_device_alloc("cnc_platform_character", -1);	
    	if (!character_dev)		
    		return -ENOMEM;	
    	ret = platform_device_add(character_dev);	
    	if (ret) {		
    		platform_device_put(character_dev);	
    		printk("\n\n\n\n\n Success platform_device_put(character_dev)\n\n\n\n\n");
    		return ret;	
    	}
    	printk("\n\n\n\n\n Failed platform_device_put(character_dev)\n\n\n\n\n");
    	return 0;
    }
    module_init(cnc_platform_character_init);
    
    static void __exit cnc_platform_character_exit(void){
    	printk("%s call\n",__func__);
    	platform_device_unregister(character_dev);
    
    }
    module_exit(cnc_platform_character_exit);
    
    MODULE_VERSION("1.0");
    MODULE_LICENSE("GPL");
    

    驱动(driver)

    #include <linux/init.h>
    #include <linux/types.h>
    #include <linux/module.h>
    #include <linux/cdev.h>
    #include <linux/fs.h>
    #include <linux/slab.h>
    #include <linux/platform_device.h>
    #include <linux/miscdevice.h>
    
    #include <linux/of_device.h>
    
    #define DRIVER_DATA_SIZE 	4096
    
    struct cnc_character_st{
    	struct cdev device;
    	u8	data[DRIVER_DATA_SIZE];
    	struct miscdevice miscdev;
    };
    
    //TODO
    static ssize_t cnc_character_read (struct file * fd, char __user * data, size_t len, loff_t * offset){
    	ssize_t ret = 0;
    	return ret;
    }
    
    //TODO
    static ssize_t cnc_character_write (struct file * fd, const char __user * data, size_t len, loff_t * offset){
    	ssize_t ret = 0;
    	return ret;
    }
    
    //TODO
    static long cnc_character_unlocked_ioctl (struct file * fd, unsigned int data, unsigned long cmd){
    	long ret = 0;
    	return ret;
    }
    
    //TODO
    static int cnc_character_open (struct inode * node, struct file * fd){
    	int ret = 0;
    	return ret;
    }
    //TODO
    static int cnc_character_release (struct inode * node, struct file * fd){
    	int ret = 0;
    	return ret;
    }
    
    
    static const struct file_operations cnc_character_ops = {
    	.owner = THIS_MODULE,
    	.read = cnc_character_read,
    	.write = cnc_character_write,
    	.open = cnc_character_open,
    	.unlocked_ioctl = cnc_character_unlocked_ioctl,
    	.release = cnc_character_release,
    };
    
    
    static int cnc_character_probe(struct platform_device *pdev){
    
    	int ret = 0;
    	struct cnc_character_st *character_dev;
    
    	character_dev = devm_kzalloc(&pdev->dev, sizeof(*character_dev),GFP_KERNEL);
    
    	character_dev->miscdev.minor = MISC_DYNAMIC_MINOR;
    	character_dev->miscdev.name = "cnc_platform_character";
    	character_dev->miscdev.fops = &cnc_character_ops;
    	//ret = misc_register(&character_dev->miscdev);
    	platform_set_drvdata(pdev, character_dev);
    	ret = misc_register(&character_dev->miscdev);
    
    	if(ret < 0){
    		return ret;
    	}
    	return 0;
    	
    }
    
    static int cnc_character_remove(struct platform_device *pdev){
    	
    	struct cnc_character_st *gl = platform_get_drvdata(pdev);
    	printk("%s call\n",__func__);
    	misc_deregister(&gl->miscdev);
    	return 0;
    }
    
    static struct platform_driver cnc_character_driver = {
    	.driver = {
    		.name = "cnc_platform_character",
    		.owner = THIS_MODULE,
    	},
    	.probe = cnc_character_probe,
    	.remove = cnc_character_remove, 
    };
    
    module_platform_driver(cnc_character_driver);
    
    MODULE_VERSION("1.0");
    MODULE_LICENSE("GPL");
    

    匹配(match)

    函数static int platform_match(struct device *dev, struct device_driver *drv)在内核drivers/base/platform.c中,其源代码如下:

    static int platform_match(struct device *dev, struct device_driver *drv)
    {
    	struct platform_device *pdev = to_platform_device(dev);
    	struct platform_driver *pdrv = to_platform_driver(drv);
    
    	/* When driver_override is set, only bind to the matching driver */
    	if (pdev->driver_override)
    		return !strcmp(pdev->driver_override, drv->name);
    
    	/* Attempt an OF style match first */
    	if (of_driver_match_device(dev, drv))
    		return 1;
    
    	/* Then try ACPI style match */
    	if (acpi_driver_match_device(dev, drv))
    		return 1;
    
    	/* Then try to match against the id table */
    	if (pdrv->id_table)
    		return platform_match_id(pdrv->id_table, pdev) != NULL;
    
    	/* fall-back to driver name match */
    	return (strcmp(pdev->name, drv->name) == 0);
    
    }
    

    从代码中可以得知,platform_match主要根据四种情况对设备和驱动进行匹配。
    根据注释可以知道,首先判断是否已经设置driver_override,后面只绑定到匹配的驱动程序。

    • 根据设备树风格的匹配;
    • 根据ACPI风格的匹配;
    • 匹配ID表(即platform_device设备名是否出现在platform_driver的ID表内)
    • 匹配platform_device设备名和驱动的name成员

    参考

    https://blog.csdn.net/clam_zxf/article/details/80675395

    https://www.cnblogs.com/chenfulin5/p/5690661.html

    http://blog.chinaunix.net/uid-25622207-id-2778126.html

    展开全文
  • linux内核之设备驱动模型前言一、设备模型的基石---kobject子系统二、设备模型的总框架---总线、设备和驱动模型三、有关驱动的虚拟内存文件系统---Sysfs系统 前言 七七八八,磨磨蹭蹭,终于大体上是把LDD3弄完了(大...
  • linux 2.6 内核设备驱动模型精华描述,包括链表、hash链表、kobject等
  • Linux内核分析值设备驱动模型,关于设备驱动模型的分析,和内核源代码注释笔记
  • Linux内核设备模型(1)

    千次阅读 2009-12-01 20:41:00
    Linux内核设备模型翻译者:郭少悲2009/12/01原文:linux/Documentation/driver-model/overview.txt概述~~~~Linux内核驱动模型是针对内核之前所有不同的驱动模型的统一抽象模型。它的目的是,通过结合一套数据和操作集...
  • Linux内核驱动模块

    千次阅读 2014-03-20 17:31:48
    Linux内核驱动模块 Linux设备驱动会以内核模块的形式出现,因此,学会编写Linux内核模块编程是学习Linux设备驱动的先决条件。 4.1~4.2节讲解了Linux内核模块的概念和结构,4.3~4.8节对Linux内核模块的各个组成...
  • Linux 设备驱动模型的初始化driver_init
  • Linux内核地址映射模型x86 CPU采用了段页式地址映射模型。进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存。段页式机制如下图。linux内核地址空间划分通常32位Linux内核地址空间划分0~3G为...
  • linux驱动内核模型

    千次阅读 2009-12-10 16:36:00
    内核驱动模型的初衷2.6内核增加了一个引人注目的新特性——统一设备模型(devicemodel)。设备模型提供了一个独立的机制专门来表示设备,并描述其在系统中的拓扑结构,从而使得系统具有以下优点:l 代码重复最小化。l...
  • linux内核大讲堂_驱动模型_示例代码_无为和尚
  • Linux内核平台总线设备驱动模型浅析

    千次阅读 2017-08-22 16:10:12
     一、Linux系统的驱动框架的基础很大一部分是围绕着总线设备驱动模型展开的。 二、涉及3个重要结构体:struct bus_type:总线struct device :设备struct device_driver:驱动 三、结构体核心代码分析(2.6.38内核...
  • Linux内核驱动中面向对象的基本规则和实现方法 - 内核版本 Linux Kernel 2.6.34, 与 Robert.Love的《Linux Kernel Development》(第三版)所讲述的内核版本一样 - 源代码下载路径: ...
  • 57 linux内核的i2c设备驱动模型

    千次阅读 2017-07-01 23:19:16
    为了实现设备驱动的可移植性及可重用性,在linux内核驱动模型里, device_driver设备驱动只需实现驱动方法和使用device设备提供的硬件资源(如用到的io口,中断号等). bus总线用于装载device设备与device_driver设备...
  • Linux内核驱动学习

    2014-12-18 14:32:29
    本人在学驱动时一不小心按照国嵌内核驱动课件整理出的学习资料,现在分享给大家。其中基础知识讲解很全面,实例非常丰富,在博文中都上传了源代码。免得Linux驱动初学者在网上到处找相关的学习资料。   1.·...
  • linux设备驱动模型

    千次阅读 2016-04-16 15:17:52
    基于一个虚拟总线分析linux设备驱动模型
  • Linux 设备驱动模型

    千次阅读 2013-10-17 22:54:56
    从这一章开始,我们将详细的介绍Linux的设备驱动模型。Linux设备驱动模型是一个相当复杂的系统,对于初学者来说真有些无从入手...早期的Linux内核(版本2.4之前)并没有实现一个统一的设备模型,设备节点的创建一般是m
  • 转自:无为和尚的Linux内核大讲堂系列,并对个别地方进行了补充更正(见标红处)。http://blog.csdn.net/z2007b/article/details/6388753 可能把驱动模型放在第一章讲会有点难度,但是只要能跨过这道坎,后面就会...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 53,334
精华内容 21,333
关键字:

linux内核驱动模型

linux 订阅