1 /* Class Device Stuff */
2
3 int class_device_create_file(struct class_device * class_dev,
4 const struct class_device_attribute * attr)
5 {
6 int error = -EINVAL;
7
8 /* [cgw]: class_dev指針不為空 */
9 if (class_dev)
10 /* [cgw]: 為class_dev->kobj對象創建一個屬性文件 */
11 error = sysfs_create_file(&class_dev->kobj, &attr->attr);
12 return error;
13 }
14
15 void class_device_remove_file(struct class_device * class_dev,
16 const struct class_device_attribute * attr)
17 {
18 /* [cgw]: class_dev指針不為空 */
19 if (class_dev)
20 /* [cgw]: 刪除class_dev->kobj對象對應的一個屬性文件 */
21 sysfs_remove_file(&class_dev->kobj, &attr->attr);
22 }
23
24 int class_device_create_bin_file(struct class_device *class_dev,
25 struct bin_attribute *attr)
26 {
27 int error = -EINVAL;
28
29 /* [cgw]: class_dev指針不為空 */
30 if (class_dev)
31 /* [cgw]: 為class_dev->kobj對象創建一個BIN文件 */
32 error = sysfs_create_bin_file(&class_dev->kobj, attr);
33 return error;
34 }
35
36 void class_device_remove_bin_file(struct class_device *class_dev,
37 struct bin_attribute *attr)
38 {
39 /* [cgw]: class_dev指針不為空 */
40 if (class_dev)
41 /* [cgw]: 刪除class_dev->kobj對象對應的一個BIN文件 */
42 sysfs_remove_bin_file(&class_dev->kobj, attr);
43 }
44
45 static ssize_t
46 class_device_attr_show(struct kobject * kobj, struct attribute * attr,
47 char * buf)
48 {
49 /* [cgw]: 找出包含這個attr的struct class_device_attribute *指針 */
50 struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
51 /* [cgw]: 找出包含這個kobj的struct class_device *指針
52 */
53 struct class_device * cd = to_class_dev(kobj);
54 ssize_t ret = 0;
55
56 /* [cgw]: class_dev_attr->show指針不為空 */
57 if (class_dev_attr->show)
58 /* [cgw]: 調用class_dev_attr->show方法 */
59 ret = class_dev_attr->show(cd, buf);
60 return ret;
61 }
62
63 static ssize_t
64 class_device_attr_store(struct kobject * kobj, struct attribute * attr,
65 const char * buf, size_t count)
66 {
67 /* [cgw]: 找出包含這個attr的struct class_device_attribute *指針 */
68 struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
69 /* [cgw]: 找出包含這個kobj的struct class_device *指針
70 */
71 struct class_device * cd = to_class_dev(kobj);
72 ssize_t ret = 0;
73
74 /* [cgw]: class_dev_attr->store指針不為空 */
75 if (class_dev_attr->store)
76 /* [cgw]: 調用class_dev_attr->store方法 */
77 ret = class_dev_attr->store(cd, buf, count);
78 return ret;
79 }
80
81 static struct sysfs_ops class_dev_sysfs_ops = {
82 .show = class_device_attr_show,
83 .store = class_device_attr_store,
84 };
85
86 static void class_dev_release(struct kobject * kobj)
87 {
88 /* [cgw]: 找出包含這個kobj的struct class_device *指針 */
89 struct class_device *cd = to_class_dev(kobj);
90 /* [cgw]: cls指向class_device的成員class */
91 struct class * cls = cd->class;
92
93 pr_debug("device class '%s': release.\n", cd->class_id);
94
95 /* [cgw]: 釋放這個class_device的class_device_attribute內存空間
96 * 並把class_device_attribute指針置為空
97 */
98 kfree(cd->devt_attr);
99 cd->devt_attr = NULL;
100
101 /* [cgw]: 調用class_device->release 方法,
102 * 釋放這個已分配的struct class_device *的內存空間
103 */
104 if (cd->release)
105 cd->release(cd);
106 else if (cls->release)
107 /* [cgw]: 調用class_device->class->release 方法
108 * 釋放這個已分配的struct class *的內存空間
109 */
110 cls->release(cd);
111 else {
112 printk(KERN_ERR "Class Device '%s' does not have a release() function, "
113 "it is broken and must be fixed.\n",
114 cd->class_id);
115 WARN_ON(1);
116 }
117 }
118
119 static struct kobj_type ktype_class_device = {
120 .sysfs_ops = &class_dev_sysfs_ops,
121 .release = class_dev_release,
122 };
123
124 static int class_uevent_filter(struct kset *kset, struct kobject *kobj)
125 {
126 /* [cgw]: 找到kobj所屬的類型ktype */
127 struct kobj_type *ktype = get_ktype(kobj);
128
129 /* [cgw]: 這個kobj的類型ktype屬於ktype_class_device */
130 if (ktype == &ktype_class_device) {
131 /* [cgw]: 找到包含這個kobj 的class_dev指針
132 */
133 struct class_device *class_dev = to_class_dev(kobj);
134 /* [cgw]: class_dev->class指針不為空 */
135 if (class_dev->class)
136 return 1;
137 }
138 return 0;
139 }
140
141 static const char *class_uevent_name(struct kset *kset, struct kobject *kobj)
142 {
143 /* [cgw]: 找到包含這個kobj 的class_dev指針
144 */
145 struct class_device *class_dev = to_class_dev(kobj);
146
147 /* [cgw]: 返回class_dev下class的名字 */
148 return class_dev->class->name;
149 }
150
151 #ifdef CONFIG_SYSFS_DEPRECATED
152 char *make_class_name(const char *name, struct kobject *kobj)
153 {
154 char *class_name;
155 int size;
156 /* [cgw]: 找出這個kobj的名字
157 * 計算兩個字符串的總長度並+2,
158 */
159 size = strlen(name) + strlen(kobject_name(kobj)) + 2;
160 /* [cgw]: 分配一個size字節的內存空間 */
161 class_name = kmalloc(size, GFP_KERNEL);
162 /* [cgw]: 分配失敗 */
163 if (!class_name)
164 return NULL;
165 /* [cgw] : 把名字name填裝到class_name */
166 strcpy(class_name, name);
167 /* [cgw] : 在名字name末尾添加":" */
168 strcat(class_name, ":");
169 /* [cgw] : 合並字符串,name+":"+kobj->k_name */
170 strcat(class_name, kobject_name(kobj));
171 return class_name;
172 }
173
174 static int make_deprecated_class_device_links(struct class_device *class_dev)
175 {
176 char *class_name;
177 int error;
178
179 /* [cgw]: class_dev->dev指針為空 */
180 if (!class_dev->dev)
181 return 0;
182 /* [cgw]: 合並class_dev->class->name和class_dev->kobj->k_name
183 */
184 class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
185 /* [cgw]: 合並成功 */
186 if (class_name)
187 /* [cgw]: 在class_dev->dev->kobj對象目錄下創建一個鏈表
188 * 設置這個鏈表的名字為class_name
189 */
190 error = sysfs_create_link(&class_dev->dev->kobj,
191 &class_dev->kobj, class_name);
192 else
193 error = -ENOMEM;
194 /* [cgw]: 釋放class_name內存空間,class_name在這裡只做臨時作用 */
195 kfree(class_name);
196 return error;
197 }
198
199 static void remove_deprecated_class_device_links(struct class_device *class_dev)
200 {
201 char *class_name;
202
203 /* [cgw]: class_dev->dev指針為空 */
204 if (!class_dev->dev)
205 return;
206
207 /* [cgw]: 合並class_dev->class->name和class_dev->kobj->k_name
208 */
209 class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
210 if (class_name)
211 /* [cgw] : 從class_dev->dev->kobj對象目錄下刪除一個名字為
212 * class_name的鏈表
213 */
214 sysfs_remove_link(&class_dev->dev->kobj, class_name);
215 /* [cgw] : 釋放class_name的內存空間 */
216 kfree(class_name);
217 }
218 #else
219 static inline int make_deprecated_class_device_links(struct class_device *cd)
220 { return 0; }
221 static void remove_deprecated_class_device_links(struct class_device *cd)
222 { }
223 #endif
224
225 static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
226 int num_envp, char *buffer, int buffer_size)
227 {
228 /* [cgw]: 找出包含這個kobj的class_device結構體指針 */
229 struct class_device *class_dev = to_class_dev(kobj);
230 struct device *dev = class_dev->dev;
231 int i = 0;
232 int length = 0;
233 int retval = 0;
234
235 pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
236
237 /* [cgw]: 主設備號不為0 */
238 if (MAJOR(class_dev->devt)) {
239 /* [cgw]: 格式化"MAJOR= MAJOR(class_dev->devt)"填裝到buffer中
240 * 並把buffer指針儲存在envp數組
241 */
242 add_uevent_var(envp, num_envp, &i,
243 buffer, buffer_size, &length,
244 "MAJOR=%u", MAJOR(class_dev->devt));
245
246 /* [cgw]: 格式化"MAJOR= MINOR(class_dev->devt)"填裝到buffer中
247 * 並把buffer指針儲存在envp數組
248 */
249 add_uevent_var(envp, num_envp, &i,
250 buffer, buffer_size, &length,
251 "MINOR=%u", MINOR(class_dev->devt));
252 }
253
254 /* [cgw]: dev指針不為空 */
255 if (dev) {
256 /* [cgw]: 獲得dev->kobj所在的路徑 */
257 const char *path = kobject_get_path(&, GFP_KERNEL);
258 /* [cgw]: 獲取成功 */
259 if (path) {
260 /* [cgw]: 格式化"PHYSDEVPATH=path"填裝到buffer中
261 * 並把buffer指針儲存在環境變量envp數組,i+1
262 */
263 add_uevent_var(envp, num_envp, &i,
264 buffer, buffer_size, &length,
265 "PHYSDEVPATH=%s", path);
266 /* [cgw]: 釋放path的內存空間 */
267 kfree(path);
268 }
269
270 /* [cgw]: dev->bus指針不為空 */
271 if (dev->bus)
272 /* [cgw]: 格式化"PHYSDEVBUS=dev->bus->name"填裝到buffer中
273 * 並把buffer指針儲存在環境變量envp數組,i+1
274 */
275 add_uevent_var(envp, num_envp, &i,
276 buffer, buffer_size, &length,
277 "PHYSDEVBUS=%s", dev->bus->name);
278
279 /* [cgw]: dev->driver指針不為空 */
280 if (dev->driver)
281 /* [cgw]: 格式化"PHYSDEVDRIVER=dev->driver->name"填裝到buffer中
282 * 並把buffer指針儲存在環境變量envp數組,i+1
283 */
284 add_uevent_var(envp, num_envp, &i,
285 buffer, buffer_size, &length,
286 "PHYSDEVDRIVER=%s", dev->driver->name);
287 }
288
289 /* terminate, set to next free slot, shrink available space */
290 /* [cgw]: 清空下一個環境變量,envp[i]是一個指針,把這個指針置0 */
291 envp[i] = NULL;
292 /* [cgw]: 重置envp的指針,指向下一個環境變量envp[i] */
293 envp = &envp[i];
294 /* [cgw]: 計算環境變量數組剩下的可用大小 */
295 num_envp -= i;
296 /* [cgw]: 重置buffer指針,指向buffer + length */
297 buffer = &buffer[length];
298 /* [cgw]: 計算環境變量buffer剩下的可用大小 */
299 buffer_size -= length;
300
301 /* [cgw]: class_dev->uevent指針不為空 */
302 if (class_dev->uevent) {
303 /* have the class device specific function add its stuff */
304 /* [cgw]: 調用class_dev->uevent方法 */
305 retval = class_dev->uevent(class_dev, envp, num_envp,
306 buffer, buffer_size);
307 if (retval)
308 pr_debug("class_dev->uevent() returned %d\n", retval);
309 } else if (class_dev->class->uevent) {
310 /* have the class specific function add its stuff */
311 /* [cgw]: 調用class_dev->class->uevent方法 */
312 retval = class_dev->class->uevent(class_dev, envp, num_envp,
313 buffer, buffer_size);
314 if (retval)
315 pr_debug("class->uevent() returned %d\n", retval);
316 }
317
318 return retval;
319 }
320
321 static struct kset_uevent_ops class_uevent_ops = {
322 .filter = class_uevent_filter,
323 .name = class_uevent_name,
324 .uevent = class_uevent,
325 };
326
327 static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);
328
329
330 static int class_device_add_attrs(struct class_device * cd)
331 {
332 int i;
333 int error = 0;
334 struct class * cls = cd->class;
335
336 /* [cgw]: cls->class_dev_attrs指針不為空,即分配了class device 的屬性 */
337 if (cls->class_dev_attrs) {
338 /* [cgw]: 歷遍class_dev_attrs[]數組,如果該屬性名字不為空,則
339 * 對應地創建一個屬性文件
340 */
341 for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) {
342 /* [cgw]: 創建一個class device屬性文件 */
343 error = class_device_create_file(cd,
344 &cls->class_dev_attrs[i]);
345 if (error)
346 goto Err;
347 }
348 }
349 Done:
350 return error;
351 Err:
352 /* [cgw]: 刪除class device的所有屬性文件 */
353 while (--i >= 0)
354 class_device_remove_file(cd,&cls->class_dev_attrs[i]);
355 goto Done;
356 }
357
358 static void class_device_remove_attrs(struct class_device * cd)
359 {
360 int i;
361 struct class * cls = cd->class;
362
363 /* [cgw]: cls->class_dev_attrs指針不為空,即此前已經添加了這個屬性列表 */
364 if (cls->class_dev_attrs) {
365 /* [cgw]: 歷遍class_dev_attrs[]數組,如果該屬性名字不為空,則
366 * 對應地刪除一個屬性文件
367 */
368 for (i = 0; attr_name(cls->class_dev_attrs[i]); i++)
369 /* [cgw]: 刪除一個屬性文件 */
370 class_device_remove_file(cd,&cls->class_dev_attrs[i]);
371 }
372 }
373
374 static int class_device_add_groups(struct class_device * cd)
375 {
376 int i;
377 int error = 0;
378
379 /* [cgw]: cd->groups指針不為空 */
380 if (cd->groups) {
381 /* [cgw]: 歷遍groups[],對應每個groups創建一個屬性組 */
382 for (i = 0; cd->groups[i]; i++) {
383 /* [cgw]: 創建一個屬性組 */
384 error = sysfs_create_group(&cd->kobj, cd->groups[i]);
385 /* [cgw]: 創建失敗 */
386 if (error) {
387 /* [cgw]: 刪除所有屬性組 */
388 while (--i >= 0)
389 /* [cgw]: 刪除一個屬性組 */
390 sysfs_remove_group(&cd->kobj, cd->groups[i]);
391 goto out;
392 }
393 }
394 }
395 out:
396 return error;
397 }
398
399 static void class_device_remove_groups(struct class_device * cd)
400 {
401 int i;
402 /* [cgw]: cd->groups指針不為空 */
403 if (cd->groups) {
404 /* [cgw]: 歷遍groups[],刪除所有屬性組 */
405 for (i = 0; cd->groups[i]; i++) {
406 /* [cgw]: 刪除一個屬性組 */
407 sysfs_remove_group(&cd->kobj, cd->groups[i]);
408 }
409 }
410 }
411
412 static ssize_t show_dev(struct class_device *class_dev, char *buf)
413 {
414 /* [cgw]: 格式化class_dev->devt的主和次設備號為字符串,
415 * 填裝到buf中
416 */
417 return print_dev_t(buf, class_dev->devt);
418 }
419
420 static ssize_t store_uevent(struct class_device *class_dev,
421 const char *buf, size_t count)
422 {
423 /* [cgw]: 對class_dev->kobj產生一個KOBJ_ADD事件通知用戶空間 */
424 kobject_uevent(&class_dev->kobj, KOBJ_ADD);
425 return count;
426 }
427
428 void class_device_initialize(struct class_device *class_dev)
429 {
430 /* [cgw]: 分配class_dev->kobj.kset,指向&class_obj_subsys */
431 kobj_set_kset_s(class_dev, class_obj_subsys);
432 /* [cgw]: 初始化class_dev->kobj */
433 kobject_init(&class_dev->kobj);
434 /* [cgw]: 初始化class_dev->node鏈表 */
435 INIT_LIST_HEAD(&class_dev->node);
436 }
437
438 int class_device_add(struct class_device *class_dev)
439 {
440 struct class *parent_class = NULL;
441 struct class_device *parent_class_dev = NULL;
442 struct class_interface *class_intf;
443 int error = -EINVAL;
444
445 /* [cgw]: class_dev->kobj引用計數+1
446 * 並根據kobj找到包含這個kobj的結構體指針class_dev
447 */
448 class_dev = class_device_get(class_dev);
449 /* [cgw]: class_dev指針為空 */
450 if (!class_dev)
451 return -EINVAL;
452
453 /* [cgw]: class_dev->class_id長度為0 */
454 if (!strlen(class_dev->class_id))
455 goto out1;
456
457 /* [cgw]: class->kobj引用計數+1
458 * 並根據kobj找到包含這個kobj的結構體指針class
459 */
460 parent_class = class_get(class_dev->class);
461 /* [cgw]: parent_class指針為空 */
462 if (!parent_class)
463 goto out1;
464
465 /* [cgw]: 找出class_dev的父節點,並且class_dev->parent->kobj
466 * 引用計數+1
467 */
468 parent_class_dev = class_device_get(class_dev->parent);
469
470 pr_debug("CLASS: registering class device: ID = '%s'\n",
471 class_dev->class_id);
472
473 /* first, register with generic layer. */
474 /* [cgw]: 以class_dev->class_id作為class_dev->kobj的名字 */
475 error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
476 /* [cgw]: 設置class_dev->kobj的名字失敗 */
477 if (error)
478 goto out2;
479
480 /* [cgw]: parent_class_dev指針不為空 */
481 if (parent_class_dev)
482 /* [cgw]: 設置class_dev的kobj的父節點為class_dev父節點的kobj */
483 class_dev->kobj.parent = &parent_class_dev->kobj;
484 else
485 /* [cgw]: 設置class_dev的kobj的父節點為class->subsys.kobj
486 * 設置class_dev的kobj的在最頂層,父節點就是kset.kobj
487 */
488 class_dev->kobj.parent = &parent_class->subsys.kobj;
489
490 /* [cgw]: 添加kobj到層,實際上是把kobj添加到kset集合
491 * entry插入到kobj->kset->list鏈表中, 為這個kobj創建目錄,
492 * 即加入到sysfs目錄,並為這個kobj添加屬性
493 */
494 error = kobject_add(&class_dev->kobj);
495 /* [cgw]: 添加失敗 */
496 if (error)
497 goto out2;
498
499 /* add the needed attributes to this device */
500 /* [cgw]: 在class_dev->kobj目錄下創建一個名為subsystem
501 * 的鏈表,指向parent_class->subsys.kobj
502 */
503 error = sysfs_create_link(&class_dev->kobj,
504 &parent_class->subsys.kobj, "subsystem");
505 /* [cgw]: 創建失敗 */
506 if (error)
507 goto out3;
508 /* [cgw]: 設置class_dev的屬性名為uevent */
509 class_dev->uevent_attr.attr.name = "uevent";
510 /* [cgw]: 權限為S_IWUSR */
511 class_dev->uevent_attr.attr.mode = S_IWUSR;
512 /* [cgw]: 設置擁有這個class_dev->uevent_attr屬性的模塊 */
513 class_dev->uevent_attr.attr.owner = parent_class->owner;
514 /* [cgw]: 分配class_dev->uevent_attr.store的方法 */
515 class_dev->uevent_attr.store = store_uevent;
516 /* [cgw]: 為class_dev->kobj創建一個屬性為class_dev->uevent_attr的
517 * 屬性文件
518 */
519 error = class_device_create_file(class_dev, &class_dev->uevent_attr);
520 /* [cgw]: 創建失敗 */
521 if (error)
522 goto out3;
523 /* [cgw]: 主設備號不為0 */
524 if (MAJOR(class_dev->devt)) {
525 struct class_device_attribute *attr;
526 /* [cgw]: 分配一塊sizeof(*attr)字節大小的內存空間 */
527 attr = kzalloc(sizeof(*attr), GFP_KERNEL);
528 /* [cgw]: 分配失敗 */
529 if (!attr) {
530 error = -ENOMEM;
531 goto out4;
532 }
533 /* [cgw]: attr的屬性名為dev */
534 attr->attr.name = "dev";
535 /* [cgw]: attr的權限為S_IRUGO */
536 attr->attr.mode = S_IRUGO;
537 /* [cgw]: 設置擁有這個attr->attr屬性的模塊 */
538 attr->attr.owner = parent_class->owner;
539 /* [cgw]: 分配attr->show的方法 */
540 attr->show = show_dev;
541 /* [cgw]: 為class_dev->kobj對象創建一個attr屬性文件 */
542 error = class_device_create_file(class_dev, attr);
543 /* [cgw]: 創建失敗 */
544 if (error) {
545 /* [cgw]: 釋放attr的內存空間 */
546 kfree(attr);
547 goto out4;
548 }
549 /* [cgw]: class_dev->devt_attr指向attr */
550 class_dev->devt_attr = attr;
551 }
552
553 /* [cgw]: 為class_dev->kobj添加屬性文件列表,屬性文件
554 * 來自於class_dev->class->class_dev_attrs[]
555 */
556 error = class_device_add_attrs(class_dev);
557 /* [cgw]: 添加失敗 */
558 if (error)
559 goto out5;
560
561 /* [cgw]: class_dev->dev指針不為空 */
562 if (class_dev->dev) {
563 /* [cgw]: 在class_dev->kobj目錄下創建一個名為device的鏈表
564 * 指向class_dev->dev->kobj
565 */
566 error = sysfs_create_link(&class_dev->kobj,
567 &class_dev->dev->kobj, "device");
568 /* [cgw]: 創建失敗 */
569 if (error)
570 goto out6;
571 }
572
573 /* [cgw]: 添加屬性組 */
574 error = class_device_add_groups(class_dev);
575 /* [cgw]: 添加失敗 */
576 if (error)
577 goto out7;
578
579 /* [cgw]: 合並class_dev->class->name和class_dev->kobj->k_name
580 * class_dev->dev->kobj對象目錄下創建一個鏈表
581 */
582 error = make_deprecated_class_device_links(class_dev);
583 /* [cgw]: 創建失敗 */
584 if (error)
585 goto out8;
586
587 /* [cgw]: 通知用戶空間,產生一個KOBJ_ADD事件 */
588 kobject_uevent(&class_dev->kobj, KOBJ_ADD);
589
590 /* notify any interfaces this device is now here */
591 /* [cgw]: 獲得信號量 */
592 down(&parent_class->sem);
593 /* [cgw]: 插入一個新節點class_dev->node到parent_class->children節點前 */
594 list_add_tail(&class_dev->node, &parent_class->children);
595 /* [cgw]: 從parent_class->interfaces的下一節點起,歷遍這個鏈表,直到又回到
596 * 頭節點(環形鏈表)
597 */
598 list_for_each_entry(class_intf, &parent_class->interfaces, node) {
599 /* [cgw]: 這個節點的class_intf->add的指針不為空 */
600 if (class_intf->add)
601 /* [cgw]: 調用class_intf->add方法 */
602 class_intf->add(class_dev, class_intf);
603 }
604 /* [cgw]: 釋放信號量 */
605 up(&parent_class->sem);
606
607 goto out1;
608
609 out8:
610 /* [cgw]: 刪除屬性組 */
611 class_device_remove_groups(class_dev);
612 out7:
613 /* [cgw]: class_dev->dev指針不為空 */
614 if (class_dev->dev)
615 /* [cgw]: 刪除class_dev->kobj目錄下,名為device的鏈表 */
616 sysfs_remove_link(&class_dev->kobj, "device");
617 out6:
618 /* [cgw]: 刪除class_dev所有屬性文件 */
619 class_device_remove_attrs(class_dev);
620 out5:
621 /* [cgw]: class_dev->devt_attr指針不為空,即已經分配了class_dev->devt_attr屬性 */
622 if (class_dev->devt_attr)
623 /* [cgw]: 刪除class_dev->kobj對象對應的一個class_dev->devt_attr屬性文件 */
624 class_device_remove_file(class_dev, class_dev->devt_attr);
625 out4:
626 /* [cgw]: 刪除class_dev->kobj對象對應的一個class_dev->uevent_attr屬性文件 */
627 class_device_remove_file(class_dev, &class_dev->uevent_attr);
628 out3:
629 /* [cgw]: 刪除class_dev->kobj,從sysfs中刪除對應class_dev->kobj的
630 * 條目
631 */
632 kobject_del(&class_dev->kobj);
633 out2:
634 /* [cgw]: parent_class_dev指針不為空(class_dev->parent) */
635 if(parent_class_dev)
636 /* [cgw]: parent_class_dev->kobj引用計數-1 */
637 class_device_put(parent_class_dev);
638 /* [cgw]: parent_class->subsys.kset.kobj引用計數-1 */
639 class_put(parent_class);
640 out1:
641 /* [cgw]: class_dev->kobj引用計數-1 */
642 class_device_put(class_dev);
643 return error;
644 }
http://xxxxxx/Linuxjc/1153667.html TechArticle