乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      設(shè)備模型(總線、設(shè)備、驅(qū)動(dòng)程序和類)

       WUCANADA 2012-06-10


      Linux設(shè)備驅(qū)動(dòng)程序?qū)W習(xí)(13)

      -Linux設(shè)備模型(總線、設(shè)備、驅(qū)動(dòng)程序和類)


      文章的例子和實(shí)驗(yàn)使用《LDD3》所配的lddbus模塊(稍作修改)。

      提示:在學(xué)習(xí)這部分內(nèi)容是一定要分析所有介紹的源代碼,知道他們與上一部分內(nèi)容(kobject、kset、attribute等等)的關(guān)系,最好要分析一個(gè)實(shí)際的“flatform device”設(shè)備,不然會(huì)只學(xué)到表象,到后面會(huì)不知所云的。

      總線

      總線是處理器和一個(gè)或多個(gè)設(shè)備之間的通道,在設(shè)備模型中, 所有的設(shè)備都通過總線相連, 甚至是內(nèi)部的虛擬"platform"總線??偩€可以相互插入。設(shè)備模型展示了總線和它們所控制的設(shè)備之間的實(shí)際連接。
      在 Linux 設(shè)備模型中, 總線由 bus_type 結(jié)構(gòu)表示, 定義在 <linux/device.h>

      struct bus_type {
          const char        * name;/*總線類型名稱*/
          struct module        * owner;/*指向模塊的指針(如果有), 此模塊負(fù)責(zé)操作這個(gè)總線*/

          struct kset        subsys;/*與該總線相關(guān)的子系統(tǒng)*/
          struct kset        drivers;/*總線驅(qū)動(dòng)程序的kset*/
          struct kset        devices;/* 掛在該總線的所有設(shè)備的kset*/

          struct klist        klist_devices;/*與該總線相關(guān)的驅(qū)動(dòng)程序鏈表*/
          struct klist        klist_drivers;/*掛接在該總線的設(shè)備鏈表*/

          struct blocking_notifier_head bus_notifier;

          struct bus_attribute    * bus_attrs; /*總線屬性*/
          struct device_attribute * dev_attrs; /*設(shè)備屬性,指向?yàn)槊總€(gè)加入總線的設(shè)備建立的默認(rèn)屬性鏈表*/
          struct driver_attribute * drv_attrs; /*驅(qū)動(dòng)程序?qū)傩?/
          struct bus_attribute drivers_autoprobe_attr;/*驅(qū)動(dòng)自動(dòng)探測(cè)屬性*/
          struct bus_attribute drivers_probe_attr;/*驅(qū)動(dòng)探測(cè)屬性*/

          int        (*match)(struct device * dev, struct device_driver * drv);
          int        (*uevent)(struct device *dev, char **envp,
                       int num_envp, char *buffer, int buffer_size);
          int        (*probe)(struct device * dev);
          int        (*remove)(struct device * dev);
          void        (*shutdown)(struct device * dev);

          int (*suspend)(struct device * dev, pm_message_t state);
          int (*suspend_late)(struct device * dev, pm_message_t state);
          int (*resume_early)(struct device * dev);
          nt (*resume)(struct device * dev);
      /*處理熱插拔、電源管理、探測(cè)和移除等事件的方法*/
          unsigned int drivers_autoprobe:1;
      };


      在更新的內(nèi)核里,這個(gè)結(jié)構(gòu)體變得更簡(jiǎn)潔了,隱藏了無需驅(qū)動(dòng)編程人員知道的一些成員:

       

      /*in Linux 2.6.26.5*/

      struct bus_type {
          const char        *name;
          struct bus_attribute    *bus_attrs;
          struct device_attribute    *dev_attrs;
          struct driver_attribute    *drv_attrs;

          int (*match)(struct device *dev, struct device_driver *drv);
          int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
          int (*probe)(struct device *dev);
          int (*remove)(struct device *dev);
          void (*shutdown)(struct device *dev);

          int (*suspend)(struct device *dev, pm_message_t state);
          int (*suspend_late)(struct device *dev, pm_message_t state);
          int (*resume_early)(struct device *dev);
          int (*resume)(struct device *dev);

          struct bus_type_private *p;
      };

      struct bus_type_private {
          struct kset subsys;
          struct kset *drivers_kset;
          struct kset *devices_kset;
          struct klist klist_devices;
          struct klist klist_drivers;
          struct blocking_notifier_head bus_notifier;
          unsigned int drivers_autoprobe:1;
          struct bus_type *bus;
      };

      總線的注冊(cè)和刪除

      總線的主要注冊(cè)步驟:

      (1)申明和初始化 bus_type 結(jié)構(gòu)體。只有很少的 bus_type 成員需要初始化,大部分都由設(shè)備模型核心控制。但必須為總線指定名字及一些必要的方法。例如:

      struct bus_type ldd_bus_type = {
          .name = "ldd",
          .match = ldd_match,
          .uevent = ldd_uevent,
      };

      (2)調(diào)用bus_register函數(shù)注冊(cè)總線。

      int bus_register(struct bus_type * bus)

      調(diào)用可能失敗, 所以必須始終檢查返回值。若成功,新的總線子系統(tǒng)將被添加進(jìn)系統(tǒng),并可在 sysfs 的 /sys/bus 下看到。之后可以向總線添加設(shè)備。
      例如:

      ret = bus_register(&ldd_bus_type);
      if (ret)
       return ret;

       
      當(dāng)必須從系統(tǒng)中刪除一個(gè)總線時(shí), 調(diào)用:

      void bus_unregister(struct bus_type *bus);

      總線方法

      在 bus_type 結(jié)構(gòu)中定義了許多方法,它們?cè)试S總線核心作為設(shè)備核心和單獨(dú)的驅(qū)動(dòng)程序之間提供服務(wù)的中介,主要介紹以下兩個(gè)方法:

      int (*match)(struct device * dev, struct device_driver * drv);
      /*當(dāng)一個(gè)新設(shè)備或者驅(qū)動(dòng)被添加到這個(gè)總線時(shí),這個(gè)方法會(huì)被調(diào)用一次或多次,若指定的驅(qū)動(dòng)程序能夠處理指定的設(shè)備,則返回非零值。必須在總線層使用這個(gè)函數(shù), 因?yàn)槟抢锎嬖谡_的邏輯,核心內(nèi)核不知道如何為每個(gè)總線類型匹配設(shè)備和驅(qū)動(dòng)程序*/

      int (*uevent)(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
      /*在為用戶空間產(chǎn)生熱插拔事件之前,這個(gè)方法允許總線添加環(huán)境變量(參數(shù)和 kset 的uevent方法相同)*/

      lddbus的match和uevent方法:

      static int ldd_match(struct device *dev, struct device_driver *driver)
      {
       return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
      }/*僅簡(jiǎn)單比較驅(qū)動(dòng)和設(shè)備的名字*/
      /*當(dāng)涉及實(shí)際硬件時(shí), match 函數(shù)常常對(duì)設(shè)備提供的硬件 ID 和驅(qū)動(dòng)所支持的 ID 做比較*/

      static int ldd_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
      {
       envp[0] = buffer;
       if (snprintf(buffer, buffer_size, "LDDBUS_VERSION=%s",
       Version) >= buffer_size)
       return -ENOMEM;
       envp[1] = NULL;
       return 0;
      }/*在環(huán)境變量中加入 lddbus 源碼的當(dāng)前版本號(hào)*/

      對(duì)設(shè)備和驅(qū)動(dòng)的迭代

      若要編寫總線層代碼, 可能不得不對(duì)所有已經(jīng)注冊(cè)到總線的設(shè)備或驅(qū)動(dòng)進(jìn)行一些操作,這可能需要仔細(xì)研究嵌入到 bus_type 結(jié)構(gòu)中的其他數(shù)據(jù)結(jié)構(gòu), 但最好使用內(nèi)核提供的輔助函數(shù):

      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 *));

      /* 這兩個(gè)函數(shù)迭代總線上的每個(gè)設(shè)備或驅(qū)動(dòng)程序, 將關(guān)聯(lián)的 device 或 device_driver 傳遞給 fn, 同時(shí)傳遞 data 值。若 start 為 NULL, 則從第一個(gè)設(shè)備開始; 否則從 start 之后的第一個(gè)設(shè)備開始。若 fn 返回非零值, 迭代停止并且那個(gè)值從 bus_for_each_dev 或bus_for_each_drv 返回。*/

      總線屬性

      幾乎 Linux 設(shè)備模型中的每一層都提供添加屬性的函數(shù), 總線層也不例外。bus_attribute 類型定義在 <linux/device.h> 如下:

      struct bus_attribute {
          struct attribute    attr;
          ssize_t (*show)(struct bus_type *, char * buf);
          ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
      };


      可以看出struct bus_attribute 和struct attribute 很相似,其實(shí)大部分在 kobject 級(jí)上的設(shè)備模型層都是以這種方式工作。

      內(nèi)核提供了一個(gè)宏在編譯時(shí)創(chuàng)建和初始化 bus_attribute 結(jié)構(gòu):

      BUS_ATTR(_name,_mode,_show,_store)/*這個(gè)宏聲明一個(gè)結(jié)構(gòu), 將 bus_attr_ 作為給定 _name 的前綴來創(chuàng)建總線的真正名稱*/

      /*總線的屬性必須顯式調(diào)用 bus_create_file 來創(chuàng)建:*/
      int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);

      /*刪除總線的屬性調(diào)用:*/
      void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr);

      例如創(chuàng)建一個(gè)包含源碼版本號(hào)簡(jiǎn)單屬性文件方法如下:

      static ssize_t show_bus_version(struct bus_type *bus, char *buf)
      {
       return snprintf(buf, PAGE_SIZE, "%s\n", Version);
      }

      static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);

      /*在模塊加載時(shí)創(chuàng)建屬性文件:*/
      if (bus_create_file(&ldd_bus_type, &bus_attr_version))
       printk(KERN_NOTICE "Unable to create version attribute\n");

      /*這個(gè)調(diào)用創(chuàng)建一個(gè)包含 lddbus 代碼的版本號(hào)的屬性文件(/sys/bus/ldd/version)*/


      設(shè)備

      在最底層, Linux 系統(tǒng)中的每個(gè)設(shè)備由一個(gè) struct device 代表:

      struct device {
          struct klist        klist_children;
          struct klist_node    knode_parent;   /* node in sibling list */
          struct klist_node    knode_driver;
          struct klist_node    knode_bus;
          struct device        *parent;/* 設(shè)備的 "父" 設(shè)備,該設(shè)備所屬的設(shè)備,通常一個(gè)父設(shè)備是某種總線或者主控制器. 如果 parent 是 NULL, 則該設(shè)備是頂層設(shè)備,較少見 */

          struct kobject kobj;/*代表該設(shè)備并將其連接到結(jié)構(gòu)體系中的 kobject; 注意:作為通用的規(guī)則, device->kobj->parent 應(yīng)等于 device->parent->kobj*/
          char    bus_id[BUS_ID_SIZE];/*在總線上唯一標(biāo)識(shí)該設(shè)備的字符串;例如: PCI 設(shè)備使用標(biāo)準(zhǔn)的 PCI ID 格式, 包含:域, 總線, 設(shè)備, 和功能號(hào).*/
          struct device_type    *type;
          unsigned        is_registered:1;
          unsigned        uevent_suppress:1;
          struct device_attribute uevent_attr;
          struct device_attribute *devt_attr;

          struct semaphore    sem;  /* semaphore to synchronize calls to its driver. */
          struct bus_type    * bus;     /*標(biāo)識(shí)該設(shè)備連接在何種類型的總線上*/
          struct device_driver *driver;    /*管理該設(shè)備的驅(qū)動(dòng)程序*/
          void        *driver_data;    /*該設(shè)備驅(qū)動(dòng)使用的私有數(shù)據(jù)成員*/
          void        *platform_data;    /* Platform specific data, device core doesn't touch it */
          struct dev_pm_info    power;

      #ifdef CONFIG_NUMA
          int        numa_node;   /* NUMA node this device is close to */
      #endif
          u64        *dma_mask;    /* dma mask (if dma'able device) */
          u64        coherent_dma_mask;
      /* Like dma_mask, but for
                           alloc_coherent mappings as
                           not all hardware supports
                           64 bit addresses for consistent
                           allocations such descriptors. */


          struct list_head    dma_pools;    /* dma pools (if dma'ble) */

          struct dma_coherent_mem    *dma_mem; /* internal for coherent mem override */
          /* arch specific additions */
          struct dev_archdata    archdata;

          spinlock_t        devres_lock;
          struct list_head    devres_head;

          /* class_device migration path */
          struct list_head    node;
          struct class        *class;
          dev_t          devt;       /* dev_t, creates the sysfs "dev" */
          struct attribute_group    **groups;    /* optional groups */

          void    (*release)(struct device * dev);/*當(dāng)這個(gè)設(shè)備的最后引用被刪除時(shí),內(nèi)核調(diào)用該方法; 它從被嵌入的 kobject 的 release 方法中調(diào)用。所有注冊(cè)到核心的設(shè)備結(jié)構(gòu)必須有一個(gè) release 方法, 否則內(nèi)核將打印錯(cuò)誤信息*/
      };
      /*在注冊(cè) struct device 前,最少要設(shè)置parent, bus_id, bus, 和 release 成員*/

      設(shè)備注冊(cè)

      設(shè)備的注冊(cè)和注銷函數(shù)為:

      int device_register(struct device *dev);
      void device_unregister(struct device *dev);

      一個(gè)實(shí)際的總線也是一個(gè)設(shè)備,所以必須單獨(dú)注冊(cè),以下為 lddbus 在編譯時(shí)注冊(cè)它的虛擬總線設(shè)備源碼:

      static void ldd_bus_release(struct device *dev)
      {
       printk(KERN_DEBUG "lddbus release\n");
      }

      struct device ldd_bus = {
       .bus_id = "ldd0",
       .release = ldd_bus_release

      }; /*這是頂層總線,parent 和 bus 成員為 NULL*/

      /*作為第一個(gè)(并且唯一)總線, 它的名字為 ldd0,這個(gè)總線設(shè)備的注冊(cè)代碼如下:*/
      ret = device_register(&ldd_bus);
      if (ret)
       printk(KERN_NOTICE "Unable to register ldd0\n");
      /*一旦調(diào)用完成, 新總線會(huì)在 sysfs 中 /sys/devices 下顯示,任何掛到這個(gè)總線的設(shè)備會(huì)在 /sys/devices/ldd0 下顯示*/

      設(shè)備屬性

      sysfs 中的設(shè)備入口可有屬性,相關(guān)的結(jié)構(gòu)是:

      /* interface for exporting device attributes 這個(gè)結(jié)構(gòu)體和《LDD3》中的不同,已經(jīng)被更新過了,請(qǐng)?zhí)貏e注意!*/
      struct device_attribute {
          struct attribute attr;
          ssize_t (*show)(struct device *dev, struct device_attribute *attr,char *buf);
          ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
      };

      /*設(shè)備屬性結(jié)構(gòu)可在編譯時(shí)建立, 使用以下宏:*/
      DEVICE_ATTR(_name,_mode,_show,_store);
      /*這個(gè)宏聲明一個(gè)結(jié)構(gòu), 將 dev_attr_ 作為給定 _name 的前綴來命名設(shè)備屬性

      /*屬性文件的實(shí)際處理使用以下函數(shù):*/

       int device_create_file(struct device *device,    struct device_attribute * entry);
       void device_remove_file(struct device * dev, struct device_attribute * attr);

      設(shè)備結(jié)構(gòu)的嵌入

      device 結(jié)構(gòu)包含設(shè)備模型核心用來模擬系統(tǒng)的信息。但大部分子系統(tǒng)記錄了關(guān)于它們又擁有的設(shè)備的額外信息,所以很少單純用 device 結(jié)構(gòu)代表設(shè)備,而是,通常將其嵌入一個(gè)設(shè)備的高層表示中。底層驅(qū)動(dòng)幾乎不知道 struct device。

      lddbus 驅(qū)動(dòng)創(chuàng)建了它自己的 device 類型,并期望每個(gè)設(shè)備驅(qū)動(dòng)使用這個(gè)類型來注冊(cè)它們的設(shè)備:

      struct ldd_device {
       char *name;
       struct ldd_driver *driver;
       struct device dev;
      };
      #define to_ldd_device(dev) container_of(dev, struct ldd_device, dev);

      lddbus 導(dǎo)出的注冊(cè)和注銷接口如下:

      /*
       * LDD devices.
       */


      /*
       * For now, no references to LDDbus devices go out which are not
       * tracked via the module reference count, so we use a no-op
       * release function.
       */

      static void ldd_dev_release(struct device *dev)
      { }

      int register_ldd_device(struct ldd_device *ldddev)
      {
          ldddev->dev.bus = &ldd_bus_type;
          ldddev->dev.parent = &ldd_bus;
          ldddev->dev.release = ldd_dev_release;
          strncpy(ldddev->dev.bus_id, ldddev->name, BUS_ID_SIZE);
          return device_register(&ldddev->dev);
      }
      EXPORT_SYMBOL(register_ldd_device);

      void unregister_ldd_device(struct ldd_device *ldddev)
      {
          device_unregister(&ldddev->dev);
      }
      EXPORT_SYMBOL(unregister_ldd_device);


       sculld 驅(qū)動(dòng)添加一個(gè)自己的屬性到它的設(shè)備入口,稱為 dev, 僅包含關(guān)聯(lián)的設(shè)備號(hào),源碼如下:

      static ssize_t sculld_show_dev(struct device *ddev,struct device_attribute *attr, char *buf)
      {
       struct sculld_dev *dev = ddev->driver_data;
       return print_dev_t(buf, dev->cdev.dev);
      }

      static DEVICE_ATTR(dev, S_IRUGO, sculld_show_dev, NULL);

      /*接著, 在初始化時(shí)間, 設(shè)備被注冊(cè), 并且 dev 屬性通過下面的函數(shù)被創(chuàng)建:*/
      static void sculld_register_dev(struct sculld_dev *dev, int index)
      {
       sprintf(dev->devname, "sculld%d", index);
       dev->ldev.name = dev->devname;
       dev->ldev.driver = &sculld_driver;
       dev->ldev.dev.driver_data = dev;
       register_ldd_device(&dev->ldev);
       if (device_create_file(&dev->ldev.dev, &dev_attr_dev))
          printk( "Unable to create dev attribute ! \n");
      } /*注意:程序使用 driver_data 成員來存儲(chǔ)指向我們自己的內(nèi)部的設(shè)備結(jié)構(gòu)的指針。請(qǐng)檢查
      device_create_file的返回值,否則編譯時(shí)會(huì)有警告。*/


      設(shè)備驅(qū)動(dòng)程序

      設(shè)備模型跟蹤所有系統(tǒng)已知的驅(qū)動(dòng),主要目的是使驅(qū)動(dòng)程序核心能協(xié)調(diào)驅(qū)動(dòng)和新設(shè)備之間的關(guān)系。一旦驅(qū)動(dòng)在系統(tǒng)中是已知的對(duì)象就可能完成大量的工作。驅(qū)動(dòng)程序的結(jié)構(gòu)體 device_driver 定義如下:

      /*定義在<linux/device.h>*/
      struct device_driver {
          const char        * name;/*驅(qū)動(dòng)程序的名字( 在 sysfs 中出現(xiàn) )*/
          struct bus_type        * bus;/*驅(qū)動(dòng)程序所操作的總線類型*/

          struct kobject        kobj;/*內(nèi)嵌的kobject對(duì)象*/
          struct klist        klist_devices;/*當(dāng)前驅(qū)動(dòng)程序能操作的設(shè)備鏈表*/
          struct klist_node    knode_bus;

          struct module        * owner;
          const char         * mod_name;    /* used for built-in modules */
          struct module_kobject    * mkobj;

          int    (*probe)    (struct device * dev);/*查詢一個(gè)特定設(shè)備是否存在及驅(qū)動(dòng)是否可以使用它的函數(shù)*/
          int    (*remove)    (struct device * dev);/*將設(shè)備從系統(tǒng)中刪除*/
          void    (*shutdown)    (struct device * dev);/*關(guān)閉設(shè)備*/
          int    (*suspend)    (struct device * dev, pm_message_t state);
          int    (*resume)    (struct device * dev);
      };

      /*注冊(cè)device_driver 結(jié)構(gòu)的函數(shù)是:*/
      int driver_register(struct device_driver *drv);
      void driver_unregister(struct device_driver *drv);

      /*driver的屬性結(jié)構(gòu)在:*/
      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);
      };
      DRIVER_ATTR(_name,_mode,_show,_store)

      /*屬性文件創(chuàng)建的方法:*/
      int driver_create_file(struct device_driver * drv, struct driver_attribute * attr);
      void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr);

      /*bus_type 結(jié)構(gòu)含有一個(gè)成員( drv_attrs ) 指向一組為屬于該總線的所有設(shè)備創(chuàng)建的默認(rèn)屬性*/


      在更新的內(nèi)核里,這個(gè)結(jié)構(gòu)體變得更簡(jiǎn)潔了,隱藏了無需驅(qū)動(dòng)編程人員知道的一些成員:

      /*in Linux 2.6.26.5*/

      struct device_driver {
          const char        *name;
          struct bus_type        *bus;

          struct module        *owner;
          const char         *mod_name;    /* used for built-in modules */

          int (*probe) (struct device *dev);
          int (*remove) (struct device *dev);
          void (*shutdown) (struct device *dev);
          int (*suspend) (struct device *dev, pm_message_t state);
          int (*resume) (struct device *dev);
          struct attribute_group **groups;

          struct driver_private *p;
      };


      struct driver_private {
          struct kobject kobj;
          struct klist klist_devices;
          struct klist_node knode_bus;
          struct module_kobject *mkobj;
          struct device_driver *driver;
      };
      #define to_driver(obj) container_of(obj, struct driver_private, kobj)


      驅(qū)動(dòng)程序結(jié)構(gòu)的嵌入

      對(duì)大多數(shù)驅(qū)動(dòng)程序核心結(jié)構(gòu), device_driver 結(jié)構(gòu)通常被嵌入到一個(gè)更高層的、總線相關(guān)的結(jié)構(gòu)中。

      以lddbus 子系統(tǒng)為例,它定義了ldd_driver 結(jié)構(gòu):

      struct ldd_driver {
       char *version;
       struct module *module;
       struct device_driver driver;
       struct driver_attribute version_attr;
      };
      #define to_ldd_driver(drv) container_of(drv, struct ldd_driver, driver);

      lddbus總線中相關(guān)的驅(qū)動(dòng)注冊(cè)和注銷函數(shù)是:

      /*
       * Crude driver interface.
       */

      static ssize_t show_version(struct device_driver *driver, char *buf)
      {
          struct ldd_driver *ldriver = to_ldd_driver(driver);
          sprintf(buf, "%s\n", ldriver->version);
          return strlen(buf);
      }

      int register_ldd_driver(struct ldd_driver *driver)
      {
       int ret;
       driver->driver.bus = &ldd_bus_type;
       ret = driver_register(&driver->driver);/*注冊(cè)底層的 device_driver 結(jié)構(gòu)到核心*/
       if (ret)
       return ret;
       driver->version_attr.attr.name = "version";/* driver_attribute 結(jié)構(gòu)必須手工填充*/
       driver->version_attr.attr.owner = driver->module;/* 注意:設(shè)定 version 屬性的擁有者為驅(qū)動(dòng)模塊, 不是 lddbus 模塊!因?yàn)?show_version 函數(shù)是使用驅(qū)動(dòng)模塊所創(chuàng)建的 ldd_driver 結(jié)構(gòu),若 ldd_driver 結(jié)構(gòu)在一個(gè)用戶空間進(jìn)程試圖讀取版本號(hào)時(shí)已經(jīng)注銷,就會(huì)出錯(cuò)*/
       driver->version_attr.attr.mode = S_IRUGO;
       driver->version_attr.show = show_version;
       driver->version_attr.store = NULL;
       return driver_create_file(&driver->driver, &driver->version_attr);/*建立版本屬性,因?yàn)檫@個(gè)屬性在運(yùn)行時(shí)被創(chuàng)建,所以不能使用 DRIVER_ATTR 宏*/
      }

      void unregister_ldd_driver(struct ldd_driver *driver)
      {
          driver_unregister(&driver->driver);
      }
      EXPORT_SYMBOL(register_ldd_driver);
      EXPORT_SYMBOL(unregister_ldd_driver);

      在sculld 中創(chuàng)建的 ldd_driver 結(jié)構(gòu)如下:

      /* Device model stuff */
      static struct ldd_driver sculld_driver = {
          .version = "$Revision: 1.21 $",
          .module = THIS_MODULE,
          .driver = {
              .name = "sculld",
          },
      };/*只要一個(gè)簡(jiǎn)單的 register_ldd_driver 調(diào)用就可添加它到系統(tǒng)中。一旦完成初始化, 驅(qū)動(dòng)信息可在 sysfs 中顯示*/


      類 子系統(tǒng)

      類是一個(gè)設(shè)備的高層視圖, 它抽象出了底層的實(shí)現(xiàn)細(xì)節(jié),從而允許用戶空間使用設(shè)備所提供的功能, 而不用關(guān)心設(shè)備是如何連接和工作的。類成員通常由上層代碼所控制, 而無需驅(qū)動(dòng)的明確支持。但有些情況下驅(qū)動(dòng)也需要直接處理類。

      幾乎所有的類都顯示在 /sys/class 目錄中。出于歷史的原因,有一個(gè)例外:塊設(shè)備顯示在 /sys/block目錄中。在許多情況, 類子系統(tǒng)是向用戶空間導(dǎo)出信息的最好方法。當(dāng)類子系統(tǒng)創(chuàng)建一個(gè)類時(shí), 它將完全擁有這個(gè)類,根本不用擔(dān)心哪個(gè)模塊擁有那些屬性,而且信息的表示也比較友好。

      為了管理類,驅(qū)動(dòng)程序核心導(dǎo)出了一些接口,其目的之一是提供包含設(shè)備號(hào)的屬性以便自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn),所以u(píng)dev的使用離不開類。 類函數(shù)和結(jié)構(gòu)與設(shè)備模型的其他部分遵循相同的模式,所以真正嶄新的概念是很少的。

      注意:class_simple 是老接口,在2.6.13中已被刪除,這里不再研究。

      管理類的接口

      類由 struct class 的結(jié)構(gòu)體來定義:

      /*
       * device classes
       */

      struct class {
          const char        * name;/*每個(gè)類需要一個(gè)唯一的名字, 它將顯示在 /sys/class 中*/
          struct module        * owner;

          struct kset        subsys;
          struct list_head    children;
          struct list_head    devices;
          struct list_head    interfaces;
          struct kset        class_dirs;
          struct semaphore    sem;    /* locks both the children and interfaces lists */

          struct class_attribute        * class_attrs;/* 指向類屬性的指針(以NULL結(jié)尾) */
          struct class_device_attribute    * class_dev_attrs;/* 指向類中每個(gè)設(shè)備的一組默認(rèn)屬性的指針 */
          struct device_attribute        * dev_attrs;

          int    (*uevent)(struct class_device *dev, char **envp,
                   int num_envp, char *buffer, int buffer_size);/* 類熱插拔產(chǎn)生時(shí)添加環(huán)境變量的函數(shù) */
          int    (*dev_uevent)(struct device *dev, char **envp, int num_envp,
                      char *buffer, int buffer_size);/* 類中的設(shè)備熱插拔時(shí)添加環(huán)境變量的函數(shù) */

          void    (*release)(struct class_device *dev);/* 把設(shè)備從類中刪除的函數(shù) */
          void    (*class_release)(struct class *class);/* 刪除類本身的函數(shù) */
          void    (*dev_release)(struct device *dev);

          int    (*suspend)(struct device *, pm_message_t state);
          int    (*resume)(struct device *);
      };


      /*類注冊(cè)函數(shù):*/
      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_t (*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);


      在更新的內(nèi)核里,這個(gè)結(jié)構(gòu)體變得簡(jiǎn)潔了,刪除了一些成員:

      /*in Linux 2.6.26.5*/

      /*
       * device classes
       */

      struct class {
          const char        *name;
          struct module        *owner;

          struct kset        subsys;
          struct list_head    devices;
          struct list_head    interfaces;
          struct kset        class_dirs;
          struct semaphore    sem; /* locks children, devices, interfaces */
          struct class_attribute        *class_attrs;
          struct device_attribute        *dev_attrs;

          int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);

          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);
      };

      類設(shè)備(在新內(nèi)核中已被刪除)

      類存在的真正目的是給作為類成員的各個(gè)設(shè)備提供一個(gè)容器,成員由 struct class_device 來表示:

      struct class_device {
          
      struct list_head    node;/*for internal use by the driver core only*/
          
      struct kobject        kobj;/*for internal use by the driver core only*/
          
      struct class        * class;    /* 指向該設(shè)備所屬的類,必須*/
          dev_t            devt
      ;        /* dev_t, creates the sysfs "dev" ,for internal use by the driver core only*/
          
      struct class_device_attribute *devt_attr;/*for internal use by the driver core only*/
          
      struct class_device_attribute uevent_attr;
          
      struct device        * dev;        /* 指向此設(shè)備相關(guān)的 device 結(jié)構(gòu)體,可選。若不為NULL,應(yīng)是一個(gè)從類入口到/sys/devices 下相應(yīng)入口的符號(hào)連接,以便用戶空間查找設(shè)備入口*/
          
      void            * class_data;    /* 私有數(shù)據(jù)指針 */
          
      struct class_device    *parent;    /* parent of this child device, if there is one */
          
      struct attribute_group ** groups;    /* optional groups */

          
      void    (*release)(struct class_device *dev);
          
      int    (*uevent)(struct class_device *dev, char **envp,
                  
      int num_envp, char *buffer, int buffer_size);
          
      char    class_id[BUS_ID_SIZE];    /* 此類中的唯一的名字 */
      };

      /*類設(shè)備注冊(cè)函數(shù):*/
      int class_device_register(struct class_device *cd);
      void class_device_unregister(struct class_device *cd);

      /*重命名一個(gè)已經(jīng)注冊(cè)的類設(shè)備入口:*/
      int class_device_rename(struct class_device *cd, char *new_name);

      /*類設(shè)備入口屬性:*/
      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);

      /*創(chuàng)建和刪除除struct class中設(shè)備默認(rèn)屬性外的屬性*/
      int class_device_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);

      類接口

      類子系統(tǒng)有一個(gè) Linux 設(shè)備模型的其他部分找不到的附加概念,稱為“接口”, 可將它理解為一種設(shè)備加入或離開類時(shí)獲得信息的觸發(fā)機(jī)制,結(jié)構(gòu)體如下:

      struct class_interface {
          struct list_head    node;
          struct class        *class;/* 指向該接口所屬的類*/

          int (*add) (struct class_device *, struct class_interface *);

      /*當(dāng)一個(gè)類設(shè)備被加入到在 class_interface 結(jié)構(gòu)中指定的類時(shí), 將調(diào)用接口的 add 函數(shù),進(jìn)行一些設(shè)備需要的額外設(shè)置,通常是添加更多屬性或其他的一些工作*/
          void (*remove)    (struct class_device *, struct class_interface *);/*一個(gè)接口的功能是簡(jiǎn)單明了的. 當(dāng)設(shè)備從類中刪除, 將調(diào)用remove 方法來進(jìn)行必要的清理*/
          int (*add_dev)     (struct device *, struct class_interface *);
          void (*remove_dev) (struct device *, struct class_interface *);
      };

      /*注冊(cè)或注銷接口的函數(shù):*/
      int class_interface_register(struct class_interface *class_intf);
      void class_interface_unregister(struct class_interface *class_intf);
      /*一個(gè)類可注冊(cè)多個(gè)接口*/


        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多