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

歡迎訪問 生活随笔!

生活随笔

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

linux

1.the linux device model--kobject kset学习笔记

發布時間:2023/12/9 linux 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 1.the linux device model--kobject kset学习笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


http://blog.chinaunix.net/uid-22547469-id-4590385.html?utm_source=jiancool

Linux設備模型就是一棟規模宏大的建筑,為了構建它,需要基本的建筑材料鋼筋:kobject、若干鋼筋組成的鋼架結構:kset,還需要一種機制sysfs,來向外界(用戶空間的程序)展示其內部構造。并且通過文件接口的方式實現與外界溝通與互動。

設備文件系統:Linux下一切皆是文件,而設備文件系統包括設備文件、設備節點以及設備特定文件,它們是驅動程序的接口?,而在文件系統中,他們就像普通文件一樣。

devfs是一種Linux2.4內核引入的設備文件系統,用來解決Linux中設備管理混亂的問題位于內核空間,可以通過程序在設備初始化時在/dev下創建設備文件,卸載時將它刪除,現已被udev取代。

udevudev是一種工具,它能夠根據系統中的硬件設備的狀況動態更新設備文件,包括設備文件的創建,刪除等。設備文件通常放在/dev目錄下,使用udev,/dev下面只包含系統中真實存在的設備。它于硬件平臺無關的,位于用戶空間,需要內核sysfstmpfs的支持,sysfsudev提供設備入口和uevent通道,tmpfsudev設備文件提供存放空間。

mdev在嵌入式系統中,通??梢杂?span style="font-family:Consolas;">udev的輕量級版本mdev,集成于busybox。

sysfsLinux2.6所提供的一種跟devfs一樣的虛擬文件系統,基于ramfs(內存文件系統)開發,掛在到/sys目錄,也是用來對系統的設備進行管理的。sysfs以文件目錄層次結構展示了系統硬件設備間的一個拓撲圖。

設備、驅動、總線:這些都是對象,已經是宏偉建筑給外界的展現形式的那部分了,主要是與這三個打交道。

詳細實現:

1、kobject[鋼筋]

kobject是組成設備模型的一個最底層的核心數據結構,與sysfs文件系統自然的綁定在一起:每個kobject對應sysfs文件系統中一個目錄。kobject結構所能處理的任務以及所支持的代碼包括:

1)引用計數;

2維持容器的層次列表和組。

3為容器的屬性提供一種用戶態查看的視圖。

4)熱插拔事件的處理:當系統中的硬件熱插拔時,在kset(其內嵌有kobject)內核對象的控制下,將產生事件以通知用戶空間,該結構一般沒有單獨定義而是嵌入到其他設備結構體中。

kobject定義如下:

點擊(此處)折疊或打開

  • <kobject.h>
  • struct kobject{
  • ????????const char *name; //該內核對象的名稱,在sysfs中,表現形式是一個新的目錄名
  • ????????struct list_head entry;//用來將一些列的內核對象構成鏈表
  • ????????struct kobject *parent;//指向設備分層的上一層的節點,構建層次化關系
  • ????????struct kset *kset;????//所屬的kset對象的指針
  • ????????struct kobj_type ktype;//用于保存屬性,在sysfs中表現為屬性文件
  • ????????struct sysfs_dirent *sd;
  • ????????struct kref kref;//對象引用計數
  • ????????......
  • }

  • 創建kobject的時候,都回、會給每個kobject一系列默認屬性。這些屬性保存在kobj_type結構中。



    點擊(此處)折疊或打開

  • <kobject.h>
  • struct kobj_type {
  • ????void (*release)(struct kobject *);
  • ????struct sysfs_ops????* sysfs_ops;//真正實現這些屬性
  • ????struct attribute????** default_attrs;//屬性列表,最后一個元素用零填充。
  • };
  • <sysfs.h>
  • struct attribute {
  • ????const char????????* name;//屬性的名字
  • ????struct module ????????* owner;//指向模塊的指針
  • ????mode_t????????????mode;//保護位,只讀:S_IRUGO。可寫:S_IWUSR
  • };
  • struct sysfs_ops {
  • ????ssize_t????(*show)(struct kobject *, struct attribute *,char *);
  • ????ssize_t????(*store)(struct kobject *,struct attribute *,const char *, size_t);
  • }

  • kobject一般不單獨定義,常內嵌于其他結構體中。

    經常遇到相反的問題,對于給定的一個kobject指針,如何獲得包含他的結構指針呢?嘎嘎,大名鼎鼎的container_of宏有有用了。

    比如kp是指向kobj的指針,而kobjcdev?device的一個成員,如何根據kp獲取只想cdev的指針,如下:

    struct?cdev?*device=container_of(kp,struct?cdev,kobj);

    ?

    kobject相關函數:

    (1)初始化前第一個操作,將整個kobject設置為0,通常使用memset函數,例如:memset(&kobj,0,sizeof(struct?kobject));

    (2)設定kobject中的name成員,使用如下函數:
    int?kobject_set_name(struct?kobject?*kobj,const?char?*fmt,...)

    (3)初始化一個內核對象的kobject結構,建立kojbect對象間的層次關系,在sysfs中建立一個目錄:

    int?kobject_init_and_add(struct?kobject?*kobj,

    struct?kobj_type?ktype,struct?kobject?*parent,const?char?*fmt,...)

    (4)從linux設備層次中刪除kobj對象:

    void?kobject_del(struct?kobject?*kobj);

    (5)增加kobject引用計數:

    struct?kobject?*?kobject_get(struct?kobject?*?kobj)

    (6)減少kobject引用計數:

    void?kobject_put(struct?kobject?*?kobj)

    (7)每個kobject都必須有一個release方法,該方法保存在kobject相關聯的kobj_type中。

    sysfs中,kobject對應目錄,kobject的屬性對應這個目錄下的文件。調用showstore函數來讀寫文件,就可以得到屬性中的內容。


    點擊(此處)折疊或打開

  • kobject.c
  • #include <linux/device.h>
  • #include <linux/module.h>
  • #include <linux/kernel.h>
  • #include <linux/init.h>
  • #include <linux/string.h>
  • #include <linux/sysfs.h>
  • #include <linux/stat.h>
  • #include <linux/mm.h>

  • /* 每個kobject必須有一個release方法,該方法保存在kobject相關聯的kobj_type中 */
  • void kobj_release(struct kobject *kobj)
  • {
  • ????printk("obj_release!\n");
  • }

  • ssize_t ops_show(struct kobject *kobj,struct attribute *attr,char *c)
  • {
  • ????printk("ops_show\n");
  • ????printk("attr->name:%s \n",attr->name);
  • ????return strlen(attr->name);
  • }

  • ssize_t ops_store(struct kobject *kobj,struct attribute *attr,const char *buf,size_t count)
  • {
  • ????printk("ops_store\n");
  • ????printk("buf:%s\n",buf);
  • ????return count;
  • }

  • struct attribute first_attr={
  • ????.name="first_attr",//屬性名字
  • ????.mode=S_IRWXUGO,????//讀寫執行權限
  • };
  • struct attribute second_attr={
  • ????.name="second_attr",//屬性名字
  • ????.mode=S_IRUGO,????????//只讀
  • };
  • static struct attribute *def_attrs[]={//指針數組,每個成員存儲了一個attribute的地址。
  • ????&first_attr,
  • ????&second_attr,
  • ????NULL,
  • };????
  • struct sysfs_ops sysops={????????//定義sysops
  • ????.show????????=????ops_show,
  • ????.store????=????ops_store,
  • };

  • struct kobj_type ktype={????//定義ktype
  • ????.release????=????kobj_release,????//每個kojbect必須包含的release方法
  • ????.sysfs_ops????=????&sysops,????????//實現屬性的函數
  • ????.default_attrs????=????def_attrs,//屬性列表,二級指針,最后一個元素必須用NULL填充
  • };

  • struct kobject kobj;????//定義kobject結構體變量

  • static __init int kobj_test_init(void) {????????//加載kobject.ko時執行該函數
  • ????printk("\n kobj_test_init\n");
  • ????memset(&kobj,0,sizeof(struct kobject));
  • ????printk("memset kobj\n");
  • ????kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");
  • ????printk("kobject_init_and_add\n");
  • ????return 0;
  • }

  • static __exit void kobj_test_exit(void) {????//卸載kobject時執行此函數
  • ????printk("kobj_test_exit\n");
  • ????kobject_del(&kobj);
  • ????//return 0;
  • }

  • module_init(kobj_test_init);
  • module_exit(kobj_test_exit);
  • MODULE_AUTHOR("MANGO");
  • MODULE_LICENSE("Dual BSD/GPL")
  • 編譯完成后生成kobject.ko文件,執行sudo?insmod?kobject.ko



    加載成功,因該kobjectparentNULL,會在sys的目錄之間建立如下文件:


    打開文件夾后,會看到兩個屬性文件:



    first_attr777權限,second_attr是只讀權限,和程序中寫的相同。

    接下來,執行?cat?first_attr,會發現驅動層自動調用了ktype中的sysfs_opsshow函數:



    同理,執行echo?“123”?>?first_attr,應該調用ops_store函數,執行結果如下:


    和預想完全相同。同理可測試second_attr文件,只是不能寫而已。

    2、kset[由若干個kobject(鋼筋)組成的鋼架結構]

    kset是同種類型的kobject對象的集合,也可以說是對象的容器,通過kset數據結構可以將kobjects組成一顆層次樹。kset的名字保存在內嵌的kobject中。

    包含在kset中的所有kobject被組織成一個雙向循環鏈表,list是這個鏈表的鏈表頭。kset數據結構還內嵌了一個kobject對象(kobj),所有屬于這個ksetkobject對象的parent域均指向這個內嵌的對象。此外,kset還依賴kobj維護引用計數。

    kset和它的kobject的關系如下圖所示:


    黑線:kset?child?list

    綠線:kobject->parent

    藍線:kobject->kset

    注意:一個kobject的父節點不一定是包含他的kset。

    ?

    數據結構如下:


    點擊(此處)折疊或打開

  • struct kset {
  • ????struct kobj_type????* ktype;
  • ????struct list_head????list;//用于連接該kset中所有kobject的鏈表頭
  • ????spinlock_t????????list_lock;//用于互斥訪問
  • ????struct kobject????????kobj;//嵌入的kobject
  • ????struct kset_uevent_ops????* uevent_ops;
  • }

  • kset相關函數:

    創建一個對象時,通常要把一個kobject添加到kset中去。兩個步驟:

    先把kobject內的kset指針指向目的kset

    int?kobject_add(struct?kobject?*kobj);

    1)初始化一個kset對象:

    void?kset_init(struct?kset?*?k);

    2)用來初始化并向系統注冊一個kset對象:

    int?kobject_register(struct?kobject?*kobj);

    (3)注銷kset

    void?kset_unregister(struct?kset?*k);

    (4)某些時候,將kobjectkset中刪除,使用:

    void?kobject_del(struct?kobject?*kobj);



    點擊(此處)折疊或打開

  • kset.c
  • #include <linux/device.h>
  • #include <linux/module.h>
  • #include <linux/kernel.h>
  • #include <linux/init.h>
  • #include <linux/string.h>
  • #include <linux/sysfs.h>
  • #include <linux/stat.h>
  • #include <linux/mm.h>

  • struct kset kset_p;????//父級kset結構體變量
  • struct kset kset_c;????//子級kset結構體變量

  • int kset_filter(struct kset *kset,struct kobject *kobj) {
  • ????printk("kset_filter()kobj->name:%s\n",kobj->name);
  • ????return 1;
  • }
  • const char *kset_name(struct kset *kset,struct kobject *kobj) {
  • ????static char buf[20];
  • ????printk("kset_name()kobj->name:%s\n",kobj->name);
  • ????sprintf(buf,"%s","kset_name");
  • ????return buf;
  • }

  • int kset_uevent(struct kset *kset,struct kobject *kobj,struct kobj_uevent_env *env){
  • ????int i=0;
  • ????printk("kset_uevent()kobj->name:%s\n",kobj->name);
  • ????printk("env:\n");
  • ????while(i<env->envp_idx){
  • ????????printk("%s\n",env->envp[i]);
  • ????????i++;
  • ????????}
  • ????return 0;
  • }
  • struct kset_uevent_ops uevent_ops={
  • ????.filter????????=????kset_filter,
  • ????.name????????????=????kset_name,
  • ????.uevent????????=????kset_uevent,
  • };

  • struct kobj_type my_kobj_type;????//定義ktype變量

  • static __init int kset_test_init(void) {????//sudo insmod kset.ko調用此函數
  • ????printk("\n kset_test_init\n");
  • ????kobject_set_name(&kset_p.kobj,"kset_p");????//由于kset名字保存在內嵌的kobject中
  • ????kset_p.uevent_ops=&uevent_ops;????????????//事件通知機制。
  • ????????kset_p.kobj.ktype=&my_kobj_type;????//為了規避oops的問題。
  • ????if(kset_register(&kset_p)){????????????????????//向系統注冊一個kset對象
  • ????????????printk("register kset p error\n");
  • ????????return -1;
  • ????}
  • ????kobject_set_name(&kset_c.kobj,"kset_c");
  • ????kset_c.kobj.kset=&kset_p;
  • ????????kset_c.kobj.ktype=&my_kobj_type;
  • ????if(kset_register(&kset_c)){
  • ????????????printk("register kset c error\n");
  • ????????return -1;
  • ????}
  • ????return 0;
  • }

  • static __exit void kset_test_exit(void)????{
  • ????printk("\nkset exit\n");
  • ????kset_unregister(&kset_p);
  • ????kset_unregister(&kset_c);
  • }

  • module_init(kset_test_init);
  • module_exit(kset_test_exit);
  • MODULE_AUTHOR("MANGO");
  • MODULE_LICENSE("Dual BSD/GPL");
  • 執行sudo?insmod?kset.ko:出現如下信息;


    在/sys文件夾,會生成kset_p文件夾,打開該文件夾后,出現kset_c文件夾。



    3、子系統(一個子系統其實就是對kset和一個信號量的封裝)


    點擊(此處)折疊或打開

  • struct subsystem{
  • struct kset kset;
  • struct rw_semaphore rwsem;
  • }
  • 子系統函數列表如下:

    void?subsystem_init(struct?kset?*);

    int??subsystem_register(struct?kset?*);

    void?subsystem_unregister(struct?kset?*);

    struct?kset?*subsys_get(struct?kset?*s);

    void?subsys_put(struct?kset?*s);

    4、屬性

    非默認屬性

    如果希望在kobject的sysfs目錄中添加新的屬性,只需要填寫一個attribute結構,并把它傳遞給下面的函數。

    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;//最大長度,如果沒有最大值設置為0

    void *private;

    ssize_t?(*read)(struct?kobject?*,?char?*,?loff_t,?size_t);

    ssize_t?(*write)(struct?kobject?*,?char?*,?loff_t,?size_t);

    int?(*mmap)(struct?kobject?*,?struct?bin_attribute?*attr,

    ????struct?vm_area_struct?*vma);

    };

    必須顯式的創建二進制屬性

    int??sysfs_create_bin_file(struct?kobject?*kobj,struct?bin_attribute?*attr);

    void?sysfs_remove_bin_file(struct?kobject?*kobj,struct?bin_attribute?*attr);

    符號鏈接

    sysfs具有常用的樹形結構,但是內核中各對象之間的關系遠比這復雜。這些樹并不能表示驅動程序及其管理的設備之間的關系,為了表示這種關系還需要其他的指針,那就是符號鏈接。

    int?sysfs_create_link(struct?kobject?*kobj,struct?kobject?*target,const?char?*name);

    void?sysfs_remove_link(struct?kobject?*,?const?char?*?name);


    5、熱插拔機制(從內核空間發送到用戶空間的通知)

    當一個設備動態加入系統時(比如插入一個U盤),設備驅動程序可以檢查到這種設備狀態的變化(加入或移除),然后通過某種機制使得在用戶空間找到該設備對應的驅動程序模塊并加載之。在linux系統上有兩種機制可以在設備狀態發生變化時,通知用戶空間去加載或者卸載該設備所對應的驅動程序模塊:一個是udev,另一個是/sbin/hotplug。在Linux早期階段只有唯一的/sbin/hotplug工具,隨著內核的發展,udev機制逐漸取代了/sbin/hotplug。很多ubuntu系統已經不提供/sbin/hotplug工具了。



    udev熱插拔機制:以守護進程的形式運行,通過偵聽內核發出來的?uevent?來管理?/dev目錄下的設備文件。不像之前的設備管理工具,udev?在用戶空間?(user?space)?運行,而不在內核空間?(kernel?space)?運行。(驗證:ps?aux?|?grep?udevd);當設備添加?/?刪除時,udev的守護進程偵聽來自內核的uevent,以此添加或者刪除?/dev下的設備文件,所以udev只為已經連接的設備產生設備文件,而不會在/dev下產生大量虛無的設備文件;通過?Linux?默認的規則文件,udev/dev/?里為所有的設備定義了內核設備名稱,比如/dev/sda、/dev/hda、/dev/fd等等。由于udev是在用戶空間(user?space)運行,Linux?用戶可以通過自定義的規則文件,靈活地產生標識性強的設備文件名,比如?/dev/boot_disk、/dev/root_disk、/dev/color_printer等等。


    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的1.the linux device model--kobject kset学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

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