http://blog.chinaunix.net/uid-20729583-id-1884552.html
設備類struct class
一個類是一個設備的高級視圖,它抽象出低級的實現細節。例如,驅動可以見到一個SCSI磁盤或者一個ATA磁盤,在類的級別,他們都是磁盤,類允許用戶空間基於它們作什么來使用設備,而不是它們如何被連接或者它們如何工作。
設備類表示一類設備,所有的class對象都屬於class_subsys子系統
struct class
{
const char *name;//類名稱
struct module *owner;//對應模塊
struct subsystem subsys;//對應的subsystem;
struct list_head children;//class_device鏈表
struct list_head interfaces;//class_interface鏈表
struct semaphore sem;//children和interfaces鏈表鎖
struct class_attribute *class_attrs;//類屬性
int (*uevent)(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); //釋放類的方法
}
一、struct list_head結構體
struct list_head {
struct list_head *next, *prev; //此處進行了結構體list_head的定義系統使用這個鏈表的形式進行系統文件資源的管理
};
二、semaphore 結構體
struct semaphore {
atomic_t count; // 右邊是atomic 的定義 typedef struct { volatile int counter; } atomic_t; (這里的volatile int 指的是counter變量可以被其他的程序更改,但是不能被你自己更改)此處使用了atomic_t類型
//是為了是引用計數不被自己更改,增強安全性,由於這個計數變量只能由其他程序更改,而其他程序只能是系統中的管理類設備的程序,所以增強了安全性
wait_queue_head_t wait; //即等待隊列頭,(在linux驅動中,可以通過等待隊列來實現阻塞進程的呼喚)右邊是wait_queue_head_t的定義 typedef struct __wait_queue_head wait_queue_head_t;
//下面是__wait_queue_head 的定義
/*
struct __wait_queue_head {
spinlock_t lock;
下面是spinlock_t的定義
/*
#include
19
20typedef struct {
21 raw_spinlock_t raw_lock;
22#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
23 unsigned int break_lock;
24#endif
25#ifdef CONFIG_DEBUG_SPINLOCK
26 unsigned int magic, owner_cpu;
27 void *owner;
28#endif
29#ifdef CONFIG_DEBUG_LOCK_ALLOC
30 struct lockdep_map dep_map;
31#endif
32} spinlock_t;
*/
struct list_head task_list;
};
*/
};
struct semaphore {
atomic_t count;
int sleepers;
wait_queue_head_t wait;
};
三、類屬性class_attribute
下面是結構體class_attribute的定義
struct class_attribute {
210 struct attribute attr;
/*
28struct attribute {
29 const char * name; //類屬性的名稱
30 struct module * owner; //類屬性所述模塊
31 mode_t mode; //保護位,如果是只讀,就要設置成 S_IRUGO,讀寫就是 S_IWUSR。
32};
*/
211 ssize_t (*show)(struct class *, char * buf); //具體實現在用戶空間/sys下面的讀操作
/*
*/
212 ssize_t (*store)(struct class *, const char * buf, size_t count); //存儲用戶通過buffer傳入的屬性值
213};
對於這個屬性結構體,可以使用函數來進行新屬性的添加
int device_create_file(struct device *,struct device_attribute *);
void device_remove_file(struct device *,struct device_attribute *);
四、用戶事件 uevent(struct class_device *dev,char **envp,int num_envp,char *buffer,int buffer_size);(即user event)
下面介紹一個與此十分相似的相關函數
static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,int num_envp, char *buffer, int buffer_size);
五、void (*release)(struct class_device *dev)
六、class_release
static void class_release(struct kobject * kobj)
51{
52 struct class *class = to_class(kobj);//此處的to_class()為一個宏定義,這個宏定義用來指向設備類,定義如右:#define to_class(obj) container_of(obj, struct class, subsys.kobj)
53
54 pr_debug("class '%s': release.\n", class->name);
55
56 if (class->class_release)
57 class->class_release(class);
58 else
59 pr_debug("class '%s' does not have a release() function, " "be careful\n", class->name); // 這是一個宏定義:#define pr_debug(fmt,arg...) printk(KERN_DEBUG fmt,##arg)
/*上面的這個宏是一個可變參數宏,詳細的解釋如下:
在 GNU C 中,宏可以接受可變數目的參數,就象函數一樣,例如:
include/linux/kernel.h
110: #define pr_debug(fmt,arg...) \
111: printk(KERN_DEBUG fmt,##arg)
這里 arg 表示其余的參數,可以是零個或多個,這些參數以及參數之間的逗號構
成 arg 的值,在宏擴展時替換 arg,例如:
pr_debug("%s:%d",filename,line)
擴展為
printk("<7>" "%s:%d", filename, line)
使用 ## 的原因是處理 arg 不匹配任何參數的情況,這時 arg 的值為空,GNU
C 預處理器在這種特殊情況下,丟棄 ## 之前的逗號,這樣
pr_debug("success!\n")
擴展為
printk("<7>" "success!\n")
注意最后沒有逗號。
*/
60}
下面是注冊和注銷class的兩個函數:
int class_register(struct class *cls);
void class_unregister(struct class *cls);
int class_register(struct class * cls)
138{
139 int error;
140
141 pr_debug("device class '%s': registering\n", cls->name);
142
143 INIT_LIST_HEAD(&cls->children);//這個函數用來初始化class_device鏈表
/*內聯函數INIT_LIST_HEAD的定義
static inline void INIT_LIST_HEAD(struct list_head *list)
31{
32 list->next = list;
33 list->prev = list;
34}
*/
144 INIT_LIST_HEAD(&cls->devices); //功能同上
145 INIT_LIST_HEAD(&cls->interfaces); //功能同上
146 kset_init(&cls->class_dirs);
147 init_MUTEX(&cls->sem); //初始化信號量
148 error = kobject_set_name(&cls->subsys.kobj, "%s", cls->name); //設置相應的kobject對象的名稱
149 if (error)
150 return error;
151
152 subsys_set_kset(cls, class_subsys); //設置相應的subsystem中的kset對象
153
154 error = subsystem_register(&cls->subsys); //注冊subsystem
155 if (!error) {
156 error = add_class_attrs(class_get(cls)); //添加類屬性
157 class_put(cls); //減少類的計數
158 }
159 return error;
160}
161
162void class_unregister(struct class * cls)
163{
164 pr_debug("device class '%s': unregistering\n", cls->name);
165 remove_class_attrs(cls); //進行類屬性移除操作
166 subsystem_unregister(&cls->subsys); //從所掛載的subsystem中移除
167}
168
二、class_device結構體
一個class可以看成是一個容器,容器總包含了很多的class_device,這些class_device是由class這個大的容器來管理的,而每個class_device都對應着一個具體的設備。
一個類的真正目的是作為一個是該類成員的設備的容器. 一個成員由 struct class_device 來表示:
每個class對象包括一個class_device鏈表,每個class_device對象表示一個邏輯設備並通過struct class_device中的dev成員(一個指向struct device的指針)關聯一個物理設備。一個邏輯設備總是對應一個物理設備,而一個物理設備卻可以對應多個邏輯設備。
struct class_device
{
struct list_head node;
struct kobject kobj;//內嵌的kobject;
struct class *class;//所屬的類;
dev_t devt;//dev_t設備號
struct class_device_attribute *devt_attr;
struct class_device_attribute uevent_attr;
struct device *dev;//如果存在,創建到/sys/devices相應入口的符號鏈接
void *class_data;//私有數據
struct class_device *parent;//父設備
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_IO_SIZE]; // u32 class_id;類標志
}
class_id 成員持有設備名子, 如同它在 sysfs 中的一樣. class 指針應當指向持有這個設備的類, 並且 dev 應當指向關聯的設備結構. 設置 dev 是可選的; 如果它是非 NULL, 它用來創建一個符號連接從類入口到對應的在 /sys/devices 下的入口, 使得易於在用戶空間找到設備入口. 類可以使用 class_data 來持有一個私有指針.
一、class_device_attribute
這個結構體為類設備屬性,定義如下:
struct class_device_attribute
{
struct attribute attr;
ssize_t (*show)(struct class_device *,char *buf);//對相應的類設備進行讀。
ssize_t (*store)(struct class_device *,const char *buf, size)t count);//對相應的類設備進行寫操作
}
注冊和注銷class_device
int class_device_register(struct class_device *class_dev); //注冊
void class_device_unregister(struct class_device *class_dev); //注銷
675int class_device_register(struct class_device *class_dev)
676{
677 class_device_initialize(class_dev); //初始化類的對應的類設備
678 return class_device_add(class_dev); //返回class_device_add(class_dev);
679}
下面是class_device_register中兩個函數的具體實現代碼:
567int class_device_add(struct class_device *class_dev) //該函數用於進行設備的添加
568{
569 struct class *parent_class = NULL; //初始化父指針為空,
570 struct class_device *parent_class_dev = NULL; //初始化設備類父指針為空,實現功能和上面的函數想類似
571 struct class_interface *class_intf;
572 int error = -EINVAL;//初始化error為-EINVAL(對應數值22)
573
574 class_dev = class_device_get(class_dev); //此函數是class_device對象的計數加1,返回class_device對象的指針
575 if (!class_dev)
576 return -EINVAL;
577
578 if (!strlen(class_dev->class_id))
579 goto out1;
580
581 parent_class = class_get(class_dev->class);
582 if (!parent_class)
583 goto out1;
584
585 parent_class_dev = class_device_get(class_dev->parent);
586
587 pr_debug("CLASS: registering class device: ID = '%s'\n",
588 class_dev->class_id);
589
590 /* first, register with generic layer. */
591 error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
592 if (error)
593 goto out2;
594
595 if (parent_class_dev)
596 class_dev->kobj.parent = &parent_class_dev->kobj;
597 else
598 class_dev->kobj.parent = &parent_class->subsys.kobj;
599
600 error = kobject_add(&class_dev->kobj);
601 if (error)
602 goto out2;
603
604 /* add the needed attributes to this device */
605 error = sysfs_create_link(&class_dev->kobj,
606 &parent_class->subsys.kobj, "subsystem");
607 if (error)
608 goto out3;
609
610 error = class_device_create_file(class_dev, &class_uevent_attr);
611 if (error)
612 goto out3;
613
614 if (MAJOR(class_dev->devt)) {
615 error = class_device_create_file(class_dev, &class_devt_attr);
616 if (error)
617 goto out4;
618 }
619
620 error = class_device_add_attrs(class_dev);
621 if (error)
622 goto out5;
623
624 if (class_dev->dev) {
625 error = sysfs_create_link(&class_dev->kobj,
626 &class_dev->dev->kobj, "device");
627 if (error)
628 goto out6;
629 }
630
631 error = class_device_add_groups(class_dev);
632 if (error)
633 goto out7;
634
635 error = make_deprecated_class_device_links(class_dev);
636 if (error)
637 goto out8;
638
639 kobject_uevent(&class_dev->kobj, KOBJ_ADD);
640
641 /* notify any interfaces this device is now here */
642 down(&parent_class->sem);
643 list_add_tail(&class_dev->node, &parent_class->children);
644 list_for_each_entry(class_intf, &parent_class->interfaces, node) {
645 if (class_intf->add)
646 class_intf->add(class_dev, class_intf);
647 }
648 up(&parent_class->sem);
649
650 goto out1;
651
652 out8:
653 class_device_remove_groups(class_dev);
654 out7:
655 if (class_dev->dev)
656 sysfs_remove_link(&class_dev->kobj, "device");
657 out6:
658 class_device_remove_attrs(class_dev);
659 out5:
660 if (MAJOR(class_dev->devt))
661 class_device_remove_file(class_dev, &class_devt_attr);
662 out4:
663 class_device_remove_file(class_dev, &class_uevent_attr);
664 out3:
665 kobject_del(&class_dev->kobj);
666 out2:
667 if(parent_class_dev)
668 class_device_put(parent_class_dev);
669 class_put(parent_class);
670 out1:
671 class_device_put(class_dev);
672 return error;
673}
上面的這個函數比較容易理解,這里就不再一一的給出每個代碼的解釋了。
674
下面這個函數為初始化class_device.
void class_device_initialize(struct class_device *class_dev)
561{
562 kobj_set_kset_s(class_dev, class_obj_subsys);
563 kobject_init(&class_dev->kobj);//對於這個函數,一般情況下,在進行設備對象的初始化時都會設計到這個函數的調用,每一個設備對象都對應kobject這樣的一個對象,這個對象的作用很重要,主要是用於對設備模型的結構化的描述。
564 INIT_LIST_HEAD(&class_dev->node);
565}
三、類接口 class_interface
struct class_interface
{
struct list_head node; //
struct class *class; //相應的class
int (*add)(struct class_device *,struct class_interface *); //設備加入時觸發
void (*remove)(struct class_device *,struct class_interface *);//設備移出時觸發
}
與class和class_device相似,class_interface也存在兩個函數用於注冊和注銷class_interface
int class_interface_register(struct class_interface *class_intf);
void class_interface_unregister(struct class_interface *class_intf);
如果想對上面的兩個函數進行徹底的了解,請參閱http://lxr.linux.no/#linux/init/do_mounts_rd.c#L17