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