Linux匯流排、裝置、驅動模型
1. 分配一個platform_device結構並呼叫platform_device_register函式進行註冊
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev); // 初始化platform_device的device成員
arch_setup_pdev_archdata(pdev);
return platform_device_add(pdev); // 向核心新增一個平臺裝置
}
2. 呼叫platform_device_add函式向核心新增一個平臺裝置
int platform_device_add(struct platform_device *pdev) { int i, ret; if (!pdev) return -EINVAL; if (!pdev->dev.parent) //如果pdev->dev.parent為空則將pdev->dev.parent設定為platform_bus pdev->dev.parent = &platform_bus; pdev->dev.bus = &platform_bus_type; // 設定匯流排型別為platform_bus_type switch (pdev->id) { // 分配名字 default: dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); break; case PLATFORM_DEVID_NONE: dev_set_name(&pdev->dev, "%s", pdev->name); break; case PLATFORM_DEVID_AUTO: /* * Automatically allocated device ID. We mark it as such so * that we remember it must be freed, and we append a suffix * to avoid namespace collision with explicit IDs. */ ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); if (ret < 0) goto err_out; pdev->id = ret; pdev->id_auto = true; dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id); break; } for (i = 0; i < pdev->num_resources; i++) { // 獲取資源 struct resource *p, *r = &pdev->resource[i]; if (r->name == NULL) r->name = dev_name(&pdev->dev); p = r->parent; if (!p) { // 設定資源型別 if (resource_type(r) == IORESOURCE_MEM) p = &iomem_resource; else if (resource_type(r) == IORESOURCE_IO) p = &ioport_resource; } if (p && insert_resource(p, r)) { dev_err(&pdev->dev, "failed to claim resource %d\n", i); ret = -EBUSY; goto failed; } } pr_debug("Registering platform device '%s'. Parent at %s\n", dev_name(&pdev->dev), dev_name(pdev->dev.parent)); ret = device_add(&pdev->dev); // 向核心新增一個device if (ret == 0) return ret; failed: if (pdev->id_auto) { ida_simple_remove(&platform_devid_ida, pdev->id); pdev->id = PLATFORM_DEVID_AUTO; } while (--i >= 0) { struct resource *r = &pdev->resource[i]; unsigned long type = resource_type(r); if (type == IORESOURCE_MEM || type == IORESOURCE_IO) release_resource(r); } err_out: return ret; }
3. 呼叫device_add函式向核心新增一個device
int device_add(struct device *dev) { struct device *parent = NULL; struct kobject *kobj; struct class_interface *class_intf; int error = -EINVAL; dev = get_device(dev); if (!dev) goto done; if (!dev->p) { error = device_private_init(dev); if (error) goto done; } /* * for statically allocated devices, which should all be converted * some day, we need to initialize the name. We prevent reading back * the name, and force the use of dev_name() */ if (dev->init_name) { dev_set_name(dev, "%s", dev->init_name); dev->init_name = NULL; } /* subsystems can specify simple device enumeration */ if (!dev_name(dev) && dev->bus && dev->bus->dev_name) dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); if (!dev_name(dev)) { error = -EINVAL; goto name_error; } pr_debug("device: '%s': %s\n", dev_name(dev), __func__); parent = get_device(dev->parent); kobj = get_device_parent(dev, parent); if (kobj) dev->kobj.parent = kobj; /* use parent numa_node */ if (parent) set_dev_node(dev, dev_to_node(parent)); /* first, register with generic layer. */ /* we require the name to be set before, and pass NULL */ error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); if (error) goto Error; /* notify platform of device entry */ if (platform_notify) platform_notify(dev); error = device_create_file(dev, &dev_attr_uevent); if (error) goto attrError; if (MAJOR(dev->devt)) { error = device_create_file(dev, &dev_attr_dev); if (error) goto ueventattrError; error = device_create_sys_dev_entry(dev); if (error) goto devtattrError; devtmpfs_create_node(dev); } error = device_add_class_symlinks(dev); if (error) goto SymlinkError; error = device_add_attrs(dev); if (error) goto AttrsError; error = bus_add_device(dev); if (error) goto BusError; error = dpm_sysfs_add(dev); if (error) goto DPMError; device_pm_add(dev); /* Notify clients of device addition. This call must come * after dpm_sysfs_add() and before kobject_uevent(). */ if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_ADD_DEVICE, dev); kobject_uevent(&dev->kobj, KOBJ_ADD); bus_probe_device(dev); // 為總線上的裝置尋找驅動 if (parent) klist_add_tail(&dev->p->knode_parent, &parent->p->klist_children); if (dev->class) { mutex_lock(&dev->class->p->mutex); /* tie the class to the device */ klist_add_tail(&dev->knode_class, &dev->class->p->klist_devices); /* notify any interfaces that the device is here */ list_for_each_entry(class_intf, &dev->class->p->interfaces, node) if (class_intf->add_dev) class_intf->add_dev(dev, class_intf); mutex_unlock(&dev->class->p->mutex); } done: put_device(dev); return error; DPMError: bus_remove_device(dev); BusError: device_remove_attrs(dev); AttrsError: device_remove_class_symlinks(dev); SymlinkError: if (MAJOR(dev->devt)) devtmpfs_delete_node(dev); if (MAJOR(dev->devt)) device_remove_sys_dev_entry(dev); devtattrError: if (MAJOR(dev->devt)) device_remove_file(dev, &dev_attr_dev); ueventattrError: device_remove_file(dev, &dev_attr_uevent); attrError: kobject_uevent(&dev->kobj, KOBJ_REMOVE); kobject_del(&dev->kobj); Error: cleanup_device_parent(dev); if (parent) put_device(parent); name_error: kfree(dev->p); dev->p = NULL; goto done; }
4. 呼叫bus_probe_device函式為總線上的裝置尋找驅動
void bus_probe_device(struct device *dev)
{
struct bus_type *bus = dev->bus;
struct subsys_interface *sif;
int ret;
if (!bus)
return;
if (bus->p->drivers_autoprobe) {
ret = device_attach(dev); // 呼叫device_attach()進行實際的尋找
WARN_ON(ret < 0);
}
mutex_lock(&bus->p->mutex);
list_for_each_entry(sif, &bus->p->interfaces, node)
if (sif->add_dev)
sif->add_dev(dev, sif);
mutex_unlock(&bus->p->mutex);
}
int device_attach(struct device *dev)
{
int ret = 0;
device_lock(dev);
if (dev->driver) {
if (klist_node_attached(&dev->p->knode_driver)) {
ret = 1;
goto out_unlock;
}
ret = device_bind_driver(dev);
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
ret = 0;
}
} else {
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); // 遍歷bus的drv連結串列為裝置尋找驅動
pm_request_idle(dev);
}
out_unlock:
device_unlock(dev);
return ret;
}
(1) bus_for_each_drv函式原始碼:
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
void *data, int (*fn)(struct device_driver *, void *))
{
struct klist_iter i;
struct device_driver *drv;
int error = 0;
if (!bus)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_drivers, &i,
start ? &start->p->knode_bus : NULL);
while ((drv = next_driver(&i)) && !error) // 遍歷整個drv連結串列
error = fn(drv, data); // 尋找該裝置匹配的驅動程式,若匹配則將二者繫結
klist_iter_exit(&i);
return error;
}
(2)__device_attach函式原始碼:
static int __device_attach(struct device_driver *drv, void *data)
{
struct device *dev = data;
if (!driver_match_device(drv, dev)) // 呼叫bus的match函式對裝置和驅動進行匹配,若不匹配driver_match_device函式的返回值為1,則程式立即返回,若匹配則繼續向下執行
return 0;
return driver_probe_device(drv, dev); // 若裝置和驅動匹配,則將該驅動程式繫結到該裝置
}
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
5. 呼叫driver_probe_device將裝置與驅動程式進行繫結(呼叫probe函式)
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
if (!device_is_registered(dev))
return -ENODEV;
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
pm_runtime_barrier(dev);
ret = really_probe(dev, drv); // 呼叫probe
pm_request_idle(dev);
return ret;
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = 0;
int local_trigger_count = atomic_read(&deferred_trigger_count);
atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));
dev->driver = drv;
/* If using pinctrl, bind pins now before probing */
ret = pinctrl_bind_pins(dev);
if (ret)
goto probe_failed;
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}
if (dev->bus->probe) { // 如果裝置本身含有probe函式,那麼久呼叫裝置的probe函式
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) { // 如果裝置不含有probe函式,那麼就呼叫驅動程式的probe函式
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
driver_bound(dev);
ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
goto done;
probe_failed:
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
dev_set_drvdata(dev, NULL);
if (ret == -EPROBE_DEFER) {
/* Driver requested deferred probing */
dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
driver_deferred_probe_add(dev);
/* Did a trigger occur while probing? Need to re-trigger if yes */
if (local_trigger_count != atomic_read(&deferred_trigger_count))
driver_deferred_probe_trigger();
} else 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_name(dev), ret);
} else {
pr_debug("%s: probe of %s rejects match %d\n",
drv->name, dev_name(dev), 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;
}
到此Linux核心的匯流排裝置驅動模型分析完畢。從上面的分析過程可以看出,所謂的platform_device並不是與字元裝置、塊裝置和網路裝置並列的概念,而是Linux系統提供的一種附加手段。
相關推薦
linux裝置驅動模型之匯流排、裝置、驅動三者的關係
匯流排、裝置、驅動,也就是bus、device、driver,在核心裡都有對應的結構體,在include/linux/device.h 裡定義。Device.h (linux-3.4.2\inclu
Linux匯流排、裝置、驅動模型
1. 分配一個platform_device結構並呼叫platform_device_register函式進行註冊 int platform_device_register(struct platform_device *pdev) { device_initialize(&pdev->de
Linux裝置模型(匯流排、裝置、驅動程式和類)之一:bus_type
匯流排是處理器和一個或多個裝置之間的通道,在裝置模型中,所有的裝置都通過匯流排相連,甚至是內部的虛擬"platform"匯流排。可以通過ls -l /sys/bus看到系統載入的所有匯流排。drwxr-xr-x root root
《Linux匯流排、裝置與驅動》自己寫的demo
本demo基於Android2.3模擬器開發,核心程式碼(Linux2.6.29)和Android程式碼可以在網上下載、這裡不在說明。 一、驅動 1.匯流排驅動 功能:匯流排驅動;提供設備註冊和裝置驅動註冊以及裝置與裝置驅動匹配等函式功能。 testbus.c #inc
【迅為iTop4412學習筆記】4. 匯流排、裝置、驅動,註冊流程
宣告 以下都是我剛開始看驅動視訊的個人強行解讀,如果有誤請指出,共同進步。 本節目標 瞭解Linux匯流排、裝置 驅動註冊的流程 基本知識 一般的裝置:接入裝置 -> 註冊裝置 -> 註冊
裝置驅動歸納總結(八):1.匯流排、裝置和驅動 —— 匯流排的註冊
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 這幾天一直在看裝置模型,核心的程式碼看得我越來越沮喪,特別是kboject、kset和ktype之間的關係。但是,裝置
一、NodeJS事件驅動模型
接觸nodejs有兩個月,對nodejs的兩大特性一直有點模糊,即非同步IO和事件驅動。通過對《深入淺出nodejs》和幾篇部落格的閱讀以後,有了大致的瞭解,總結一下。 幾個例子 在開始之前,先來看幾個簡單例子,這也是我在使用nodejs時候遇到的幾個比較困惑的例子。 example
核心、裝置、驅動、檔案系統、核心空間、使用者空間
學習驅動過程中有一些疑問,記錄下來,並希望能在2015-6-30之前能夠有一個明確的答案。 疑問: 一、當裝置插上的時候,核心怎麼發現裝置並更新/sys、/dev、/proc檔案系統、怎麼通知給使用者空間?更具體一點是probe的過程 二、device和driver怎麼配對
linux驅動開發:匯流排,裝置,驅動三要素
平臺匯流排和IIC,SPI,IIS都是匯流排型別,一般的,匯流排下,掛載對應的裝置。但實際上,裝置要正常運轉,是需要驅動程式來未知提供驅動的。所以linux核心也把驅動掛載在對應的匯流排下。匯流排,驅動,裝置三者缺一不可. 相應的,核心衍生出來的平臺匯流排,那
裝置檔案、裝置檔案節點 、裝置 、裝置驅動 區別
1.裝置Linux下的裝置通常分為三類,字元裝置,塊裝置和網路裝置。見的字元裝置有滑鼠、鍵盤、串列埠、控制檯等。常見的塊裝置有各種硬碟、flash磁碟、RAM磁碟等。在Linux裡一個網路裝置也可以叫做一個網路介面,如eth0,應用程式是通過Socket而不是裝置節點來訪問網
linux裝置驅動歸納總結(九):1.platform匯流排的裝置和驅動
linux裝置驅動歸納總結(九):1.platform匯流排的裝置和驅動 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 這一節可
【Tensorflow】Tensorflow的圖、會話、裝置、變數、核心
前言 基礎知識,前面我們介紹到,Tensorflow的資料流圖是由節點和邊組成的有向無環圖,此外,還涉及一些其他概念,如圖、會話、裝置、變數、核心等。 圖(Graph) import tensorflow as tf # 建立圖 # 建立一個常量運算操作,產生一個1 x 2
linux 下platform裝置和驅動註冊的先後順序
我明白了,你說的是另一種情況,象USB 的hcd驅動一樣,先註冊驅動,後註冊裝置。 在註冊裝置時,遍歷裝置所在匯流排,找到與裝置匹配的驅動,再呼叫device_attach()--> driver_probe_device()時的情況。 這時,會呼叫裝置所在匯流排的probe()函式,如果沒有
[Swift通天遁地]五、高階擴充套件-(9)顏色、裝置、UserDefaults、URL等擴充套件方法
本文將演示顏色、裝置、UserDefaults、URL等擴充套件方法。 首先確保在專案中已經安裝了所需的第三方庫。 點選【Podfile】,檢視安裝配置檔案。 1 platform :ios, '12.0' 2 use_frameworks! 3 4 target 'DemoApp' do
linux裝置驅動模型之Kobject、kobj_type、kset
一、sysfs檔案系統簡介: 1、sysfs概述 sysfs檔案系統是核心物件(kobject)、屬性(kobj_type)、及它們相互關係的一種表現。 sysfs非常重要的特徵:使用者可以從sysfs中讀出核心資料,也可以將使用者資料寫入核心。 2、核心結構與sysfs對應關係:
Linux I2C核心、匯流排與裝置驅動
I2C匯流排僅僅使用SCL、 SDA這兩根訊號線就實現了裝置之間的資料互動,極大地簡化了對硬體資源和PCB板佈線空間的佔用。因此, I2C匯流排非常廣泛地應用在EEPROM、實時鐘、小型LCD等裝置與C
裝置、驅動、匯流排模型簡介
前言 在Linux系統中,有很多的框架提供驅動編寫者使用,比如前面我寫過的一篇文章:input子系統的架構分析及應用。都是將純軟體相關的程式碼和操作硬體相關的程式碼分離開,這樣就使得驅動的編寫者省去編寫大量的、重複的程式碼,只要專注於底層硬體相關的程式碼就可
Linux裝置驅動模型框架分析(三)——LDDM的實體bus_type、device和device_driver
在Linux裝置模型中,Bus(匯流排)是一類特殊的裝置,它是連線處理器和其它裝置之間的通道(channel)。為了方便裝置模型的實現,核心規定,系統中的每個裝置都要連線在一個Bus上,這個Bus可以是一個內部Bus、虛擬Bus或者Platform Bus。 device
嵌入式Linux驅動筆記(十六)------裝置驅動模型(kobject、kset、ktype)
你好!這裡是風箏的部落格, 歡迎和我一起交流。 前幾天去面試,被問到Linux裝置驅動模型這個問題,沒答好,回來後惡補知識,找了些資料,希望下次能答出個滿意答案。 Linux早期時候,一個驅動對應一個裝置,也就對應一個硬體地址,那當有兩個一樣的裝置
Linux裝置、匯流排和驅動之間的關係
(一)、驅動、匯流排和裝置的主要資料結構 (include/linux/device.h) (/driver/base/base.h) (include/device.h) 匯流排中的那兩條連結串列是怎麼形成的。核心要求每次出現一個裝置就要向匯流排彙報,或者