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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值