日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

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

發布時間:2023/12/10 linux 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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)

總結

以上是生活随笔為你收集整理的linux 内核驱动的名字,Linux内核驱动的的platform机制的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。