1/* 2 * thinkpad_acpi.c - ThinkPad ACPI Extras 3 * 4 * 5 * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> 6 * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 21 * 02110-1301, USA. 22 */ 23 24#define IBM_VERSION "0.14" 25#define TPACPI_SYSFS_VERSION 0x000100 26 27/* 28 * Changelog: 29 * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to 30 * drivers/misc. 31 * 32 * 2006-11-22 0.13 new maintainer 33 * changelog now lives in git commit history, and will 34 * not be updated further in-file. 35 * 36 * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels 37 * 2005-03-17 0.11 support for 600e, 770x 38 * thanks to Jamie Lentin <lentinj@dial.pipex.com> 39 * support for 770e, G41 40 * G40 and G41 don't have a thinklight 41 * temperatures no longer experimental 42 * experimental brightness control 43 * experimental volume control 44 * experimental fan enable/disable 45 * 2005-01-16 0.10 fix module loading on R30, R31 46 * 2005-01-16 0.9 support for 570, R30, R31 47 * ultrabay support on A22p, A3x 48 * limit arg for cmos, led, beep, drop experimental status 49 * more capable led control on A21e, A22p, T20-22, X20 50 * experimental temperatures and fan speed 51 * experimental embedded controller register dump 52 * mark more functions as __init, drop incorrect __exit 53 * use MODULE_VERSION 54 * thanks to Henrik Brix Andersen <brix@gentoo.org> 55 * fix parameter passing on module loading 56 * thanks to Rusty Russell <rusty@rustcorp.com.au> 57 * thanks to Jim Radford <radford@blackbean.org> 58 * 2004-11-08 0.8 fix init error case, don't return from a macro 59 * thanks to Chris Wright <chrisw@osdl.org> 60 * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20 61 * fix led control on A21e 62 * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device 63 * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20 64 * proc file format changed 65 * video_switch command 66 * experimental cmos control 67 * experimental led control 68 * experimental acpi sounds 69 * 2004-09-16 0.4 support for module parameters 70 * hotkey mask can be prefixed by 0x 71 * video output switching 72 * video expansion control 73 * ultrabay eject support 74 * removed lcd brightness/on/off control, didn't work 75 * 2004-08-17 0.3 support for R40 76 * lcd off, brightness control 77 * thinklight on/off 78 * 2004-08-14 0.2 support for T series, X20 79 * bluetooth enable/disable 80 * hotkey events disabled by default 81 * removed fan control, currently useless 82 * 2004-08-09 0.1 initial release, support for X series 83 */ 84 85#include "thinkpad_acpi.h" 86 87MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); 88MODULE_DESCRIPTION(IBM_DESC); 89MODULE_VERSION(IBM_VERSION); 90MODULE_LICENSE("GPL"); 91 92/* Please remove this in year 2009 */ 93MODULE_ALIAS("ibm_acpi"); 94 95#define __unused __attribute__ ((unused)) 96 97/**************************************************************************** 98 **************************************************************************** 99 * 100 * ACPI Helpers and device model 101 * 102 **************************************************************************** 103 ****************************************************************************/ 104 105/************************************************************************* 106 * ACPI basic handles 107 */ 108 109static acpi_handle root_handle = NULL; 110 111#define IBM_HANDLE(object, parent, paths...) \ 112 static acpi_handle object##_handle; \ 113 static acpi_handle *object##_parent = &parent##_handle; \ 114 static char *object##_path; \ 115 static char *object##_paths[] = { paths } 116 117IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ 118 "\\_SB.PCI.ISA.EC", /* 570 */ 119 "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ 120 "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */ 121 "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */ 122 "\\_SB.PCI0.ICH3.EC0", /* R31 */ 123 "\\_SB.PCI0.LPC.EC", /* all others */ 124 ); 125 126IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ 127IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ 128 129 130/************************************************************************* 131 * Misc ACPI handles 132 */ 133 134IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ 135 "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ 136 "\\CMS", /* R40, R40e */ 137 ); /* all others */ 138 139IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ 140 "^HKEY", /* R30, R31 */ 141 "HKEY", /* all others */ 142 ); /* 570 */ 143 144 145/************************************************************************* 146 * ACPI helpers 147 */ 148 149static int acpi_evalf(acpi_handle handle, 150 void *res, char *method, char *fmt, ...) 151{ 152 char *fmt0 = fmt; 153 struct acpi_object_list params; 154 union acpi_object in_objs[IBM_MAX_ACPI_ARGS]; 155 struct acpi_buffer result, *resultp; 156 union acpi_object out_obj; 157 acpi_status status; 158 va_list ap; 159 char res_type; 160 int success; 161 int quiet; 162 163 if (!*fmt) { 164 printk(IBM_ERR "acpi_evalf() called with empty format\n"); 165 return 0; 166 } 167 168 if (*fmt == 'q') { 169 quiet = 1; 170 fmt++; 171 } else 172 quiet = 0; 173 174 res_type = *(fmt++); 175 176 params.count = 0; 177 params.pointer = &in_objs[0]; 178 179 va_start(ap, fmt); 180 while (*fmt) { 181 char c = *(fmt++); 182 switch (c) { 183 case 'd': /* int */ 184 in_objs[params.count].integer.value = va_arg(ap, int); 185 in_objs[params.count++].type = ACPI_TYPE_INTEGER; 186 break; 187 /* add more types as needed */ 188 default: 189 printk(IBM_ERR "acpi_evalf() called " 190 "with invalid format character '%c'\n", c); 191 return 0; 192 } 193 } 194 va_end(ap); 195 196 if (res_type != 'v') { 197 result.length = sizeof(out_obj); 198 result.pointer = &out_obj; 199 resultp = &result; 200 } else 201 resultp = NULL; 202 203 status = acpi_evaluate_object(handle, method, ¶ms, resultp); 204 205 switch (res_type) { 206 case 'd': /* int */ 207 if (res) 208 *(int *)res = out_obj.integer.value; 209 success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER; 210 break; 211 case 'v': /* void */ 212 success = status == AE_OK; 213 break; 214 /* add more types as needed */ 215 default: 216 printk(IBM_ERR "acpi_evalf() called " 217 "with invalid format character '%c'\n", res_type); 218 return 0; 219 } 220 221 if (!success && !quiet) 222 printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n", 223 method, fmt0, status); 224 225 return success; 226} 227 228static void __unused acpi_print_int(acpi_handle handle, char *method) 229{ 230 int i; 231 232 if (acpi_evalf(handle, &i, method, "d")) 233 printk(IBM_INFO "%s = 0x%x\n", method, i); 234 else 235 printk(IBM_ERR "error calling %s\n", method); 236} 237 238static int acpi_ec_read(int i, u8 * p) 239{ 240 int v; 241 242 if (ecrd_handle) { 243 if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i)) 244 return 0; 245 *p = v; 246 } else { 247 if (ec_read(i, p) < 0) 248 return 0; 249 } 250 251 return 1; 252} 253 254static int acpi_ec_write(int i, u8 v) 255{ 256 if (ecwr_handle) { 257 if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v)) 258 return 0; 259 } else { 260 if (ec_write(i, v) < 0) 261 return 0; 262 } 263 264 return 1; 265} 266 267static int _sta(acpi_handle handle) 268{ 269 int status; 270 271 if (!handle || !acpi_evalf(handle, &status, "_STA", "d")) 272 status = 0; 273 274 return status; 275} 276 277static int issue_thinkpad_cmos_command(int cmos_cmd) 278{ 279 if (!cmos_handle) 280 return -ENXIO; 281 282 if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd)) 283 return -EIO; 284 285 return 0; 286} 287 288/************************************************************************* 289 * ACPI device model 290 */ 291 292static void drv_acpi_handle_init(char *name, 293 acpi_handle *handle, acpi_handle parent, 294 char **paths, int num_paths, char **path) 295{ 296 int i; 297 acpi_status status; 298 299 vdbg_printk(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n", 300 name); 301 302 for (i = 0; i < num_paths; i++) { 303 status = acpi_get_handle(parent, paths[i], handle); 304 if (ACPI_SUCCESS(status)) { 305 *path = paths[i]; 306 dbg_printk(TPACPI_DBG_INIT, 307 "Found ACPI handle %s for %s\n", 308 *path, name); 309 return; 310 } 311 } 312 313 vdbg_printk(TPACPI_DBG_INIT, "ACPI handle for %s not found\n", 314 name); 315 *handle = NULL; 316} 317 318static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) 319{ 320 struct ibm_struct *ibm = data; 321 322 if (!ibm || !ibm->acpi || !ibm->acpi->notify) 323 return; 324 325 ibm->acpi->notify(ibm, event); 326} 327 328static int __init setup_acpi_notify(struct ibm_struct *ibm) 329{ 330 acpi_status status; 331 int rc; 332 333 BUG_ON(!ibm->acpi); 334 335 if (!*ibm->acpi->handle) 336 return 0; 337 338 vdbg_printk(TPACPI_DBG_INIT, 339 "setting up ACPI notify for %s\n", ibm->name); 340 341 rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device); 342 if (rc < 0) { 343 printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n", 344 ibm->name, rc); 345 return -ENODEV; 346 } 347 348 acpi_driver_data(ibm->acpi->device) = ibm; 349 sprintf(acpi_device_class(ibm->acpi->device), "%s/%s", 350 IBM_ACPI_EVENT_PREFIX, 351 ibm->name); 352 353 status = acpi_install_notify_handler(*ibm->acpi->handle, 354 ibm->acpi->type, dispatch_acpi_notify, ibm); 355 if (ACPI_FAILURE(status)) { 356 if (status == AE_ALREADY_EXISTS) { 357 printk(IBM_NOTICE "another device driver is already handling %s events\n", 358 ibm->name); 359 } else { 360 printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n", 361 ibm->name, status); 362 } 363 return -ENODEV; 364 } 365 ibm->flags.acpi_notify_installed = 1; 366 return 0; 367} 368 369static int __init tpacpi_device_add(struct acpi_device *device) 370{ 371 return 0; 372} 373 374static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) 375{ 376 int rc; 377 378 dbg_printk(TPACPI_DBG_INIT, 379 "registering %s as an ACPI driver\n", ibm->name); 380 381 BUG_ON(!ibm->acpi); 382 383 ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); 384 if (!ibm->acpi->driver) { 385 printk(IBM_ERR "kzalloc(ibm->driver) failed\n"); 386 return -ENOMEM; 387 } 388 389 sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name); 390 ibm->acpi->driver->ids = ibm->acpi->hid; 391 ibm->acpi->driver->ops.add = &tpacpi_device_add; 392 393 rc = acpi_bus_register_driver(ibm->acpi->driver); 394 if (rc < 0) { 395 printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n", 396 ibm->acpi->hid, rc); 397 kfree(ibm->acpi->driver); 398 ibm->acpi->driver = NULL; 399 } else if (!rc) 400 ibm->flags.acpi_driver_registered = 1; 401 402 return rc; 403} 404 405 406/**************************************************************************** 407 **************************************************************************** 408 * 409 * Procfs Helpers 410 * 411 **************************************************************************** 412 ****************************************************************************/ 413 414static int dispatch_procfs_read(char *page, char **start, off_t off, 415 int count, int *eof, void *data) 416{ 417 struct ibm_struct *ibm = data; 418 int len; 419 420 if (!ibm || !ibm->read) 421 return -EINVAL; 422 423 len = ibm->read(page); 424 if (len < 0) 425 return len; 426 427 if (len <= off + count) 428 *eof = 1; 429 *start = page + off; 430 len -= off; 431 if (len > count) 432 len = count; 433 if (len < 0) 434 len = 0; 435 436 return len; 437} 438 439static int dispatch_procfs_write(struct file *file, 440 const char __user * userbuf, 441 unsigned long count, void *data) 442{ 443 struct ibm_struct *ibm = data; 444 char *kernbuf; 445 int ret; 446 447 if (!ibm || !ibm->write) 448 return -EINVAL; 449 450 kernbuf = kmalloc(count + 2, GFP_KERNEL); 451 if (!kernbuf) 452 return -ENOMEM; 453 454 if (copy_from_user(kernbuf, userbuf, count)) { 455 kfree(kernbuf); 456 return -EFAULT; 457 } 458 459 kernbuf[count] = 0; 460 strcat(kernbuf, ","); 461 ret = ibm->write(kernbuf); 462 if (ret == 0) 463 ret = count; 464 465 kfree(kernbuf); 466 467 return ret; 468} 469 470static char *next_cmd(char **cmds) 471{ 472 char *start = *cmds; 473 char *end; 474 475 while ((end = strchr(start, ',')) && end == start) 476 start = end + 1; 477 478 if (!end) 479 return NULL; 480 481 *end = 0; 482 *cmds = end + 1; 483 return start; 484} 485 486 487/**************************************************************************** 488 **************************************************************************** 489 * 490 * Device model: hwmon and platform 491 * 492 **************************************************************************** 493 ****************************************************************************/ 494 495static struct platform_device *tpacpi_pdev = NULL; 496static struct class_device *tpacpi_hwmon = NULL; 497 498static struct platform_driver tpacpi_pdriver = { 499 .driver = { 500 .name = IBM_DRVR_NAME, 501 .owner = THIS_MODULE, 502 }, 503}; 504 505 506/************************************************************************* 507 * thinkpad-acpi driver attributes 508 */ 509 510/* interface_version --------------------------------------------------- */ 511static ssize_t tpacpi_driver_interface_version_show( 512 struct device_driver *drv, 513 char *buf) 514{ 515 return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION); 516} 517 518static DRIVER_ATTR(interface_version, S_IRUGO, 519 tpacpi_driver_interface_version_show, NULL); 520 521/* debug_level --------------------------------------------------------- */ 522static ssize_t tpacpi_driver_debug_show(struct device_driver *drv, 523 char *buf) 524{ 525 return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level); 526} 527 528static ssize_t tpacpi_driver_debug_store(struct device_driver *drv, 529 const char *buf, size_t count) 530{ 531 unsigned long t; 532 533 if (parse_strtoul(buf, 0xffff, &t)) 534 return -EINVAL; 535 536 dbg_level = t; 537 538 return count; 539} 540 541static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, 542 tpacpi_driver_debug_show, tpacpi_driver_debug_store); 543 544/* version ------------------------------------------------------------- */ 545static ssize_t tpacpi_driver_version_show(struct device_driver *drv, 546 char *buf) 547{ 548 return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION); 549} 550 551static DRIVER_ATTR(version, S_IRUGO, 552 tpacpi_driver_version_show, NULL); 553 554/* --------------------------------------------------------------------- */ 555 556static struct driver_attribute* tpacpi_driver_attributes[] = { 557 &driver_attr_debug_level, &driver_attr_version, 558 &driver_attr_interface_version, 559}; 560 561static int __init tpacpi_create_driver_attributes(struct device_driver *drv) 562{ 563 int i, res; 564 565 i = 0; 566 res = 0; 567 while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) { 568 res = driver_create_file(drv, tpacpi_driver_attributes[i]); 569 i++; 570 } 571 572 return res; 573} 574 575static void tpacpi_remove_driver_attributes(struct device_driver *drv) 576{ 577 int i; 578 579 for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) 580 driver_remove_file(drv, tpacpi_driver_attributes[i]); 581} 582 583/************************************************************************* 584 * sysfs support helpers 585 */ 586 587struct attribute_set_obj { 588 struct attribute_set s; 589 struct attribute *a; 590} __attribute__((packed)); 591 592static struct attribute_set *create_attr_set(unsigned int max_members, 593 const char* name) 594{ 595 struct attribute_set_obj *sobj; 596 597 if (max_members == 0) 598 return NULL; 599 600 /* Allocates space for implicit NULL at the end too */ 601 sobj = kzalloc(sizeof(struct attribute_set_obj) + 602 max_members * sizeof(struct attribute *), 603 GFP_KERNEL); 604 if (!sobj) 605 return NULL; 606 sobj->s.max_members = max_members; 607 sobj->s.group.attrs = &sobj->a; 608 sobj->s.group.name = name; 609 610 return &sobj->s; 611} 612 613/* not multi-threaded safe, use it in a single thread per set */ 614static int add_to_attr_set(struct attribute_set* s, struct attribute *attr) 615{ 616 if (!s || !attr) 617 return -EINVAL; 618 619 if (s->members >= s->max_members) 620 return -ENOMEM; 621 622 s->group.attrs[s->members] = attr; 623 s->members++; 624 625 return 0; 626} 627 628static int add_many_to_attr_set(struct attribute_set* s, 629 struct attribute **attr, 630 unsigned int count) 631{ 632 int i, res; 633 634 for (i = 0; i < count; i++) { 635 res = add_to_attr_set(s, attr[i]); 636 if (res) 637 return res; 638 } 639 640 return 0; 641} 642 643static void delete_attr_set(struct attribute_set* s, struct kobject *kobj) 644{ 645 sysfs_remove_group(kobj, &s->group); 646 destroy_attr_set(s); 647} 648 649static int parse_strtoul(const char *buf, 650 unsigned long max, unsigned long *value) 651{ 652 char *endp; 653 654 *value = simple_strtoul(buf, &endp, 0); 655 while (*endp && isspace(*endp)) 656 endp++; 657 if (*endp || *value > max) 658 return -EINVAL; 659 660 return 0; 661} 662 663/**************************************************************************** 664 **************************************************************************** 665 * 666 * Subdrivers 667 * 668 **************************************************************************** 669 ****************************************************************************/ 670 671/************************************************************************* 672 * thinkpad-acpi init subdriver 673 */ 674 675static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) 676{ 677 printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); 678 printk(IBM_INFO "%s\n", IBM_URL); 679 680 if (ibm_thinkpad_ec_found) 681 printk(IBM_INFO "ThinkPad EC firmware %s\n", 682 ibm_thinkpad_ec_found); 683 684 return 0; 685} 686 687static int thinkpad_acpi_driver_read(char *p) 688{ 689 int len = 0; 690 691 len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC); 692 len += sprintf(p + len, "version:\t%s\n", IBM_VERSION); 693 694 return len; 695} 696 697static struct ibm_struct thinkpad_acpi_driver_data = { 698 .name = "driver", 699 .read = thinkpad_acpi_driver_read, 700}; 701 702/************************************************************************* 703 * Hotkey subdriver 704 */ 705 706static int hotkey_orig_status; 707static int hotkey_orig_mask; 708 709static struct attribute_set *hotkey_dev_attributes = NULL; 710 711/* sysfs hotkey enable ------------------------------------------------- */ 712static ssize_t hotkey_enable_show(struct device *dev, 713 struct device_attribute *attr, 714 char *buf) 715{ 716 int res, status, mask; 717 718 res = hotkey_get(&status, &mask); 719 if (res) 720 return res; 721 722 return snprintf(buf, PAGE_SIZE, "%d\n", status); 723} 724 725static ssize_t hotkey_enable_store(struct device *dev, 726 struct device_attribute *attr, 727 const char *buf, size_t count) 728{ 729 unsigned long t; 730 int res, status, mask; 731 732 if (parse_strtoul(buf, 1, &t)) 733 return -EINVAL; 734 735 res = hotkey_get(&status, &mask); 736 if (!res) 737 res = hotkey_set(t, mask); 738 739 return (res) ? res : count; 740} 741 742static struct device_attribute dev_attr_hotkey_enable = 743 __ATTR(hotkey_enable, S_IWUSR | S_IRUGO, 744 hotkey_enable_show, hotkey_enable_store); 745 746/* sysfs hotkey mask --------------------------------------------------- */ 747static ssize_t hotkey_mask_show(struct device *dev, 748 struct device_attribute *attr, 749 char *buf) 750{ 751 int res, status, mask; 752 753 res = hotkey_get(&status, &mask); 754 if (res) 755 return res; 756 757 return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask); 758} 759 760static ssize_t hotkey_mask_store(struct device *dev, 761 struct device_attribute *attr, 762 const char *buf, size_t count) 763{ 764 unsigned long t; 765 int res, status, mask; 766 767 if (parse_strtoul(buf, 0xffff, &t)) 768 return -EINVAL; 769 770 res = hotkey_get(&status, &mask); 771 if (!res) 772 hotkey_set(status, t); 773 774 return (res) ? res : count; 775} 776 777static struct device_attribute dev_attr_hotkey_mask = 778 __ATTR(hotkey_mask, S_IWUSR | S_IRUGO, 779 hotkey_mask_show, hotkey_mask_store); 780 781/* sysfs hotkey bios_enabled ------------------------------------------- */ 782static ssize_t hotkey_bios_enabled_show(struct device *dev, 783 struct device_attribute *attr, 784 char *buf) 785{ 786 return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status); 787} 788 789static struct device_attribute dev_attr_hotkey_bios_enabled = 790 __ATTR(hotkey_bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL); 791 792/* sysfs hotkey bios_mask ---------------------------------------------- */ 793static ssize_t hotkey_bios_mask_show(struct device *dev, 794 struct device_attribute *attr, 795 char *buf) 796{ 797 return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask); 798} 799 800static struct device_attribute dev_attr_hotkey_bios_mask = 801 __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL); 802 803/* --------------------------------------------------------------------- */ 804 805static struct attribute *hotkey_mask_attributes[] = { 806 &dev_attr_hotkey_mask.attr, 807 &dev_attr_hotkey_bios_enabled.attr, 808 &dev_attr_hotkey_bios_mask.attr, 809}; 810 811static int __init hotkey_init(struct ibm_init_struct *iibm) 812{ 813 int res; 814 815 vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); 816 817 IBM_ACPIHANDLE_INIT(hkey); 818 mutex_init(&hotkey_mutex); 819 820 /* hotkey not supported on 570 */ 821 tp_features.hotkey = hkey_handle != NULL; 822 823 vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n", 824 str_supported(tp_features.hotkey)); 825 826 if (tp_features.hotkey) { 827 hotkey_dev_attributes = create_attr_set(4, NULL); 828 if (!hotkey_dev_attributes) 829 return -ENOMEM; 830 res = add_to_attr_set(hotkey_dev_attributes, 831 &dev_attr_hotkey_enable.attr); 832 if (res) 833 return res; 834 835 /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, 836 A30, R30, R31, T20-22, X20-21, X22-24 */ 837 tp_features.hotkey_mask = 838 acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); 839 840 vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", 841 str_supported(tp_features.hotkey_mask)); 842 843 res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); 844 if (!res && tp_features.hotkey_mask) { 845 res = add_many_to_attr_set(hotkey_dev_attributes, 846 hotkey_mask_attributes, 847 ARRAY_SIZE(hotkey_mask_attributes)); 848 } 849 if (!res) 850 res = register_attr_set_with_sysfs( 851 hotkey_dev_attributes, 852 &tpacpi_pdev->dev.kobj); 853 854 if (res) 855 return res; 856 } 857 858 return (tp_features.hotkey)? 0 : 1; 859} 860 861static void hotkey_exit(void) 862{ 863 int res; 864 865 if (tp_features.hotkey) { 866 dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n"); 867 res = hotkey_set(hotkey_orig_status, hotkey_orig_mask); 868 if (res) 869 printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n"); 870 } 871 872 if (hotkey_dev_attributes) { 873 delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); 874 hotkey_dev_attributes = NULL; 875 } 876} 877 878static void hotkey_notify(struct ibm_struct *ibm, u32 event) 879{ 880 int hkey; 881 882 if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) 883 acpi_bus_generate_event(ibm->acpi->device, event, hkey); 884 else { 885 printk(IBM_ERR "unknown hotkey event %d\n", event); 886 acpi_bus_generate_event(ibm->acpi->device, event, 0); 887 } 888} 889 890/* 891 * Call with hotkey_mutex held 892 */ 893static int hotkey_get(int *status, int *mask) 894{ 895 if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) 896 return -EIO; 897 898 if (tp_features.hotkey_mask) 899 if (!acpi_evalf(hkey_handle, mask, "DHKN", "d")) 900 return -EIO; 901 902 return 0; 903} 904 905/* 906 * Call with hotkey_mutex held 907 */ 908static int hotkey_set(int status, int mask) 909{ 910 int i; 911 912 if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) 913 return -EIO; 914 915 if (tp_features.hotkey_mask) 916 for (i = 0; i < 32; i++) { 917 int bit = ((1 << i) & mask) != 0; 918 if (!acpi_evalf(hkey_handle, 919 NULL, "MHKM", "vdd", i + 1, bit)) 920 return -EIO; 921 } 922 923 return 0; 924} 925 926/* procfs -------------------------------------------------------------- */ 927static int hotkey_read(char *p) 928{ 929 int res, status, mask; 930 int len = 0; 931 932 if (!tp_features.hotkey) { 933 len += sprintf(p + len, "status:\t\tnot supported\n"); 934 return len; 935 } 936 937 res = mutex_lock_interruptible(&hotkey_mutex); 938 if (res < 0) 939 return res; 940 res = hotkey_get(&status, &mask); 941 mutex_unlock(&hotkey_mutex); 942 if (res) 943 return res; 944 945 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); 946 if (tp_features.hotkey_mask) { 947 len += sprintf(p + len, "mask:\t\t0x%04x\n", mask); 948 len += sprintf(p + len, 949 "commands:\tenable, disable, reset, <mask>\n"); 950 } else { 951 len += sprintf(p + len, "mask:\t\tnot supported\n"); 952 len += sprintf(p + len, "commands:\tenable, disable, reset\n"); 953 } 954 955 return len; 956} 957 958static int hotkey_write(char *buf) 959{ 960 int res, status, mask; 961 char *cmd; 962 int do_cmd = 0; 963 964 if (!tp_features.hotkey) 965 return -ENODEV; 966 967 res = mutex_lock_interruptible(&hotkey_mutex); 968 if (res < 0) 969 return res; 970 971 res = hotkey_get(&status, &mask); 972 if (res) 973 goto errexit; 974 975 res = 0; 976 while ((cmd = next_cmd(&buf))) { 977 if (strlencmp(cmd, "enable") == 0) { 978 status = 1; 979 } else if (strlencmp(cmd, "disable") == 0) { 980 status = 0; 981 } else if (strlencmp(cmd, "reset") == 0) { 982 status = hotkey_orig_status; 983 mask = hotkey_orig_mask; 984 } else if (sscanf(cmd, "0x%x", &mask) == 1) { 985 /* mask set */ 986 } else if (sscanf(cmd, "%x", &mask) == 1) { 987 /* mask set */ 988 } else { 989 res = -EINVAL; 990 goto errexit; 991 } 992 do_cmd = 1; 993 } 994 995 if (do_cmd) 996 res = hotkey_set(status, mask); 997 998errexit: 999 mutex_unlock(&hotkey_mutex); 1000 return res; 1001} 1002 1003static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = { 1004 .hid = IBM_HKEY_HID, 1005 .notify = hotkey_notify, 1006 .handle = &hkey_handle, 1007 .type = ACPI_DEVICE_NOTIFY, 1008}; 1009 1010static struct ibm_struct hotkey_driver_data = { 1011 .name = "hotkey", 1012 .read = hotkey_read, 1013 .write = hotkey_write, 1014 .exit = hotkey_exit, 1015 .acpi = &ibm_hotkey_acpidriver, 1016}; 1017 1018/************************************************************************* 1019 * Bluetooth subdriver 1020 */ 1021 1022/* sysfs bluetooth enable ---------------------------------------------- */ 1023static ssize_t bluetooth_enable_show(struct device *dev, 1024 struct device_attribute *attr, 1025 char *buf) 1026{ 1027 int status; 1028 1029 status = bluetooth_get_radiosw(); 1030 if (status < 0) 1031 return status; 1032 1033 return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); 1034} 1035 1036static ssize_t bluetooth_enable_store(struct device *dev, 1037 struct device_attribute *attr, 1038 const char *buf, size_t count) 1039{ 1040 unsigned long t; 1041 int res; 1042 1043 if (parse_strtoul(buf, 1, &t)) 1044 return -EINVAL; 1045 1046 res = bluetooth_set_radiosw(t); 1047 1048 return (res) ? res : count; 1049} 1050 1051static struct device_attribute dev_attr_bluetooth_enable = 1052 __ATTR(bluetooth_enable, S_IWUSR | S_IRUGO, 1053 bluetooth_enable_show, bluetooth_enable_store); 1054 1055/* --------------------------------------------------------------------- */ 1056 1057static struct attribute *bluetooth_attributes[] = { 1058 &dev_attr_bluetooth_enable.attr, 1059 NULL 1060}; 1061 1062static const struct attribute_group bluetooth_attr_group = { 1063 .attrs = bluetooth_attributes, 1064}; 1065 1066static int __init bluetooth_init(struct ibm_init_struct *iibm) 1067{ 1068 int res; 1069 int status = 0; 1070 1071 vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); 1072 1073 IBM_ACPIHANDLE_INIT(hkey); 1074 1075 /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, 1076 G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ 1077 tp_features.bluetooth = hkey_handle && 1078 acpi_evalf(hkey_handle, &status, "GBDC", "qd"); 1079 1080 vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n", 1081 str_supported(tp_features.bluetooth), 1082 status); 1083 1084 if (tp_features.bluetooth) { 1085 if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { 1086 /* no bluetooth hardware present in system */ 1087 tp_features.bluetooth = 0; 1088 dbg_printk(TPACPI_DBG_INIT, 1089 "bluetooth hardware not installed\n"); 1090 } else { 1091 res = sysfs_create_group(&tpacpi_pdev->dev.kobj, 1092 &bluetooth_attr_group); 1093 if (res) 1094 return res; 1095 } 1096 } 1097 1098 return (tp_features.bluetooth)? 0 : 1; 1099} 1100 1101static void bluetooth_exit(void) 1102{ 1103 sysfs_remove_group(&tpacpi_pdev->dev.kobj, 1104 &bluetooth_attr_group); 1105} 1106 1107static int bluetooth_get_radiosw(void) 1108{ 1109 int status; 1110 1111 if (!tp_features.bluetooth) 1112 return -ENODEV; 1113 1114 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) 1115 return -EIO; 1116 1117 return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0); 1118} 1119 1120static int bluetooth_set_radiosw(int radio_on) 1121{ 1122 int status; 1123 1124 if (!tp_features.bluetooth) 1125 return -ENODEV; 1126 1127 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) 1128 return -EIO; 1129 if (radio_on) 1130 status |= TP_ACPI_BLUETOOTH_RADIOSSW; 1131 else 1132 status &= ~TP_ACPI_BLUETOOTH_RADIOSSW; 1133 if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) 1134 return -EIO; 1135 1136 return 0; 1137} 1138 1139/* procfs -------------------------------------------------------------- */ 1140static int bluetooth_read(char *p) 1141{ 1142 int len = 0; 1143 int status = bluetooth_get_radiosw(); 1144 1145 if (!tp_features.bluetooth) 1146 len += sprintf(p + len, "status:\t\tnot supported\n"); 1147 else { 1148 len += sprintf(p + len, "status:\t\t%s\n", 1149 (status)? "enabled" : "disabled"); 1150 len += sprintf(p + len, "commands:\tenable, disable\n"); 1151 } 1152 1153 return len; 1154} 1155 1156static int bluetooth_write(char *buf) 1157{ 1158 char *cmd; 1159 1160 if (!tp_features.bluetooth) 1161 return -ENODEV; 1162 1163 while ((cmd = next_cmd(&buf))) { 1164 if (strlencmp(cmd, "enable") == 0) { 1165 bluetooth_set_radiosw(1); 1166 } else if (strlencmp(cmd, "disable") == 0) { 1167 bluetooth_set_radiosw(0); 1168 } else 1169 return -EINVAL; 1170 } 1171 1172 return 0; 1173} 1174 1175static struct ibm_struct bluetooth_driver_data = { 1176 .name = "bluetooth", 1177 .read = bluetooth_read, 1178 .write = bluetooth_write, 1179 .exit = bluetooth_exit, 1180}; 1181 1182/************************************************************************* 1183 * Wan subdriver 1184 */ 1185 1186/* sysfs wan enable ---------------------------------------------------- */ 1187static ssize_t wan_enable_show(struct device *dev, 1188 struct device_attribute *attr, 1189 char *buf) 1190{ 1191 int status; 1192 1193 status = wan_get_radiosw(); 1194 if (status < 0) 1195 return status; 1196 1197 return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); 1198} 1199 1200static ssize_t wan_enable_store(struct device *dev, 1201 struct device_attribute *attr, 1202 const char *buf, size_t count) 1203{ 1204 unsigned long t; 1205 int res; 1206 1207 if (parse_strtoul(buf, 1, &t)) 1208 return -EINVAL; 1209 1210 res = wan_set_radiosw(t); 1211 1212 return (res) ? res : count; 1213} 1214 1215static struct device_attribute dev_attr_wan_enable = 1216 __ATTR(wwan_enable, S_IWUSR | S_IRUGO, 1217 wan_enable_show, wan_enable_store); 1218 1219/* --------------------------------------------------------------------- */ 1220 1221static struct attribute *wan_attributes[] = { 1222 &dev_attr_wan_enable.attr, 1223 NULL 1224}; 1225 1226static const struct attribute_group wan_attr_group = { 1227 .attrs = wan_attributes, 1228}; 1229 1230static int __init wan_init(struct ibm_init_struct *iibm) 1231{ 1232 int res; 1233 int status = 0; 1234 1235 vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); 1236 1237 IBM_ACPIHANDLE_INIT(hkey); 1238 1239 tp_features.wan = hkey_handle && 1240 acpi_evalf(hkey_handle, &status, "GWAN", "qd"); 1241 1242 vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n", 1243 str_supported(tp_features.wan), 1244 status); 1245 1246 if (tp_features.wan) { 1247 if (!(status & TP_ACPI_WANCARD_HWPRESENT)) { 1248 /* no wan hardware present in system */ 1249 tp_features.wan = 0; 1250 dbg_printk(TPACPI_DBG_INIT, 1251 "wan hardware not installed\n"); 1252 } else { 1253 res = sysfs_create_group(&tpacpi_pdev->dev.kobj, 1254 &wan_attr_group); 1255 if (res) 1256 return res; 1257 } 1258 } 1259 1260 return (tp_features.wan)? 0 : 1; 1261} 1262 1263static void wan_exit(void) 1264{ 1265 sysfs_remove_group(&tpacpi_pdev->dev.kobj, 1266 &wan_attr_group); 1267} 1268 1269static int wan_get_radiosw(void) 1270{ 1271 int status; 1272 1273 if (!tp_features.wan) 1274 return -ENODEV; 1275 1276 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) 1277 return -EIO; 1278 1279 return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0); 1280} 1281 1282static int wan_set_radiosw(int radio_on) 1283{ 1284 int status; 1285 1286 if (!tp_features.wan) 1287 return -ENODEV; 1288 1289 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) 1290 return -EIO; 1291 if (radio_on) 1292 status |= TP_ACPI_WANCARD_RADIOSSW; 1293 else 1294 status &= ~TP_ACPI_WANCARD_RADIOSSW; 1295 if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) 1296 return -EIO; 1297 1298 return 0; 1299} 1300 1301/* procfs -------------------------------------------------------------- */ 1302static int wan_read(char *p) 1303{ 1304 int len = 0; 1305 int status = wan_get_radiosw(); 1306 1307 if (!tp_features.wan) 1308 len += sprintf(p + len, "status:\t\tnot supported\n"); 1309 else { 1310 len += sprintf(p + len, "status:\t\t%s\n", 1311 (status)? "enabled" : "disabled"); 1312 len += sprintf(p + len, "commands:\tenable, disable\n"); 1313 } 1314 1315 return len; 1316} 1317 1318static int wan_write(char *buf) 1319{ 1320 char *cmd; 1321 1322 if (!tp_features.wan) 1323 return -ENODEV; 1324 1325 while ((cmd = next_cmd(&buf))) { 1326 if (strlencmp(cmd, "enable") == 0) { 1327 wan_set_radiosw(1); 1328 } else if (strlencmp(cmd, "disable") == 0) { 1329 wan_set_radiosw(0); 1330 } else 1331 return -EINVAL; 1332 } 1333 1334 return 0; 1335} 1336 1337static struct ibm_struct wan_driver_data = { 1338 .name = "wan", 1339 .read = wan_read, 1340 .write = wan_write, 1341 .exit = wan_exit, 1342 .flags.experimental = 1, 1343}; 1344 1345/************************************************************************* 1346 * Video subdriver 1347 */ 1348 1349static enum video_access_mode video_supported; 1350static int video_orig_autosw; 1351 1352IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ 1353 "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ 1354 "\\_SB.PCI0.VID0", /* 770e */ 1355 "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ 1356 "\\_SB.PCI0.AGP.VID", /* all others */ 1357 ); /* R30, R31 */ 1358 1359IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ 1360 1361static int __init video_init(struct ibm_init_struct *iibm) 1362{ 1363 int ivga; 1364 1365 vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n"); 1366 1367 IBM_ACPIHANDLE_INIT(vid); 1368 IBM_ACPIHANDLE_INIT(vid2); 1369 1370 if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) 1371 /* G41, assume IVGA doesn't change */ 1372 vid_handle = vid2_handle; 1373 1374 if (!vid_handle) 1375 /* video switching not supported on R30, R31 */ 1376 video_supported = TPACPI_VIDEO_NONE; 1377 else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) 1378 /* 570 */ 1379 video_supported = TPACPI_VIDEO_570; 1380 else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) 1381 /* 600e/x, 770e, 770x */ 1382 video_supported = TPACPI_VIDEO_770; 1383 else 1384 /* all others */ 1385 video_supported = TPACPI_VIDEO_NEW; 1386 1387 vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n", 1388 str_supported(video_supported != TPACPI_VIDEO_NONE), 1389 video_supported); 1390 1391 return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1; 1392} 1393 1394static void video_exit(void) 1395{ 1396 dbg_printk(TPACPI_DBG_EXIT, 1397 "restoring original video autoswitch mode\n"); 1398 if (video_autosw_set(video_orig_autosw)) 1399 printk(IBM_ERR "error while trying to restore original " 1400 "video autoswitch mode\n"); 1401} 1402 1403static int video_outputsw_get(void) 1404{ 1405 int status = 0; 1406 int i; 1407 1408 switch (video_supported) { 1409 case TPACPI_VIDEO_570: 1410 if (!acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 1411 TP_ACPI_VIDEO_570_PHSCMD)) 1412 return -EIO; 1413 status = i & TP_ACPI_VIDEO_570_PHSMASK; 1414 break; 1415 case TPACPI_VIDEO_770: 1416 if (!acpi_evalf(NULL, &i, "\\VCDL", "d")) 1417 return -EIO; 1418 if (i) 1419 status |= TP_ACPI_VIDEO_S_LCD; 1420 if (!acpi_evalf(NULL, &i, "\\VCDC", "d")) 1421 return -EIO; 1422 if (i) 1423 status |= TP_ACPI_VIDEO_S_CRT; 1424 break; 1425 case TPACPI_VIDEO_NEW: 1426 if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1) || 1427 !acpi_evalf(NULL, &i, "\\VCDC", "d")) 1428 return -EIO; 1429 if (i) 1430 status |= TP_ACPI_VIDEO_S_CRT; 1431 1432 if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0) || 1433 !acpi_evalf(NULL, &i, "\\VCDL", "d")) 1434 return -EIO; 1435 if (i) 1436 status |= TP_ACPI_VIDEO_S_LCD; 1437 if (!acpi_evalf(NULL, &i, "\\VCDD", "d")) 1438 return -EIO; 1439 if (i) 1440 status |= TP_ACPI_VIDEO_S_DVI; 1441 break; 1442 default: 1443 return -ENOSYS; 1444 } 1445 1446 return status; 1447} 1448 1449static int video_outputsw_set(int status) 1450{ 1451 int autosw; 1452 int res = 0; 1453 1454 switch (video_supported) { 1455 case TPACPI_VIDEO_570: 1456 res = acpi_evalf(NULL, NULL, 1457 "\\_SB.PHS2", "vdd", 1458 TP_ACPI_VIDEO_570_PHS2CMD, 1459 status | TP_ACPI_VIDEO_570_PHS2SET); 1460 break; 1461 case TPACPI_VIDEO_770: 1462 autosw = video_autosw_get(); 1463 if (autosw < 0) 1464 return autosw; 1465 1466 res = video_autosw_set(1); 1467 if (res) 1468 return res; 1469 res = acpi_evalf(vid_handle, NULL, 1470 "ASWT", "vdd", status * 0x100, 0); 1471 if (!autosw && video_autosw_set(autosw)) { 1472 printk(IBM_ERR "video auto-switch left enabled due to error\n"); 1473 return -EIO; 1474 } 1475 break; 1476 case TPACPI_VIDEO_NEW: 1477 res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) && 1478 acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1); 1479 break; 1480 default: 1481 return -ENOSYS; 1482 } 1483 1484 return (res)? 0 : -EIO; 1485} 1486 1487static int video_autosw_get(void) 1488{ 1489 int autosw = 0; 1490 1491 switch (video_supported) { 1492 case TPACPI_VIDEO_570: 1493 if (!acpi_evalf(vid_handle, &autosw, "SWIT", "d")) 1494 return -EIO; 1495 break; 1496 case TPACPI_VIDEO_770: 1497 case TPACPI_VIDEO_NEW: 1498 if (!acpi_evalf(vid_handle, &autosw, "^VDEE", "d")) 1499 return -EIO; 1500 break; 1501 default: 1502 return -ENOSYS; 1503 } 1504 1505 return autosw & 1; 1506} 1507 1508static int video_autosw_set(int enable) 1509{ 1510 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0)) 1511 return -EIO; 1512 return 0; 1513} 1514 1515static int video_outputsw_cycle(void) 1516{ 1517 int autosw = video_autosw_get(); 1518 int res; 1519 1520 if (autosw < 0) 1521 return autosw; 1522 1523 switch (video_supported) { 1524 case TPACPI_VIDEO_570: 1525 res = video_autosw_set(1); 1526 if (res) 1527 return res; 1528 res = acpi_evalf(ec_handle, NULL, "_Q16", "v"); 1529 break; 1530 case TPACPI_VIDEO_770: 1531 case TPACPI_VIDEO_NEW: 1532 res = video_autosw_set(1); 1533 if (res) 1534 return res; 1535 res = acpi_evalf(vid_handle, NULL, "VSWT", "v"); 1536 break; 1537 default: 1538 return -ENOSYS; 1539 } 1540 if (!autosw && video_autosw_set(autosw)) { 1541 printk(IBM_ERR "video auto-switch left enabled due to error\n"); 1542 return -EIO; 1543 } 1544 1545 return (res)? 0 : -EIO; 1546} 1547 1548static int video_expand_toggle(void) 1549{ 1550 switch (video_supported) { 1551 case TPACPI_VIDEO_570: 1552 return acpi_evalf(ec_handle, NULL, "_Q17", "v")? 1553 0 : -EIO; 1554 case TPACPI_VIDEO_770: 1555 return acpi_evalf(vid_handle, NULL, "VEXP", "v")? 1556 0 : -EIO; 1557 case TPACPI_VIDEO_NEW: 1558 return acpi_evalf(NULL, NULL, "\\VEXP", "v")? 1559 0 : -EIO; 1560 default: 1561 return -ENOSYS; 1562 } 1563 /* not reached */ 1564} 1565 1566static int video_read(char *p) 1567{ 1568 int status, autosw; 1569 int len = 0; 1570 1571 if (video_supported == TPACPI_VIDEO_NONE) { 1572 len += sprintf(p + len, "status:\t\tnot supported\n"); 1573 return len; 1574 } 1575 1576 status = video_outputsw_get(); 1577 if (status < 0) 1578 return status; 1579 1580 autosw = video_autosw_get(); 1581 if (autosw < 0) 1582 return autosw; 1583 1584 len += sprintf(p + len, "status:\t\tsupported\n"); 1585 len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); 1586 len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); 1587 if (video_supported == TPACPI_VIDEO_NEW) 1588 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); 1589 len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); 1590 len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); 1591 len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); 1592 if (video_supported == TPACPI_VIDEO_NEW) 1593 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); 1594 len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); 1595 len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); 1596 1597 return len; 1598} 1599 1600static int video_write(char *buf) 1601{ 1602 char *cmd; 1603 int enable, disable, status; 1604 int res; 1605 1606 if (video_supported == TPACPI_VIDEO_NONE) 1607 return -ENODEV; 1608 1609 enable = 0; 1610 disable = 0; 1611 1612 while ((cmd = next_cmd(&buf))) { 1613 if (strlencmp(cmd, "lcd_enable") == 0) { 1614 enable |= TP_ACPI_VIDEO_S_LCD; 1615 } else if (strlencmp(cmd, "lcd_disable") == 0) { 1616 disable |= TP_ACPI_VIDEO_S_LCD; 1617 } else if (strlencmp(cmd, "crt_enable") == 0) { 1618 enable |= TP_ACPI_VIDEO_S_CRT; 1619 } else if (strlencmp(cmd, "crt_disable") == 0) { 1620 disable |= TP_ACPI_VIDEO_S_CRT; 1621 } else if (video_supported == TPACPI_VIDEO_NEW && 1622 strlencmp(cmd, "dvi_enable") == 0) { 1623 enable |= TP_ACPI_VIDEO_S_DVI; 1624 } else if (video_supported == TPACPI_VIDEO_NEW && 1625 strlencmp(cmd, "dvi_disable") == 0) { 1626 disable |= TP_ACPI_VIDEO_S_DVI; 1627 } else if (strlencmp(cmd, "auto_enable") == 0) { 1628 res = video_autosw_set(1); 1629 if (res) 1630 return res; 1631 } else if (strlencmp(cmd, "auto_disable") == 0) { 1632 res = video_autosw_set(0); 1633 if (res) 1634 return res; 1635 } else if (strlencmp(cmd, "video_switch") == 0) { 1636 res = video_outputsw_cycle(); 1637 if (res) 1638 return res; 1639 } else if (strlencmp(cmd, "expand_toggle") == 0) { 1640 res = video_expand_toggle(); 1641 if (res) 1642 return res; 1643 } else 1644 return -EINVAL; 1645 } 1646 1647 if (enable || disable) { 1648 status = video_outputsw_get(); 1649 if (status < 0) 1650 return status; 1651 res = video_outputsw_set((status & ~disable) | enable); 1652 if (res) 1653 return res; 1654 } 1655 1656 return 0; 1657} 1658 1659static struct ibm_struct video_driver_data = { 1660 .name = "video", 1661 .read = video_read, 1662 .write = video_write, 1663 .exit = video_exit, 1664}; 1665 1666/************************************************************************* 1667 * Light (thinklight) subdriver 1668 */ 1669 1670IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ 1671IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */ 1672 1673static int __init light_init(struct ibm_init_struct *iibm) 1674{ 1675 vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); 1676 1677 IBM_ACPIHANDLE_INIT(ledb); 1678 IBM_ACPIHANDLE_INIT(lght); 1679 IBM_ACPIHANDLE_INIT(cmos); 1680 1681 /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ 1682 tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; 1683 1684 if (tp_features.light) 1685 /* light status not supported on 1686 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */ 1687 tp_features.light_status = 1688 acpi_evalf(ec_handle, NULL, "KBLT", "qv"); 1689 1690 vdbg_printk(TPACPI_DBG_INIT, "light is %s\n", 1691 str_supported(tp_features.light)); 1692 1693 return (tp_features.light)? 0 : 1; 1694} 1695 1696static int light_read(char *p) 1697{ 1698 int len = 0; 1699 int status = 0; 1700 1701 if (!tp_features.light) { 1702 len += sprintf(p + len, "status:\t\tnot supported\n"); 1703 } else if (!tp_features.light_status) { 1704 len += sprintf(p + len, "status:\t\tunknown\n"); 1705 len += sprintf(p + len, "commands:\ton, off\n"); 1706 } else { 1707 if (!acpi_evalf(ec_handle, &status, "KBLT", "d")) 1708 return -EIO; 1709 len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0)); 1710 len += sprintf(p + len, "commands:\ton, off\n"); 1711 } 1712 1713 return len; 1714} 1715 1716static int light_write(char *buf) 1717{ 1718 int cmos_cmd, lght_cmd; 1719 char *cmd; 1720 int success; 1721 1722 if (!tp_features.light) 1723 return -ENODEV; 1724 1725 while ((cmd = next_cmd(&buf))) { 1726 if (strlencmp(cmd, "on") == 0) { 1727 cmos_cmd = 0x0c; 1728 lght_cmd = 1; 1729 } else if (strlencmp(cmd, "off") == 0) { 1730 cmos_cmd = 0x0d; 1731 lght_cmd = 0; 1732 } else 1733 return -EINVAL; 1734 1735 success = cmos_handle ? 1736 acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) : 1737 acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd); 1738 if (!success) 1739 return -EIO; 1740 } 1741 1742 return 0; 1743} 1744 1745static struct ibm_struct light_driver_data = { 1746 .name = "light", 1747 .read = light_read, 1748 .write = light_write, 1749}; 1750 1751/************************************************************************* 1752 * Dock subdriver 1753 */ 1754 1755#ifdef CONFIG_THINKPAD_ACPI_DOCK 1756 1757IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ 1758 "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */ 1759 "\\_SB.PCI0.PCI1.DOCK", /* all others */ 1760 "\\_SB.PCI.ISA.SLCE", /* 570 */ 1761 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ 1762 1763/* don't list other alternatives as we install a notify handler on the 570 */ 1764IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ 1765 1766static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = { 1767 { 1768 .notify = dock_notify, 1769 .handle = &dock_handle, 1770 .type = ACPI_SYSTEM_NOTIFY, 1771 }, 1772 { 1773 .hid = IBM_PCI_HID, 1774 .notify = dock_notify, 1775 .handle = &pci_handle, 1776 .type = ACPI_SYSTEM_NOTIFY, 1777 }, 1778}; 1779 1780static struct ibm_struct dock_driver_data[2] = { 1781 { 1782 .name = "dock", 1783 .read = dock_read, 1784 .write = dock_write, 1785 .acpi = &ibm_dock_acpidriver[0], 1786 }, 1787 { 1788 .name = "dock", 1789 .acpi = &ibm_dock_acpidriver[1], 1790 }, 1791}; 1792 1793#define dock_docked() (_sta(dock_handle) & 1) 1794 1795static int __init dock_init(struct ibm_init_struct *iibm) 1796{ 1797 vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n"); 1798 1799 IBM_ACPIHANDLE_INIT(dock); 1800 1801 vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n", 1802 str_supported(dock_handle != NULL)); 1803 1804 return (dock_handle)? 0 : 1; 1805} 1806 1807static int __init dock_init2(struct ibm_init_struct *iibm) 1808{ 1809 int dock2_needed; 1810 1811 vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver part 2\n"); 1812 1813 if (dock_driver_data[0].flags.acpi_driver_registered && 1814 dock_driver_data[0].flags.acpi_notify_installed) { 1815 IBM_ACPIHANDLE_INIT(pci); 1816 dock2_needed = (pci_handle != NULL); 1817 vdbg_printk(TPACPI_DBG_INIT, 1818 "dock PCI handler for the TP 570 is %s\n", 1819 str_supported(dock2_needed)); 1820 } else { 1821 vdbg_printk(TPACPI_DBG_INIT, 1822 "dock subdriver part 2 not required\n"); 1823 dock2_needed = 0; 1824 } 1825 1826 return (dock2_needed)? 0 : 1; 1827} 1828 1829static void dock_notify(struct ibm_struct *ibm, u32 event) 1830{ 1831 int docked = dock_docked(); 1832 int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID); 1833 1834 if (event == 1 && !pci) /* 570 */ 1835 acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ 1836 else if (event == 1 && pci) /* 570 */ 1837 acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */ 1838 else if (event == 3 && docked) 1839 acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ 1840 else if (event == 3 && !docked) 1841 acpi_bus_generate_event(ibm->acpi->device, event, 2); /* undock */ 1842 else if (event == 0 && docked) 1843 acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */ 1844 else { 1845 printk(IBM_ERR "unknown dock event %d, status %d\n", 1846 event, _sta(dock_handle)); 1847 acpi_bus_generate_event(ibm->acpi->device, event, 0); /* unknown */ 1848 } 1849} 1850 1851static int dock_read(char *p) 1852{ 1853 int len = 0; 1854 int docked = dock_docked(); 1855 1856 if (!dock_handle) 1857 len += sprintf(p + len, "status:\t\tnot supported\n"); 1858 else if (!docked) 1859 len += sprintf(p + len, "status:\t\tundocked\n"); 1860 else { 1861 len += sprintf(p + len, "status:\t\tdocked\n"); 1862 len += sprintf(p + len, "commands:\tdock, undock\n"); 1863 } 1864 1865 return len; 1866} 1867 1868static int dock_write(char *buf) 1869{ 1870 char *cmd; 1871 1872 if (!dock_docked()) 1873 return -ENODEV; 1874 1875 while ((cmd = next_cmd(&buf))) { 1876 if (strlencmp(cmd, "undock") == 0) { 1877 if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) || 1878 !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1)) 1879 return -EIO; 1880 } else if (strlencmp(cmd, "dock") == 0) { 1881 if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1)) 1882 return -EIO; 1883 } else 1884 return -EINVAL; 1885 } 1886 1887 return 0; 1888} 1889 1890#endif /* CONFIG_THINKPAD_ACPI_DOCK */ 1891 1892/************************************************************************* 1893 * Bay subdriver 1894 */ 1895 1896#ifdef CONFIG_THINKPAD_ACPI_BAY 1897IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ 1898 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ 1899 "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ 1900 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */ 1901 ); /* A21e, R30, R31 */ 1902IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */ 1903 "_EJ0", /* all others */ 1904 ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */ 1905IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */ 1906 "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */ 1907 ); /* all others */ 1908IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ 1909 "_EJ0", /* 770x */ 1910 ); /* all others */ 1911 1912static int __init bay_init(struct ibm_init_struct *iibm) 1913{ 1914 vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n"); 1915 1916 IBM_ACPIHANDLE_INIT(bay); 1917 if (bay_handle) 1918 IBM_ACPIHANDLE_INIT(bay_ej); 1919 IBM_ACPIHANDLE_INIT(bay2); 1920 if (bay2_handle) 1921 IBM_ACPIHANDLE_INIT(bay2_ej); 1922 1923 tp_features.bay_status = bay_handle && 1924 acpi_evalf(bay_handle, NULL, "_STA", "qv"); 1925 tp_features.bay_status2 = bay2_handle && 1926 acpi_evalf(bay2_handle, NULL, "_STA", "qv"); 1927 1928 tp_features.bay_eject = bay_handle && bay_ej_handle && 1929 (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental); 1930 tp_features.bay_eject2 = bay2_handle && bay2_ej_handle && 1931 (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental); 1932 1933 vdbg_printk(TPACPI_DBG_INIT, 1934 "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n", 1935 str_supported(tp_features.bay_status), 1936 str_supported(tp_features.bay_eject), 1937 str_supported(tp_features.bay_status2), 1938 str_supported(tp_features.bay_eject2)); 1939 1940 return (tp_features.bay_status || tp_features.bay_eject || 1941 tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1; 1942} 1943 1944static void bay_notify(struct ibm_struct *ibm, u32 event) 1945{ 1946 acpi_bus_generate_event(ibm->acpi->device, event, 0); 1947} 1948 1949#define bay_occupied(b) (_sta(b##_handle) & 1) 1950 1951static int bay_read(char *p) 1952{ 1953 int len = 0; 1954 int occupied = bay_occupied(bay); 1955 int occupied2 = bay_occupied(bay2); 1956 int eject, eject2; 1957 1958 len += sprintf(p + len, "status:\t\t%s\n", 1959 tp_features.bay_status ? 1960 (occupied ? "occupied" : "unoccupied") : 1961 "not supported"); 1962 if (tp_features.bay_status2) 1963 len += sprintf(p + len, "status2:\t%s\n", occupied2 ? 1964 "occupied" : "unoccupied"); 1965 1966 eject = tp_features.bay_eject && occupied; 1967 eject2 = tp_features.bay_eject2 && occupied2; 1968 1969 if (eject && eject2) 1970 len += sprintf(p + len, "commands:\teject, eject2\n"); 1971 else if (eject) 1972 len += sprintf(p + len, "commands:\teject\n"); 1973 else if (eject2) 1974 len += sprintf(p + len, "commands:\teject2\n"); 1975 1976 return len; 1977} 1978 1979static int bay_write(char *buf) 1980{ 1981 char *cmd; 1982 1983 if (!tp_features.bay_eject && !tp_features.bay_eject2) 1984 return -ENODEV; 1985 1986 while ((cmd = next_cmd(&buf))) { 1987 if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) { 1988 if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1)) 1989 return -EIO; 1990 } else if (tp_features.bay_eject2 && 1991 strlencmp(cmd, "eject2") == 0) { 1992 if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1)) 1993 return -EIO; 1994 } else 1995 return -EINVAL; 1996 } 1997 1998 return 0; 1999} 2000 2001static struct tp_acpi_drv_struct ibm_bay_acpidriver = { 2002 .notify = bay_notify, 2003 .handle = &bay_handle, 2004 .type = ACPI_SYSTEM_NOTIFY, 2005}; 2006 2007static struct ibm_struct bay_driver_data = { 2008 .name = "bay", 2009 .read = bay_read, 2010 .write = bay_write, 2011 .acpi = &ibm_bay_acpidriver, 2012}; 2013 2014#endif /* CONFIG_THINKPAD_ACPI_BAY */ 2015 2016/************************************************************************* 2017 * CMOS subdriver 2018 */ 2019 2020/* sysfs cmos_command -------------------------------------------------- */ 2021static ssize_t cmos_command_store(struct device *dev, 2022 struct device_attribute *attr, 2023 const char *buf, size_t count) 2024{ 2025 unsigned long cmos_cmd; 2026 int res; 2027 2028 if (parse_strtoul(buf, 21, &cmos_cmd)) 2029 return -EINVAL; 2030 2031 res = issue_thinkpad_cmos_command(cmos_cmd); 2032 return (res)? res : count; 2033} 2034 2035static struct device_attribute dev_attr_cmos_command = 2036 __ATTR(cmos_command, S_IWUSR, NULL, cmos_command_store); 2037 2038/* --------------------------------------------------------------------- */ 2039 2040static int __init cmos_init(struct ibm_init_struct *iibm) 2041{ 2042 int res; 2043 2044 vdbg_printk(TPACPI_DBG_INIT, 2045 "initializing cmos commands subdriver\n"); 2046 2047 IBM_ACPIHANDLE_INIT(cmos); 2048 2049 vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n", 2050 str_supported(cmos_handle != NULL)); 2051 2052 res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); 2053 if (res) 2054 return res; 2055 2056 return (cmos_handle)? 0 : 1; 2057} 2058 2059static void cmos_exit(void) 2060{ 2061 device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); 2062} 2063 2064static int cmos_read(char *p) 2065{ 2066 int len = 0; 2067 2068 /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, 2069 R30, R31, T20-22, X20-21 */ 2070 if (!cmos_handle) 2071 len += sprintf(p + len, "status:\t\tnot supported\n"); 2072 else { 2073 len += sprintf(p + len, "status:\t\tsupported\n"); 2074 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n"); 2075 } 2076 2077 return len; 2078} 2079 2080static int cmos_write(char *buf) 2081{ 2082 char *cmd; 2083 int cmos_cmd, res; 2084 2085 while ((cmd = next_cmd(&buf))) { 2086 if (sscanf(cmd, "%u", &cmos_cmd) == 1 && 2087 cmos_cmd >= 0 && cmos_cmd <= 21) { 2088 /* cmos_cmd set */ 2089 } else 2090 return -EINVAL; 2091 2092 res = issue_thinkpad_cmos_command(cmos_cmd); 2093 if (res) 2094 return res; 2095 } 2096 2097 return 0; 2098} 2099 2100static struct ibm_struct cmos_driver_data = { 2101 .name = "cmos", 2102 .read = cmos_read, 2103 .write = cmos_write, 2104 .exit = cmos_exit, 2105}; 2106 2107/************************************************************************* 2108 * LED subdriver 2109 */ 2110 2111static enum led_access_mode led_supported; 2112 2113IBM_HANDLE(led, ec, "SLED", /* 570 */ 2114 "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ 2115 "LED", /* all others */ 2116 ); /* R30, R31 */ 2117 2118static int __init led_init(struct ibm_init_struct *iibm) 2119{ 2120 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); 2121 2122 IBM_ACPIHANDLE_INIT(led); 2123 2124 if (!led_handle) 2125 /* led not supported on R30, R31 */ 2126 led_supported = TPACPI_LED_NONE; 2127 else if (strlencmp(led_path, "SLED") == 0) 2128 /* 570 */ 2129 led_supported = TPACPI_LED_570; 2130 else if (strlencmp(led_path, "SYSL") == 0) 2131 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ 2132 led_supported = TPACPI_LED_OLD; 2133 else 2134 /* all others */ 2135 led_supported = TPACPI_LED_NEW; 2136 2137 vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", 2138 str_supported(led_supported), led_supported); 2139 2140 return (led_supported != TPACPI_LED_NONE)? 0 : 1; 2141} 2142 2143#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking")) 2144 2145static int led_read(char *p) 2146{ 2147 int len = 0; 2148 2149 if (!led_supported) { 2150 len += sprintf(p + len, "status:\t\tnot supported\n"); 2151 return len; 2152 } 2153 len += sprintf(p + len, "status:\t\tsupported\n"); 2154 2155 if (led_supported == TPACPI_LED_570) { 2156 /* 570 */ 2157 int i, status; 2158 for (i = 0; i < 8; i++) { 2159 if (!acpi_evalf(ec_handle, 2160 &status, "GLED", "dd", 1 << i)) 2161 return -EIO; 2162 len += sprintf(p + len, "%d:\t\t%s\n", 2163 i, led_status(status)); 2164 } 2165 } 2166 2167 len += sprintf(p + len, "commands:\t" 2168 "<led> on, <led> off, <led> blink (<led> is 0-7)\n"); 2169 2170 return len; 2171} 2172 2173/* off, on, blink */ 2174static const int led_sled_arg1[] = { 0, 1, 3 }; 2175static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */ 2176static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */ 2177static const int led_led_arg1[] = { 0, 0x80, 0xc0 }; 2178 2179static int led_write(char *buf) 2180{ 2181 char *cmd; 2182 int led, ind, ret; 2183 2184 if (!led_supported) 2185 return -ENODEV; 2186 2187 while ((cmd = next_cmd(&buf))) { 2188 if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7) 2189 return -EINVAL; 2190 2191 if (strstr(cmd, "off")) { 2192 ind = 0; 2193 } else if (strstr(cmd, "on")) { 2194 ind = 1; 2195 } else if (strstr(cmd, "blink")) { 2196 ind = 2; 2197 } else 2198 return -EINVAL; 2199 2200 if (led_supported == TPACPI_LED_570) { 2201 /* 570 */ 2202 led = 1 << led; 2203 if (!acpi_evalf(led_handle, NULL, NULL, "vdd", 2204 led, led_sled_arg1[ind])) 2205 return -EIO; 2206 } else if (led_supported == TPACPI_LED_OLD) { 2207 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ 2208 led = 1 << led; 2209 ret = ec_write(TPACPI_LED_EC_HLMS, led); 2210 if (ret >= 0) 2211 ret = 2212 ec_write(TPACPI_LED_EC_HLBL, 2213 led * led_exp_hlbl[ind]); 2214 if (ret >= 0) 2215 ret = 2216 ec_write(TPACPI_LED_EC_HLCL, 2217 led * led_exp_hlcl[ind]); 2218 if (ret < 0) 2219 return ret; 2220 } else { 2221 /* all others */ 2222 if (!acpi_evalf(led_handle, NULL, NULL, "vdd", 2223 led, led_led_arg1[ind])) 2224 return -EIO; 2225 } 2226 } 2227 2228 return 0; 2229} 2230 2231static struct ibm_struct led_driver_data = { 2232 .name = "led", 2233 .read = led_read, 2234 .write = led_write, 2235}; 2236 2237/************************************************************************* 2238 * Beep subdriver 2239 */ 2240 2241IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ 2242 2243static int __init beep_init(struct ibm_init_struct *iibm) 2244{ 2245 vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n"); 2246 2247 IBM_ACPIHANDLE_INIT(beep); 2248 2249 vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n", 2250 str_supported(beep_handle != NULL)); 2251 2252 return (beep_handle)? 0 : 1; 2253} 2254 2255static int beep_read(char *p) 2256{ 2257 int len = 0; 2258 2259 if (!beep_handle) 2260 len += sprintf(p + len, "status:\t\tnot supported\n"); 2261 else { 2262 len += sprintf(p + len, "status:\t\tsupported\n"); 2263 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n"); 2264 } 2265 2266 return len; 2267} 2268 2269static int beep_write(char *buf) 2270{ 2271 char *cmd; 2272 int beep_cmd; 2273 2274 if (!beep_handle) 2275 return -ENODEV; 2276 2277 while ((cmd = next_cmd(&buf))) { 2278 if (sscanf(cmd, "%u", &beep_cmd) == 1 && 2279 beep_cmd >= 0 && beep_cmd <= 17) { 2280 /* beep_cmd set */ 2281 } else 2282 return -EINVAL; 2283 if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0)) 2284 return -EIO; 2285 } 2286 2287 return 0; 2288} 2289 2290static struct ibm_struct beep_driver_data = { 2291 .name = "beep", 2292 .read = beep_read, 2293 .write = beep_write, 2294}; 2295 2296/************************************************************************* 2297 * Thermal subdriver 2298 */ 2299 2300static enum thermal_access_mode thermal_read_mode; 2301 2302/* sysfs temp##_input -------------------------------------------------- */ 2303 2304static ssize_t thermal_temp_input_show(struct device *dev, 2305 struct device_attribute *attr, 2306 char *buf) 2307{ 2308 struct sensor_device_attribute *sensor_attr = 2309 to_sensor_dev_attr(attr); 2310 int idx = sensor_attr->index; 2311 s32 value; 2312 int res; 2313 2314 res = thermal_get_sensor(idx, &value); 2315 if (res) 2316 return res; 2317 if (value == TP_EC_THERMAL_TMP_NA * 1000) 2318 return -ENXIO; 2319 2320 return snprintf(buf, PAGE_SIZE, "%d\n", value); 2321} 2322 2323#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \ 2324 SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB) 2325 2326static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = { 2327 THERMAL_SENSOR_ATTR_TEMP(1, 0), 2328 THERMAL_SENSOR_ATTR_TEMP(2, 1), 2329 THERMAL_SENSOR_ATTR_TEMP(3, 2), 2330 THERMAL_SENSOR_ATTR_TEMP(4, 3), 2331 THERMAL_SENSOR_ATTR_TEMP(5, 4), 2332 THERMAL_SENSOR_ATTR_TEMP(6, 5), 2333 THERMAL_SENSOR_ATTR_TEMP(7, 6), 2334 THERMAL_SENSOR_ATTR_TEMP(8, 7), 2335 THERMAL_SENSOR_ATTR_TEMP(9, 8), 2336 THERMAL_SENSOR_ATTR_TEMP(10, 9), 2337 THERMAL_SENSOR_ATTR_TEMP(11, 10), 2338 THERMAL_SENSOR_ATTR_TEMP(12, 11), 2339 THERMAL_SENSOR_ATTR_TEMP(13, 12), 2340 THERMAL_SENSOR_ATTR_TEMP(14, 13), 2341 THERMAL_SENSOR_ATTR_TEMP(15, 14), 2342 THERMAL_SENSOR_ATTR_TEMP(16, 15), 2343}; 2344 2345#define THERMAL_ATTRS(X) \ 2346 &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr 2347 2348static struct attribute *thermal_temp_input_attr[] = { 2349 THERMAL_ATTRS(8), 2350 THERMAL_ATTRS(9), 2351 THERMAL_ATTRS(10), 2352 THERMAL_ATTRS(11), 2353 THERMAL_ATTRS(12), 2354 THERMAL_ATTRS(13), 2355 THERMAL_ATTRS(14), 2356 THERMAL_ATTRS(15), 2357 THERMAL_ATTRS(0), 2358 THERMAL_ATTRS(1), 2359 THERMAL_ATTRS(2), 2360 THERMAL_ATTRS(3), 2361 THERMAL_ATTRS(4), 2362 THERMAL_ATTRS(5), 2363 THERMAL_ATTRS(6), 2364 THERMAL_ATTRS(7), 2365 NULL 2366}; 2367 2368static const struct attribute_group thermal_temp_input16_group = { 2369 .attrs = thermal_temp_input_attr 2370}; 2371 2372static const struct attribute_group thermal_temp_input8_group = { 2373 .attrs = &thermal_temp_input_attr[8] 2374}; 2375 2376#undef THERMAL_SENSOR_ATTR_TEMP 2377#undef THERMAL_ATTRS 2378 2379/* --------------------------------------------------------------------- */ 2380 2381static int __init thermal_init(struct ibm_init_struct *iibm) 2382{ 2383 u8 t, ta1, ta2; 2384 int i; 2385 int acpi_tmp7; 2386 int res; 2387 2388 vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n"); 2389 2390 acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); 2391 2392 if (ibm_thinkpad_ec_found && experimental) { 2393 /* 2394 * Direct EC access mode: sensors at registers 2395 * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for 2396 * non-implemented, thermal sensors return 0x80 when 2397 * not available 2398 */ 2399 2400 ta1 = ta2 = 0; 2401 for (i = 0; i < 8; i++) { 2402 if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) { 2403 ta1 |= t; 2404 } else { 2405 ta1 = 0; 2406 break; 2407 } 2408 if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) { 2409 ta2 |= t; 2410 } else { 2411 ta1 = 0; 2412 break; 2413 } 2414 } 2415 if (ta1 == 0) { 2416 /* This is sheer paranoia, but we handle it anyway */ 2417 if (acpi_tmp7) { 2418 printk(IBM_ERR 2419 "ThinkPad ACPI EC access misbehaving, " 2420 "falling back to ACPI TMPx access mode\n"); 2421 thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; 2422 } else { 2423 printk(IBM_ERR 2424 "ThinkPad ACPI EC access misbehaving, " 2425 "disabling thermal sensors access\n"); 2426 thermal_read_mode = TPACPI_THERMAL_NONE; 2427 } 2428 } else { 2429 thermal_read_mode = 2430 (ta2 != 0) ? 2431 TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8; 2432 } 2433 } else if (acpi_tmp7) { 2434 if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { 2435 /* 600e/x, 770e, 770x */ 2436 thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT; 2437 } else { 2438 /* Standard ACPI TMPx access, max 8 sensors */ 2439 thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; 2440 } 2441 } else { 2442 /* temperatures not supported on 570, G4x, R30, R31, R32 */ 2443 thermal_read_mode = TPACPI_THERMAL_NONE; 2444 } 2445 2446 vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n", 2447 str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), 2448 thermal_read_mode); 2449 2450 switch(thermal_read_mode) { 2451 case TPACPI_THERMAL_TPEC_16: 2452 res = sysfs_create_group(&tpacpi_pdev->dev.kobj, 2453 &thermal_temp_input16_group); 2454 if (res) 2455 return res; 2456 break; 2457 case TPACPI_THERMAL_TPEC_8: 2458 case TPACPI_THERMAL_ACPI_TMP07: 2459 case TPACPI_THERMAL_ACPI_UPDT: 2460 res = sysfs_create_group(&tpacpi_pdev->dev.kobj, 2461 &thermal_temp_input8_group); 2462 if (res) 2463 return res; 2464 break; 2465 case TPACPI_THERMAL_NONE: 2466 default: 2467 return 1; 2468 } 2469 2470 return 0; 2471} 2472 2473static void thermal_exit(void) 2474{ 2475 switch(thermal_read_mode) { 2476 case TPACPI_THERMAL_TPEC_16: 2477 sysfs_remove_group(&tpacpi_pdev->dev.kobj, 2478 &thermal_temp_input16_group); 2479 break; 2480 case TPACPI_THERMAL_TPEC_8: 2481 case TPACPI_THERMAL_ACPI_TMP07: 2482 case TPACPI_THERMAL_ACPI_UPDT: 2483 sysfs_remove_group(&tpacpi_pdev->dev.kobj, 2484 &thermal_temp_input16_group); 2485 break; 2486 case TPACPI_THERMAL_NONE: 2487 default: 2488 break; 2489 } 2490} 2491 2492/* idx is zero-based */ 2493static int thermal_get_sensor(int idx, s32 *value) 2494{ 2495 int t; 2496 s8 tmp; 2497 char tmpi[5]; 2498 2499 t = TP_EC_THERMAL_TMP0; 2500 2501 switch (thermal_read_mode) { 2502#if TPACPI_MAX_THERMAL_SENSORS >= 16 2503 case TPACPI_THERMAL_TPEC_16: 2504 if (idx >= 8 && idx <= 15) { 2505 t = TP_EC_THERMAL_TMP8; 2506 idx -= 8; 2507 } 2508 /* fallthrough */ 2509#endif 2510 case TPACPI_THERMAL_TPEC_8: 2511 if (idx <= 7) { 2512 if (!acpi_ec_read(t + idx, &tmp)) 2513 return -EIO; 2514 *value = tmp * 1000; 2515 return 0; 2516 } 2517 break; 2518 2519 case TPACPI_THERMAL_ACPI_UPDT: 2520 if (idx <= 7) { 2521 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); 2522 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) 2523 return -EIO; 2524 if (!acpi_evalf(ec_handle, &t, tmpi, "d")) 2525 return -EIO; 2526 *value = (t - 2732) * 100; 2527 return 0; 2528 } 2529 break; 2530 2531 case TPACPI_THERMAL_ACPI_TMP07: 2532 if (idx <= 7) { 2533 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); 2534 if (!acpi_evalf(ec_handle, &t, tmpi, "d")) 2535 return -EIO; 2536 *value = t * 1000; 2537 return 0; 2538 } 2539 break; 2540 2541 case TPACPI_THERMAL_NONE: 2542 default: 2543 return -ENOSYS; 2544 } 2545 2546 return -EINVAL; 2547} 2548 2549static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) 2550{ 2551 int res, i; 2552 int n; 2553 2554 n = 8; 2555 i = 0; 2556 2557 if (!s) 2558 return -EINVAL; 2559 2560 if (thermal_read_mode == TPACPI_THERMAL_TPEC_16) 2561 n = 16; 2562 2563 for(i = 0 ; i < n; i++) { 2564 res = thermal_get_sensor(i, &s->temp[i]); 2565 if (res) 2566 return res; 2567 } 2568 2569 return n; 2570} 2571 2572static int thermal_read(char *p) 2573{ 2574 int len = 0; 2575 int n, i; 2576 struct ibm_thermal_sensors_struct t; 2577 2578 n = thermal_get_sensors(&t); 2579 if (unlikely(n < 0)) 2580 return n; 2581 2582 len += sprintf(p + len, "temperatures:\t"); 2583 2584 if (n > 0) { 2585 for (i = 0; i < (n - 1); i++) 2586 len += sprintf(p + len, "%d ", t.temp[i] / 1000); 2587 len += sprintf(p + len, "%d\n", t.temp[i] / 1000); 2588 } else 2589 len += sprintf(p + len, "not supported\n"); 2590 2591 return len; 2592} 2593 2594static struct ibm_struct thermal_driver_data = { 2595 .name = "thermal", 2596 .read = thermal_read, 2597 .exit = thermal_exit, 2598}; 2599 2600/************************************************************************* 2601 * EC Dump subdriver 2602 */ 2603 2604static u8 ecdump_regs[256]; 2605 2606static int ecdump_read(char *p) 2607{ 2608 int len = 0; 2609 int i, j; 2610 u8 v; 2611 2612 len += sprintf(p + len, "EC " 2613 " +00 +01 +02 +03 +04 +05 +06 +07" 2614 " +08 +09 +0a +0b +0c +0d +0e +0f\n"); 2615 for (i = 0; i < 256; i += 16) { 2616 len += sprintf(p + len, "EC 0x%02x:", i); 2617 for (j = 0; j < 16; j++) { 2618 if (!acpi_ec_read(i + j, &v)) 2619 break; 2620 if (v != ecdump_regs[i + j]) 2621 len += sprintf(p + len, " *%02x", v); 2622 else 2623 len += sprintf(p + len, " %02x", v); 2624 ecdump_regs[i + j] = v; 2625 } 2626 len += sprintf(p + len, "\n"); 2627 if (j != 16) 2628 break; 2629 } 2630 2631 /* These are way too dangerous to advertise openly... */ 2632 return len; 2633} 2634 2635static int ecdump_write(char *buf) 2636{ 2637 char *cmd; 2638 int i, v; 2639 2640 while ((cmd = next_cmd(&buf))) { 2641 if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) { 2642 /* i and v set */ 2643 } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) { 2644 /* i and v set */ 2645 } else 2646 return -EINVAL; 2647 if (i >= 0 && i < 256 && v >= 0 && v < 256) { 2648 if (!acpi_ec_write(i, v)) 2649 return -EIO; 2650 } else 2651 return -EINVAL; 2652 } 2653 2654 return 0; 2655} 2656 2657static struct ibm_struct ecdump_driver_data = { 2658 .name = "ecdump", 2659 .read = ecdump_read, 2660 .write = ecdump_write, 2661 .flags.experimental = 1, 2662}; 2663 2664/************************************************************************* 2665 * Backlight/brightness subdriver 2666 */ 2667 2668static struct backlight_device *ibm_backlight_device = NULL; 2669 2670static struct backlight_ops ibm_backlight_data = { 2671 .get_brightness = brightness_get, 2672 .update_status = brightness_update_status, 2673}; 2674 2675static int __init brightness_init(struct ibm_init_struct *iibm) 2676{ 2677 int b; 2678 2679 vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); 2680 2681 b = brightness_get(NULL); 2682 if (b < 0) 2683 return b; 2684 2685 ibm_backlight_device = backlight_device_register( 2686 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, 2687 &ibm_backlight_data); 2688 if (IS_ERR(ibm_backlight_device)) { 2689 printk(IBM_ERR "Could not register backlight device\n"); 2690 return PTR_ERR(ibm_backlight_device); 2691 } 2692 vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); 2693 2694 ibm_backlight_device->props.max_brightness = 7; 2695 ibm_backlight_device->props.brightness = b; 2696 backlight_update_status(ibm_backlight_device); 2697 2698 return 0; 2699} 2700 2701static void brightness_exit(void) 2702{ 2703 if (ibm_backlight_device) { 2704 vdbg_printk(TPACPI_DBG_EXIT, 2705 "calling backlight_device_unregister()\n"); 2706 backlight_device_unregister(ibm_backlight_device); 2707 ibm_backlight_device = NULL; 2708 } 2709} 2710 2711static int brightness_update_status(struct backlight_device *bd) 2712{ 2713 return brightness_set( 2714 (bd->props.fb_blank == FB_BLANK_UNBLANK && 2715 bd->props.power == FB_BLANK_UNBLANK) ? 2716 bd->props.brightness : 0); 2717} 2718 2719static int brightness_get(struct backlight_device *bd) 2720{ 2721 u8 level; 2722 if (!acpi_ec_read(brightness_offset, &level)) 2723 return -EIO; 2724 2725 level &= 0x7; 2726 2727 return level; 2728} 2729 2730static int brightness_set(int value) 2731{ 2732 int cmos_cmd, inc, i; 2733 int current_value = brightness_get(NULL); 2734 2735 value &= 7; 2736 2737 cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN; 2738 inc = value > current_value ? 1 : -1; 2739 for (i = current_value; i != value; i += inc) { 2740 if (issue_thinkpad_cmos_command(cmos_cmd)) 2741 return -EIO; 2742 if (!acpi_ec_write(brightness_offset, i + inc)) 2743 return -EIO; 2744 } 2745 2746 return 0; 2747} 2748 2749static int brightness_read(char *p) 2750{ 2751 int len = 0; 2752 int level; 2753 2754 if ((level = brightness_get(NULL)) < 0) { 2755 len += sprintf(p + len, "level:\t\tunreadable\n"); 2756 } else { 2757 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7); 2758 len += sprintf(p + len, "commands:\tup, down\n"); 2759 len += sprintf(p + len, "commands:\tlevel <level>" 2760 " (<level> is 0-7)\n"); 2761 } 2762 2763 return len; 2764} 2765 2766static int brightness_write(char *buf) 2767{ 2768 int level; 2769 int new_level; 2770 char *cmd; 2771 2772 while ((cmd = next_cmd(&buf))) { 2773 if ((level = brightness_get(NULL)) < 0) 2774 return level; 2775 level &= 7; 2776 2777 if (strlencmp(cmd, "up") == 0) { 2778 new_level = level == 7 ? 7 : level + 1; 2779 } else if (strlencmp(cmd, "down") == 0) { 2780 new_level = level == 0 ? 0 : level - 1; 2781 } else if (sscanf(cmd, "level %d", &new_level) == 1 && 2782 new_level >= 0 && new_level <= 7) { 2783 /* new_level set */ 2784 } else 2785 return -EINVAL; 2786 2787 brightness_set(new_level); 2788 } 2789 2790 return 0; 2791} 2792 2793static struct ibm_struct brightness_driver_data = { 2794 .name = "brightness", 2795 .read = brightness_read, 2796 .write = brightness_write, 2797 .exit = brightness_exit, 2798}; 2799 2800/************************************************************************* 2801 * Volume subdriver 2802 */ 2803 2804static int volume_read(char *p) 2805{ 2806 int len = 0; 2807 u8 level; 2808 2809 if (!acpi_ec_read(volume_offset, &level)) { 2810 len += sprintf(p + len, "level:\t\tunreadable\n"); 2811 } else { 2812 len += sprintf(p + len, "level:\t\t%d\n", level & 0xf); 2813 len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6)); 2814 len += sprintf(p + len, "commands:\tup, down, mute\n"); 2815 len += sprintf(p + len, "commands:\tlevel <level>" 2816 " (<level> is 0-15)\n"); 2817 } 2818 2819 return len; 2820} 2821 2822static int volume_write(char *buf) 2823{ 2824 int cmos_cmd, inc, i; 2825 u8 level, mute; 2826 int new_level, new_mute; 2827 char *cmd; 2828 2829 while ((cmd = next_cmd(&buf))) { 2830 if (!acpi_ec_read(volume_offset, &level)) 2831 return -EIO; 2832 new_mute = mute = level & 0x40; 2833 new_level = level = level & 0xf; 2834 2835 if (strlencmp(cmd, "up") == 0) { 2836 if (mute) 2837 new_mute = 0; 2838 else 2839 new_level = level == 15 ? 15 : level + 1; 2840 } else if (strlencmp(cmd, "down") == 0) { 2841 if (mute) 2842 new_mute = 0; 2843 else 2844 new_level = level == 0 ? 0 : level - 1; 2845 } else if (sscanf(cmd, "level %d", &new_level) == 1 && 2846 new_level >= 0 && new_level <= 15) { 2847 /* new_level set */ 2848 } else if (strlencmp(cmd, "mute") == 0) { 2849 new_mute = 0x40; 2850 } else 2851 return -EINVAL; 2852 2853 if (new_level != level) { /* mute doesn't change */ 2854 cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN; 2855 inc = new_level > level ? 1 : -1; 2856 2857 if (mute && (issue_thinkpad_cmos_command(cmos_cmd) || 2858 !acpi_ec_write(volume_offset, level))) 2859 return -EIO; 2860 2861 for (i = level; i != new_level; i += inc) 2862 if (issue_thinkpad_cmos_command(cmos_cmd) || 2863 !acpi_ec_write(volume_offset, i + inc)) 2864 return -EIO; 2865 2866 if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) || 2867 !acpi_ec_write(volume_offset, 2868 new_level + mute))) 2869 return -EIO; 2870 } 2871 2872 if (new_mute != mute) { /* level doesn't change */ 2873 cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP; 2874 2875 if (issue_thinkpad_cmos_command(cmos_cmd) || 2876 !acpi_ec_write(volume_offset, level + new_mute)) 2877 return -EIO; 2878 } 2879 } 2880 2881 return 0; 2882} 2883 2884static struct ibm_struct volume_driver_data = { 2885 .name = "volume", 2886 .read = volume_read, 2887 .write = volume_write, 2888}; 2889 2890/************************************************************************* 2891 * Fan subdriver 2892 */ 2893 2894/* 2895 * FAN ACCESS MODES 2896 * 2897 * TPACPI_FAN_RD_ACPI_GFAN: 2898 * ACPI GFAN method: returns fan level 2899 * 2900 * see TPACPI_FAN_WR_ACPI_SFAN 2901 * EC 0x2f (HFSP) not available if GFAN exists 2902 * 2903 * TPACPI_FAN_WR_ACPI_SFAN: 2904 * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max) 2905 * 2906 * EC 0x2f (HFSP) might be available *for reading*, but do not use 2907 * it for writing. 2908 * 2909 * TPACPI_FAN_WR_TPEC: 2910 * ThinkPad EC register 0x2f (HFSP): fan control loop mode 2911 * Supported on almost all ThinkPads 2912 * 2913 * Fan speed changes of any sort (including those caused by the 2914 * disengaged mode) are usually done slowly by the firmware as the 2915 * maximum ammount of fan duty cycle change per second seems to be 2916 * limited. 2917 * 2918 * Reading is not available if GFAN exists. 2919 * Writing is not available if SFAN exists. 2920 * 2921 * Bits 2922 * 7 automatic mode engaged; 2923 * (default operation mode of the ThinkPad) 2924 * fan level is ignored in this mode. 2925 * 6 full speed mode (takes precedence over bit 7); 2926 * not available on all thinkpads. May disable 2927 * the tachometer while the fan controller ramps up 2928 * the speed (which can take up to a few *minutes*). 2929 * Speeds up fan to 100% duty-cycle, which is far above 2930 * the standard RPM levels. It is not impossible that 2931 * it could cause hardware damage. 2932 * 5-3 unused in some models. Extra bits for fan level 2933 * in others, but still useless as all values above 2934 * 7 map to the same speed as level 7 in these models. 2935 * 2-0 fan level (0..7 usually) 2936 * 0x00 = stop 2937 * 0x07 = max (set when temperatures critical) 2938 * Some ThinkPads may have other levels, see 2939 * TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41) 2940 * 2941 * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at 2942 * boot. Apparently the EC does not intialize it, so unless ACPI DSDT 2943 * does so, its initial value is meaningless (0x07). 2944 * 2945 * For firmware bugs, refer to: 2946 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues 2947 * 2948 * ---- 2949 * 2950 * ThinkPad EC register 0x84 (LSB), 0x85 (MSB): 2951 * Main fan tachometer reading (in RPM) 2952 * 2953 * This register is present on all ThinkPads with a new-style EC, and 2954 * it is known not to be present on the A21m/e, and T22, as there is 2955 * something else in offset 0x84 according to the ACPI DSDT. Other 2956 * ThinkPads from this same time period (and earlier) probably lack the 2957 * tachometer as well. 2958 * 2959 * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare 2960 * was never fixed by IBM to report the EC firmware version string 2961 * probably support the tachometer (like the early X models), so 2962 * detecting it is quite hard. We need more data to know for sure. 2963 * 2964 * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings 2965 * might result. 2966 * 2967 * FIRMWARE BUG: may go stale while the EC is switching to full speed 2968 * mode. 2969 * 2970 * For firmware bugs, refer to: 2971 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues 2972 * 2973 * TPACPI_FAN_WR_ACPI_FANS: 2974 * ThinkPad X31, X40, X41. Not available in the X60. 2975 * 2976 * FANS ACPI handle: takes three arguments: low speed, medium speed, 2977 * high speed. ACPI DSDT seems to map these three speeds to levels 2978 * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH 2979 * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3") 2980 * 2981 * The speeds are stored on handles 2982 * (FANA:FAN9), (FANC:FANB), (FANE:FAND). 2983 * 2984 * There are three default speed sets, acessible as handles: 2985 * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H 2986 * 2987 * ACPI DSDT switches which set is in use depending on various 2988 * factors. 2989 * 2990 * TPACPI_FAN_WR_TPEC is also available and should be used to 2991 * command the fan. The X31/X40/X41 seems to have 8 fan levels, 2992 * but the ACPI tables just mention level 7. 2993 */ 2994 2995static enum fan_status_access_mode fan_status_access_mode; 2996static enum fan_control_access_mode fan_control_access_mode; 2997static enum fan_control_commands fan_control_commands; 2998 2999static u8 fan_control_initial_status; 3000static u8 fan_control_desired_level; 3001 3002static void fan_watchdog_fire(struct work_struct *ignored); 3003static int fan_watchdog_maxinterval; 3004static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); 3005 3006IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ 3007IBM_HANDLE(gfan, ec, "GFAN", /* 570 */ 3008 "\\FSPD", /* 600e/x, 770e, 770x */ 3009 ); /* all others */ 3010IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ 3011 "JFNS", /* 770x-JL */ 3012 ); /* all others */ 3013 3014/* 3015 * SYSFS fan layout: hwmon compatible (device) 3016 * 3017 * pwm*_enable: 3018 * 0: "disengaged" mode 3019 * 1: manual mode 3020 * 2: native EC "auto" mode (recommended, hardware default) 3021 * 3022 * pwm*: set speed in manual mode, ignored otherwise. 3023 * 0 is level 0; 255 is level 7. Intermediate points done with linear 3024 * interpolation. 3025 * 3026 * fan*_input: tachometer reading, RPM 3027 * 3028 * 3029 * SYSFS fan layout: extensions 3030 * 3031 * fan_watchdog (driver): 3032 * fan watchdog interval in seconds, 0 disables (default), max 120 3033 */ 3034 3035/* sysfs fan pwm1_enable ----------------------------------------------- */ 3036static ssize_t fan_pwm1_enable_show(struct device *dev, 3037 struct device_attribute *attr, 3038 char *buf) 3039{ 3040 int res, mode; 3041 u8 status; 3042 3043 res = fan_get_status_safe(&status); 3044 if (res) 3045 return res; 3046 3047 if (unlikely(tp_features.fan_ctrl_status_undef)) { 3048 if (status != fan_control_initial_status) { 3049 tp_features.fan_ctrl_status_undef = 0; 3050 } else { 3051 /* Return most likely status. In fact, it 3052 * might be the only possible status */ 3053 status = TP_EC_FAN_AUTO; 3054 } 3055 } 3056 3057 if (status & TP_EC_FAN_FULLSPEED) { 3058 mode = 0; 3059 } else if (status & TP_EC_FAN_AUTO) { 3060 mode = 2; 3061 } else 3062 mode = 1; 3063 3064 return snprintf(buf, PAGE_SIZE, "%d\n", mode); 3065} 3066 3067static ssize_t fan_pwm1_enable_store(struct device *dev, 3068 struct device_attribute *attr, 3069 const char *buf, size_t count) 3070{ 3071 unsigned long t; 3072 int res, level; 3073 3074 if (parse_strtoul(buf, 2, &t)) 3075 return -EINVAL; 3076 3077 switch (t) { 3078 case 0: 3079 level = TP_EC_FAN_FULLSPEED; 3080 break; 3081 case 1: 3082 level = TPACPI_FAN_LAST_LEVEL; 3083 break; 3084 case 2: 3085 level = TP_EC_FAN_AUTO; 3086 break; 3087 case 3: 3088 /* reserved for software-controlled auto mode */ 3089 return -ENOSYS; 3090 default: 3091 return -EINVAL; 3092 } 3093 3094 res = fan_set_level_safe(level); 3095 if (res == -ENXIO) 3096 return -EINVAL; 3097 else if (res < 0) 3098 return res; 3099 3100 fan_watchdog_reset(); 3101 3102 return count; 3103} 3104 3105static struct device_attribute dev_attr_fan_pwm1_enable = 3106 __ATTR(pwm1_enable, S_IWUSR | S_IRUGO, 3107 fan_pwm1_enable_show, fan_pwm1_enable_store); 3108 3109/* sysfs fan pwm1 ------------------------------------------------------ */ 3110static ssize_t fan_pwm1_show(struct device *dev, 3111 struct device_attribute *attr, 3112 char *buf) 3113{ 3114 int res; 3115 u8 status; 3116 3117 res = fan_get_status_safe(&status); 3118 if (res) 3119 return res; 3120 3121 if (unlikely(tp_features.fan_ctrl_status_undef)) { 3122 if (status != fan_control_initial_status) { 3123 tp_features.fan_ctrl_status_undef = 0; 3124 } else { 3125 status = TP_EC_FAN_AUTO; 3126 } 3127 } 3128 3129 if ((status & 3130 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0) 3131 status = fan_control_desired_level; 3132 3133 if (status > 7) 3134 status = 7; 3135 3136 return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7); 3137} 3138 3139static ssize_t fan_pwm1_store(struct device *dev, 3140 struct device_attribute *attr, 3141 const char *buf, size_t count) 3142{ 3143 unsigned long s; 3144 int rc; 3145 u8 status, newlevel; 3146 3147 if (parse_strtoul(buf, 255, &s)) 3148 return -EINVAL; 3149 3150 /* scale down from 0-255 to 0-7 */ 3151 newlevel = (s >> 5) & 0x07; 3152 3153 rc = mutex_lock_interruptible(&fan_mutex); 3154 if (rc < 0) 3155 return rc; 3156 3157 rc = fan_get_status(&status); 3158 if (!rc && (status & 3159 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { 3160 rc = fan_set_level(newlevel); 3161 if (rc == -ENXIO) 3162 rc = -EINVAL; 3163 else if (!rc) { 3164 fan_update_desired_level(newlevel); 3165 fan_watchdog_reset(); 3166 } 3167 } 3168 3169 mutex_unlock(&fan_mutex); 3170 return (rc)? rc : count; 3171} 3172 3173static struct device_attribute dev_attr_fan_pwm1 = 3174 __ATTR(pwm1, S_IWUSR | S_IRUGO, 3175 fan_pwm1_show, fan_pwm1_store); 3176 3177/* sysfs fan fan1_input ------------------------------------------------ */ 3178static ssize_t fan_fan1_input_show(struct device *dev, 3179 struct device_attribute *attr, 3180 char *buf) 3181{ 3182 int res; 3183 unsigned int speed; 3184 3185 res = fan_get_speed(&speed); 3186 if (res < 0) 3187 return res; 3188 3189 return snprintf(buf, PAGE_SIZE, "%u\n", speed); 3190} 3191 3192static struct device_attribute dev_attr_fan_fan1_input = 3193 __ATTR(fan1_input, S_IRUGO, 3194 fan_fan1_input_show, NULL); 3195 3196/* sysfs fan fan_watchdog (driver) ------------------------------------- */ 3197static ssize_t fan_fan_watchdog_show(struct device_driver *drv, 3198 char *buf) 3199{ 3200 return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval); 3201} 3202 3203static ssize_t fan_fan_watchdog_store(struct device_driver *drv, 3204 const char *buf, size_t count) 3205{ 3206 unsigned long t; 3207 3208 if (parse_strtoul(buf, 120, &t)) 3209 return -EINVAL; 3210 3211 if (!fan_control_allowed) 3212 return -EPERM; 3213 3214 fan_watchdog_maxinterval = t; 3215 fan_watchdog_reset(); 3216 3217 return count; 3218} 3219 3220static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO, 3221 fan_fan_watchdog_show, fan_fan_watchdog_store); 3222 3223/* --------------------------------------------------------------------- */ 3224static struct attribute *fan_attributes[] = { 3225 &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr, 3226 &dev_attr_fan_fan1_input.attr, 3227 NULL 3228}; 3229 3230static const struct attribute_group fan_attr_group = { 3231 .attrs = fan_attributes, 3232}; 3233 3234static int __init fan_init(struct ibm_init_struct *iibm) 3235{ 3236 int rc; 3237 3238 vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); 3239 3240 mutex_init(&fan_mutex); 3241 fan_status_access_mode = TPACPI_FAN_NONE; 3242 fan_control_access_mode = TPACPI_FAN_WR_NONE; 3243 fan_control_commands = 0; 3244 fan_watchdog_maxinterval = 0; 3245 tp_features.fan_ctrl_status_undef = 0; 3246 fan_control_desired_level = 7; 3247 3248 IBM_ACPIHANDLE_INIT(fans); 3249 IBM_ACPIHANDLE_INIT(gfan); 3250 IBM_ACPIHANDLE_INIT(sfan); 3251 3252 if (gfan_handle) { 3253 /* 570, 600e/x, 770e, 770x */ 3254 fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; 3255 } else { 3256 /* all other ThinkPads: note that even old-style 3257 * ThinkPad ECs supports the fan control register */ 3258 if (likely(acpi_ec_read(fan_status_offset, 3259 &fan_control_initial_status))) { 3260 fan_status_access_mode = TPACPI_FAN_RD_TPEC; 3261 3262 /* In some ThinkPads, neither the EC nor the ACPI 3263 * DSDT initialize the fan status, and it ends up 3264 * being set to 0x07 when it *could* be either 3265 * 0x07 or 0x80. 3266 * 3267 * Enable for TP-1Y (T43), TP-78 (R51e), 3268 * TP-76 (R52), TP-70 (T43, R52), which are known 3269 * to be buggy. */ 3270 if (fan_control_initial_status == 0x07 && 3271 ibm_thinkpad_ec_found && 3272 ((ibm_thinkpad_ec_found[0] == '1' && 3273 ibm_thinkpad_ec_found[1] == 'Y') || 3274 (ibm_thinkpad_ec_found[0] == '7' && 3275 (ibm_thinkpad_ec_found[1] == '6' || 3276 ibm_thinkpad_ec_found[1] == '8' || 3277 ibm_thinkpad_ec_found[1] == '0')) 3278 )) { 3279 printk(IBM_NOTICE 3280 "fan_init: initial fan status is " 3281 "unknown, assuming it is in auto " 3282 "mode\n"); 3283 tp_features.fan_ctrl_status_undef = 1; 3284 } 3285 } else { 3286 printk(IBM_ERR 3287 "ThinkPad ACPI EC access misbehaving, " 3288 "fan status and control unavailable\n"); 3289 return 1; 3290 } 3291 } 3292 3293 if (sfan_handle) { 3294 /* 570, 770x-JL */ 3295 fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN; 3296 fan_control_commands |= 3297 TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE; 3298 } else { 3299 if (!gfan_handle) { 3300 /* gfan without sfan means no fan control */ 3301 /* all other models implement TP EC 0x2f control */ 3302 3303 if (fans_handle) { 3304 /* X31, X40, X41 */ 3305 fan_control_access_mode = 3306 TPACPI_FAN_WR_ACPI_FANS; 3307 fan_control_commands |= 3308 TPACPI_FAN_CMD_SPEED | 3309 TPACPI_FAN_CMD_LEVEL | 3310 TPACPI_FAN_CMD_ENABLE; 3311 } else { 3312 fan_control_access_mode = TPACPI_FAN_WR_TPEC; 3313 fan_control_commands |= 3314 TPACPI_FAN_CMD_LEVEL | 3315 TPACPI_FAN_CMD_ENABLE; 3316 } 3317 } 3318 } 3319 3320 vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n", 3321 str_supported(fan_status_access_mode != TPACPI_FAN_NONE || 3322 fan_control_access_mode != TPACPI_FAN_WR_NONE), 3323 fan_status_access_mode, fan_control_access_mode); 3324 3325 /* fan control master switch */ 3326 if (!fan_control_allowed) { 3327 fan_control_access_mode = TPACPI_FAN_WR_NONE; 3328 fan_control_commands = 0; 3329 dbg_printk(TPACPI_DBG_INIT, 3330 "fan control features disabled by parameter\n"); 3331 } 3332 3333 /* update fan_control_desired_level */ 3334 if (fan_status_access_mode != TPACPI_FAN_NONE) 3335 fan_get_status_safe(NULL); 3336 3337 if (fan_status_access_mode != TPACPI_FAN_NONE || 3338 fan_control_access_mode != TPACPI_FAN_WR_NONE) { 3339 rc = sysfs_create_group(&tpacpi_pdev->dev.kobj, 3340 &fan_attr_group); 3341 if (!(rc < 0)) 3342 rc = driver_create_file(&tpacpi_pdriver.driver, 3343 &driver_attr_fan_watchdog); 3344 if (rc < 0) 3345 return rc; 3346 return 0; 3347 } else 3348 return 1; 3349} 3350 3351/* 3352 * Call with fan_mutex held 3353 */ 3354static void fan_update_desired_level(u8 status) 3355{ 3356 if ((status & 3357 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { 3358 if (status > 7) 3359 fan_control_desired_level = 7; 3360 else 3361 fan_control_desired_level = status; 3362 } 3363} 3364 3365static int fan_get_status(u8 *status) 3366{ 3367 u8 s; 3368 3369 /* TODO: 3370 * Add TPACPI_FAN_RD_ACPI_FANS ? */ 3371 3372 switch (fan_status_access_mode) { 3373 case TPACPI_FAN_RD_ACPI_GFAN: 3374 /* 570, 600e/x, 770e, 770x */ 3375 3376 if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) 3377 return -EIO; 3378 3379 if (likely(status)) 3380 *status = s & 0x07; 3381 3382 break; 3383 3384 case TPACPI_FAN_RD_TPEC: 3385 /* all except 570, 600e/x, 770e, 770x */ 3386 if (unlikely(!acpi_ec_read(fan_status_offset, &s))) 3387 return -EIO; 3388 3389 if (likely(status)) 3390 *status = s; 3391 3392 break; 3393 3394 default: 3395 return -ENXIO; 3396 } 3397 3398 return 0; 3399} 3400 3401static int fan_get_status_safe(u8 *status) 3402{ 3403 int rc; 3404 u8 s; 3405 3406 rc = mutex_lock_interruptible(&fan_mutex); 3407 if (rc < 0) 3408 return rc; 3409 rc = fan_get_status(&s); 3410 if (!rc) 3411 fan_update_desired_level(s); 3412 mutex_unlock(&fan_mutex); 3413 3414 if (status) 3415 *status = s; 3416 3417 return rc; 3418} 3419 3420static void fan_exit(void) 3421{ 3422 vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); 3423 3424 sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group); 3425 driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog); 3426 3427 cancel_delayed_work(&fan_watchdog_task); 3428 flush_scheduled_work(); 3429} 3430 3431static int fan_get_speed(unsigned int *speed) 3432{ 3433 u8 hi, lo; 3434 3435 switch (fan_status_access_mode) { 3436 case TPACPI_FAN_RD_TPEC: 3437 /* all except 570, 600e/x, 770e, 770x */ 3438 if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || 3439 !acpi_ec_read(fan_rpm_offset + 1, &hi))) 3440 return -EIO; 3441 3442 if (likely(speed)) 3443 *speed = (hi << 8) | lo; 3444 3445 break; 3446 3447 default: 3448 return -ENXIO; 3449 } 3450 3451 return 0; 3452} 3453 3454static void fan_watchdog_fire(struct work_struct *ignored) 3455{ 3456 int rc; 3457 3458 printk(IBM_NOTICE "fan watchdog: enabling fan\n"); 3459 rc = fan_set_enable(); 3460 if (rc < 0) { 3461 printk(IBM_ERR "fan watchdog: error %d while enabling fan, " 3462 "will try again later...\n", -rc); 3463 /* reschedule for later */ 3464 fan_watchdog_reset(); 3465 } 3466} 3467 3468static void fan_watchdog_reset(void) 3469{ 3470 static int fan_watchdog_active = 0; 3471 3472 if (fan_control_access_mode == TPACPI_FAN_WR_NONE) 3473 return; 3474 3475 if (fan_watchdog_active) 3476 cancel_delayed_work(&fan_watchdog_task); 3477 3478 if (fan_watchdog_maxinterval > 0) { 3479 fan_watchdog_active = 1; 3480 if (!schedule_delayed_work(&fan_watchdog_task, 3481 msecs_to_jiffies(fan_watchdog_maxinterval 3482 * 1000))) { 3483 printk(IBM_ERR "failed to schedule the fan watchdog, " 3484 "watchdog will not trigger\n"); 3485 } 3486 } else 3487 fan_watchdog_active = 0; 3488} 3489 3490static int fan_set_level(int level) 3491{ 3492 if (!fan_control_allowed) 3493 return -EPERM; 3494 3495 switch (fan_control_access_mode) { 3496 case TPACPI_FAN_WR_ACPI_SFAN: 3497 if (level >= 0 && level <= 7) { 3498 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) 3499 return -EIO; 3500 } else 3501 return -EINVAL; 3502 break; 3503 3504 case TPACPI_FAN_WR_ACPI_FANS: 3505 case TPACPI_FAN_WR_TPEC: 3506 if ((level != TP_EC_FAN_AUTO) && 3507 (level != TP_EC_FAN_FULLSPEED) && 3508 ((level < 0) || (level > 7))) 3509 return -EINVAL; 3510 3511 /* safety net should the EC not support AUTO 3512 * or FULLSPEED mode bits and just ignore them */ 3513 if (level & TP_EC_FAN_FULLSPEED) 3514 level |= 7; /* safety min speed 7 */ 3515 else if (level & TP_EC_FAN_FULLSPEED) 3516 level |= 4; /* safety min speed 4 */ 3517 3518 if (!acpi_ec_write(fan_status_offset, level)) 3519 return -EIO; 3520 else 3521 tp_features.fan_ctrl_status_undef = 0; 3522 break; 3523 3524 default: 3525 return -ENXIO; 3526 } 3527 return 0; 3528} 3529 3530static int fan_set_level_safe(int level) 3531{ 3532 int rc; 3533 3534 if (!fan_control_allowed) 3535 return -EPERM; 3536 3537 rc = mutex_lock_interruptible(&fan_mutex); 3538 if (rc < 0) 3539 return rc; 3540 3541 if (level == TPACPI_FAN_LAST_LEVEL) 3542 level = fan_control_desired_level; 3543 3544 rc = fan_set_level(level); 3545 if (!rc) 3546 fan_update_desired_level(level); 3547 3548 mutex_unlock(&fan_mutex); 3549 return rc; 3550} 3551 3552static int fan_set_enable(void) 3553{ 3554 u8 s; 3555 int rc; 3556 3557 if (!fan_control_allowed) 3558 return -EPERM; 3559 3560 rc = mutex_lock_interruptible(&fan_mutex); 3561 if (rc < 0) 3562 return rc; 3563 3564 switch (fan_control_access_mode) { 3565 case TPACPI_FAN_WR_ACPI_FANS: 3566 case TPACPI_FAN_WR_TPEC: 3567 rc = fan_get_status(&s); 3568 if (rc < 0) 3569 break; 3570 3571 /* Don't go out of emergency fan mode */ 3572 if (s != 7) { 3573 s &= 0x07; 3574 s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */ 3575 } 3576 3577 if (!acpi_ec_write(fan_status_offset, s)) 3578 rc = -EIO; 3579 else { 3580 tp_features.fan_ctrl_status_undef = 0; 3581 rc = 0; 3582 } 3583 break; 3584 3585 case TPACPI_FAN_WR_ACPI_SFAN: 3586 rc = fan_get_status(&s); 3587 if (rc < 0) 3588 break; 3589 3590 s &= 0x07; 3591 3592 /* Set fan to at least level 4 */ 3593 s |= 4; 3594 3595 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) 3596 rc= -EIO; 3597 else 3598 rc = 0; 3599 break; 3600 3601 default: 3602 rc = -ENXIO; 3603 } 3604 3605 mutex_unlock(&fan_mutex); 3606 return rc; 3607} 3608 3609static int fan_set_disable(void) 3610{ 3611 int rc; 3612 3613 if (!fan_control_allowed) 3614 return -EPERM; 3615 3616 rc = mutex_lock_interruptible(&fan_mutex); 3617 if (rc < 0) 3618 return rc; 3619 3620 rc = 0; 3621 switch (fan_control_access_mode) { 3622 case TPACPI_FAN_WR_ACPI_FANS: 3623 case TPACPI_FAN_WR_TPEC: 3624 if (!acpi_ec_write(fan_status_offset, 0x00)) 3625 rc = -EIO; 3626 else { 3627 fan_control_desired_level = 0; 3628 tp_features.fan_ctrl_status_undef = 0; 3629 } 3630 break; 3631 3632 case TPACPI_FAN_WR_ACPI_SFAN: 3633 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) 3634 rc = -EIO; 3635 else 3636 fan_control_desired_level = 0; 3637 break; 3638 3639 default: 3640 rc = -ENXIO; 3641 } 3642 3643 3644 mutex_unlock(&fan_mutex); 3645 return rc; 3646} 3647 3648static int fan_set_speed(int speed) 3649{ 3650 int rc; 3651 3652 if (!fan_control_allowed) 3653 return -EPERM; 3654 3655 rc = mutex_lock_interruptible(&fan_mutex); 3656 if (rc < 0) 3657 return rc; 3658 3659 rc = 0; 3660 switch (fan_control_access_mode) { 3661 case TPACPI_FAN_WR_ACPI_FANS: 3662 if (speed >= 0 && speed <= 65535) { 3663 if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", 3664 speed, speed, speed)) 3665 rc = -EIO; 3666 } else 3667 rc = -EINVAL; 3668 break; 3669 3670 default: 3671 rc = -ENXIO; 3672 } 3673 3674 mutex_unlock(&fan_mutex); 3675 return rc; 3676} 3677 3678static int fan_read(char *p) 3679{ 3680 int len = 0; 3681 int rc; 3682 u8 status; 3683 unsigned int speed = 0; 3684 3685 switch (fan_status_access_mode) { 3686 case TPACPI_FAN_RD_ACPI_GFAN: 3687 /* 570, 600e/x, 770e, 770x */ 3688 if ((rc = fan_get_status_safe(&status)) < 0) 3689 return rc; 3690 3691 len += sprintf(p + len, "status:\t\t%s\n" 3692 "level:\t\t%d\n", 3693 (status != 0) ? "enabled" : "disabled", status); 3694 break; 3695 3696 case TPACPI_FAN_RD_TPEC: 3697 /* all except 570, 600e/x, 770e, 770x */ 3698 if ((rc = fan_get_status_safe(&status)) < 0) 3699 return rc; 3700 3701 if (unlikely(tp_features.fan_ctrl_status_undef)) { 3702 if (status != fan_control_initial_status) 3703 tp_features.fan_ctrl_status_undef = 0; 3704 else 3705 /* Return most likely status. In fact, it 3706 * might be the only possible status */ 3707 status = TP_EC_FAN_AUTO; 3708 } 3709 3710 len += sprintf(p + len, "status:\t\t%s\n", 3711 (status != 0) ? "enabled" : "disabled"); 3712 3713 if ((rc = fan_get_speed(&speed)) < 0) 3714 return rc; 3715 3716 len += sprintf(p + len, "speed:\t\t%d\n", speed); 3717 3718 if (status & TP_EC_FAN_FULLSPEED) 3719 /* Disengaged mode takes precedence */ 3720 len += sprintf(p + len, "level:\t\tdisengaged\n"); 3721 else if (status & TP_EC_FAN_AUTO) 3722 len += sprintf(p + len, "level:\t\tauto\n"); 3723 else 3724 len += sprintf(p + len, "level:\t\t%d\n", status); 3725 break; 3726 3727 case TPACPI_FAN_NONE: 3728 default: 3729 len += sprintf(p + len, "status:\t\tnot supported\n"); 3730 } 3731 3732 if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) { 3733 len += sprintf(p + len, "commands:\tlevel <level>"); 3734 3735 switch (fan_control_access_mode) { 3736 case TPACPI_FAN_WR_ACPI_SFAN: 3737 len += sprintf(p + len, " (<level> is 0-7)\n"); 3738 break; 3739 3740 default: 3741 len += sprintf(p + len, " (<level> is 0-7, " 3742 "auto, disengaged, full-speed)\n"); 3743 break; 3744 } 3745 } 3746 3747 if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) 3748 len += sprintf(p + len, "commands:\tenable, disable\n" 3749 "commands:\twatchdog <timeout> (<timeout> is 0 (off), " 3750 "1-120 (seconds))\n"); 3751 3752 if (fan_control_commands & TPACPI_FAN_CMD_SPEED) 3753 len += sprintf(p + len, "commands:\tspeed <speed>" 3754 " (<speed> is 0-65535)\n"); 3755 3756 return len; 3757} 3758 3759static int fan_write_cmd_level(const char *cmd, int *rc) 3760{ 3761 int level; 3762 3763 if (strlencmp(cmd, "level auto") == 0) 3764 level = TP_EC_FAN_AUTO; 3765 else if ((strlencmp(cmd, "level disengaged") == 0) | 3766 (strlencmp(cmd, "level full-speed") == 0)) 3767 level = TP_EC_FAN_FULLSPEED; 3768 else if (sscanf(cmd, "level %d", &level) != 1) 3769 return 0; 3770 3771 if ((*rc = fan_set_level_safe(level)) == -ENXIO) 3772 printk(IBM_ERR "level command accepted for unsupported " 3773 "access mode %d", fan_control_access_mode); 3774 3775 return 1; 3776} 3777 3778static int fan_write_cmd_enable(const char *cmd, int *rc) 3779{ 3780 if (strlencmp(cmd, "enable") != 0) 3781 return 0; 3782 3783 if ((*rc = fan_set_enable()) == -ENXIO) 3784 printk(IBM_ERR "enable command accepted for unsupported " 3785 "access mode %d", fan_control_access_mode); 3786 3787 return 1; 3788} 3789 3790static int fan_write_cmd_disable(const char *cmd, int *rc) 3791{ 3792 if (strlencmp(cmd, "disable") != 0) 3793 return 0; 3794 3795 if ((*rc = fan_set_disable()) == -ENXIO) 3796 printk(IBM_ERR "disable command accepted for unsupported " 3797 "access mode %d", fan_control_access_mode); 3798 3799 return 1; 3800} 3801 3802static int fan_write_cmd_speed(const char *cmd, int *rc) 3803{ 3804 int speed; 3805 3806 /* TODO: 3807 * Support speed <low> <medium> <high> ? */ 3808 3809 if (sscanf(cmd, "speed %d", &speed) != 1) 3810 return 0; 3811 3812 if ((*rc = fan_set_speed(speed)) == -ENXIO) 3813 printk(IBM_ERR "speed command accepted for unsupported " 3814 "access mode %d", fan_control_access_mode); 3815 3816 return 1; 3817} 3818 3819static int fan_write_cmd_watchdog(const char *cmd, int *rc) 3820{ 3821 int interval; 3822 3823 if (sscanf(cmd, "watchdog %d", &interval) != 1) 3824 return 0; 3825 3826 if (interval < 0 || interval > 120) 3827 *rc = -EINVAL; 3828 else 3829 fan_watchdog_maxinterval = interval; 3830 3831 return 1; 3832} 3833 3834static int fan_write(char *buf) 3835{ 3836 char *cmd; 3837 int rc = 0; 3838 3839 while (!rc && (cmd = next_cmd(&buf))) { 3840 if (!((fan_control_commands & TPACPI_FAN_CMD_LEVEL) && 3841 fan_write_cmd_level(cmd, &rc)) && 3842 !((fan_control_commands & TPACPI_FAN_CMD_ENABLE) && 3843 (fan_write_cmd_enable(cmd, &rc) || 3844 fan_write_cmd_disable(cmd, &rc) || 3845 fan_write_cmd_watchdog(cmd, &rc))) && 3846 !((fan_control_commands & TPACPI_FAN_CMD_SPEED) && 3847 fan_write_cmd_speed(cmd, &rc)) 3848 ) 3849 rc = -EINVAL; 3850 else if (!rc) 3851 fan_watchdog_reset(); 3852 } 3853 3854 return rc; 3855} 3856 3857static struct ibm_struct fan_driver_data = { 3858 .name = "fan", 3859 .read = fan_read, 3860 .write = fan_write, 3861 .exit = fan_exit, 3862}; 3863 3864/**************************************************************************** 3865 **************************************************************************** 3866 * 3867 * Infrastructure 3868 * 3869 **************************************************************************** 3870 ****************************************************************************/ 3871 3872/* /proc support */ 3873static struct proc_dir_entry *proc_dir = NULL; 3874 3875/* Subdriver registry */ 3876static LIST_HEAD(tpacpi_all_drivers); 3877 3878 3879/* 3880 * Module and infrastructure proble, init and exit handling 3881 */ 3882 3883#ifdef CONFIG_THINKPAD_ACPI_DEBUG 3884static const char * __init str_supported(int is_supported) 3885{ 3886 static char text_unsupported[] __initdata = "not supported"; 3887 3888 return (is_supported)? &text_unsupported[4] : &text_unsupported[0]; 3889} 3890#endif /* CONFIG_THINKPAD_ACPI_DEBUG */ 3891 3892static int __init ibm_init(struct ibm_init_struct *iibm) 3893{ 3894 int ret; 3895 struct ibm_struct *ibm = iibm->data; 3896 struct proc_dir_entry *entry; 3897 3898 BUG_ON(ibm == NULL); 3899 3900 INIT_LIST_HEAD(&ibm->all_drivers); 3901 3902 if (ibm->flags.experimental && !experimental) 3903 return 0; 3904 3905 dbg_printk(TPACPI_DBG_INIT, 3906 "probing for %s\n", ibm->name); 3907 3908 if (iibm->init) { 3909 ret = iibm->init(iibm); 3910 if (ret > 0) 3911 return 0; /* probe failed */ 3912 if (ret) 3913 return ret; 3914 3915 ibm->flags.init_called = 1; 3916 } 3917 3918 if (ibm->acpi) { 3919 if (ibm->acpi->hid) { 3920 ret = register_tpacpi_subdriver(ibm); 3921 if (ret) 3922 goto err_out; 3923 } 3924 3925 if (ibm->acpi->notify) { 3926 ret = setup_acpi_notify(ibm); 3927 if (ret == -ENODEV) { 3928 printk(IBM_NOTICE "disabling subdriver %s\n", 3929 ibm->name); 3930 ret = 0; 3931 goto err_out; 3932 } 3933 if (ret < 0) 3934 goto err_out; 3935 } 3936 } 3937 3938 dbg_printk(TPACPI_DBG_INIT, 3939 "%s installed\n", ibm->name); 3940 3941 if (ibm->read) { 3942 entry = create_proc_entry(ibm->name, 3943 S_IFREG | S_IRUGO | S_IWUSR, 3944 proc_dir); 3945 if (!entry) { 3946 printk(IBM_ERR "unable to create proc entry %s\n", 3947 ibm->name); 3948 ret = -ENODEV; 3949 goto err_out; 3950 } 3951 entry->owner = THIS_MODULE; 3952 entry->data = ibm; 3953 entry->read_proc = &dispatch_procfs_read; 3954 if (ibm->write) 3955 entry->write_proc = &dispatch_procfs_write; 3956 ibm->flags.proc_created = 1; 3957 } 3958 3959 list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers); 3960 3961 return 0; 3962 3963err_out: 3964 dbg_printk(TPACPI_DBG_INIT, 3965 "%s: at error exit path with result %d\n", 3966 ibm->name, ret); 3967 3968 ibm_exit(ibm); 3969 return (ret < 0)? ret : 0; 3970} 3971 3972static void ibm_exit(struct ibm_struct *ibm) 3973{ 3974 dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name); 3975 3976 list_del_init(&ibm->all_drivers); 3977 3978 if (ibm->flags.acpi_notify_installed) { 3979 dbg_printk(TPACPI_DBG_EXIT, 3980 "%s: acpi_remove_notify_handler\n", ibm->name); 3981 BUG_ON(!ibm->acpi); 3982 acpi_remove_notify_handler(*ibm->acpi->handle, 3983 ibm->acpi->type, 3984 dispatch_acpi_notify); 3985 ibm->flags.acpi_notify_installed = 0; 3986 ibm->flags.acpi_notify_installed = 0; 3987 } 3988 3989 if (ibm->flags.proc_created) { 3990 dbg_printk(TPACPI_DBG_EXIT, 3991 "%s: remove_proc_entry\n", ibm->name); 3992 remove_proc_entry(ibm->name, proc_dir); 3993 ibm->flags.proc_created = 0; 3994 } 3995 3996 if (ibm->flags.acpi_driver_registered) { 3997 dbg_printk(TPACPI_DBG_EXIT, 3998 "%s: acpi_bus_unregister_driver\n", ibm->name); 3999 BUG_ON(!ibm->acpi); 4000 acpi_bus_unregister_driver(ibm->acpi->driver); 4001 kfree(ibm->acpi->driver); 4002 ibm->acpi->driver = NULL; 4003 ibm->flags.acpi_driver_registered = 0; 4004 } 4005 4006 if (ibm->flags.init_called && ibm->exit) { 4007 ibm->exit(); 4008 ibm->flags.init_called = 0; 4009 } 4010 4011 dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name); 4012} 4013 4014/* Probing */ 4015 4016static char *ibm_thinkpad_ec_found = NULL; 4017 4018static char* __init check_dmi_for_ec(void) 4019{ 4020 struct dmi_device *dev = NULL; 4021 char ec_fw_string[18]; 4022 4023 /* 4024 * ThinkPad T23 or newer, A31 or newer, R50e or newer, 4025 * X32 or newer, all Z series; Some models must have an 4026 * up-to-date BIOS or they will not be detected. 4027 * 4028 * See http://thinkwiki.org/wiki/List_of_DMI_IDs 4029 */ 4030 while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { 4031 if (sscanf(dev->name, 4032 "IBM ThinkPad Embedded Controller -[%17c", 4033 ec_fw_string) == 1) { 4034 ec_fw_string[sizeof(ec_fw_string) - 1] = 0; 4035 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; 4036 return kstrdup(ec_fw_string, GFP_KERNEL); 4037 } 4038 } 4039 return NULL; 4040} 4041 4042static int __init probe_for_thinkpad(void) 4043{ 4044 int is_thinkpad; 4045 4046 if (acpi_disabled) 4047 return -ENODEV; 4048 4049 /* 4050 * Non-ancient models have better DMI tagging, but very old models 4051 * don't. 4052 */ 4053 is_thinkpad = dmi_name_in_vendors("ThinkPad"); 4054 4055 /* ec is required because many other handles are relative to it */ 4056 IBM_ACPIHANDLE_INIT(ec); 4057 if (!ec_handle) { 4058 if (is_thinkpad) 4059 printk(IBM_ERR 4060 "Not yet supported ThinkPad detected!\n"); 4061 return -ENODEV; 4062 } 4063 4064 /* 4065 * Risks a regression on very old machines, but reduces potential 4066 * false positives a damn great deal 4067 */ 4068 if (!is_thinkpad) 4069 is_thinkpad = dmi_name_in_vendors("IBM"); 4070 4071 if (!is_thinkpad && !force_load) 4072 return -ENODEV; 4073 4074 return 0; 4075} 4076 4077 4078/* Module init, exit, parameters */ 4079 4080static struct ibm_init_struct ibms_init[] __initdata = { 4081 { 4082 .init = thinkpad_acpi_driver_init, 4083 .data = &thinkpad_acpi_driver_data, 4084 }, 4085 { 4086 .init = hotkey_init, 4087 .data = &hotkey_driver_data, 4088 }, 4089 { 4090 .init = bluetooth_init, 4091 .data = &bluetooth_driver_data, 4092 }, 4093 { 4094 .init = wan_init, 4095 .data = &wan_driver_data, 4096 }, 4097 { 4098 .init = video_init, 4099 .data = &video_driver_data, 4100 }, 4101 { 4102 .init = light_init, 4103 .data = &light_driver_data, 4104 }, 4105#ifdef CONFIG_THINKPAD_ACPI_DOCK 4106 { 4107 .init = dock_init, 4108 .data = &dock_driver_data[0], 4109 }, 4110 { 4111 .init = dock_init2, 4112 .data = &dock_driver_data[1], 4113 }, 4114#endif 4115#ifdef CONFIG_THINKPAD_ACPI_BAY 4116 { 4117 .init = bay_init, 4118 .data = &bay_driver_data, 4119 }, 4120#endif 4121 { 4122 .init = cmos_init, 4123 .data = &cmos_driver_data, 4124 }, 4125 { 4126 .init = led_init, 4127 .data = &led_driver_data, 4128 }, 4129 { 4130 .init = beep_init, 4131 .data = &beep_driver_data, 4132 }, 4133 { 4134 .init = thermal_init, 4135 .data = &thermal_driver_data, 4136 }, 4137 { 4138 .data = &ecdump_driver_data, 4139 }, 4140 { 4141 .init = brightness_init, 4142 .data = &brightness_driver_data, 4143 }, 4144 { 4145 .data = &volume_driver_data, 4146 }, 4147 { 4148 .init = fan_init, 4149 .data = &fan_driver_data, 4150 }, 4151}; 4152 4153static int __init set_ibm_param(const char *val, struct kernel_param *kp) 4154{ 4155 unsigned int i; 4156 struct ibm_struct *ibm; 4157 4158 for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { 4159 ibm = ibms_init[i].data; 4160 BUG_ON(ibm == NULL); 4161 4162 if (strcmp(ibm->name, kp->name) == 0 && ibm->write) { 4163 if (strlen(val) > sizeof(ibms_init[i].param) - 2) 4164 return -ENOSPC; 4165 strcpy(ibms_init[i].param, val); 4166 strcat(ibms_init[i].param, ","); 4167 return 0; 4168 } 4169 } 4170 4171 return -EINVAL; 4172} 4173 4174static int experimental; 4175module_param(experimental, int, 0); 4176 4177static u32 dbg_level; 4178module_param_named(debug, dbg_level, uint, 0); 4179 4180static int force_load; 4181module_param(force_load, int, 0); 4182 4183static int fan_control_allowed; 4184module_param_named(fan_control, fan_control_allowed, int, 0); 4185 4186#define IBM_PARAM(feature) \ 4187 module_param_call(feature, set_ibm_param, NULL, NULL, 0) 4188 4189IBM_PARAM(hotkey); 4190IBM_PARAM(bluetooth); 4191IBM_PARAM(video); 4192IBM_PARAM(light); 4193#ifdef CONFIG_THINKPAD_ACPI_DOCK 4194IBM_PARAM(dock); 4195#endif 4196#ifdef CONFIG_THINKPAD_ACPI_BAY 4197IBM_PARAM(bay); 4198#endif /* CONFIG_THINKPAD_ACPI_BAY */ 4199IBM_PARAM(cmos); 4200IBM_PARAM(led); 4201IBM_PARAM(beep); 4202IBM_PARAM(ecdump); 4203IBM_PARAM(brightness); 4204IBM_PARAM(volume); 4205IBM_PARAM(fan); 4206 4207static int __init thinkpad_acpi_module_init(void) 4208{ 4209 int ret, i; 4210 4211 /* Driver-level probe */ 4212 ret = probe_for_thinkpad(); 4213 if (ret) 4214 return ret; 4215 4216 /* Driver initialization */ 4217 ibm_thinkpad_ec_found = check_dmi_for_ec(); 4218 IBM_ACPIHANDLE_INIT(ecrd); 4219 IBM_ACPIHANDLE_INIT(ecwr); 4220 4221 proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir); 4222 if (!proc_dir) { 4223 printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR); 4224 thinkpad_acpi_module_exit(); 4225 return -ENODEV; 4226 } 4227 proc_dir->owner = THIS_MODULE; 4228 4229 ret = platform_driver_register(&tpacpi_pdriver); 4230 if (ret) { 4231 printk(IBM_ERR "unable to register platform driver\n"); 4232 thinkpad_acpi_module_exit(); 4233 return ret; 4234 } 4235 ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); 4236 if (ret) { 4237 printk(IBM_ERR "unable to create sysfs driver attributes\n"); 4238 thinkpad_acpi_module_exit(); 4239 return ret; 4240 } 4241 4242 4243 /* Device initialization */ 4244 tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1, 4245 NULL, 0); 4246 if (IS_ERR(tpacpi_pdev)) { 4247 ret = PTR_ERR(tpacpi_pdev); 4248 tpacpi_pdev = NULL; 4249 printk(IBM_ERR "unable to register platform device\n"); 4250 thinkpad_acpi_module_exit(); 4251 return ret; 4252 } 4253 tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev); 4254 if (IS_ERR(tpacpi_hwmon)) { 4255 ret = PTR_ERR(tpacpi_hwmon); 4256 tpacpi_hwmon = NULL; 4257 printk(IBM_ERR "unable to register hwmon device\n"); 4258 thinkpad_acpi_module_exit(); 4259 return ret; 4260 } 4261 for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { 4262 ret = ibm_init(&ibms_init[i]); 4263 if (ret >= 0 && *ibms_init[i].param) 4264 ret = ibms_init[i].data->write(ibms_init[i].param); 4265 if (ret < 0) { 4266 thinkpad_acpi_module_exit(); 4267 return ret; 4268 } 4269 } 4270 4271 return 0; 4272} 4273 4274static void thinkpad_acpi_module_exit(void) 4275{ 4276 struct ibm_struct *ibm, *itmp; 4277 4278 list_for_each_entry_safe_reverse(ibm, itmp, 4279 &tpacpi_all_drivers, 4280 all_drivers) { 4281 ibm_exit(ibm); 4282 } 4283 4284 dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); 4285 4286 if (tpacpi_hwmon) 4287 hwmon_device_unregister(tpacpi_hwmon); 4288 4289 if (tpacpi_pdev) 4290 platform_device_unregister(tpacpi_pdev); 4291 4292 tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); 4293 platform_driver_unregister(&tpacpi_pdriver); 4294 4295 if (proc_dir) 4296 remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); 4297 4298 kfree(ibm_thinkpad_ec_found); 4299} 4300 4301module_init(thinkpad_acpi_module_init); 4302module_exit(thinkpad_acpi_module_exit); 4303