mdev_筆記

參考文章:http://www.cnblogs.com/hnrainll/archive/2011/06/10/2077435.html

mdev是busybox自帶的一個簡化版udev,作用是在系統啓動與熱插拔或動態加載驅動時候,自動產生節點文件。

 

執行mdev -s命令,mdev掃描/sys/block和sys/class兩個目錄下的dev屬性文件,獲取設備編號,並以包含該dev屬性文件的目錄名稱作爲設備名device_name,在dev目錄下創建相應的設備文件。

例如:cat /sys/class/tty/tty0/dev會得到4:0, subsystem爲tty,device_name爲tty0。

 

當mdev因爲熱插拔(uevent/hotplug)事件被調用,通過uevent時間傳遞的環境變量獲取引起該事件的設備action以及該設備路徑device path。然後判斷該action是什麼:

如果action是add,即有新設備加入系統,mdev通過device path的dev屬性文件獲取設備編號,以device path最後一個目錄作爲設備名,在dev目錄下創建設備文件。

如果action是remove,則設備已從系統移除,刪除對應設備文件。

 

由上可知:當設備加入或移除,mdev創建/刪除設備文件,必須做到以下三點:

1、在/sys/class的某個subsystem目錄下

2、創建以設備名device name作爲名稱的目錄

3、該目錄下包含dev屬性文件,該文件以"major:minor\n"形式輸出設備編號

 

 

linux設備驅動模型兩個重要的數據結構 class 和 class_device。(linux 2.6.24.7)

1、class

class代表一類設備,所有class都屬於class_subsys,即出現在/sys/class目錄下,出了塊設備可能出現在/sys/block或/sys/class/block。

 

/* class結構體 */ structclass{ 

  constchar * name; /* class的名稱 */ 

  struct module * owner; /* 擁有該class的模塊 */ 

  struct kset subsys; /* 該class對應的子系統 */ 

  struct list_head children; /* 該class的class_device列表 */ 

  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;/* 該class的默認屬性,以NULL結尾 */ 

  struct class_device_attribute * class_dev_attrs;/* 添加到class的class_device所擁有的默認屬性 */ 

  struct device_attribute * dev_attrs; 

  /* 該函數提供在產生熱插拔class_device事件時,添加環境變量的能力 */ 

  int (*uevent)(struct class_device *dev,struct kobj_uevent_env *env); 

  /* 該函數提供在產生熱插拔device(物理設備)事件時,添加環境變量的能力 */ 

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

  /* 添加到class的class_device移除時,調用該函數進行必要的清理工作 */ 

  void(*release)(struct class_device *dev); 

  /* class被移除時,調用該函數進行必要的清理工作 */ 

  void(*class_release)(structclass*class); 

  void(*dev_release)(struct device *dev); 

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

  int (*resume)(struct device *); 

  }; 

  /* class註冊函數 */ 

  int __must_check class_register(structclass*); 

  void class_unregister(structclass*); 建立一個class有兩種方法 

  a、根據需要,填充一個struct class,然後再調用class_register註冊該class就ok了(此法比較靈活,可以自己定製很多東西) 

  b、就是通過下面的class_create來創建一個class,該函數會返回一個指向剛建立的class的指針(創建class的最簡單方法) 

  /* class_create用於創建一個名爲name的class,其owner參數一般爲THIS_MODULE。class_create內部調用了class_register */ 

  structclass*class_create(struct module *owner,constchar*name); 

  /* class_destroy用於刪除一個class,實際上其內部只是簡單調用了class_unregister(cls)來註銷cls */ 

   void class_destroy(structclass*cls); 一個class屬性對應於/sys/class/class.name(class.name就是該class的名稱)目錄裏的一個文件。通過這些文件, 可以向用戶空間輸出一些關於該class的信息,也可從用戶空間獲取到一些信息。 

  /* class屬性結構體 */ 

  struct class_attribute { 

  struct attribute attr; 

  /* 當用戶空間讀取該屬性時,調用show函數輸出一個"屬性值"給用戶空間 */ 

  ssize_t (*show)(structclass*,char* buf); 

  /* 當用戶空間寫該屬性時,調用store函數保存用戶寫入的"屬性值" */ 

  ssize_t (*store)(structclass*,constchar* buf,size_tcount); 

  }; 

  struct attribute { 

  constchar * name; 

  struct module * owner; 

  mode_t mode; 

  }; 

  /* CLASS_ATTR可以在編譯時創建一個class屬性,該屬性的名稱爲class_attr_name */ 

  #define CLASS_ATTR(_name,_mode,_show,_store) \ 

  struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store) 

  /* class_create_file與class_remove_file用於創建與刪除class默認屬性外的屬性 */ 

  int __must_check class_create_file(structclass*, 

  conststruct class_attribute *); 

  void class_remove_file(structclass*,conststruct class_attribute *); 


2、class_device

 

class_device對應一個具體設備。

每個class對象包括一個class_device鏈表,每個class_device對象表示一個邏輯設備並通過struct class_device中的dev成員(一個指向struct_device的指針)關聯一個物理設備。

一個邏輯設備總是對應一個物理設備,而一個物理設備可以對應多個邏輯設備。

 

/* class_device結構體 */ struct class_device { 

  struct list_head node; /* 僅供驅動核心內部使用 */ 

  struct kobject kobj; /* 該class_device相應的kobject,僅供驅動核心內部使用 */ 

  structclass *class; /* 該class_device所屬的class,必須有 */ 

  dev_t devt; /* 該class_device的設備編號,用於創建其dev屬性文件,僅供驅動核心內部使用 */ 

   struct device * dev; /* 指向該class_device相關的device結構體(物理設備),可選.若不爲NULL,用於創建一個從class入口到/sys/devices 下相應入口的符號連接,以便用戶空間查找設備入口 */ 

  void * class_data; /* 該class_device的私有數據指針 */ 

  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,struct kobj_uevent_env *env); 

  char class_id[BUS_ID_SIZE]; /* 該class_device的名稱,在其所屬class中應是唯一的,不可重名 */ 

  }; 

  /* class_devic註冊函數 */ 

  int __must_check class_device_register(struct class_device *); 

  void class_device_unregister(struct class_device *); 與class一樣,建立一個class_device也有兩種方法 

  a、根據需要,填充一個struct class_device,然後再調用class_device_register註冊該class_device就ok了(此法比較靈活,可以自己定製很多東西) 

  b、就是通過下面的class_device_create來創建一個class_device,該函數會返回一個指向剛建立的class_device的指針(創建class_device的最簡單方法) 

  /* class_device_create用於創建一個class_device,其名稱最後兩個參數決定(類似於printf的格式化字符串) 

  * cls指明瞭其所屬的class,可以是自己填充的class或由class_create返回的class 

  * parent指明瞭該class_device的父class_device,若沒有,則爲NULL 

  * 該class_device的設備編號,用於創建其dev屬性文件,必須指明 

  * device指明瞭該class_device(邏輯設備)對應的device(物理設備),可有可無,無則爲NULL 

  * 實際上,class_device_create也就是填充一個class_device,然後調用了class_device_register註冊該class_device 

  */ 

  struct class_device *class_device_create(structclass*cls, 

  struct class_device *parent, 

  dev_t devt, 

  struct device *device, 

  constchar*fmt,...) 

  __attribute__((format(printf,5,6))); 

  /* class_destroy用於刪除一個class,內部調用了class_unregister(cls)來註銷cls */ 

   void class_device_destroy(structclass*cls, dev_t devt); class_device屬性對應於/sys/class/class.name/class_device.class_id目錄下一個文件。通過這些 文件,可以向用戶空間輸出一些關於該class_device的信息,也可從用戶空間獲取到一些信息。 

  /* class_device屬性,其show和store函數類似於class屬性的show和store函數 */ 

  struct class_device_attribute { 

  struct attribute attr; 

  ssize_t (*show)(struct class_device *,char* buf); 

  ssize_t (*store)(struct class_device *,constchar* buf,size_tcount); 

  }; 

  /* CLASS_DEVICE_ATTR可以在編譯時創建一個class_device屬性,該屬性的名稱爲class_device_attr_name */ 

  #define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) \ 

  struct class_device_attribute class_device_attr_##_name = \ 

  __ATTR(_name,_mode,_show,_store) 

  /* class_device_create_file與class_device_remove_file用於創建與刪除class_device默認屬性外的屬性 */ 

  int __must_check class_device_create_file(struct class_device *, 

  conststruct class_device_attribute *); 

  void class_device_remove_file(struct class_device * class_dev, 

  conststruct class_device_attribute * attr); 其實,在調用class_device_register註冊一個class_device時,該函數內部調用了 

  int class_device_add(struct class_device *class_dev) 

   在class_device_add內,通過class_device_create_file創建dev、uevent和該class_device 所擁有的默認屬性(由class_device.class->class_dev_attrs指定)等屬性文件。這樣第3點也有了。 

  dev屬性文件用於向用戶空間輸出該class_device的設備編號。 

  uevent屬性文件使用戶可以手動觸發uevent事件(通過向該文件寫,如add、remove等字符串)。 

  接下來是兩個基於mdev的驅動例子。 

  struct class_interface { 

  struct list_head node; 

  struct class *class; /* 該class_interface所屬的class */ 

  int (*add) (struct class_device *, struct class_interface *); /* class屬性 */ 

  void (*remove) (struct class_device *, struct class_interface *); /* class屬性 */ 

  int (*add_dev) (struct device *, struct class_interface *); 

  void (*remove_dev) (struct device *, struct class_interface *); 

  }; 

  /* class_interface註冊函數 */ 

  int __must_check class_interface_register(struct class_interface *); 

  void class_interface_unregister(struct class_interface *);

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章