linux 内核驱动的名字,Linux内核驱动的的platform机制

接下来来看platform_driver结构体的原型定义,在include/linux/platform_device.h中,代码如下:

struct platform_driver {

int (*probe)(struct platform_device *);

int (*remove)(struct platform_device *);

void (*shutdown)(struct platform_device *);

int (*suspend)(struct platform_device *, pm_message_t state);

int (*suspend_late)(struct platform_device *, pm_message_t state);

int (*resume_early)(struct platform_device *);

int (*resume)(struct platform_device *);

struct device_driver driver;

};

内核提供的platform_driver结构体的注册函数为platform_driver_register(),其原型定义在driver/base/platform.c文件中,具体实现代码如下:

int platform_driver_register(struct platform_driver *drv)

{

drv->driver.bus = &platform_bus_type;

if (drv->probe)

drv->driver.probe = platform_drv_probe;

if (drv->remove)

drv->driver.remove = platform_drv_remove;

if (drv->shutdown)

drv->driver.shutdown = platform_drv_shutdown;

if (drv->suspend)

drv->driver.suspend = platform_drv_suspend;

if (drv->resume)

drv->driver.resume = platform_drv_resume;

return driver_register(&drv->driver);

}

总结,通常情况下只要和内核本身运行依赖性不大的外围设备,相对独立的,拥有各自独自的资源(地址总线和IRQs),都可以用platform_driver实现。如:LCD,网卡、USB、UART等,都可以用platfrom_driver写,而timer,irq等小系统之内的设备则最好不用platfrom_driver机制。

/*******************************************************************************/

device和driver之间是如何通过注册的名字进行连接的:

下面是转载的一份网友用dm9000为例写的联系:

1.3    驱动注册

下面是DM9000网卡的驱动加载代码:

static int __init

dm9000_init(void)

{

printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME);

return platform_driver_register(&dm9000_driver);   /* search board and register */

}

module_init(dm9000_init);

很简单的代码,直接调用platform_driver_register注册驱动,这里dm9000_driver的定义为:

static struct platform_driver dm9000_driver = {

.driver  = {

.name    = "dm9000",

.owner   = THIS_MODULE,

},

.probe   = dm9000_probe,

.remove  = dm9000_drv_remove,

.suspend = dm9000_drv_suspend,

.resume  = dm9000_drv_resume,

};

1.3.1   platform_driver_register

这个函数定义为:

/**

*   platform_driver_register

*   @drv: platform driver structure

*/

int platform_driver_register(struct platform_driver *drv)

{

drv->driver.bus = &platform_bus_type;

if (drv->probe)

drv->driver.probe = platform_drv_probe;

if (drv->remove)

drv->driver.remove = platform_drv_remove;

if (drv->shutdown)

drv->driver.shutdown = platform_drv_shutdown;

if (drv->suspend)

drv->driver.suspend = platform_drv_suspend;

if (drv->resume)

drv->driver.resume = platform_drv_resume;

return driver_register(&drv->driver);

}

注意由于DM9000的platform_driver中指定了probe,remove,suspend,resume这四个函数,因此device_driver结构体中的这几个函数指针将进行初始化设置。最后再调用driver_register注册driver成员,有点奇怪,怎么就抛弃了platform_driver呢?

1.3.2   driver_register

这个函数定义为:

/**

*   driver_register - register driver with bus

*   @drv:    driver to register

*

*   We pass off most of the work to the bus_add_driver() call,

*   since most of the things we have to do deal with the bus

*   structures.

*/

int driver_register(struct device_driver * drv)

{

if ((drv->bus->probe && drv->probe) ||

(drv->bus->remove && drv->remove) ||

(drv->bus->shutdown && drv->shutdown)) {

printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);

}

klist_init(&drv->klist_devices, NULL, NULL);

return bus_add_driver(drv);

}

当函数执行到这里的时候,drv->bus指向的是platform_bus_type这一全局变量。

struct bus_type platform_bus_type = {

.name         = "platform",

.dev_attrs    = platform_dev_attrs,

.match        = platform_match,

.uevent       = platform_uevent,

.suspend = platform_suspend,

.suspend_late = platform_suspend_late,

.resume_early = platform_resume_early,

.resume       = platform_resume,

};

1.3.3   bus_add_driver

这个函数定义为:

/**

*   bus_add_driver - Add a driver to the bus.

*   @drv:    driver.

*

*/

int bus_add_driver(struct device_driver *drv)

{

struct bus_type * bus = get_bus(drv->bus);

int error = 0;

if (!bus)

return -EINVAL;

pr_debug("bus %s: add driver %s\n", bus->name, drv->name);

error = kobject_set_name(&drv->kobj, "%s", drv->name);

if (error)

goto out_put_bus;

drv->kobj.kset = &bus->drivers;

if ((error = kobject_register(&drv->kobj)))

goto out_put_bus;

if (drv->bus->drivers_autoprobe) {

error = driver_attach(drv);

if (error)

goto out_unregister;

}

klist_add_tail(&drv->knode_bus, &bus->klist_drivers);

module_add_driver(drv->owner, drv);

error = driver_add_attrs(bus, drv);

if (error) {

/* How the hell do we get out of this pickle? Give up */

printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",

__FUNCTION__, drv->name);

}

error = add_bind_files(drv);

if (error) {

/* Ditto */

printk(KERN_ERR "%s: add_bind_files(%s) failed\n",

__FUNCTION__, drv->name);

}

return error;

out_unregister:

kobject_unregister(&drv->kobj);

out_put_bus:

put_bus(bus);

return error;

}

当函数执行到此的时候,drv->bus将指向platform_bus_type这一全局变量,而这一全局变量的drivers_autoprobe成员在bus_register这一全局初始化函数中设置为1。因此这里将调用driver_attach函数,注意此时传递进去的参数drv指向的是dm9000_driver的driver成员。

1.3.4   driver_attach

这一函数定义为:

/**

*   driver_attach - try to bind driver to devices.

*   @drv:    driver.

*

*   Walk the list of devices that the bus has on it and try to

*   match the driver with each one.  If driver_probe_device()

*   returns 0 and the @dev->driver is set, we've found a

*   compatible pair.

*/

int driver_attach(struct device_driver * drv)

{

return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

}

很简单,转向bus_for_each_dev。

1.3.5   bus_for_each_dev

这一函数定义为:

/**

*   bus_for_each_dev - device iterator.

*   @bus:    bus type.

*   @start:  device to start iterating from.

*   @data:   data for the callback.

*   @fn: function to be called for each device.

*

*   Iterate over @bus's list of devices, and call @fn for each,

*   passing it @data. If @start is not NULL, we use that device to

*   begin iterating from.

*

*   We check the return of @fn each time. If it returns anything

*   other than 0, we break out and return that value.

*

*   NOTE: The device that returns a non-zero value is not retained

*   in any way, nor is its refcount incremented. If the caller needs

*   to retain this data, it should do, and increment the reference

*   count in the supplied callback.

*/

int bus_for_each_dev(struct bus_type * bus, struct device * start,

void * data, int (*fn)(struct device *, void *))

{

struct klist_iter i;

struct device * dev;

int error = 0;

if (!bus)

return -EINVAL;

klist_iter_init_node(&bus->klist_devices, &i,

(start ? &start->knode_bus : NULL));

while ((dev = next_device(&i)) && !error)

error = fn(dev, data);

klist_iter_exit(&i);

return error;

}

简单枚举此总线上注册的device,然后为其调用__driver_attach函数,试图将一个device和传递进来的driver相匹配。

1.3.6   __driver_attach

这一函数定义为:

static int __driver_attach(struct device * dev, void * data)

{

struct device_driver * drv = data;

/*

* Lock device and try to bind to it. We drop the error

* here and always return 0, because we need to keep trying

* to bind to devices and some drivers will return an error

* simply if it didn't support the device.

*

* driver_probe_device() will spit a warning if there

* is an error.

*/

if (dev->parent)   /* Needed for USB */

down(&dev->parent->sem);

down(&dev->sem);

if (!dev->driver)

driver_probe_device(drv, dev);

up(&dev->sem);

if (dev->parent)

up(&dev->parent->sem);

return 0;

}

很简单,转而调用driver_probe_device进行驱动的匹配。

1.3.7   driver_probe_device

这个函数定义为:

/**

* driver_probe_device - attempt to bind device & driver together

* @drv: driver to bind a device to

* @dev: device to try to bind to the driver

*

* First, we call the bus's match function, if one present, which should

* compare the device IDs the driver supports with the device IDs of the

* device. Note we don't do this ourselves because we don't know the

* format of the ID structures, nor what is to be considered a match and

* what is not.

*

* This function returns 1 if a match is found, -ENODEV if the device is

* not registered, and 0 otherwise.

*

* This function must be called with @dev->sem held.  When called for a

* USB interface, @dev->parent->sem must be held as well.

*/

int driver_probe_device(struct device_driver * drv, struct device * dev)

{

int ret = 0;

if (!device_is_registered(dev))

return -ENODEV;

if (drv->bus->match && !drv->bus->match(dev, drv))

goto done;

pr_debug("%s: Matched Device %s with Driver %s\n",

drv->bus->name, dev->bus_id, drv->name);

ret = really_probe(dev, drv);

done:

return ret;

}

此时的drv->bus指向platform_bus_type这一全局变量,而它的match函数为platform_match,且让我们看看它是如何确定device和driver是否匹配的。

/**

*   platform_match - bind platform device to platform driver.

*   @dev:    device.

*   @drv:    driver.

*

*   Platform device IDs are assumed to be encoded like this:

*   "", where is a short description of the

*   type of device, like "pci" or "floppy", and is the

*   enumerated instance of the device, like '0' or '42'.

*   Driver IDs are simply "".

*   So, extract the from the platform_device structure,

*   and compare it against the name of the driver. Return whether

*   they match or not.

*/

static int platform_match(struct device * dev, struct device_driver * drv)

{

struct platform_device *pdev = container_of(dev, struct platform_device, dev);

return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);

}

也就是说,它通过比较pdev->name和drv->name是否匹配来决定。

对于DM9000的驱动来说,这里的pdev指向dm9000_bfin_device,看看它的初始值:

static struct platform_device dm9000_bfin_device = {

.name = "dm9000",

.id = -1,

.num_resources = ARRAY_SIZE(dm9000_bfin_resources),

.resource = dm9000_bfin_resources,

};

再看drv,其指向dm9000_driver这一变量中的driver成员。

static struct platform_driver dm9000_driver = {

.driver  = {

.name    = "dm9000",

.owner   = THIS_MODULE,

},

.probe   = dm9000_probe,

.remove  = dm9000_drv_remove,

.suspend = dm9000_drv_suspend,

.resume  = dm9000_drv_resume,

};

在进行了正确的名称匹配之后,将调用really_probe进行硬件检测。

1.3.8   really_probe

这一函数定义为:

static int really_probe(struct device *dev, struct device_driver *drv)

{

int ret = 0;

atomic_inc(&probe_count);

pr_debug("%s: Probing driver %s with device %s\n",

drv->bus->name, drv->name, dev->bus_id);

WARN_ON(!list_empty(&dev->devres_head));

dev->driver = drv;

if (driver_sysfs_add(dev)) {

printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",

__FUNCTION__, dev->bus_id);

goto probe_failed;

}

if (dev->bus->probe) {

ret = dev->bus->probe(dev);

if (ret)

goto probe_failed;

} else if (drv->probe) {

ret = drv->probe(dev);

if (ret)

goto probe_failed;

}

driver_bound(dev);

ret = 1;

pr_debug("%s: Bound Device %s to Driver %s\n",

drv->bus->name, dev->bus_id, drv->name);

goto done;

probe_failed:

devres_release_all(dev);

driver_sysfs_remove(dev);

dev->driver = NULL;

if (ret != -ENODEV && ret != -ENXIO) {

/* driver matched but the probe failed */

printk(KERN_WARNING

"%s: probe of %s failed with error %d\n",

drv->name, dev->bus_id, ret);

}

/*

* Ignore errors returned by ->probe so that the next driver can try

* its luck.

*/

ret = 0;

done:

atomic_dec(&probe_count);

wake_up(&probe_waitqueue);

return ret;

}

此时的drv->bus指向platform_bus_type这一全局变量,其probe回调函数没有指定,而drv->probe函数则指向dm9000_probe。因此转向dm9000_probe执行,并将dm9000_bfin_device做为参数传递进去。

1.4    结论

platform device和driver分别向platform_bus_type这一中介注册,并通过名称进行相互间的匹配。很是有点婚姻中介的味道,还有点对暗号的神秘,呵呵!

2       参考资料

从DM9000驱动看platform device与driver的关系(2009-6-8)

uclinux内核驱动的初始化顺序(2009-6-7)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/265384.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

超赞!12套你没见过的社交媒体 社交网站图标

如今,社交网络成为我们信息获取和传播的重要途径,很多网站都有把内容分享到社交媒体的功能。社交媒体图标作为向用户传递信息的重要媒介,不管是在网页还是 Web 应用程序中都非常需要。今天这篇文章和大家分享12套你没见过的社交媒体 & 社…

I2C实验

参考:I2C 总线协议详解 作者:一只青木呀 发布时间:2020-09-21 11:41:25 网址:https://blog.csdn.net/weixin_45309916/article/details/108705297 目录I2C 简介I2C 协议I2C协议有关术语1、起始位2、停止位3、数据传输4、应答信号5…

测试php

/*** 测试guzzle** return void*/public function index(){$client new GuzzleHttp\Client();//12306抓取票价$request new Request(get, https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date2018-12-14&leftTicketDTO.from_stationZZF&leftTicke…

linux安装ffmpeg版本太多,Linux安装FFmpeg的方法

FFmpeg是一款优秀的播放器解码插件,可以跨平台,有不同平台的版本,对于解码,编码和录制以及转换作用的很多的软件都是使用FFmpeg的插件来实现的.FFmpeg:https://www.ffmpeg.org/download.html安装方法:#wget…

大学生成绩管理系统(C语言)

功能:成绩管理系统包含了学生的全部信息,每个学生是一个记录,包括学号,姓名,性别,班级,各科成绩(语数外)。 系统功能: 1.信息录入——录入学生信息; 2.信息输…

官方系统镜像烧写(windows下使用OTG)

目录OTG系统烧写为什么能通过VBS将系统烧写进去呢?OTG系统烧写 选择对应的烧写工具,USB_OTG线连接好,双击即可进行烧写。 注意: 当然也可以烧写到SD卡里面。前面我们烧写裸机代码都是选择从SD卡启动。Mfgtool这个工具先向板子下载…

SQL Server中通用数据库角色权限的处理详解

SQL Server中通用数据库角色权限的处理详解 前言 安全性是所有数据库管理系统的一个重要特征。理解安全性问题是理解数据库管理系统安全性机制的前提。 最近和同事在做数据库权限清理的事情,主要是删除一些账号;取消一些账号的较大的权限等,例…

linux之xargs命令用途

实现文件删除的方法大致有以下几种:1.rm find /a -type f 2.find /a -type f -exec|-ok rm -rf { } \;3.find /a -type f -exec|-ok rm -rf { } ;本例中xargs将find产生的长串文件列表拆散成多个子串,然后…

什么是U-Boot以及如何下载U-Boot源码

参考:什么是U-Boot以及如何下载U-Boot源码? 作者:一只青木呀 发布时间: 2020-10-20 11:05:59 网址:https://blog.csdn.net/weixin_45309916/article/details/109176510 目录前言系统的启动过程uboot简介uboot源码下载选…

linux系统重装win系统教程,Win10如何重装linux系统 Win10重装linux系统教程

Windows10如何重装linux系统?下面小编就给大家介绍一下Win10重装linux系统教程。1、我们按下wini打开设置 后点击【更新和安全】->【windows更新】;2、我们在左侧点击【针对开发人员】,在右侧点击【发开人员模式】;3、我们按winx键->选择【程序和功能】;4、我…

通过Docker发布RestAPI遇到的种种问题

目标:发布一个分词API 问题1:Docker外无法访问API 原因: Docker映射的地址是0.0.0.0:8888端口,而flask启动的时候默认地址是127.0.0.1:5000,需要手动配置一下 问题2:使用curl命令访问接口不成功 原因&#…

Uboot初次编译、烧写、启动(启动界面log简析)

目录U-Boot 初次编译U-Boot 烧写与启动上述笔记第三点就是建立shell脚本实现的 第四点就是修改Makefile文件实现的,下面均有实现步骤讲解。 U-Boot 初次编译 先编译体验一下正点原子提供的UBOOT。 首先在Ubuntu 中安装ncurses 库,否则编译会报错&#…

Mysq常用语句2

一)创建,删除和最基本查询:显示数据库 mysql->show databases;创建数据库 mysql->create database db;删除数据库  mysql->drop database db;选择数据库 mysql->use db创建表 mysql->create table mytable(name va…

360 linux 扩展文件夹,360签具名工Linux下载0907 官方版

腾牛网提供的这款360签名工具Linux版,共有两个版本,分别是图形界面版和命令行界面版,两种选择为apk签名具有一样的正版效果。相关下载:360加固助手pc端Linux签名工具使用流程(图形界面)使用方法:一、准备工作&#xff…

锁优化

前言 高效并发是从JDK1.5到JDK1.6的一个重要改进,HotSpot虚拟机开发团队在这个版本上花费了大量的精力去实现各种锁优化技术,如适应性自旋、锁消除、锁粗化、轻量级锁和偏向锁等,这些技术都是为了在线程之间高效的共享数据,以及解…

WPF--ComboBox数据绑定

0-在ComboBox中显示图片&#xff1a; <ComboBox Height"33" HorizontalAlignment"Right" Margin"0,94,31,0" x:Name"comboBox1" VerticalAlignment"Top" Width"142" SelectedIndex"0"> <Co…

linux系统lsmod命令,linux lsmod命令 及相关信息

语法&#xff1a;lsmod功能&#xff1a;lsmod命令&#xff1a;是一个小程序&#xff0c;用来显示文件、proc/modules的信息&#xff0c;也就是显示当前内核模块装载的模块。补充说明&#xff1a;执行lsmod指令&#xff0c;会列出所有已载入系统的模块。Linux操作系统的核心具有…

U-Boot源码目录分析(VScode工程创建及文件夹过滤)

参考&#xff1a;U-Boot工程目录介绍 作者&#xff1a;一只青木呀 发布时间&#xff1a; 2020-10-21 14:47:30 网址&#xff1a;https://blog.csdn.net/weixin_45309916/article/details/109199081 目录0、Uboot下载编译VScode工程创建及文件夹过滤2、重要文件2.1、arch文件夹&…

Spring Security 案例实现和执行流程剖析

在线演示 演示地址&#xff1a;http://139.196.87.48:9002/kitty 用户名&#xff1a;admin 密码&#xff1a;admin Spring Security Spring Security 是 Spring 社区的一个顶级项目&#xff0c;也是 Spring Boot 官方推荐使用的安全框架。除了常规的认证&#xff08;Authentica…

KVO 的进一步理解

这篇文章讲述了KVO的深入理解 http://blog.csdn.net/kesalin/article/details/8194240 对kvo有了更深入的理解 如下连接的文章讲述了kvo接口的一些缺陷 http://www.mikeash.com/pyblog/key-value-observing-done-right.html 主要是不能自定义selector&#xff08;如NSNotificat…