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

歡迎訪問 生活随笔!

生活随笔

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

linux

linux设备模型之Class

發布時間:2025/3/21 linux 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux设备模型之Class 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? 參考:http://www.wowotech.net/device_model/class.html

? ? 剛開始寫字符設備驅動程序的時候,老師教我們自動創建設備節點,“要先創建類,在類下面創建設備,類名字不重要“。

? ? ? ? firstdrv_class = class_create(THIS_MODULE, "firstdrv");
? ? ? ? firstdrv_class_dev = device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */

? ? 于是乎,這兩行代碼被糊里糊涂的復制粘貼了好多次,差點成為一種習慣~ ? ? ? ?

? ? 前面分析設備總線驅動模型的時候,我們知道,將一個設備調用 device_add 函數注冊到內核中去的時候,如果指定了設備號,那么用戶空間的 mdev 會根據 sysfs 文件系統中的設備信息去自動創建設備節點。我們看到前面第二行代碼里有一個?device_create ,參數里還有設備號 ,八九不離十,里邊也間接調用了device_add ,不信一會分析代碼。

? ? 類是一個設備的高層視圖,它抽象出了低層的實現細節,大概意思就是抽象出了一個通用的接口吧。常見的類設備有 Input 、tty 、usb 、rtc?等等。

? ? class 就好比 bus ,我們在設備總線驅動模型中創建設備時,要指定它所屬的 Bus ,那么在創建類設備的時候也需要指定它所從屬的類,class 也離不開 Kobject ,因此如果你了解總線設備驅動模型,你就會發現,其實真的都是差不多的東西。

  • struct?class?{??
  • ????const?char??????*name;??
  • ????struct?module???????*owner;??
  • ????struct?class_attribute??????*class_attrs;??
  • ????struct?device_attribute?????*dev_attrs;??
  • ????struct?kobject??????????*dev_kobj;??
  • ????int?(*dev_uevent)(struct?device?*dev,?struct?kobj_uevent_env?*env);??
  • ????char?*(*devnode)(struct?device?*dev,?mode_t?*mode);??
  • ????void?(*class_release)(struct?class?*class);??
  • ????void?(*dev_release)(struct?device?*dev);??
  • ????int?(*suspend)(struct?device?*dev,?pm_message_t?state);??
  • ????int?(*resume)(struct?device?*dev);??
  • ????const?struct?dev_pm_ops?*pm;??
  • ????struct?class_private?*p;??
  • };??
  • ? ? name,class的名稱,會在“/sys/class/”目錄下體現。
    ? ??class_atrrs,該class的默認attribute,會在class注冊到內核時,自動在“/sys/class/xxx_class”下創建對應的attribute文件。
    ? ??dev_attrs,該class下每個設備的attribute,會在設備注冊到內核時,自動在該設備的sysfs目錄下創建對應的attribute文件。
    ? ??dev_bin_attrs,類似dev_attrs,只不過是二進制類型attribute。
    ? ??dev_kobj,表示該class下的設備在/sys/dev/下的目錄,現在一般有char和block兩個,如果dev_kobj為NULL,則默認選擇char。
    ? ??dev_uevent,當該class下有設備發生變化時,會調用class的uevent回調函數。
    ? ??class_release,用于release自身的回調函數。
    ? ??dev_release,用于release class內設備的回調函數。在device_release接口中,會依次檢查Device、Device Type以及Device所在的class,是否注冊release接口,如果有則調用相應的release接口release設備指針。

  • struct?class_private?{??
  • ????struct?kset?class_subsys;??
  • ????struct?klist?class_devices;??
  • ????struct?list_head?class_interfaces;??
  • ????struct?kset?class_dirs;??
  • ????struct?mutex?class_mutex;??
  • ????struct?class?*class;??
  • };??
  • ? ? struct class_interface是這樣的一個結構:它允許class driver在class下有設備添加或移除的時候,調用預先設置好的回調函數(add_dev和remove_dev)。那調用它們做什么呢?想做什么都行(例如修改設備的名稱),由具體的class driver實現。
    ? ? 該結構的定義如下:
  • struct?class_interface?{??
  • ????struct?list_head????????node;??
  • ????struct?class????????????*class;??
  • ??
  • ????int?(*add_dev)??????????(struct?device?*,?struct?class_interface?*);??
  • ????void?(*remove_dev)??????(struct?device?*,?struct?class_interface?*);??
  • };??
  • ? ? 下面,我們來看 Class 的注冊過程,前面我們提到,class->name 會出現在/sys/class 目錄下,那么這個目錄是哪里來的,代碼一看便知。

  • int?__init?classes_init(void)??
  • {??
  • ????class_kset?=?kset_create_and_add("class",?NULL,?NULL);??
  • ????if?(!class_kset)??
  • ????????return?-ENOMEM;??
  • ????return?0;??
  • }??
  • ? ? 下面,我們來看一下一個Class 的注冊過程

  • #define?class_create(owner,?name)???????\??
  • ({??????????????????????\??
  • ????static?struct?lock_class_key?__key;?\??
  • ????__class_create(owner,?name,?&__key);????\??
  • })??
  • struct?class?*__class_create(struct?module?*owner,?const?char?*name,??
  • ?????????????????struct?lock_class_key?*key)??
  • {??
  • ????struct?class?*cls;??
  • ????int?retval;??
  • ??
  • ????cls?=?kzalloc(sizeof(*cls),?GFP_KERNEL);??
  • ????if?(!cls)?{??
  • ????????retval?=?-ENOMEM;??
  • ????????goto?error;??
  • ????}??
  • ??
  • ????cls->name?=?name;??
  • ????cls->owner?=?owner;??
  • ????cls->class_release?=?class_create_release;??
  • ??
  • ????retval?=?__class_register(cls,?key);??
  • ????if?(retval)??
  • ????????goto?error;??
  • ??
  • ????return?cls;??
  • ??
  • error:??
  • ????kfree(cls);??
  • ????return?ERR_PTR(retval);??
  • }??
  • ? ? 在 class_create 函數中,只是簡單構造了一個class結構體,設置了名字以及所屬的模塊,然后調用 class_register?

  • int?__class_register(struct?class?*cls,?struct?lock_class_key?*key)??
  • {??
  • ????struct?class_private?*cp;??
  • ????int?error;??
  • ??
  • ????pr_debug("device?class?'%s':?registering\n",?cls->name);??
  • ??
  • ????cp?=?kzalloc(sizeof(*cp),?GFP_KERNEL);??
  • ????if?(!cp)??
  • ????????return?-ENOMEM;??
  • ????klist_init(&cp->class_devices,?klist_class_dev_get,?klist_class_dev_put);??
  • ????INIT_LIST_HEAD(&cp->class_interfaces);??
  • ????kset_init(&cp->class_dirs);??
  • ????__mutex_init(&cp->class_mutex,?"struct?class?mutex",?key);??
  • ????error?=?kobject_set_name(&cp->class_subsys.kobj,?"%s",?cls->name);??
  • ????if?(error)?{??
  • ????????kfree(cp);??
  • ????????return?error;??
  • ????}??
  • ??
  • ????/*?set?the?default?/sys/dev?directory?for?devices?of?this?class?*/??
  • ????if?(!cls->dev_kobj)??
  • ????????cls->dev_kobj?=?sysfs_dev_char_kobj;??
  • ??
  • #if?defined(CONFIG_SYSFS_DEPRECATED)?&&?defined(CONFIG_BLOCK)??
  • ????/*?let?the?block?class?directory?show?up?in?the?root?of?sysfs?*/??
  • ????if?(cls?!=?&block_class)??
  • ????????cp->class_subsys.kobj.kset?=?class_kset;??
  • #else??
  • ????cp->class_subsys.kobj.kset?=?class_kset;??
  • #endif??
  • ????cp->class_subsys.kobj.ktype?=?&class_ktype;??
  • ????cp->class?=?cls;??
  • ????cls->p?=?cp;??
  • ??
  • ????error?=?kset_register(&cp->class_subsys);??
  • ????if?(error)?{??
  • ????????kfree(cp);??
  • ????????return?error;??
  • ????}??
  • ????error?=?add_class_attrs(class_get(cls));??
  • ????class_put(cls);??
  • ????return?error;??
  • }??
  • ? ? 代碼第15行,將 cp->class_subsys.kobj 的 name 設置為cls->name

    ? ? 代碼第28行,將cp->class_subsys.kobj.kest 設置為class_kest

    ? ? 代碼第36行,將cp->class_subsys 注冊進內核,沒有設置 cp->class_subsys.kobj.parent ,內核會將cp->class_subsys.kobj.kset.kobj 設置成它的Parent ,這也就是為什么說 class->name ?會出現在 /sys/class 目錄下的原因。


    ? ? 下面,來看向 class 注冊 device 的過程

  • struct?device?*device_create(struct?class?*class,?struct?device?*parent,??
  • ?????????????????dev_t?devt,?void?*drvdata,?const?char?*fmt,?...)??
  • {??
  • ????va_list?vargs;??
  • ????struct?device?*dev;??
  • ??
  • ????va_start(vargs,?fmt);??
  • ????dev?=?device_create_vargs(class,?parent,?devt,?drvdata,?fmt,?vargs);??
  • ????va_end(vargs);??
  • ????return?dev;??
  • }??
  • struct?device?*device_create_vargs(struct?class?*class,?struct?device?*parent,??
  • ???????????????????dev_t?devt,?void?*drvdata,?const?char?*fmt,??
  • ???????????????????va_list?args)??
  • {??
  • ????struct?device?*dev?=?NULL;??
  • ????int?retval?=?-ENODEV;??
  • ??
  • ????if?(class?==?NULL?||?IS_ERR(class))??
  • ????????goto?error;??
  • ??
  • ????dev?=?kzalloc(sizeof(*dev),?GFP_KERNEL);??
  • ????if?(!dev)?{??
  • ????????retval?=?-ENOMEM;??
  • ????????goto?error;??
  • ????}??
  • ??
  • ????dev->devt?=?devt;??
  • ????dev->class?=?class;??
  • ????dev->parent?=?parent;??
  • ????dev->release?=?device_create_release;??
  • ????dev_set_drvdata(dev,?drvdata);??
  • ??
  • ????retval?=?kobject_set_name_vargs(&dev->kobj,?fmt,?args);??
  • ????if?(retval)??
  • ????????goto?error;??
  • ??
  • ????retval?=?device_register(dev);??
  • ????if?(retval)??
  • ????????goto?error;??
  • ??
  • ????return?dev;??
  • ??
  • error:??
  • ????put_device(dev);??
  • ????return?ERR_PTR(retval);??
  • }??
  • ? ? 上邊代碼也沒有什么好分析的,與我們分析設備總線驅動模型時分析 device 時有一點不一樣的就是這里設置的是 dev->class 而不是 dev->bus ,同時這里為 dev設置了設備號 devt ,因此,在sysfs中會創建 dev 屬性文件,mdev 就會自動為我們創建設備節點了。

  • int?device_register(struct?device?*dev)??
  • {??
  • ????device_initialize(dev);??
  • ????return?device_add(dev);??
  • }??
  • int?device_add(struct?device?*dev)??
  • {??
  • ????struct?device?*parent?=?NULL;??
  • ????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;??
  • ????}??
  • ??
  • ????if?(!dev_name(dev))??
  • ????????goto?name_error;??
  • ??
  • ????pr_debug("device:?'%s':?%s\n",?dev_name(dev),?__func__);??
  • ??
  • ????parent?=?get_device(dev->parent);??
  • ????setup_parent(dev,?parent);??
  • ??
  • ????/*?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,?&uevent_attr);??
  • ????if?(error)??
  • ????????goto?attrError;??
  • ??
  • ????if?(MAJOR(dev->devt))?{??
  • ????????error?=?device_create_file(dev,?&devt_attr);??
  • ????????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_sysf_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->class_mutex);??
  • ????????/*?tie?the?class?to?the?device?*/??
  • ????????klist_add_tail(&dev->knode_class,??
  • ???????????????????&dev->class->p->class_devices);??
  • ??
  • ????????/*?notify?any?interfaces?that?the?device?is?here?*/??
  • ????????list_for_each_entry(class_intf,??
  • ????????????????????&dev->class->p->class_interfaces,?node)??
  • ????????????if?(class_intf->add_dev)??
  • ????????????????class_intf->add_dev(dev,?class_intf);??
  • ????????mutex_unlock(&dev->class->p->class_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))??
  • ????????device_remove_sys_dev_entry(dev);??
  • ?devtattrError:??
  • ????if?(MAJOR(dev->devt))??
  • ????????device_remove_file(dev,?&devt_attr);??
  • ?ueventattrError:??
  • ????device_remove_file(dev,?&uevent_attr);??
  • ?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;??
  • }??
  • ? ? 代碼第41行,將 dev->kobj 注冊進內核,會在/sys/devices 目錄下創建目錄。

    ? ? 代碼第53-63行,是創建屬性文件dev 的過程,也就是這一步,讓mdev能夠自動為我們創建設備節點。

    ? ? 代碼第65行,創建 /sys/class 到 /sys/device/xx/dev->name的符號鏈接,這個跟設備總線驅動模型中創建/sys/bus 到?/sys/device/xx/dev->name的符號鏈接是一樣一樣的。

    ? ? 代碼第92-103行,將 dev 加入 class的設備鏈表,并調用?class_interfaces 鏈表中的每一個?class_intf 結構,調用里面的?add_dev 函數。

    ? ? 分析到這,class 好像并沒有干什么實質性的事情。后面到input、tty、rtc在具體分析吧。

    總結

    以上是生活随笔為你收集整理的linux设备模型之Class的全部內容,希望文章能夠幫你解決所遇到的問題。

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