Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at cba767175becadc5c4016cceb7bfdd2c7fe722f4 899 lines 24 kB view raw
1/* 2 * thermal.c - Generic Thermal Management Sysfs support. 3 * 4 * Copyright (C) 2008 Intel Corp 5 * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> 6 * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> 7 * 8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; version 2 of the License. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, write to the Free Software Foundation, Inc., 21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 22 * 23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 24 */ 25 26#include <linux/module.h> 27#include <linux/device.h> 28#include <linux/err.h> 29#include <linux/kdev_t.h> 30#include <linux/idr.h> 31#include <linux/thermal.h> 32#include <linux/spinlock.h> 33 34MODULE_AUTHOR("Zhang Rui"); 35MODULE_DESCRIPTION("Generic thermal management sysfs support"); 36MODULE_LICENSE("GPL"); 37 38#define PREFIX "Thermal: " 39 40struct thermal_cooling_device_instance { 41 int id; 42 char name[THERMAL_NAME_LENGTH]; 43 struct thermal_zone_device *tz; 44 struct thermal_cooling_device *cdev; 45 int trip; 46 char attr_name[THERMAL_NAME_LENGTH]; 47 struct device_attribute attr; 48 struct list_head node; 49}; 50 51static DEFINE_IDR(thermal_tz_idr); 52static DEFINE_IDR(thermal_cdev_idr); 53static DEFINE_MUTEX(thermal_idr_lock); 54 55static LIST_HEAD(thermal_tz_list); 56static LIST_HEAD(thermal_cdev_list); 57static DEFINE_MUTEX(thermal_list_lock); 58 59static int get_idr(struct idr *idr, struct mutex *lock, int *id) 60{ 61 int err; 62 63 again: 64 if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0)) 65 return -ENOMEM; 66 67 if (lock) 68 mutex_lock(lock); 69 err = idr_get_new(idr, NULL, id); 70 if (lock) 71 mutex_unlock(lock); 72 if (unlikely(err == -EAGAIN)) 73 goto again; 74 else if (unlikely(err)) 75 return err; 76 77 *id = *id & MAX_ID_MASK; 78 return 0; 79} 80 81static void release_idr(struct idr *idr, struct mutex *lock, int id) 82{ 83 if (lock) 84 mutex_lock(lock); 85 idr_remove(idr, id); 86 if (lock) 87 mutex_unlock(lock); 88} 89 90/* sys I/F for thermal zone */ 91 92#define to_thermal_zone(_dev) \ 93 container_of(_dev, struct thermal_zone_device, device) 94 95static ssize_t 96type_show(struct device *dev, struct device_attribute *attr, char *buf) 97{ 98 struct thermal_zone_device *tz = to_thermal_zone(dev); 99 100 return sprintf(buf, "%s\n", tz->type); 101} 102 103static ssize_t 104temp_show(struct device *dev, struct device_attribute *attr, char *buf) 105{ 106 struct thermal_zone_device *tz = to_thermal_zone(dev); 107 108 if (!tz->ops->get_temp) 109 return -EPERM; 110 111 return tz->ops->get_temp(tz, buf); 112} 113 114static ssize_t 115mode_show(struct device *dev, struct device_attribute *attr, char *buf) 116{ 117 struct thermal_zone_device *tz = to_thermal_zone(dev); 118 119 if (!tz->ops->get_mode) 120 return -EPERM; 121 122 return tz->ops->get_mode(tz, buf); 123} 124 125static ssize_t 126mode_store(struct device *dev, struct device_attribute *attr, 127 const char *buf, size_t count) 128{ 129 struct thermal_zone_device *tz = to_thermal_zone(dev); 130 int result; 131 132 if (!tz->ops->set_mode) 133 return -EPERM; 134 135 result = tz->ops->set_mode(tz, buf); 136 if (result) 137 return result; 138 139 return count; 140} 141 142static ssize_t 143trip_point_type_show(struct device *dev, struct device_attribute *attr, 144 char *buf) 145{ 146 struct thermal_zone_device *tz = to_thermal_zone(dev); 147 int trip; 148 149 if (!tz->ops->get_trip_type) 150 return -EPERM; 151 152 if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) 153 return -EINVAL; 154 155 return tz->ops->get_trip_type(tz, trip, buf); 156} 157 158static ssize_t 159trip_point_temp_show(struct device *dev, struct device_attribute *attr, 160 char *buf) 161{ 162 struct thermal_zone_device *tz = to_thermal_zone(dev); 163 int trip; 164 165 if (!tz->ops->get_trip_temp) 166 return -EPERM; 167 168 if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip)) 169 return -EINVAL; 170 171 return tz->ops->get_trip_temp(tz, trip, buf); 172} 173 174static DEVICE_ATTR(type, 0444, type_show, NULL); 175static DEVICE_ATTR(temp, 0444, temp_show, NULL); 176static DEVICE_ATTR(mode, 0644, mode_show, mode_store); 177 178static struct device_attribute trip_point_attrs[] = { 179 __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL), 180 __ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL), 181 __ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL), 182 __ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL), 183 __ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL), 184 __ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL), 185 __ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL), 186 __ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL), 187 __ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL), 188 __ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL), 189 __ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL), 190 __ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL), 191 __ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL), 192 __ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL), 193 __ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL), 194 __ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL), 195 __ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL), 196 __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL), 197 __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL), 198 __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL), 199 __ATTR(trip_point_10_type, 0444, trip_point_type_show, NULL), 200 __ATTR(trip_point_10_temp, 0444, trip_point_temp_show, NULL), 201 __ATTR(trip_point_11_type, 0444, trip_point_type_show, NULL), 202 __ATTR(trip_point_11_temp, 0444, trip_point_temp_show, NULL), 203}; 204 205#define TRIP_POINT_ATTR_ADD(_dev, _index, result) \ 206do { \ 207 result = device_create_file(_dev, \ 208 &trip_point_attrs[_index * 2]); \ 209 if (result) \ 210 break; \ 211 result = device_create_file(_dev, \ 212 &trip_point_attrs[_index * 2 + 1]); \ 213} while (0) 214 215#define TRIP_POINT_ATTR_REMOVE(_dev, _index) \ 216do { \ 217 device_remove_file(_dev, &trip_point_attrs[_index * 2]); \ 218 device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ 219} while (0) 220 221/* sys I/F for cooling device */ 222#define to_cooling_device(_dev) \ 223 container_of(_dev, struct thermal_cooling_device, device) 224 225static ssize_t 226thermal_cooling_device_type_show(struct device *dev, 227 struct device_attribute *attr, char *buf) 228{ 229 struct thermal_cooling_device *cdev = to_cooling_device(dev); 230 231 return sprintf(buf, "%s\n", cdev->type); 232} 233 234static ssize_t 235thermal_cooling_device_max_state_show(struct device *dev, 236 struct device_attribute *attr, char *buf) 237{ 238 struct thermal_cooling_device *cdev = to_cooling_device(dev); 239 240 return cdev->ops->get_max_state(cdev, buf); 241} 242 243static ssize_t 244thermal_cooling_device_cur_state_show(struct device *dev, 245 struct device_attribute *attr, char *buf) 246{ 247 struct thermal_cooling_device *cdev = to_cooling_device(dev); 248 249 return cdev->ops->get_cur_state(cdev, buf); 250} 251 252static ssize_t 253thermal_cooling_device_cur_state_store(struct device *dev, 254 struct device_attribute *attr, 255 const char *buf, size_t count) 256{ 257 struct thermal_cooling_device *cdev = to_cooling_device(dev); 258 int state; 259 int result; 260 261 if (!sscanf(buf, "%d\n", &state)) 262 return -EINVAL; 263 264 if (state < 0) 265 return -EINVAL; 266 267 result = cdev->ops->set_cur_state(cdev, state); 268 if (result) 269 return result; 270 return count; 271} 272 273static struct device_attribute dev_attr_cdev_type = 274__ATTR(type, 0444, thermal_cooling_device_type_show, NULL); 275static DEVICE_ATTR(max_state, 0444, 276 thermal_cooling_device_max_state_show, NULL); 277static DEVICE_ATTR(cur_state, 0644, 278 thermal_cooling_device_cur_state_show, 279 thermal_cooling_device_cur_state_store); 280 281static ssize_t 282thermal_cooling_device_trip_point_show(struct device *dev, 283 struct device_attribute *attr, char *buf) 284{ 285 struct thermal_cooling_device_instance *instance; 286 287 instance = 288 container_of(attr, struct thermal_cooling_device_instance, attr); 289 290 if (instance->trip == THERMAL_TRIPS_NONE) 291 return sprintf(buf, "-1\n"); 292 else 293 return sprintf(buf, "%d\n", instance->trip); 294} 295 296/* Device management */ 297 298#if defined(CONFIG_THERMAL_HWMON) 299 300/* hwmon sys I/F */ 301#include <linux/hwmon.h> 302static LIST_HEAD(thermal_hwmon_list); 303 304static ssize_t 305name_show(struct device *dev, struct device_attribute *attr, char *buf) 306{ 307 struct thermal_hwmon_device *hwmon = dev->driver_data; 308 return sprintf(buf, "%s\n", hwmon->type); 309} 310static DEVICE_ATTR(name, 0444, name_show, NULL); 311 312static ssize_t 313temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) 314{ 315 struct thermal_hwmon_attr *hwmon_attr 316 = container_of(attr, struct thermal_hwmon_attr, attr); 317 struct thermal_zone_device *tz 318 = container_of(hwmon_attr, struct thermal_zone_device, 319 temp_input); 320 321 return tz->ops->get_temp(tz, buf); 322} 323 324static ssize_t 325temp_crit_show(struct device *dev, struct device_attribute *attr, 326 char *buf) 327{ 328 struct thermal_hwmon_attr *hwmon_attr 329 = container_of(attr, struct thermal_hwmon_attr, attr); 330 struct thermal_zone_device *tz 331 = container_of(hwmon_attr, struct thermal_zone_device, 332 temp_crit); 333 334 return tz->ops->get_trip_temp(tz, 0, buf); 335} 336 337 338static int 339thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) 340{ 341 struct thermal_hwmon_device *hwmon; 342 int new_hwmon_device = 1; 343 int result; 344 345 mutex_lock(&thermal_list_lock); 346 list_for_each_entry(hwmon, &thermal_hwmon_list, node) 347 if (!strcmp(hwmon->type, tz->type)) { 348 new_hwmon_device = 0; 349 mutex_unlock(&thermal_list_lock); 350 goto register_sys_interface; 351 } 352 mutex_unlock(&thermal_list_lock); 353 354 hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL); 355 if (!hwmon) 356 return -ENOMEM; 357 358 INIT_LIST_HEAD(&hwmon->tz_list); 359 strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH); 360 hwmon->device = hwmon_device_register(NULL); 361 if (IS_ERR(hwmon->device)) { 362 result = PTR_ERR(hwmon->device); 363 goto free_mem; 364 } 365 hwmon->device->driver_data = hwmon; 366 result = device_create_file(hwmon->device, &dev_attr_name); 367 if (result) 368 goto unregister_hwmon_device; 369 370 register_sys_interface: 371 tz->hwmon = hwmon; 372 hwmon->count++; 373 374 snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH, 375 "temp%d_input", hwmon->count); 376 tz->temp_input.attr.attr.name = tz->temp_input.name; 377 tz->temp_input.attr.attr.mode = 0444; 378 tz->temp_input.attr.show = temp_input_show; 379 result = device_create_file(hwmon->device, &tz->temp_input.attr); 380 if (result) 381 goto unregister_hwmon_device; 382 383 if (tz->ops->get_crit_temp) { 384 unsigned long temperature; 385 if (!tz->ops->get_crit_temp(tz, &temperature)) { 386 snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH, 387 "temp%d_crit", hwmon->count); 388 tz->temp_crit.attr.attr.name = tz->temp_crit.name; 389 tz->temp_crit.attr.attr.mode = 0444; 390 tz->temp_crit.attr.show = temp_crit_show; 391 result = device_create_file(hwmon->device, 392 &tz->temp_crit.attr); 393 if (result) 394 goto unregister_hwmon_device; 395 } 396 } 397 398 mutex_lock(&thermal_list_lock); 399 if (new_hwmon_device) 400 list_add_tail(&hwmon->node, &thermal_hwmon_list); 401 list_add_tail(&tz->hwmon_node, &hwmon->tz_list); 402 mutex_unlock(&thermal_list_lock); 403 404 return 0; 405 406 unregister_hwmon_device: 407 device_remove_file(hwmon->device, &tz->temp_crit.attr); 408 device_remove_file(hwmon->device, &tz->temp_input.attr); 409 if (new_hwmon_device) { 410 device_remove_file(hwmon->device, &dev_attr_name); 411 hwmon_device_unregister(hwmon->device); 412 } 413 free_mem: 414 if (new_hwmon_device) 415 kfree(hwmon); 416 417 return result; 418} 419 420static void 421thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) 422{ 423 struct thermal_hwmon_device *hwmon = tz->hwmon; 424 425 tz->hwmon = NULL; 426 device_remove_file(hwmon->device, &tz->temp_input.attr); 427 device_remove_file(hwmon->device, &tz->temp_crit.attr); 428 429 mutex_lock(&thermal_list_lock); 430 list_del(&tz->hwmon_node); 431 if (!list_empty(&hwmon->tz_list)) { 432 mutex_unlock(&thermal_list_lock); 433 return; 434 } 435 list_del(&hwmon->node); 436 mutex_unlock(&thermal_list_lock); 437 438 device_remove_file(hwmon->device, &dev_attr_name); 439 hwmon_device_unregister(hwmon->device); 440 kfree(hwmon); 441} 442#else 443static int 444thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) 445{ 446 return 0; 447} 448 449static void 450thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) 451{ 452} 453#endif 454 455 456/** 457 * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone 458 * @tz: thermal zone device 459 * @trip: indicates which trip point the cooling devices is 460 * associated with in this thermal zone. 461 * @cdev: thermal cooling device 462 * 463 * This function is usually called in the thermal zone device .bind callback. 464 */ 465int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, 466 int trip, 467 struct thermal_cooling_device *cdev) 468{ 469 struct thermal_cooling_device_instance *dev; 470 struct thermal_cooling_device_instance *pos; 471 struct thermal_zone_device *pos1; 472 struct thermal_cooling_device *pos2; 473 int result; 474 475 if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE)) 476 return -EINVAL; 477 478 list_for_each_entry(pos1, &thermal_tz_list, node) { 479 if (pos1 == tz) 480 break; 481 } 482 list_for_each_entry(pos2, &thermal_cdev_list, node) { 483 if (pos2 == cdev) 484 break; 485 } 486 487 if (tz != pos1 || cdev != pos2) 488 return -EINVAL; 489 490 dev = 491 kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL); 492 if (!dev) 493 return -ENOMEM; 494 dev->tz = tz; 495 dev->cdev = cdev; 496 dev->trip = trip; 497 result = get_idr(&tz->idr, &tz->lock, &dev->id); 498 if (result) 499 goto free_mem; 500 501 sprintf(dev->name, "cdev%d", dev->id); 502 result = 503 sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name); 504 if (result) 505 goto release_idr; 506 507 sprintf(dev->attr_name, "cdev%d_trip_point", dev->id); 508 dev->attr.attr.name = dev->attr_name; 509 dev->attr.attr.mode = 0444; 510 dev->attr.show = thermal_cooling_device_trip_point_show; 511 result = device_create_file(&tz->device, &dev->attr); 512 if (result) 513 goto remove_symbol_link; 514 515 mutex_lock(&tz->lock); 516 list_for_each_entry(pos, &tz->cooling_devices, node) 517 if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) { 518 result = -EEXIST; 519 break; 520 } 521 if (!result) 522 list_add_tail(&dev->node, &tz->cooling_devices); 523 mutex_unlock(&tz->lock); 524 525 if (!result) 526 return 0; 527 528 device_remove_file(&tz->device, &dev->attr); 529 remove_symbol_link: 530 sysfs_remove_link(&tz->device.kobj, dev->name); 531 release_idr: 532 release_idr(&tz->idr, &tz->lock, dev->id); 533 free_mem: 534 kfree(dev); 535 return result; 536} 537 538EXPORT_SYMBOL(thermal_zone_bind_cooling_device); 539 540/** 541 * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone 542 * @tz: thermal zone device 543 * @trip: indicates which trip point the cooling devices is 544 * associated with in this thermal zone. 545 * @cdev: thermal cooling device 546 * 547 * This function is usually called in the thermal zone device .unbind callback. 548 */ 549int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, 550 int trip, 551 struct thermal_cooling_device *cdev) 552{ 553 struct thermal_cooling_device_instance *pos, *next; 554 555 mutex_lock(&tz->lock); 556 list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) { 557 if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) { 558 list_del(&pos->node); 559 mutex_unlock(&tz->lock); 560 goto unbind; 561 } 562 } 563 mutex_unlock(&tz->lock); 564 565 return -ENODEV; 566 567 unbind: 568 device_remove_file(&tz->device, &pos->attr); 569 sysfs_remove_link(&tz->device.kobj, pos->name); 570 release_idr(&tz->idr, &tz->lock, pos->id); 571 kfree(pos); 572 return 0; 573} 574 575EXPORT_SYMBOL(thermal_zone_unbind_cooling_device); 576 577static void thermal_release(struct device *dev) 578{ 579 struct thermal_zone_device *tz; 580 struct thermal_cooling_device *cdev; 581 582 if (!strncmp(dev->bus_id, "thermal_zone", sizeof "thermal_zone" - 1)) { 583 tz = to_thermal_zone(dev); 584 kfree(tz); 585 } else { 586 cdev = to_cooling_device(dev); 587 kfree(cdev); 588 } 589} 590 591static struct class thermal_class = { 592 .name = "thermal", 593 .dev_release = thermal_release, 594}; 595 596/** 597 * thermal_cooling_device_register - register a new thermal cooling device 598 * @type: the thermal cooling device type. 599 * @devdata: device private data. 600 * @ops: standard thermal cooling devices callbacks. 601 */ 602struct thermal_cooling_device *thermal_cooling_device_register(char *type, 603 void *devdata, 604 struct 605 thermal_cooling_device_ops 606 *ops) 607{ 608 struct thermal_cooling_device *cdev; 609 struct thermal_zone_device *pos; 610 int result; 611 612 if (strlen(type) >= THERMAL_NAME_LENGTH) 613 return ERR_PTR(-EINVAL); 614 615 if (!ops || !ops->get_max_state || !ops->get_cur_state || 616 !ops->set_cur_state) 617 return ERR_PTR(-EINVAL); 618 619 cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL); 620 if (!cdev) 621 return ERR_PTR(-ENOMEM); 622 623 result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id); 624 if (result) { 625 kfree(cdev); 626 return ERR_PTR(result); 627 } 628 629 strcpy(cdev->type, type); 630 cdev->ops = ops; 631 cdev->device.class = &thermal_class; 632 cdev->devdata = devdata; 633 sprintf(cdev->device.bus_id, "cooling_device%d", cdev->id); 634 result = device_register(&cdev->device); 635 if (result) { 636 release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); 637 kfree(cdev); 638 return ERR_PTR(result); 639 } 640 641 /* sys I/F */ 642 if (type) { 643 result = device_create_file(&cdev->device, &dev_attr_cdev_type); 644 if (result) 645 goto unregister; 646 } 647 648 result = device_create_file(&cdev->device, &dev_attr_max_state); 649 if (result) 650 goto unregister; 651 652 result = device_create_file(&cdev->device, &dev_attr_cur_state); 653 if (result) 654 goto unregister; 655 656 mutex_lock(&thermal_list_lock); 657 list_add(&cdev->node, &thermal_cdev_list); 658 list_for_each_entry(pos, &thermal_tz_list, node) { 659 if (!pos->ops->bind) 660 continue; 661 result = pos->ops->bind(pos, cdev); 662 if (result) 663 break; 664 665 } 666 mutex_unlock(&thermal_list_lock); 667 668 if (!result) 669 return cdev; 670 671 unregister: 672 release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); 673 device_unregister(&cdev->device); 674 return ERR_PTR(result); 675} 676 677EXPORT_SYMBOL(thermal_cooling_device_register); 678 679/** 680 * thermal_cooling_device_unregister - removes the registered thermal cooling device 681 * @cdev: the thermal cooling device to remove. 682 * 683 * thermal_cooling_device_unregister() must be called when the device is no 684 * longer needed. 685 */ 686void thermal_cooling_device_unregister(struct 687 thermal_cooling_device 688 *cdev) 689{ 690 struct thermal_zone_device *tz; 691 struct thermal_cooling_device *pos = NULL; 692 693 if (!cdev) 694 return; 695 696 mutex_lock(&thermal_list_lock); 697 list_for_each_entry(pos, &thermal_cdev_list, node) 698 if (pos == cdev) 699 break; 700 if (pos != cdev) { 701 /* thermal cooling device not found */ 702 mutex_unlock(&thermal_list_lock); 703 return; 704 } 705 list_del(&cdev->node); 706 list_for_each_entry(tz, &thermal_tz_list, node) { 707 if (!tz->ops->unbind) 708 continue; 709 tz->ops->unbind(tz, cdev); 710 } 711 mutex_unlock(&thermal_list_lock); 712 if (cdev->type[0]) 713 device_remove_file(&cdev->device, &dev_attr_cdev_type); 714 device_remove_file(&cdev->device, &dev_attr_max_state); 715 device_remove_file(&cdev->device, &dev_attr_cur_state); 716 717 release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); 718 device_unregister(&cdev->device); 719 return; 720} 721 722EXPORT_SYMBOL(thermal_cooling_device_unregister); 723 724/** 725 * thermal_zone_device_register - register a new thermal zone device 726 * @type: the thermal zone device type 727 * @trips: the number of trip points the thermal zone support 728 * @devdata: private device data 729 * @ops: standard thermal zone device callbacks 730 * 731 * thermal_zone_device_unregister() must be called when the device is no 732 * longer needed. 733 */ 734struct thermal_zone_device *thermal_zone_device_register(char *type, 735 int trips, 736 void *devdata, struct 737 thermal_zone_device_ops 738 *ops) 739{ 740 struct thermal_zone_device *tz; 741 struct thermal_cooling_device *pos; 742 int result; 743 int count; 744 745 if (strlen(type) >= THERMAL_NAME_LENGTH) 746 return ERR_PTR(-EINVAL); 747 748 if (trips > THERMAL_MAX_TRIPS || trips < 0) 749 return ERR_PTR(-EINVAL); 750 751 if (!ops || !ops->get_temp) 752 return ERR_PTR(-EINVAL); 753 754 tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL); 755 if (!tz) 756 return ERR_PTR(-ENOMEM); 757 758 INIT_LIST_HEAD(&tz->cooling_devices); 759 idr_init(&tz->idr); 760 mutex_init(&tz->lock); 761 result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id); 762 if (result) { 763 kfree(tz); 764 return ERR_PTR(result); 765 } 766 767 strcpy(tz->type, type); 768 tz->ops = ops; 769 tz->device.class = &thermal_class; 770 tz->devdata = devdata; 771 tz->trips = trips; 772 sprintf(tz->device.bus_id, "thermal_zone%d", tz->id); 773 result = device_register(&tz->device); 774 if (result) { 775 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); 776 kfree(tz); 777 return ERR_PTR(result); 778 } 779 780 /* sys I/F */ 781 if (type) { 782 result = device_create_file(&tz->device, &dev_attr_type); 783 if (result) 784 goto unregister; 785 } 786 787 result = device_create_file(&tz->device, &dev_attr_temp); 788 if (result) 789 goto unregister; 790 791 if (ops->get_mode) { 792 result = device_create_file(&tz->device, &dev_attr_mode); 793 if (result) 794 goto unregister; 795 } 796 797 for (count = 0; count < trips; count++) { 798 TRIP_POINT_ATTR_ADD(&tz->device, count, result); 799 if (result) 800 goto unregister; 801 } 802 803 result = thermal_add_hwmon_sysfs(tz); 804 if (result) 805 goto unregister; 806 807 mutex_lock(&thermal_list_lock); 808 list_add_tail(&tz->node, &thermal_tz_list); 809 if (ops->bind) 810 list_for_each_entry(pos, &thermal_cdev_list, node) { 811 result = ops->bind(tz, pos); 812 if (result) 813 break; 814 } 815 mutex_unlock(&thermal_list_lock); 816 817 if (!result) 818 return tz; 819 820 unregister: 821 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); 822 device_unregister(&tz->device); 823 return ERR_PTR(result); 824} 825 826EXPORT_SYMBOL(thermal_zone_device_register); 827 828/** 829 * thermal_device_unregister - removes the registered thermal zone device 830 * @tz: the thermal zone device to remove 831 */ 832void thermal_zone_device_unregister(struct thermal_zone_device *tz) 833{ 834 struct thermal_cooling_device *cdev; 835 struct thermal_zone_device *pos = NULL; 836 int count; 837 838 if (!tz) 839 return; 840 841 mutex_lock(&thermal_list_lock); 842 list_for_each_entry(pos, &thermal_tz_list, node) 843 if (pos == tz) 844 break; 845 if (pos != tz) { 846 /* thermal zone device not found */ 847 mutex_unlock(&thermal_list_lock); 848 return; 849 } 850 list_del(&tz->node); 851 if (tz->ops->unbind) 852 list_for_each_entry(cdev, &thermal_cdev_list, node) 853 tz->ops->unbind(tz, cdev); 854 mutex_unlock(&thermal_list_lock); 855 856 if (tz->type[0]) 857 device_remove_file(&tz->device, &dev_attr_type); 858 device_remove_file(&tz->device, &dev_attr_temp); 859 if (tz->ops->get_mode) 860 device_remove_file(&tz->device, &dev_attr_mode); 861 862 for (count = 0; count < tz->trips; count++) 863 TRIP_POINT_ATTR_REMOVE(&tz->device, count); 864 865 thermal_remove_hwmon_sysfs(tz); 866 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); 867 idr_destroy(&tz->idr); 868 mutex_destroy(&tz->lock); 869 device_unregister(&tz->device); 870 return; 871} 872 873EXPORT_SYMBOL(thermal_zone_device_unregister); 874 875static int __init thermal_init(void) 876{ 877 int result = 0; 878 879 result = class_register(&thermal_class); 880 if (result) { 881 idr_destroy(&thermal_tz_idr); 882 idr_destroy(&thermal_cdev_idr); 883 mutex_destroy(&thermal_idr_lock); 884 mutex_destroy(&thermal_list_lock); 885 } 886 return result; 887} 888 889static void __exit thermal_exit(void) 890{ 891 class_unregister(&thermal_class); 892 idr_destroy(&thermal_tz_idr); 893 idr_destroy(&thermal_cdev_idr); 894 mutex_destroy(&thermal_idr_lock); 895 mutex_destroy(&thermal_list_lock); 896} 897 898subsys_initcall(thermal_init); 899module_exit(thermal_exit);