linux 内核驱动的名字,Linux内核驱动的的platform机制
接下來來看platform_driver結(jié)構(gòu)體的原型定義,在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;
};
內(nèi)核提供的platform_driver結(jié)構(gòu)體的注冊(cè)函數(shù)為platform_driver_register(),其原型定義在driver/base/platform.c文件中,具體實(shí)現(xiàn)代碼如下:
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);
}
總結(jié),通常情況下只要和內(nèi)核本身運(yùn)行依賴性不大的外圍設(shè)備,相對(duì)獨(dú)立的,擁有各自獨(dú)自的資源(地址總線和IRQs),都可以用platform_driver實(shí)現(xiàn)。如:LCD,網(wǎng)卡、USB、UART等,都可以用platfrom_driver寫,而timer,irq等小系統(tǒng)之內(nèi)的設(shè)備則最好不用platfrom_driver機(jī)制。
/*******************************************************************************/
device和driver之間是如何通過注冊(cè)的名字進(jìn)行連接的:
下面是轉(zhuǎn)載的一份網(wǎng)友用dm9000為例寫的聯(lián)系:
1.3??? 驅(qū)動(dòng)注冊(cè)
下面是DM9000網(wǎng)卡的驅(qū)動(dòng)加載代碼:
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);
很簡(jiǎn)單的代碼,直接調(diào)用platform_driver_register注冊(cè)驅(qū)動(dòng),這里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
這個(gè)函數(shù)定義為:
/**
*?? 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這四個(gè)函數(shù),因此device_driver結(jié)構(gòu)體中的這幾個(gè)函數(shù)指針將進(jìn)行初始化設(shè)置。最后再調(diào)用driver_register注冊(cè)driver成員,有點(diǎn)奇怪,怎么就拋棄了platform_driver呢?
1.3.2?? driver_register
這個(gè)函數(shù)定義為:
/**
*?? 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);
}
當(dāng)函數(shù)執(zhí)行到這里的時(shí)候,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
這個(gè)函數(shù)定義為:
/**
*?? 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;
}
當(dāng)函數(shù)執(zhí)行到此的時(shí)候,drv->bus將指向platform_bus_type這一全局變量,而這一全局變量的drivers_autoprobe成員在bus_register這一全局初始化函數(shù)中設(shè)置為1。因此這里將調(diào)用driver_attach函數(shù),注意此時(shí)傳遞進(jìn)去的參數(shù)drv指向的是dm9000_driver的driver成員。
1.3.4?? driver_attach
這一函數(shù)定義為:
/**
*?? 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);
}
很簡(jiǎn)單,轉(zhuǎn)向bus_for_each_dev。
1.3.5?? bus_for_each_dev
這一函數(shù)定義為:
/**
*?? 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;
}
簡(jiǎn)單枚舉此總線上注冊(cè)的device,然后為其調(diào)用__driver_attach函數(shù),試圖將一個(gè)device和傳遞進(jìn)來的driver相匹配。
1.3.6?? __driver_attach
這一函數(shù)定義為:
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;
}
很簡(jiǎn)單,轉(zhuǎn)而調(diào)用driver_probe_device進(jìn)行驅(qū)動(dòng)的匹配。
1.3.7?? driver_probe_device
這個(gè)函數(shù)定義為:
/**
* 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;
}
此時(shí)的drv->bus指向platform_bus_type這一全局變量,而它的match函數(shù)為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是否匹配來決定。
對(duì)于DM9000的驅(qū)動(dòng)來說,這里的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,
};
在進(jìn)行了正確的名稱匹配之后,將調(diào)用really_probe進(jìn)行硬件檢測(cè)。
1.3.8?? really_probe
這一函數(shù)定義為:
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;
}
此時(shí)的drv->bus指向platform_bus_type這一全局變量,其probe回調(diào)函數(shù)沒有指定,而drv->probe函數(shù)則指向dm9000_probe。因此轉(zhuǎn)向dm9000_probe執(zhí)行,并將dm9000_bfin_device做為參數(shù)傳遞進(jìn)去。
1.4??? 結(jié)論
platform device和driver分別向platform_bus_type這一中介注冊(cè),并通過名稱進(jìn)行相互間的匹配。很是有點(diǎn)婚姻中介的味道,還有點(diǎn)對(duì)暗號(hào)的神秘,呵呵!
2?????? 參考資料
從DM9000驅(qū)動(dòng)看platform device與driver的關(guān)系(2009-6-8)
uclinux內(nèi)核驅(qū)動(dòng)的初始化順序(2009-6-7)
總結(jié)
以上是生活随笔為你收集整理的linux 内核驱动的名字,Linux内核驱动的的platform机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 哈理工OJ 1983 Math(前缀和)
- 下一篇: 什么是响应式网页
