1. 程式人生 > >《Linux Device Drivers》第十四章 Linux 裝置模型

《Linux Device Drivers》第十四章 Linux 裝置模型

  • 簡介
    • 2.6核心的裝置模型提供一個對系統結構的一般性抽象描述,用以支援多種不同的任務
      • 電源管理和系統關機
      • 與使用者空間通訊
      • 熱插拔裝置
      • 裝置型別
      • 物件生命週期
  • kobject、kset和子系統
    • kobject是組成裝置模型的基本結構
      • 物件的引用計數
      • sysfs表述
      • 資料結構關聯
      • 熱插拔事件處理
    • kobject基礎知識
      • <linux/kobject.h>
      • 嵌入的kobject
        • 核心程式碼很少去建立一個單獨的kobject物件,kobject用於控制對大型域相關物件的訪問
      • kobject的初始化
        • 首先將kobject設定為0,通常使用memset
        • void kobject_init(struct kobject *kobj);
        • int kobject_set_name(struct kobject *kobj, const char *format, …);
        • ktype、kset和parent
      • 對引用計數的操作
        • struct kobject *kobjct_get(struct kobject *kobj);
        • void kobject_put(struct kobject *kobj);
      • release函式和kobject型別
        • void my_object_readse(struct kobject *kobj)
          • struct my_object *mine = container_of(kobj, struct my_object, kobj);
          • kfree(mine);
        • struct kobj_type
          • void (*release) (struct kobject *);
          • struct sysfs_ops *sysfs_ops;
          • struct attribute **default_attrs;
        • struct kobj_type *get_ktype(struct kobject *kobj);
    • kobject層次結構、kset和子系統
      • 核心用kobject結構將各個物件連線起來組成一個分層的結構體系,有兩種獨立的機制用於連線:parent指標和kset
      • 在kobject結構的parent成員中,儲存了另外一個kobject結構的指標,這個結構表示了分層結構中上一層的節點
      • kset
        • 一個kset是嵌入相同型別結構的kobject的集合
        • kset結構關心提物件的聚焦與集合
        • 可以認為kset是kobject的頂層容器類
        • kset總是在sysfs中出現
        • 先把kobject的kset成員指向目的kset,然後使用下面函式新增kobject
        • int kobject_add(struct kobject *kobj);
        • extern int kobject_register(struct kobject *kobj);
          • kobject_init和kobject_add的簡單組合
        • void kobject_del(struct kobject *kobj);
        • kset在一個標準的核心連結串列中儲存了它的子節點
      • kset上的操作
        • void kset_init(struct kset *kset);
        • int kset_add(struct kset *kset);
        • int kset_register(struct kset *kset);
        • void kset_unregister(struct kset *kset);
      • 子系統
        • 子系統通常顯示在sysfs分層結構中的頂層
        • 核心中的子系統
          • block_subsys(對塊裝置來說是/sys/block)
          • devices_subsys(/sys/devices,裝置分層結構的核心)
          • 核心所知曉的用於各種匯流排的特定子系統
          • decl_subsys(name, struct kobj_type *type, struct kset_hotplug_ops *hotplug_ops);
          • void subsysstem_init(struct subsystem *subsys);
          • int subsystem_register(struct subsystem *subsys);
          • void subsystem_unregister(struct subsystem *subsys);
          • struct subsystem *subsys_get(struct subsystem *subsys);
          • void subsys_put(struct subsystem *subsys);
  • 低層sysfs操作
    • kobject是隱藏在sysfs虛擬檔案系統後的機制,對於sysfs中的每個目錄,核心中都會存在一個對應的kobject
    • <linux/sysfs.h>
    • sysfs入口
      • kobject在sysfs中的入口始終是一個目錄
      • 分配閥給kobject的名字是sysfs中的目錄名
      • sysfs入口在目錄中的位置對應於kobject的parent指標
    • 預設屬性
      • kobject預設屬性儲存在kobj_type結構中
      • default_attrs成員儲存了屬性列表
      • sysfs_ops提供了實現這些屬性的方法
      • struct attribute
        • char *name
        • struct module *owner
        • mode_t mode
          • 只讀:S_IRUGO
          • 可寫:S_IWUSR
          • <linux/stat.h>
      • struct sysfs_ops
        • ssize_t (*show) (struct kobject * kobj, struct attribute *attr, char *buffer);
        • ssize_t (*store) (struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size);
    • 非預設屬性
      • int sysfs_create_file(struct kobject *kobj, struct attribute *attr);
      • int sysfs_remove_file(struct kobject *kobj, struct attribute *attr);
    • 二進位制屬性
      • struct bin_attribute
        • struct attribute attr;
        • size_t size;
        • ssize_t (*read) (struct kobject *kobj, char *buffer, loff_t pos, size_t size);
        • ssize_t (*write) (struct kobject *kobj, char *buffer, loff_t pos, size_t size);
      • int sysfs_create_bin_file(struct kobject *kobj, struct bin_attribute *attr);
      • int sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
    • 符號連結
      • int sysfs_create_link(struct kobject *kobj, struct kobject *target, char *name);
      • void sysfs_remove_link(struct kobject *kobj, char *name);
  • 熱插拔事件的產生
    • 一個熱插拔事件是從核心空間傳送到使用者空間的通知,它表明系統配置出現了變化
    • 無論kobject被建立還是被刪除,都會產生這種事件
    • 熱插拔操作
      • struct kset_hotplug_ops
        • int (*filter) (struct kset *kset, struct kobject *kobj);
        • char * (*name) (struct kset *kset, struct kobject *kobj);
        • int (*hotplug) (struct kset *kset, struct kobject *kobj, char **envp, int num_envp, char *buffer, int buffer_size);
      • 當核心要為指定的kobject產生事件時,都要呼叫filter函式,如果返回0,將不產生事件
  • 匯流排、裝置和驅動程式
    • 匯流排
      • 匯流排是處理器與一個或者多個裝置之間的通道
      • <linux/device.h>
        • struct bus_type
          • char *name;
          • struct subsystem subsys;
          • struct kset drivers;
          • struct kset devices;
          • int (*match) (struct device *dev, struct device_driver *drv);
          • struct device *(*add) (struct device *parent, char *bus_id);
          • int (*hotplug) (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
      • 每個匯流排都有自己的子系統
      • 一個匯流排包含兩個kset,分別代表了匯流排的驅動程式和插入匯流排的所有裝置
      • 匯流排的註冊
        • example
          • struct bus_type ldd_bus_type = {.name=”ldd”, .match=ldd_match, .hotplug=ldd_hotplug,};
          • ret = bus_register(&ldd_bus_type);
          • if (res) return ret;
        • void bus_unregister(struct bus_type *bus);
      • 匯流排方法
        • 當一個總線上的新裝置或者新驅動程式被新增時,會一次或多次呼叫match函式
        • 在為使用者空間產生熱插拔事件前,hotplug方法允許匯流排新增環境變數
        • 在呼叫真實的硬體時,match函式通常對裝置提供的硬體ID和驅動所支援的ID做某種型別的比較
      • 對裝置和驅動程式的迭代
        • int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn) (struct device *, void *));
        • int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, int (*fn)(struct device_driver *, void *));
      • 匯流排屬性
        • <linux/device.h>
          • struct bus_attribute
            • struct attribute attr;
            • ssize_t (*show) (struct bus_type *bus, char *buf);
            • ssize_t (*store) (struct bus_type *bus, const char *buf, size_t count);
        • BUS_ATTR(name, mode, show, store);
        • int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);
        • void bus_remove_file(struct bus_tyep *bus, struct bus_attribute *attr);
    • 裝置
      • struct device
        • struct device *parent;
        • struct kobject kobj;
        • char bus_id[BUS_ID_SIZE];
        • struct bus_type *bus;
        • struct device_driver *driver;
        • void *driver_data
        • void (*release) (struct device *dev);
      • 設備註冊
        • int device_register(struct device *dev);
        • void device_unregister(struct device *dev);
      • 裝置屬性
        • struct device_attribute
          • struct attribute attr;
          • ssize_t (*show) (struct device *dev, char *buf);
          • ssize_t (*store) (struct device *dev, const char *buf, size_t count);
        • DEVICE_ATTR(name, mode, show, store);
        • int device_create_file(struct device *device, struct device_attribute *entry);
        • void device_remove_file(struct device *dev, struct device_attribute *attr);
      • 裝置結構的嵌入
        • device結構中包含了裝置模型核心用來模擬系統的資訊
        • 通常,底層驅動程式並不知道device結構
    • 裝置驅動程式
      • struct device_driver
        • char *name;
        • struct bus_type *bus;
        • struct kobject kobj;
        • struct list_head devices;
        • int (*probe) (struct device *dev);
        • int (*remove) (struct device *dev);
        • void (*shutdown) (struct device *dev);
      • probe是用來查詢特定裝置是否存在的函式
      • 當裝置從系統中刪除的時候要呼叫remove函式
      • 在關機的時候呼叫shutdown函式關閉裝置
      • int driver_register(struct device_driver *drv);
      • void driver_unregister(struct device_driver *drv);
      • struct driver_attribute
        • struct attribute attr;
        • ssize_t (*show) (struct device_driver *drv, char *buf);
        • ssize_t (*store) (struct device_driver *drv, const char *buf, size_t count);
      • int driver_create_file(struct device_driver *drv, struct driver_attribute *attr);
      • void driver_remove_file(struct device_driver *drv, struct driver_attribute *attr);
      • 驅動程式結構的嵌入
        • device_driver結構通常被包含在高層和總結相關的結構中
    • 類是一個裝置的高層檢視,它抽象出了低層的實現細節
    • 幾乎所有類都顯示在/sys/class目錄中
      • /sys/class/net
      • /sys/class/input
      • /sys/class/tty
      • /sys/block
    • class_simple介面
      • 建立類本身
        • struct class_simple *class_simple_create(struct module *owner, char *name);
      • 銷燬一個簡單類
        • void class_simple_destroy(struct class_simple *cs);
      • 為一個簡單類新增裝置
        • struct class_device *class_simple_device_add(struct class_simple *cs, dev_t devnum, struct device *device, const char *fmt, …);
      • int class_simple_set_hotplug(struct class_simple *cs, int (*hotplug) (struct class_device *dev, char **envp, int num_envp, crah *buffer, int buffer_size));
      • void class_simple_device_remove(dev_t dev);
    • 完整的類介面
      • 管理類
        • struct class
          • char *name;
          • struct class_attribute *class_attrs;
          • struct class_device_attribute *class_dev_attrs;
          • int (*hotplug) (struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
          • void (*release) (struct class_device *dev);
          • void (*class_release) (struct class *class);
        • int class_register(struct class *cls);
        • void class_unregister(struct class *cls);
        • struct class_attribute
          • struct attribute attr;
          • ssize_t (*show) (struct class *cls, char *buf);
          • ssize (*store) (struct class *cls, const char *buf, size_t count);
        • CLASS_ATTR(name, mode, show, store);
        • int class_create_file(struct class *cls, const struct class_attribute *attr);
        • void class_remove_file(struct class *cls, const struct class_attribute *attr);
      • 類裝置
        • strict class_device
          • struct kobject kobj;
          • struct class *class;
          • struct device *dev;
          • void *class_data;
          • char class_id[BUS_ID_SIZE];
        • int class_device_register(struct class_device *cd);
        • void class_device_unregister(struct class_device *cd);
        • int class_device_renmae(struct class_device *cd, char *new_name);
        • struct class_device_attribute
          • struct attribute attr;
          • ssize_t (*show) (struct class_device *cls, char *buf);
          • ssize_t (*store) (struct class_device *cls, const char *buf, size_t count);
        • CLASS_DEVICE_ATTR(name, mode, show, store);
        • int class_deivce_create_file(struct class_device *cls, const struct class_device_attribute *attr);
        • void class_device_remove_file(struct class_device *cls, const struct class_device_attribute *attr);
      • 類介面
        • struct class_interface
          • struct class *class;
          • int (*add) (struct class_device *cd);
          • void (*remove) (struct class_device *cd);
        • int class_interface_register(struct class_interface *intf);
        • void class_interface_unregister(struct class_interface *intf);
  • 各環節的整合
    • 新增一個裝置
      • PCI子系統聲明瞭一個bus_type結構,稱為pci_bus_type
        • struct bus_type pci_bus_type
          • .name = “pci”,
          • .match = pci_bus_match,
          • .hotplug = pci_hotplug,
          • .suspend = pci_device_suspend,
          • .resume = pci_device_resume,
          • .dev_attrs = pci_dev_attrs,
      • 註冊後,將會建立一個sysfs目錄/sys/bus/pci,其中包含了兩個目錄:devices和drivers
      • 所有的PCI驅動程式都必須定義一個pci_driver結構變數,這個結構中包含了一個device_driver結構,在註冊PCI驅動程式時,這個結構將被初始化
        • drv->driver.name = drv->name;
        • drv->driver.bus = &pci_bus_type;
        • drv->driver.probe = pci_device_probe;
        • drv->driver.remove = pci_device_remove;
        • drv->driver.kobj.ktype = &pci_deiver_kobj_type;
        • error = driver_register(&drv->driver);
      • 當一個PCI裝置被找到時,PCI核心在記憶體中建立一個pci_dev型別的結構變數
        • struct pci_dev
          • unsigned int devfn;
          • unsigned short vendor;
          • unsigned short device;
          • unsigned short subsystem_vendor;
          • unsigned short subsystem_device;
          • unsigned int class;
          • struct pci_driver *driver;
          • struct device dev;
        • 初始化時,device結構變數的parent變數被設定為PCI裝置所在的匯流排裝置
      • device_register(&dev->dev);
      • device_register函式中,驅動程式核心向kobject核心註冊裝置的kobject
      • 接著裝置將被新增到與匯流排相關的所有裝置連結串列中,遍歷這個連結串列,並且為每個驅動程式呼叫該匯流排的match函式,同時指定該裝置
      • 如果匹配工作圓滿完成,函式向驅動程式核心返回1,驅動程式核心將device結構中的driver指標指向這個驅動程式,然後呼叫device_driver結構中指定的probe函式
    • 刪除裝置
      • 呼叫pci_remove_bus_device函式
      • 該函式做些PCI相關的清理工作,然後使用指向pci_dev中的device結構的指標,呼叫device_unregister函式
      • device_unregister函式中,驅動程式核心只是刪除了從繫結裝置的驅動程式到sysfs檔案的符號連結,從內部裝置連結串列中刪除了該裝置,並且以device結構中的kobject結構指標為引數,呼叫kobject_del函式
      • kobject_del函式刪除了裝置的kobject引用,如果該引用是最後一個,就要呼叫該PCI裝置的release函式
    • 新增驅動程式
      • 呼叫pci_register_driver函式時,一個PCI驅動程式被新增到PCI核心中
      • 該函式只是初始化了包含在pci_driver結構中的device_driver結構
      • PCI核心用包含在pci_driver結構的device_driver結構指標作為引數,在驅動程式核心內呼叫driver_register函式
      • driver_reigster函式初始化了幾個device_driver中的鎖,然後呼叫bus_add_driver函式,該函式按以下步驟操作
        • 查詢與驅動程式相關的匯流排
        • 根據驅動程式的名字以及相關的匯流排,建立驅動程式的sysfs目錄
        • 獲取匯流排內部的鎖,接著遍歷所有向匯流排註冊的裝置,為這些裝置呼叫match函式
    • 刪除驅動程式
      • 呼叫pci_unregister_driver函式
      • 該函式用包含在pci_driver結構中的device_driver結構作為引數,呼叫驅動程式核心函式driver_unregister
      • driver_unregister函式清除在sysfs樹中屬於驅動程式的sysfs屬性
      • 遍歷所有屬於該驅動程式的裝置,併為其呼叫release函式
  • 處理韌體
    • 將韌體程式碼放入驅動程式會使驅動程式程式碼膨脹,使得韌體升級困難,並容易導致許可證問題
    • 不要把包含韌體的驅動程式放入核心,或者包含在Linux發行版中
    • 核心韌體介面
      • <linux/firmware.h>
        • int request_firmware(const struct firmware **fw, char *name, struct device *device);
        • struct firmware
          • size_t size;
          • u8 *data;
        • void release_firmware(struct firmware *fw);
        • int request_firmware_nowait(struct module *module, char *name, struct device *device, void *context, void (*cont)(const struct firmware *fw, void *context));
    • 工作原理
      • 韌體子系統使用sysfs和熱插拔機制工作
      • 呼叫request_firmware時,在/sys/class/firmware下將建立一個目錄,該目錄使用裝置名作為它的目錄名,該目錄包含三個屬性
        • loading
          • 由負責裝載韌體的使用者空間程序設定為1
        • data
          • 是一個二進位制屬性,用來接收韌體資料
        • device
          • 該屬性是到/sys/devices下相應入口的符號連結
      • 一旦sysfs入口被建立,核心將為裝置產生熱插拔事件,傳遞給熱插拔處理程式的環境包括一個FIRMWARE變數,它將設定為提供給request_firmware的名字
      • 處理程式定位韌體檔案,使用所提供的屬性把韌體檔案拷貝到核心,如果不能發現韌體檔案,處理程式將設定loading屬性為-1
      • 如果在10秒鐘之內不能為韌體的請求提供服務,核心將放棄努力並向驅動程式返回錯誤狀態,這個超時值可以通過修改sysfs屬性/sys/class/firmware/timeout來改變
      • 不能在沒有製造商許可的情況下發行裝置的韌體

相關推薦

Linux Device Drivers Linux 裝置模型

簡介 2.6核心的裝置模型提供一個對系統結構的一般性抽象描述,用以支援多種不同的任務 電源管理和系統關機與使用者空間通訊熱插拔裝置裝置型別物件生命週期kobject、kset和子系統 kobject是

LINUX新安全FIREWALLD-CENTOS7.5知識

一、FIRWALLDFilewalld(動態防火牆)作為redhat7系統中變更對於netfilter核心模組的管理工具;iptables service 管理防火牆規則的模式(靜態):使用者將新的防火牆規則新增進 /etc/sysconfig/iptables 配置檔案當中,再執行命令 /etc/init.

《機器學習》 周志華學習筆記 概率圖模型(課後習題)python實現

一、基本內容 1.隱馬爾可夫模型 1.1. 假定所有關心的變數集合為Y,可觀測變數集合為O,其他變數集合為R, 生成式模型考慮聯合分佈P(Y,R,O),判別式模型考慮條件分佈P(Y,R|O),給定一組觀測變數值,推斷就是要由P(Y,R,O)或者P(Y,R|O)得到條件概率分佈P(Y,

機器學習(周志華) 參考答案 概率圖模型

機器學習(周志華西瓜書) 參考答案 總目錄 1.試用盤式記法表示條件隨機場和樸素貝葉斯分類器。 條件隨機場: 這樣畫的問題在於無法表示N個y之間的關係,到底怎麼畫我也不知道。 樸素貝葉斯分類器:y依賴於所有的變數x 2.證明

Linux Device Drivers裝置驅動程式——note

簡介 一個塊裝置驅動程式主要通過傳輸固定大小的隨機資料來訪問裝置 Linux核心視塊裝置為與字元裝置相異的基本裝置型別 Linux塊裝置驅動程式介面使得塊裝置可以發揮其最大的功效,但是其複雜程式又是程式設計者必須面對的一個問題 一個數據塊指的是固

Linux就該這麽學 20181010(DHCP)

網關 搜索 lin none 作用 offset 而在 class 設備 參考鏈接:https://www.linuxprobe.com DHCP動態地址分配協議 作用域:定義一個很大的網段地址池:真正為用戶去分配的地址地址池要小於等於作用域排除範圍:作用域-地址池租約-默

Linux 賬號管理與 ACL 許可權配置

要如何在 Linux 的系統新增一個使用者啊?呵呵~真是太簡單了~我們登陸系統時會輸入 (1)賬號與 (2)口令, 所以建立一個可用的賬號同樣的也需要這兩個資料。那賬號可以使用 useradd 來新建使用者,口令的給予則使用 passwd 這個命令!這兩個命令下達方法如下: us

linux程式設計——使用訊號量(

14.1.4    使用訊號量 下面將用完整的程式設計介面為二進位制訊號量建立一個簡單得多的PV型別介面,然後用這個非常簡單的介面來演示訊號量是如何工作的。 用程式sem1.c來試驗訊號量,該程式可以被多次呼叫。通過一個可選的引數來指定程式是負責建立訊號量還是負責刪除訊號量

鳥哥的Linux私房菜——:正規表示法

打印 全部 相關 sed 新增 class 簡介 rep .com   視頻鏈接   土豆:   B站:   本章講的是   目錄如下 1. 前言:2. 基礎正規表示法:2.1 以 grep 擷取字符串      (grep -iv i是忽略大小寫,v是反

鳥哥的Linux私房菜——:磁盤配額quota

創建 repquota 個人 沒有 網絡硬盤 存在 當前 mage 技術分享   視頻鏈接:   磁盤配額quota的意思是給用戶進行使用磁盤額度的空間的劃分,舉個例子,你的百度網盤的使用空間,其他雲盤的使用空間。在使用quota這個命令之前,我們需要進行一些操作,

鳥哥的Linux私房菜——:例行命令的建立

crontab bsp 鳥哥 onf ges fig 什麽 執行 inux   視頻鏈接: 1. 什麽是例行性命令                (分為兩種,一種是周期性的,一種是突發性的)1.1 Linux 工作排程的種類: at, cron        (

linux系統學習天-<<工程師技術>>

linux工程師技術 linux管理員技術 linux雲計算 深圳雲計算王森 雲計算運維工程師 RAID磁盤陣列 ? 廉價冗余磁盤陣列 – Redundant Arrays of Inexpensive Disks – 通過硬件/軟件技術,將多個較小/低速的磁盤整合成一 個大磁盤 –

Linux集群架構

linux18.1 集群介紹集群概述根據功能劃分為兩大類:高可用和負載均衡.1)高可用集群通常為兩臺服務器,一臺工作,另外一臺作為冗余,當提供服務的機器宕機,冗余將接替繼續提供服務實現高可用的開源軟件有:heartbeat、keepalived。後者好用,前者好久未更新了。2)負載均衡集群,需要有一臺服務器

Linux監控平臺搭建

  19.1 Linux監控平臺介紹 19.2 zabbix監控介紹 19.3 安裝zabbix(上) •vim /etc/my.cnf //需要增加配置 character_set_server

Linux叢集架構(下)

18.11 LVS DR模式搭建 dir 上的指令碼檔案 dir 網絡卡配置 rs1上的指令碼配置檔案 rs1上的網絡卡配置 rs2 上的指令碼檔案 rs2的網絡卡配置 測試

Linux叢集架構(上)

18.1 叢集介紹 18.2 keepalived介紹 18.3 用keepalived配置高可用叢集(上) 準備兩臺機器 一個為mater   另一個為backup 兩臺機器都關閉防火牆 兩臺機器都安裝上nginx,為了下一步

linux~FTP

1。1,配置好網路源 vim /etc/yum.repos.d/rhel_dvd.repo systemctl start vsftpd 重啟服務 2,firewall-config 防火牆配置 3,vim /etc/sysconfig/sel

linux~ selinux

1.SELinux的全稱是Security Enhanced Linux, 就是安全加強的Linux vim /etc/sysconfig/selinux 更改防火牆的狀態 命令"getenforce"可以檢視SElinux的狀態,SElinux的狀態分為以

linux~系統排錯

1.怎麼樣更改root使用者的密碼 當你不小心忘記自己的root密碼時,可以用下面的操作來更改root密碼 啟動時用上下鍵停留在選擇介面,按e進入 尋找linux16 這一行,從ro之後全部刪除,將ro改為rw,在後面加上rd.break,然後按ctrl+x

單元 Linux網路原理及基礎設定

  使用ifconfig命令來維護網路 ifconfig命令的功能 ifconfig命令的用法舉例 使用ifup和ifdown命令啟動和停止網絡卡 ifup命令的功能 ifdown命令的功能 ifup命令的用法舉例 ifdown命令的用法舉例 網路配置檔案 網絡卡對應的網路配置檔案 什麼是網路配置