2 * thinkpad_acpi.c - ThinkPad ACPI Extras
5 * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
6 * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
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.
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.
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
24 #define IBM_VERSION "0.17"
25 #define TPACPI_SYSFS_VERSION 0x020000
29 * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to
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.
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
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
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
85 #include "thinkpad_acpi.h"
87 MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
88 MODULE_DESCRIPTION(IBM_DESC);
89 MODULE_VERSION(IBM_VERSION);
90 MODULE_LICENSE("GPL");
92 /* Please remove this in year 2009 */
93 MODULE_ALIAS("ibm_acpi");
96 * DMI matching for module autoloading
98 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
99 * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
101 * Only models listed in thinkwiki will be supported, so add yours
102 * if it is not there yet.
104 #define IBM_BIOS_MODULE_ALIAS(__type) \
105 MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
107 /* Non-ancient thinkpads */
108 MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
109 MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
111 /* Ancient thinkpad BIOSes have to be identified by
112 * BIOS type or model number, and there are far less
113 * BIOS types than model numbers... */
114 IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
115 IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
116 IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
118 #define __unused __attribute__ ((unused))
121 TPACPI_LIFE_INIT = 0,
126 /****************************************************************************
127 ****************************************************************************
129 * ACPI Helpers and device model
131 ****************************************************************************
132 ****************************************************************************/
134 /*************************************************************************
138 static acpi_handle root_handle;
140 #define IBM_HANDLE(object, parent, paths...) \
141 static acpi_handle object##_handle; \
142 static acpi_handle *object##_parent = &parent##_handle; \
143 static char *object##_path; \
144 static char *object##_paths[] = { paths }
146 IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
147 "\\_SB.PCI.ISA.EC", /* 570 */
148 "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
149 "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
150 "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */
151 "\\_SB.PCI0.ICH3.EC0", /* R31 */
152 "\\_SB.PCI0.LPC.EC", /* all others */
155 IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
156 IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
159 /*************************************************************************
163 IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */
164 "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
165 "\\CMS", /* R40, R40e */
168 IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
169 "^HKEY", /* R30, R31 */
170 "HKEY", /* all others */
174 /*************************************************************************
178 static int acpi_evalf(acpi_handle handle,
179 void *res, char *method, char *fmt, ...)
182 struct acpi_object_list params;
183 union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
184 struct acpi_buffer result, *resultp;
185 union acpi_object out_obj;
193 printk(IBM_ERR "acpi_evalf() called with empty format\n");
206 params.pointer = &in_objs[0];
213 in_objs[params.count].integer.value = va_arg(ap, int);
214 in_objs[params.count++].type = ACPI_TYPE_INTEGER;
216 /* add more types as needed */
218 printk(IBM_ERR "acpi_evalf() called "
219 "with invalid format character '%c'\n", c);
225 if (res_type != 'v') {
226 result.length = sizeof(out_obj);
227 result.pointer = &out_obj;
232 status = acpi_evaluate_object(handle, method, ¶ms, resultp);
237 *(int *)res = out_obj.integer.value;
238 success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
241 success = status == AE_OK;
243 /* add more types as needed */
245 printk(IBM_ERR "acpi_evalf() called "
246 "with invalid format character '%c'\n", res_type);
250 if (!success && !quiet)
251 printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
252 method, fmt0, status);
257 static void __unused acpi_print_int(acpi_handle handle, char *method)
261 if (acpi_evalf(handle, &i, method, "d"))
262 printk(IBM_INFO "%s = 0x%x\n", method, i);
264 printk(IBM_ERR "error calling %s\n", method);
267 static int acpi_ec_read(int i, u8 * p)
272 if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
276 if (ec_read(i, p) < 0)
283 static int acpi_ec_write(int i, u8 v)
286 if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
289 if (ec_write(i, v) < 0)
296 static int _sta(acpi_handle handle)
300 if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
306 static int issue_thinkpad_cmos_command(int cmos_cmd)
311 if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd))
317 /*************************************************************************
321 static void drv_acpi_handle_init(char *name,
322 acpi_handle *handle, acpi_handle parent,
323 char **paths, int num_paths, char **path)
328 vdbg_printk(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n",
331 for (i = 0; i < num_paths; i++) {
332 status = acpi_get_handle(parent, paths[i], handle);
333 if (ACPI_SUCCESS(status)) {
335 dbg_printk(TPACPI_DBG_INIT,
336 "Found ACPI handle %s for %s\n",
342 vdbg_printk(TPACPI_DBG_INIT, "ACPI handle for %s not found\n",
347 static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data)
349 struct ibm_struct *ibm = data;
351 if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
354 if (!ibm || !ibm->acpi || !ibm->acpi->notify)
357 ibm->acpi->notify(ibm, event);
360 static int __init setup_acpi_notify(struct ibm_struct *ibm)
367 if (!*ibm->acpi->handle)
370 vdbg_printk(TPACPI_DBG_INIT,
371 "setting up ACPI notify for %s\n", ibm->name);
373 rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
375 printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n",
380 acpi_driver_data(ibm->acpi->device) = ibm;
381 sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
382 IBM_ACPI_EVENT_PREFIX,
385 status = acpi_install_notify_handler(*ibm->acpi->handle,
386 ibm->acpi->type, dispatch_acpi_notify, ibm);
387 if (ACPI_FAILURE(status)) {
388 if (status == AE_ALREADY_EXISTS) {
389 printk(IBM_NOTICE "another device driver is already handling %s events\n",
392 printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
397 ibm->flags.acpi_notify_installed = 1;
401 static int __init tpacpi_device_add(struct acpi_device *device)
406 static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
410 dbg_printk(TPACPI_DBG_INIT,
411 "registering %s as an ACPI driver\n", ibm->name);
415 ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
416 if (!ibm->acpi->driver) {
417 printk(IBM_ERR "kzalloc(ibm->driver) failed\n");
421 sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name);
422 ibm->acpi->driver->ids = ibm->acpi->hid;
424 ibm->acpi->driver->ops.add = &tpacpi_device_add;
426 rc = acpi_bus_register_driver(ibm->acpi->driver);
428 printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
430 kfree(ibm->acpi->driver);
431 ibm->acpi->driver = NULL;
433 ibm->flags.acpi_driver_registered = 1;
439 /****************************************************************************
440 ****************************************************************************
444 ****************************************************************************
445 ****************************************************************************/
447 static int dispatch_procfs_read(char *page, char **start, off_t off,
448 int count, int *eof, void *data)
450 struct ibm_struct *ibm = data;
453 if (!ibm || !ibm->read)
456 len = ibm->read(page);
460 if (len <= off + count)
472 static int dispatch_procfs_write(struct file *file,
473 const char __user * userbuf,
474 unsigned long count, void *data)
476 struct ibm_struct *ibm = data;
480 if (!ibm || !ibm->write)
483 kernbuf = kmalloc(count + 2, GFP_KERNEL);
487 if (copy_from_user(kernbuf, userbuf, count)) {
493 strcat(kernbuf, ",");
494 ret = ibm->write(kernbuf);
503 static char *next_cmd(char **cmds)
508 while ((end = strchr(start, ',')) && end == start)
520 /****************************************************************************
521 ****************************************************************************
523 * Device model: input, hwmon and platform
525 ****************************************************************************
526 ****************************************************************************/
528 static struct platform_device *tpacpi_pdev;
529 static struct platform_device *tpacpi_sensors_pdev;
530 static struct device *tpacpi_hwmon;
531 static struct input_dev *tpacpi_inputdev;
532 static struct mutex tpacpi_inputdev_send_mutex;
535 static int tpacpi_resume_handler(struct platform_device *pdev)
537 struct ibm_struct *ibm, *itmp;
539 list_for_each_entry_safe(ibm, itmp,
549 static struct platform_driver tpacpi_pdriver = {
551 .name = IBM_DRVR_NAME,
552 .owner = THIS_MODULE,
554 .resume = tpacpi_resume_handler,
557 static struct platform_driver tpacpi_hwmon_pdriver = {
559 .name = IBM_HWMON_DRVR_NAME,
560 .owner = THIS_MODULE,
564 /*************************************************************************
565 * thinkpad-acpi driver attributes
568 /* interface_version --------------------------------------------------- */
569 static ssize_t tpacpi_driver_interface_version_show(
570 struct device_driver *drv,
573 return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
576 static DRIVER_ATTR(interface_version, S_IRUGO,
577 tpacpi_driver_interface_version_show, NULL);
579 /* debug_level --------------------------------------------------------- */
580 static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
583 return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
586 static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
587 const char *buf, size_t count)
591 if (parse_strtoul(buf, 0xffff, &t))
599 static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
600 tpacpi_driver_debug_show, tpacpi_driver_debug_store);
602 /* version ------------------------------------------------------------- */
603 static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
606 return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION);
609 static DRIVER_ATTR(version, S_IRUGO,
610 tpacpi_driver_version_show, NULL);
612 /* --------------------------------------------------------------------- */
614 static struct driver_attribute* tpacpi_driver_attributes[] = {
615 &driver_attr_debug_level, &driver_attr_version,
616 &driver_attr_interface_version,
619 static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
625 while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
626 res = driver_create_file(drv, tpacpi_driver_attributes[i]);
633 static void tpacpi_remove_driver_attributes(struct device_driver *drv)
637 for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
638 driver_remove_file(drv, tpacpi_driver_attributes[i]);
641 /*************************************************************************
642 * sysfs support helpers
645 struct attribute_set_obj {
646 struct attribute_set s;
648 } __attribute__((packed));
650 static struct attribute_set *create_attr_set(unsigned int max_members,
653 struct attribute_set_obj *sobj;
655 if (max_members == 0)
658 /* Allocates space for implicit NULL at the end too */
659 sobj = kzalloc(sizeof(struct attribute_set_obj) +
660 max_members * sizeof(struct attribute *),
664 sobj->s.max_members = max_members;
665 sobj->s.group.attrs = &sobj->a;
666 sobj->s.group.name = name;
671 /* not multi-threaded safe, use it in a single thread per set */
672 static int add_to_attr_set(struct attribute_set* s, struct attribute *attr)
677 if (s->members >= s->max_members)
680 s->group.attrs[s->members] = attr;
686 static int add_many_to_attr_set(struct attribute_set* s,
687 struct attribute **attr,
692 for (i = 0; i < count; i++) {
693 res = add_to_attr_set(s, attr[i]);
701 static void delete_attr_set(struct attribute_set* s, struct kobject *kobj)
703 sysfs_remove_group(kobj, &s->group);
707 static int parse_strtoul(const char *buf,
708 unsigned long max, unsigned long *value)
712 while (*buf && isspace(*buf))
714 *value = simple_strtoul(buf, &endp, 0);
715 while (*endp && isspace(*endp))
717 if (*endp || *value > max)
723 /****************************************************************************
724 ****************************************************************************
728 ****************************************************************************
729 ****************************************************************************/
731 /*************************************************************************
732 * thinkpad-acpi init subdriver
735 static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
737 printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
738 printk(IBM_INFO "%s\n", IBM_URL);
740 printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n",
741 (thinkpad_id.bios_version_str) ?
742 thinkpad_id.bios_version_str : "unknown",
743 (thinkpad_id.ec_version_str) ?
744 thinkpad_id.ec_version_str : "unknown");
746 if (thinkpad_id.vendor && thinkpad_id.model_str)
747 printk(IBM_INFO "%s %s\n",
748 (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
749 "IBM" : ((thinkpad_id.vendor ==
750 PCI_VENDOR_ID_LENOVO) ?
751 "Lenovo" : "Unknown vendor"),
752 thinkpad_id.model_str);
757 static int thinkpad_acpi_driver_read(char *p)
761 len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
762 len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
767 static struct ibm_struct thinkpad_acpi_driver_data = {
769 .read = thinkpad_acpi_driver_read,
772 /*************************************************************************
776 static int hotkey_orig_status;
777 static u32 hotkey_orig_mask;
778 static u32 hotkey_all_mask;
779 static u32 hotkey_reserved_mask;
781 static u16 *hotkey_keycode_map;
783 static struct attribute_set *hotkey_dev_attributes;
785 static int hotkey_get_wlsw(int *status)
787 if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
792 /* sysfs hotkey enable ------------------------------------------------- */
793 static ssize_t hotkey_enable_show(struct device *dev,
794 struct device_attribute *attr,
800 res = hotkey_get(&status, &mask);
804 return snprintf(buf, PAGE_SIZE, "%d\n", status);
807 static ssize_t hotkey_enable_store(struct device *dev,
808 struct device_attribute *attr,
809 const char *buf, size_t count)
815 if (parse_strtoul(buf, 1, &t))
818 res = hotkey_get(&status, &mask);
820 res = hotkey_set(t, mask);
822 return (res) ? res : count;
825 static struct device_attribute dev_attr_hotkey_enable =
826 __ATTR(hotkey_enable, S_IWUSR | S_IRUGO,
827 hotkey_enable_show, hotkey_enable_store);
829 /* sysfs hotkey mask --------------------------------------------------- */
830 static ssize_t hotkey_mask_show(struct device *dev,
831 struct device_attribute *attr,
837 res = hotkey_get(&status, &mask);
841 return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask);
844 static ssize_t hotkey_mask_store(struct device *dev,
845 struct device_attribute *attr,
846 const char *buf, size_t count)
852 if (parse_strtoul(buf, 0xffffffffUL, &t))
855 res = hotkey_get(&status, &mask);
857 hotkey_set(status, t);
859 return (res) ? res : count;
862 static struct device_attribute dev_attr_hotkey_mask =
863 __ATTR(hotkey_mask, S_IWUSR | S_IRUGO,
864 hotkey_mask_show, hotkey_mask_store);
866 /* sysfs hotkey bios_enabled ------------------------------------------- */
867 static ssize_t hotkey_bios_enabled_show(struct device *dev,
868 struct device_attribute *attr,
871 return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status);
874 static struct device_attribute dev_attr_hotkey_bios_enabled =
875 __ATTR(hotkey_bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL);
877 /* sysfs hotkey bios_mask ---------------------------------------------- */
878 static ssize_t hotkey_bios_mask_show(struct device *dev,
879 struct device_attribute *attr,
882 return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask);
885 static struct device_attribute dev_attr_hotkey_bios_mask =
886 __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
888 /* sysfs hotkey all_mask ----------------------------------------------- */
889 static ssize_t hotkey_all_mask_show(struct device *dev,
890 struct device_attribute *attr,
893 return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask);
896 static struct device_attribute dev_attr_hotkey_all_mask =
897 __ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL);
899 /* sysfs hotkey recommended_mask --------------------------------------- */
900 static ssize_t hotkey_recommended_mask_show(struct device *dev,
901 struct device_attribute *attr,
904 return snprintf(buf, PAGE_SIZE, "0x%08x\n",
905 hotkey_all_mask & ~hotkey_reserved_mask);
908 static struct device_attribute dev_attr_hotkey_recommended_mask =
909 __ATTR(hotkey_recommended_mask, S_IRUGO,
910 hotkey_recommended_mask_show, NULL);
912 /* sysfs hotkey radio_sw ----------------------------------------------- */
913 static ssize_t hotkey_radio_sw_show(struct device *dev,
914 struct device_attribute *attr,
918 res = hotkey_get_wlsw(&s);
922 return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
925 static struct device_attribute dev_attr_hotkey_radio_sw =
926 __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
928 /* sysfs hotkey report_mode -------------------------------------------- */
929 static ssize_t hotkey_report_mode_show(struct device *dev,
930 struct device_attribute *attr,
933 return snprintf(buf, PAGE_SIZE, "%d\n",
934 (hotkey_report_mode != 0) ? hotkey_report_mode : 1);
937 static struct device_attribute dev_attr_hotkey_report_mode =
938 __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
940 /* --------------------------------------------------------------------- */
942 static struct attribute *hotkey_attributes[] __initdata = {
943 &dev_attr_hotkey_enable.attr,
944 &dev_attr_hotkey_report_mode.attr,
947 static struct attribute *hotkey_mask_attributes[] __initdata = {
948 &dev_attr_hotkey_mask.attr,
949 &dev_attr_hotkey_bios_enabled.attr,
950 &dev_attr_hotkey_bios_mask.attr,
951 &dev_attr_hotkey_all_mask.attr,
952 &dev_attr_hotkey_recommended_mask.attr,
955 static int __init hotkey_init(struct ibm_init_struct *iibm)
958 static u16 ibm_keycode_map[] __initdata = {
959 /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
960 KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP,
961 KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
962 KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
963 /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
964 KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
965 KEY_UNKNOWN, /* 0x0D: FN+INSERT */
966 KEY_UNKNOWN, /* 0x0E: FN+DELETE */
967 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
968 /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
969 KEY_RESERVED, /* 0x10: FN+END (brightness down) */
970 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
971 KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
972 KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
973 KEY_RESERVED, /* 0x14: VOLUME UP */
974 KEY_RESERVED, /* 0x15: VOLUME DOWN */
975 KEY_RESERVED, /* 0x16: MUTE */
976 KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
977 /* (assignments unknown, please report if found) */
978 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
979 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
981 static u16 lenovo_keycode_map[] __initdata = {
982 /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
983 KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP,
984 KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
985 KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
986 /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
987 KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
988 KEY_UNKNOWN, /* 0x0D: FN+INSERT */
989 KEY_UNKNOWN, /* 0x0E: FN+DELETE */
990 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
991 /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
992 KEY_RESERVED, /* 0x10: FN+END (brightness down) */
993 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
994 KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
995 KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
996 KEY_RESERVED, /* 0x14: VOLUME UP */
997 KEY_RESERVED, /* 0x15: VOLUME DOWN */
998 KEY_RESERVED, /* 0x16: MUTE */
999 KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
1000 /* (assignments unknown, please report if found) */
1001 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
1002 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
1005 #define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map)
1006 #define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map)
1007 #define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0])
1013 vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
1015 BUG_ON(!tpacpi_inputdev);
1017 IBM_ACPIHANDLE_INIT(hkey);
1018 mutex_init(&hotkey_mutex);
1020 /* hotkey not supported on 570 */
1021 tp_features.hotkey = hkey_handle != NULL;
1023 vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",
1024 str_supported(tp_features.hotkey));
1026 if (tp_features.hotkey) {
1027 hotkey_dev_attributes = create_attr_set(8, NULL);
1028 if (!hotkey_dev_attributes)
1030 res = add_many_to_attr_set(hotkey_dev_attributes,
1032 ARRAY_SIZE(hotkey_attributes));
1036 /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
1037 A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking
1038 for HKEY interface version 0x100 */
1039 if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
1040 if ((hkeyv >> 8) != 1) {
1041 printk(IBM_ERR "unknown version of the "
1042 "HKEY interface: 0x%x\n", hkeyv);
1043 printk(IBM_ERR "please report this to %s\n",
1047 * MHKV 0x100 in A31, R40, R40e,
1048 * T4x, X31, and later
1050 tp_features.hotkey_mask = 1;
1054 vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
1055 str_supported(tp_features.hotkey_mask));
1057 if (tp_features.hotkey_mask) {
1058 if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
1061 "missing MHKA handler, "
1062 "please report this to %s\n",
1064 hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
1068 res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
1069 if (!res && tp_features.hotkey_mask) {
1070 res = add_many_to_attr_set(hotkey_dev_attributes,
1071 hotkey_mask_attributes,
1072 ARRAY_SIZE(hotkey_mask_attributes));
1075 /* Not all thinkpads have a hardware radio switch */
1076 if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
1077 tp_features.hotkey_wlsw = 1;
1079 "radio switch found; radios are %s\n",
1080 enabled(status, 0));
1081 res = add_to_attr_set(hotkey_dev_attributes,
1082 &dev_attr_hotkey_radio_sw.attr);
1086 res = register_attr_set_with_sysfs(
1087 hotkey_dev_attributes,
1088 &tpacpi_pdev->dev.kobj);
1092 /* Set up key map */
1094 hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
1096 if (!hotkey_keycode_map) {
1097 printk(IBM_ERR "failed to allocate memory for key map\n");
1101 if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
1102 dbg_printk(TPACPI_DBG_INIT,
1103 "using Lenovo default hot key map\n");
1104 memcpy(hotkey_keycode_map, &lenovo_keycode_map,
1105 TPACPI_HOTKEY_MAP_SIZE);
1107 dbg_printk(TPACPI_DBG_INIT,
1108 "using IBM default hot key map\n");
1109 memcpy(hotkey_keycode_map, &ibm_keycode_map,
1110 TPACPI_HOTKEY_MAP_SIZE);
1113 set_bit(EV_KEY, tpacpi_inputdev->evbit);
1114 set_bit(EV_MSC, tpacpi_inputdev->evbit);
1115 set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
1116 tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
1117 tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
1118 tpacpi_inputdev->keycode = hotkey_keycode_map;
1119 for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
1120 if (hotkey_keycode_map[i] != KEY_RESERVED) {
1121 set_bit(hotkey_keycode_map[i],
1122 tpacpi_inputdev->keybit);
1124 if (i < sizeof(hotkey_reserved_mask)*8)
1125 hotkey_reserved_mask |= 1 << i;
1129 if (tp_features.hotkey_wlsw) {
1130 set_bit(EV_SW, tpacpi_inputdev->evbit);
1131 set_bit(SW_RADIO, tpacpi_inputdev->swbit);
1134 dbg_printk(TPACPI_DBG_INIT,
1135 "enabling hot key handling\n");
1136 res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask)
1137 | hotkey_orig_mask);
1141 dbg_printk(TPACPI_DBG_INIT,
1142 "legacy hot key reporting over procfs %s\n",
1143 (hotkey_report_mode < 2) ?
1144 "enabled" : "disabled");
1147 return (tp_features.hotkey)? 0 : 1;
1150 static void hotkey_exit(void)
1154 if (tp_features.hotkey) {
1155 dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n");
1156 res = hotkey_set(hotkey_orig_status, hotkey_orig_mask);
1158 printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n");
1161 if (hotkey_dev_attributes) {
1162 delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
1163 hotkey_dev_attributes = NULL;
1167 static void tpacpi_input_send_key(unsigned int scancode,
1168 unsigned int keycode)
1170 if (keycode != KEY_RESERVED) {
1171 mutex_lock(&tpacpi_inputdev_send_mutex);
1173 input_report_key(tpacpi_inputdev, keycode, 1);
1174 if (keycode == KEY_UNKNOWN)
1175 input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
1177 input_sync(tpacpi_inputdev);
1179 input_report_key(tpacpi_inputdev, keycode, 0);
1180 if (keycode == KEY_UNKNOWN)
1181 input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
1183 input_sync(tpacpi_inputdev);
1185 mutex_unlock(&tpacpi_inputdev_send_mutex);
1189 static void tpacpi_input_send_radiosw(void)
1193 mutex_lock(&tpacpi_inputdev_send_mutex);
1195 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
1196 input_report_switch(tpacpi_inputdev,
1198 input_sync(tpacpi_inputdev);
1201 mutex_unlock(&tpacpi_inputdev_send_mutex);
1204 static void hotkey_notify(struct ibm_struct *ibm, u32 event)
1207 unsigned int keycode, scancode;
1211 if (event != 0x80) {
1212 printk(IBM_ERR "unknown HKEY notification event %d\n", event);
1213 /* forward it to userspace, maybe it knows how to handle it */
1214 acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
1215 ibm->acpi->device->dev.bus_id,
1221 if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
1222 printk(IBM_ERR "failed to retrieve HKEY event\n");
1234 switch (hkey >> 12) {
1236 /* 0x1000-0x1FFF: key presses */
1237 scancode = hkey & 0xfff;
1238 if (scancode > 0 && scancode < 0x21) {
1240 keycode = hotkey_keycode_map[scancode];
1241 tpacpi_input_send_key(scancode, keycode);
1244 "hotkey 0x%04x out of range for keyboard map\n",
1250 /* 0x5000-0x5FFF: LID */
1251 /* we don't handle it through this path, just
1252 * eat up known LID events */
1253 if (hkey != 0x5001 && hkey != 0x5002) {
1255 "unknown LID-related HKEY event: 0x%04x\n",
1263 /* 0x7000-0x7FFF: misc */
1264 if (tp_features.hotkey_wlsw && hkey == 0x7000) {
1265 tpacpi_input_send_radiosw();
1268 /* fallthrough to default */
1270 /* case 2: dock-related */
1271 /* 0x2305 - T43 waking up due to bay lever eject while aslept */
1272 /* case 3: ultra-bay related. maybe bay in dock? */
1273 /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */
1274 printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey);
1279 if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) {
1280 acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
1283 /* netlink events */
1284 if (!ignore_acpi_ev && send_acpi_ev) {
1285 acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
1286 ibm->acpi->device->dev.bus_id,
1292 static void hotkey_resume(void)
1294 tpacpi_input_send_radiosw();
1298 * Call with hotkey_mutex held
1300 static int hotkey_get(int *status, u32 *mask)
1302 if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
1305 if (tp_features.hotkey_mask)
1306 if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
1313 * Call with hotkey_mutex held
1315 static int hotkey_set(int status, u32 mask)
1319 if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
1322 if (tp_features.hotkey_mask)
1323 for (i = 0; i < 32; i++) {
1324 int bit = ((1 << i) & mask) != 0;
1325 if (!acpi_evalf(hkey_handle,
1326 NULL, "MHKM", "vdd", i + 1, bit))
1333 /* procfs -------------------------------------------------------------- */
1334 static int hotkey_read(char *p)
1340 if (!tp_features.hotkey) {
1341 len += sprintf(p + len, "status:\t\tnot supported\n");
1345 if (mutex_lock_interruptible(&hotkey_mutex))
1346 return -ERESTARTSYS;
1347 res = hotkey_get(&status, &mask);
1348 mutex_unlock(&hotkey_mutex);
1352 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
1353 if (tp_features.hotkey_mask) {
1354 len += sprintf(p + len, "mask:\t\t0x%08x\n", mask);
1355 len += sprintf(p + len,
1356 "commands:\tenable, disable, reset, <mask>\n");
1358 len += sprintf(p + len, "mask:\t\tnot supported\n");
1359 len += sprintf(p + len, "commands:\tenable, disable, reset\n");
1365 static int hotkey_write(char *buf)
1372 if (!tp_features.hotkey)
1375 if (mutex_lock_interruptible(&hotkey_mutex))
1376 return -ERESTARTSYS;
1378 res = hotkey_get(&status, &mask);
1383 while ((cmd = next_cmd(&buf))) {
1384 if (strlencmp(cmd, "enable") == 0) {
1386 } else if (strlencmp(cmd, "disable") == 0) {
1388 } else if (strlencmp(cmd, "reset") == 0) {
1389 status = hotkey_orig_status;
1390 mask = hotkey_orig_mask;
1391 } else if (sscanf(cmd, "0x%x", &mask) == 1) {
1393 } else if (sscanf(cmd, "%x", &mask) == 1) {
1403 res = hotkey_set(status, mask);
1406 mutex_unlock(&hotkey_mutex);
1410 static const struct acpi_device_id ibm_htk_device_ids[] = {
1415 static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = {
1416 .hid = ibm_htk_device_ids,
1417 .notify = hotkey_notify,
1418 .handle = &hkey_handle,
1419 .type = ACPI_DEVICE_NOTIFY,
1422 static struct ibm_struct hotkey_driver_data = {
1424 .read = hotkey_read,
1425 .write = hotkey_write,
1426 .exit = hotkey_exit,
1427 .resume = hotkey_resume,
1428 .acpi = &ibm_hotkey_acpidriver,
1431 /*************************************************************************
1432 * Bluetooth subdriver
1435 /* sysfs bluetooth enable ---------------------------------------------- */
1436 static ssize_t bluetooth_enable_show(struct device *dev,
1437 struct device_attribute *attr,
1442 status = bluetooth_get_radiosw();
1446 return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);
1449 static ssize_t bluetooth_enable_store(struct device *dev,
1450 struct device_attribute *attr,
1451 const char *buf, size_t count)
1456 if (parse_strtoul(buf, 1, &t))
1459 res = bluetooth_set_radiosw(t);
1461 return (res) ? res : count;
1464 static struct device_attribute dev_attr_bluetooth_enable =
1465 __ATTR(bluetooth_enable, S_IWUSR | S_IRUGO,
1466 bluetooth_enable_show, bluetooth_enable_store);
1468 /* --------------------------------------------------------------------- */
1470 static struct attribute *bluetooth_attributes[] = {
1471 &dev_attr_bluetooth_enable.attr,
1475 static const struct attribute_group bluetooth_attr_group = {
1476 .attrs = bluetooth_attributes,
1479 static int __init bluetooth_init(struct ibm_init_struct *iibm)
1484 vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n");
1486 IBM_ACPIHANDLE_INIT(hkey);
1488 /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
1489 G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
1490 tp_features.bluetooth = hkey_handle &&
1491 acpi_evalf(hkey_handle, &status, "GBDC", "qd");
1493 vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n",
1494 str_supported(tp_features.bluetooth),
1497 if (tp_features.bluetooth) {
1498 if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) {
1499 /* no bluetooth hardware present in system */
1500 tp_features.bluetooth = 0;
1501 dbg_printk(TPACPI_DBG_INIT,
1502 "bluetooth hardware not installed\n");
1504 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
1505 &bluetooth_attr_group);
1511 return (tp_features.bluetooth)? 0 : 1;
1514 static void bluetooth_exit(void)
1516 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
1517 &bluetooth_attr_group);
1520 static int bluetooth_get_radiosw(void)
1524 if (!tp_features.bluetooth)
1527 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
1530 return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0);
1533 static int bluetooth_set_radiosw(int radio_on)
1537 if (!tp_features.bluetooth)
1540 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
1543 status |= TP_ACPI_BLUETOOTH_RADIOSSW;
1545 status &= ~TP_ACPI_BLUETOOTH_RADIOSSW;
1546 if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
1552 /* procfs -------------------------------------------------------------- */
1553 static int bluetooth_read(char *p)
1556 int status = bluetooth_get_radiosw();
1558 if (!tp_features.bluetooth)
1559 len += sprintf(p + len, "status:\t\tnot supported\n");
1561 len += sprintf(p + len, "status:\t\t%s\n",
1562 (status)? "enabled" : "disabled");
1563 len += sprintf(p + len, "commands:\tenable, disable\n");
1569 static int bluetooth_write(char *buf)
1573 if (!tp_features.bluetooth)
1576 while ((cmd = next_cmd(&buf))) {
1577 if (strlencmp(cmd, "enable") == 0) {
1578 bluetooth_set_radiosw(1);
1579 } else if (strlencmp(cmd, "disable") == 0) {
1580 bluetooth_set_radiosw(0);
1588 static struct ibm_struct bluetooth_driver_data = {
1589 .name = "bluetooth",
1590 .read = bluetooth_read,
1591 .write = bluetooth_write,
1592 .exit = bluetooth_exit,
1595 /*************************************************************************
1599 /* sysfs wan enable ---------------------------------------------------- */
1600 static ssize_t wan_enable_show(struct device *dev,
1601 struct device_attribute *attr,
1606 status = wan_get_radiosw();
1610 return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);
1613 static ssize_t wan_enable_store(struct device *dev,
1614 struct device_attribute *attr,
1615 const char *buf, size_t count)
1620 if (parse_strtoul(buf, 1, &t))
1623 res = wan_set_radiosw(t);
1625 return (res) ? res : count;
1628 static struct device_attribute dev_attr_wan_enable =
1629 __ATTR(wwan_enable, S_IWUSR | S_IRUGO,
1630 wan_enable_show, wan_enable_store);
1632 /* --------------------------------------------------------------------- */
1634 static struct attribute *wan_attributes[] = {
1635 &dev_attr_wan_enable.attr,
1639 static const struct attribute_group wan_attr_group = {
1640 .attrs = wan_attributes,
1643 static int __init wan_init(struct ibm_init_struct *iibm)
1648 vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n");
1650 IBM_ACPIHANDLE_INIT(hkey);
1652 tp_features.wan = hkey_handle &&
1653 acpi_evalf(hkey_handle, &status, "GWAN", "qd");
1655 vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n",
1656 str_supported(tp_features.wan),
1659 if (tp_features.wan) {
1660 if (!(status & TP_ACPI_WANCARD_HWPRESENT)) {
1661 /* no wan hardware present in system */
1662 tp_features.wan = 0;
1663 dbg_printk(TPACPI_DBG_INIT,
1664 "wan hardware not installed\n");
1666 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
1673 return (tp_features.wan)? 0 : 1;
1676 static void wan_exit(void)
1678 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
1682 static int wan_get_radiosw(void)
1686 if (!tp_features.wan)
1689 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
1692 return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0);
1695 static int wan_set_radiosw(int radio_on)
1699 if (!tp_features.wan)
1702 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
1705 status |= TP_ACPI_WANCARD_RADIOSSW;
1707 status &= ~TP_ACPI_WANCARD_RADIOSSW;
1708 if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
1714 /* procfs -------------------------------------------------------------- */
1715 static int wan_read(char *p)
1718 int status = wan_get_radiosw();
1720 if (!tp_features.wan)
1721 len += sprintf(p + len, "status:\t\tnot supported\n");
1723 len += sprintf(p + len, "status:\t\t%s\n",
1724 (status)? "enabled" : "disabled");
1725 len += sprintf(p + len, "commands:\tenable, disable\n");
1731 static int wan_write(char *buf)
1735 if (!tp_features.wan)
1738 while ((cmd = next_cmd(&buf))) {
1739 if (strlencmp(cmd, "enable") == 0) {
1741 } else if (strlencmp(cmd, "disable") == 0) {
1750 static struct ibm_struct wan_driver_data = {
1755 .flags.experimental = 1,
1758 /*************************************************************************
1762 static enum video_access_mode video_supported;
1763 static int video_orig_autosw;
1765 IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
1766 "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
1767 "\\_SB.PCI0.VID0", /* 770e */
1768 "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
1769 "\\_SB.PCI0.AGP.VID", /* all others */
1772 IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
1774 static int __init video_init(struct ibm_init_struct *iibm)
1778 vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
1780 IBM_ACPIHANDLE_INIT(vid);
1781 IBM_ACPIHANDLE_INIT(vid2);
1783 if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
1784 /* G41, assume IVGA doesn't change */
1785 vid_handle = vid2_handle;
1788 /* video switching not supported on R30, R31 */
1789 video_supported = TPACPI_VIDEO_NONE;
1790 else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
1792 video_supported = TPACPI_VIDEO_570;
1793 else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
1794 /* 600e/x, 770e, 770x */
1795 video_supported = TPACPI_VIDEO_770;
1798 video_supported = TPACPI_VIDEO_NEW;
1800 vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n",
1801 str_supported(video_supported != TPACPI_VIDEO_NONE),
1804 return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1;
1807 static void video_exit(void)
1809 dbg_printk(TPACPI_DBG_EXIT,
1810 "restoring original video autoswitch mode\n");
1811 if (video_autosw_set(video_orig_autosw))
1812 printk(IBM_ERR "error while trying to restore original "
1813 "video autoswitch mode\n");
1816 static int video_outputsw_get(void)
1821 switch (video_supported) {
1822 case TPACPI_VIDEO_570:
1823 if (!acpi_evalf(NULL, &i, "\\_SB.PHS", "dd",
1824 TP_ACPI_VIDEO_570_PHSCMD))
1826 status = i & TP_ACPI_VIDEO_570_PHSMASK;
1828 case TPACPI_VIDEO_770:
1829 if (!acpi_evalf(NULL, &i, "\\VCDL", "d"))
1832 status |= TP_ACPI_VIDEO_S_LCD;
1833 if (!acpi_evalf(NULL, &i, "\\VCDC", "d"))
1836 status |= TP_ACPI_VIDEO_S_CRT;
1838 case TPACPI_VIDEO_NEW:
1839 if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1) ||
1840 !acpi_evalf(NULL, &i, "\\VCDC", "d"))
1843 status |= TP_ACPI_VIDEO_S_CRT;
1845 if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0) ||
1846 !acpi_evalf(NULL, &i, "\\VCDL", "d"))
1849 status |= TP_ACPI_VIDEO_S_LCD;
1850 if (!acpi_evalf(NULL, &i, "\\VCDD", "d"))
1853 status |= TP_ACPI_VIDEO_S_DVI;
1862 static int video_outputsw_set(int status)
1867 switch (video_supported) {
1868 case TPACPI_VIDEO_570:
1869 res = acpi_evalf(NULL, NULL,
1870 "\\_SB.PHS2", "vdd",
1871 TP_ACPI_VIDEO_570_PHS2CMD,
1872 status | TP_ACPI_VIDEO_570_PHS2SET);
1874 case TPACPI_VIDEO_770:
1875 autosw = video_autosw_get();
1879 res = video_autosw_set(1);
1882 res = acpi_evalf(vid_handle, NULL,
1883 "ASWT", "vdd", status * 0x100, 0);
1884 if (!autosw && video_autosw_set(autosw)) {
1885 printk(IBM_ERR "video auto-switch left enabled due to error\n");
1889 case TPACPI_VIDEO_NEW:
1890 res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
1891 acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
1897 return (res)? 0 : -EIO;
1900 static int video_autosw_get(void)
1904 switch (video_supported) {
1905 case TPACPI_VIDEO_570:
1906 if (!acpi_evalf(vid_handle, &autosw, "SWIT", "d"))
1909 case TPACPI_VIDEO_770:
1910 case TPACPI_VIDEO_NEW:
1911 if (!acpi_evalf(vid_handle, &autosw, "^VDEE", "d"))
1921 static int video_autosw_set(int enable)
1923 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0))
1928 static int video_outputsw_cycle(void)
1930 int autosw = video_autosw_get();
1936 switch (video_supported) {
1937 case TPACPI_VIDEO_570:
1938 res = video_autosw_set(1);
1941 res = acpi_evalf(ec_handle, NULL, "_Q16", "v");
1943 case TPACPI_VIDEO_770:
1944 case TPACPI_VIDEO_NEW:
1945 res = video_autosw_set(1);
1948 res = acpi_evalf(vid_handle, NULL, "VSWT", "v");
1953 if (!autosw && video_autosw_set(autosw)) {
1954 printk(IBM_ERR "video auto-switch left enabled due to error\n");
1958 return (res)? 0 : -EIO;
1961 static int video_expand_toggle(void)
1963 switch (video_supported) {
1964 case TPACPI_VIDEO_570:
1965 return acpi_evalf(ec_handle, NULL, "_Q17", "v")?
1967 case TPACPI_VIDEO_770:
1968 return acpi_evalf(vid_handle, NULL, "VEXP", "v")?
1970 case TPACPI_VIDEO_NEW:
1971 return acpi_evalf(NULL, NULL, "\\VEXP", "v")?
1979 static int video_read(char *p)
1984 if (video_supported == TPACPI_VIDEO_NONE) {
1985 len += sprintf(p + len, "status:\t\tnot supported\n");
1989 status = video_outputsw_get();
1993 autosw = video_autosw_get();
1997 len += sprintf(p + len, "status:\t\tsupported\n");
1998 len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
1999 len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
2000 if (video_supported == TPACPI_VIDEO_NEW)
2001 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
2002 len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
2003 len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
2004 len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
2005 if (video_supported == TPACPI_VIDEO_NEW)
2006 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
2007 len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
2008 len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
2013 static int video_write(char *buf)
2016 int enable, disable, status;
2019 if (video_supported == TPACPI_VIDEO_NONE)
2025 while ((cmd = next_cmd(&buf))) {
2026 if (strlencmp(cmd, "lcd_enable") == 0) {
2027 enable |= TP_ACPI_VIDEO_S_LCD;
2028 } else if (strlencmp(cmd, "lcd_disable") == 0) {
2029 disable |= TP_ACPI_VIDEO_S_LCD;
2030 } else if (strlencmp(cmd, "crt_enable") == 0) {
2031 enable |= TP_ACPI_VIDEO_S_CRT;
2032 } else if (strlencmp(cmd, "crt_disable") == 0) {
2033 disable |= TP_ACPI_VIDEO_S_CRT;
2034 } else if (video_supported == TPACPI_VIDEO_NEW &&
2035 strlencmp(cmd, "dvi_enable") == 0) {
2036 enable |= TP_ACPI_VIDEO_S_DVI;
2037 } else if (video_supported == TPACPI_VIDEO_NEW &&
2038 strlencmp(cmd, "dvi_disable") == 0) {
2039 disable |= TP_ACPI_VIDEO_S_DVI;
2040 } else if (strlencmp(cmd, "auto_enable") == 0) {
2041 res = video_autosw_set(1);
2044 } else if (strlencmp(cmd, "auto_disable") == 0) {
2045 res = video_autosw_set(0);
2048 } else if (strlencmp(cmd, "video_switch") == 0) {
2049 res = video_outputsw_cycle();
2052 } else if (strlencmp(cmd, "expand_toggle") == 0) {
2053 res = video_expand_toggle();
2060 if (enable || disable) {
2061 status = video_outputsw_get();
2064 res = video_outputsw_set((status & ~disable) | enable);
2072 static struct ibm_struct video_driver_data = {
2075 .write = video_write,
2079 /*************************************************************************
2080 * Light (thinklight) subdriver
2083 IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
2084 IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */
2086 static int __init light_init(struct ibm_init_struct *iibm)
2088 vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
2090 IBM_ACPIHANDLE_INIT(ledb);
2091 IBM_ACPIHANDLE_INIT(lght);
2092 IBM_ACPIHANDLE_INIT(cmos);
2094 /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
2095 tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
2097 if (tp_features.light)
2098 /* light status not supported on
2099 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
2100 tp_features.light_status =
2101 acpi_evalf(ec_handle, NULL, "KBLT", "qv");
2103 vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",
2104 str_supported(tp_features.light));
2106 return (tp_features.light)? 0 : 1;
2109 static int light_read(char *p)
2114 if (!tp_features.light) {
2115 len += sprintf(p + len, "status:\t\tnot supported\n");
2116 } else if (!tp_features.light_status) {
2117 len += sprintf(p + len, "status:\t\tunknown\n");
2118 len += sprintf(p + len, "commands:\ton, off\n");
2120 if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
2122 len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
2123 len += sprintf(p + len, "commands:\ton, off\n");
2129 static int light_write(char *buf)
2131 int cmos_cmd, lght_cmd;
2135 if (!tp_features.light)
2138 while ((cmd = next_cmd(&buf))) {
2139 if (strlencmp(cmd, "on") == 0) {
2142 } else if (strlencmp(cmd, "off") == 0) {
2148 success = cmos_handle ?
2149 acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
2150 acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
2158 static struct ibm_struct light_driver_data = {
2161 .write = light_write,
2164 /*************************************************************************
2168 #ifdef CONFIG_THINKPAD_ACPI_DOCK
2170 IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
2171 "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
2172 "\\_SB.PCI0.PCI1.DOCK", /* all others */
2173 "\\_SB.PCI.ISA.SLCE", /* 570 */
2174 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
2176 /* don't list other alternatives as we install a notify handler on the 570 */
2177 IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
2179 static const struct acpi_device_id ibm_pci_device_ids[] = {
2180 {PCI_ROOT_HID_STRING, 0},
2184 static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
2186 .notify = dock_notify,
2187 .handle = &dock_handle,
2188 .type = ACPI_SYSTEM_NOTIFY,
2191 /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING.
2192 * We just use it to get notifications of dock hotplug
2193 * in very old thinkpads */
2194 .hid = ibm_pci_device_ids,
2195 .notify = dock_notify,
2196 .handle = &pci_handle,
2197 .type = ACPI_SYSTEM_NOTIFY,
2201 static struct ibm_struct dock_driver_data[2] = {
2205 .write = dock_write,
2206 .acpi = &ibm_dock_acpidriver[0],
2210 .acpi = &ibm_dock_acpidriver[1],
2214 #define dock_docked() (_sta(dock_handle) & 1)
2216 static int __init dock_init(struct ibm_init_struct *iibm)
2218 vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
2220 IBM_ACPIHANDLE_INIT(dock);
2222 vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
2223 str_supported(dock_handle != NULL));
2225 return (dock_handle)? 0 : 1;
2228 static int __init dock_init2(struct ibm_init_struct *iibm)
2232 vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver part 2\n");
2234 if (dock_driver_data[0].flags.acpi_driver_registered &&
2235 dock_driver_data[0].flags.acpi_notify_installed) {
2236 IBM_ACPIHANDLE_INIT(pci);
2237 dock2_needed = (pci_handle != NULL);
2238 vdbg_printk(TPACPI_DBG_INIT,
2239 "dock PCI handler for the TP 570 is %s\n",
2240 str_supported(dock2_needed));
2242 vdbg_printk(TPACPI_DBG_INIT,
2243 "dock subdriver part 2 not required\n");
2247 return (dock2_needed)? 0 : 1;
2250 static void dock_notify(struct ibm_struct *ibm, u32 event)
2252 int docked = dock_docked();
2253 int pci = ibm->acpi->hid && ibm->acpi->device &&
2254 acpi_match_device_ids(ibm->acpi->device, ibm_pci_device_ids);
2257 if (event == 1 && !pci) /* 570 */
2258 data = 1; /* button */
2259 else if (event == 1 && pci) /* 570 */
2260 data = 3; /* dock */
2261 else if (event == 3 && docked)
2262 data = 1; /* button */
2263 else if (event == 3 && !docked)
2264 data = 2; /* undock */
2265 else if (event == 0 && docked)
2266 data = 3; /* dock */
2268 printk(IBM_ERR "unknown dock event %d, status %d\n",
2269 event, _sta(dock_handle));
2270 data = 0; /* unknown */
2272 acpi_bus_generate_proc_event(ibm->acpi->device, event, data);
2273 acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
2274 ibm->acpi->device->dev.bus_id,
2278 static int dock_read(char *p)
2281 int docked = dock_docked();
2284 len += sprintf(p + len, "status:\t\tnot supported\n");
2286 len += sprintf(p + len, "status:\t\tundocked\n");
2288 len += sprintf(p + len, "status:\t\tdocked\n");
2289 len += sprintf(p + len, "commands:\tdock, undock\n");
2295 static int dock_write(char *buf)
2302 while ((cmd = next_cmd(&buf))) {
2303 if (strlencmp(cmd, "undock") == 0) {
2304 if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
2305 !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
2307 } else if (strlencmp(cmd, "dock") == 0) {
2308 if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
2317 #endif /* CONFIG_THINKPAD_ACPI_DOCK */
2319 /*************************************************************************
2323 #ifdef CONFIG_THINKPAD_ACPI_BAY
2324 IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
2325 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
2326 "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
2327 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
2328 ); /* A21e, R30, R31 */
2329 IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
2330 "_EJ0", /* all others */
2331 ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
2332 IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
2333 "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
2335 IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
2339 static int __init bay_init(struct ibm_init_struct *iibm)
2341 vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
2343 IBM_ACPIHANDLE_INIT(bay);
2345 IBM_ACPIHANDLE_INIT(bay_ej);
2346 IBM_ACPIHANDLE_INIT(bay2);
2348 IBM_ACPIHANDLE_INIT(bay2_ej);
2350 tp_features.bay_status = bay_handle &&
2351 acpi_evalf(bay_handle, NULL, "_STA", "qv");
2352 tp_features.bay_status2 = bay2_handle &&
2353 acpi_evalf(bay2_handle, NULL, "_STA", "qv");
2355 tp_features.bay_eject = bay_handle && bay_ej_handle &&
2356 (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
2357 tp_features.bay_eject2 = bay2_handle && bay2_ej_handle &&
2358 (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
2360 vdbg_printk(TPACPI_DBG_INIT,
2361 "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n",
2362 str_supported(tp_features.bay_status),
2363 str_supported(tp_features.bay_eject),
2364 str_supported(tp_features.bay_status2),
2365 str_supported(tp_features.bay_eject2));
2367 return (tp_features.bay_status || tp_features.bay_eject ||
2368 tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1;
2371 static void bay_notify(struct ibm_struct *ibm, u32 event)
2373 acpi_bus_generate_proc_event(ibm->acpi->device, event, 0);
2374 acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
2375 ibm->acpi->device->dev.bus_id,
2379 #define bay_occupied(b) (_sta(b##_handle) & 1)
2381 static int bay_read(char *p)
2384 int occupied = bay_occupied(bay);
2385 int occupied2 = bay_occupied(bay2);
2388 len += sprintf(p + len, "status:\t\t%s\n",
2389 tp_features.bay_status ?
2390 (occupied ? "occupied" : "unoccupied") :
2392 if (tp_features.bay_status2)
2393 len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
2394 "occupied" : "unoccupied");
2396 eject = tp_features.bay_eject && occupied;
2397 eject2 = tp_features.bay_eject2 && occupied2;
2399 if (eject && eject2)
2400 len += sprintf(p + len, "commands:\teject, eject2\n");
2402 len += sprintf(p + len, "commands:\teject\n");
2404 len += sprintf(p + len, "commands:\teject2\n");
2409 static int bay_write(char *buf)
2413 if (!tp_features.bay_eject && !tp_features.bay_eject2)
2416 while ((cmd = next_cmd(&buf))) {
2417 if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) {
2418 if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
2420 } else if (tp_features.bay_eject2 &&
2421 strlencmp(cmd, "eject2") == 0) {
2422 if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
2431 static struct tp_acpi_drv_struct ibm_bay_acpidriver = {
2432 .notify = bay_notify,
2433 .handle = &bay_handle,
2434 .type = ACPI_SYSTEM_NOTIFY,
2437 static struct ibm_struct bay_driver_data = {
2441 .acpi = &ibm_bay_acpidriver,
2444 #endif /* CONFIG_THINKPAD_ACPI_BAY */
2446 /*************************************************************************
2450 /* sysfs cmos_command -------------------------------------------------- */
2451 static ssize_t cmos_command_store(struct device *dev,
2452 struct device_attribute *attr,
2453 const char *buf, size_t count)
2455 unsigned long cmos_cmd;
2458 if (parse_strtoul(buf, 21, &cmos_cmd))
2461 res = issue_thinkpad_cmos_command(cmos_cmd);
2462 return (res)? res : count;
2465 static struct device_attribute dev_attr_cmos_command =
2466 __ATTR(cmos_command, S_IWUSR, NULL, cmos_command_store);
2468 /* --------------------------------------------------------------------- */
2470 static int __init cmos_init(struct ibm_init_struct *iibm)
2474 vdbg_printk(TPACPI_DBG_INIT,
2475 "initializing cmos commands subdriver\n");
2477 IBM_ACPIHANDLE_INIT(cmos);
2479 vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
2480 str_supported(cmos_handle != NULL));
2482 res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
2486 return (cmos_handle)? 0 : 1;
2489 static void cmos_exit(void)
2491 device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
2494 static int cmos_read(char *p)
2498 /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
2499 R30, R31, T20-22, X20-21 */
2501 len += sprintf(p + len, "status:\t\tnot supported\n");
2503 len += sprintf(p + len, "status:\t\tsupported\n");
2504 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
2510 static int cmos_write(char *buf)
2515 while ((cmd = next_cmd(&buf))) {
2516 if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
2517 cmos_cmd >= 0 && cmos_cmd <= 21) {
2522 res = issue_thinkpad_cmos_command(cmos_cmd);
2530 static struct ibm_struct cmos_driver_data = {
2533 .write = cmos_write,
2537 /*************************************************************************
2541 static enum led_access_mode led_supported;
2543 IBM_HANDLE(led, ec, "SLED", /* 570 */
2544 "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
2545 "LED", /* all others */
2548 static int __init led_init(struct ibm_init_struct *iibm)
2550 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
2552 IBM_ACPIHANDLE_INIT(led);
2555 /* led not supported on R30, R31 */
2556 led_supported = TPACPI_LED_NONE;
2557 else if (strlencmp(led_path, "SLED") == 0)
2559 led_supported = TPACPI_LED_570;
2560 else if (strlencmp(led_path, "SYSL") == 0)
2561 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
2562 led_supported = TPACPI_LED_OLD;
2565 led_supported = TPACPI_LED_NEW;
2567 vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
2568 str_supported(led_supported), led_supported);
2570 return (led_supported != TPACPI_LED_NONE)? 0 : 1;
2573 #define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
2575 static int led_read(char *p)
2579 if (!led_supported) {
2580 len += sprintf(p + len, "status:\t\tnot supported\n");
2583 len += sprintf(p + len, "status:\t\tsupported\n");
2585 if (led_supported == TPACPI_LED_570) {
2588 for (i = 0; i < 8; i++) {
2589 if (!acpi_evalf(ec_handle,
2590 &status, "GLED", "dd", 1 << i))
2592 len += sprintf(p + len, "%d:\t\t%s\n",
2593 i, led_status(status));
2597 len += sprintf(p + len, "commands:\t"
2598 "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
2603 /* off, on, blink */
2604 static const int led_sled_arg1[] = { 0, 1, 3 };
2605 static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
2606 static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
2607 static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
2609 static int led_write(char *buf)
2617 while ((cmd = next_cmd(&buf))) {
2618 if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
2621 if (strstr(cmd, "off")) {
2623 } else if (strstr(cmd, "on")) {
2625 } else if (strstr(cmd, "blink")) {
2630 if (led_supported == TPACPI_LED_570) {
2633 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
2634 led, led_sled_arg1[ind]))
2636 } else if (led_supported == TPACPI_LED_OLD) {
2637 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
2639 ret = ec_write(TPACPI_LED_EC_HLMS, led);
2642 ec_write(TPACPI_LED_EC_HLBL,
2643 led * led_exp_hlbl[ind]);
2646 ec_write(TPACPI_LED_EC_HLCL,
2647 led * led_exp_hlcl[ind]);
2652 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
2653 led, led_led_arg1[ind]))
2661 static struct ibm_struct led_driver_data = {
2667 /*************************************************************************
2671 IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
2673 static int __init beep_init(struct ibm_init_struct *iibm)
2675 vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
2677 IBM_ACPIHANDLE_INIT(beep);
2679 vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
2680 str_supported(beep_handle != NULL));
2682 return (beep_handle)? 0 : 1;
2685 static int beep_read(char *p)
2690 len += sprintf(p + len, "status:\t\tnot supported\n");
2692 len += sprintf(p + len, "status:\t\tsupported\n");
2693 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
2699 static int beep_write(char *buf)
2707 while ((cmd = next_cmd(&buf))) {
2708 if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
2709 beep_cmd >= 0 && beep_cmd <= 17) {
2713 if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
2720 static struct ibm_struct beep_driver_data = {
2723 .write = beep_write,
2726 /*************************************************************************
2730 static enum thermal_access_mode thermal_read_mode;
2732 /* sysfs temp##_input -------------------------------------------------- */
2734 static ssize_t thermal_temp_input_show(struct device *dev,
2735 struct device_attribute *attr,
2738 struct sensor_device_attribute *sensor_attr =
2739 to_sensor_dev_attr(attr);
2740 int idx = sensor_attr->index;
2744 res = thermal_get_sensor(idx, &value);
2747 if (value == TP_EC_THERMAL_TMP_NA * 1000)
2750 return snprintf(buf, PAGE_SIZE, "%d\n", value);
2753 #define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \
2754 SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB)
2756 static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = {
2757 THERMAL_SENSOR_ATTR_TEMP(1, 0),
2758 THERMAL_SENSOR_ATTR_TEMP(2, 1),
2759 THERMAL_SENSOR_ATTR_TEMP(3, 2),
2760 THERMAL_SENSOR_ATTR_TEMP(4, 3),
2761 THERMAL_SENSOR_ATTR_TEMP(5, 4),
2762 THERMAL_SENSOR_ATTR_TEMP(6, 5),
2763 THERMAL_SENSOR_ATTR_TEMP(7, 6),
2764 THERMAL_SENSOR_ATTR_TEMP(8, 7),
2765 THERMAL_SENSOR_ATTR_TEMP(9, 8),
2766 THERMAL_SENSOR_ATTR_TEMP(10, 9),
2767 THERMAL_SENSOR_ATTR_TEMP(11, 10),
2768 THERMAL_SENSOR_ATTR_TEMP(12, 11),
2769 THERMAL_SENSOR_ATTR_TEMP(13, 12),
2770 THERMAL_SENSOR_ATTR_TEMP(14, 13),
2771 THERMAL_SENSOR_ATTR_TEMP(15, 14),
2772 THERMAL_SENSOR_ATTR_TEMP(16, 15),
2775 #define THERMAL_ATTRS(X) \
2776 &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr
2778 static struct attribute *thermal_temp_input_attr[] = {
2798 static const struct attribute_group thermal_temp_input16_group = {
2799 .attrs = thermal_temp_input_attr
2802 static const struct attribute_group thermal_temp_input8_group = {
2803 .attrs = &thermal_temp_input_attr[8]
2806 #undef THERMAL_SENSOR_ATTR_TEMP
2807 #undef THERMAL_ATTRS
2809 /* --------------------------------------------------------------------- */
2811 static int __init thermal_init(struct ibm_init_struct *iibm)
2818 vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n");
2820 acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
2822 if (thinkpad_id.ec_model) {
2824 * Direct EC access mode: sensors at registers
2825 * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
2826 * non-implemented, thermal sensors return 0x80 when
2831 for (i = 0; i < 8; i++) {
2832 if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) {
2838 if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) {
2846 /* This is sheer paranoia, but we handle it anyway */
2849 "ThinkPad ACPI EC access misbehaving, "
2850 "falling back to ACPI TMPx access mode\n");
2851 thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
2854 "ThinkPad ACPI EC access misbehaving, "
2855 "disabling thermal sensors access\n");
2856 thermal_read_mode = TPACPI_THERMAL_NONE;
2861 TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8;
2863 } else if (acpi_tmp7) {
2864 if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
2865 /* 600e/x, 770e, 770x */
2866 thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT;
2868 /* Standard ACPI TMPx access, max 8 sensors */
2869 thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
2872 /* temperatures not supported on 570, G4x, R30, R31, R32 */
2873 thermal_read_mode = TPACPI_THERMAL_NONE;
2876 vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n",
2877 str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
2880 switch(thermal_read_mode) {
2881 case TPACPI_THERMAL_TPEC_16:
2882 res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
2883 &thermal_temp_input16_group);
2887 case TPACPI_THERMAL_TPEC_8:
2888 case TPACPI_THERMAL_ACPI_TMP07:
2889 case TPACPI_THERMAL_ACPI_UPDT:
2890 res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
2891 &thermal_temp_input8_group);
2895 case TPACPI_THERMAL_NONE:
2903 static void thermal_exit(void)
2905 switch(thermal_read_mode) {
2906 case TPACPI_THERMAL_TPEC_16:
2907 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
2908 &thermal_temp_input16_group);
2910 case TPACPI_THERMAL_TPEC_8:
2911 case TPACPI_THERMAL_ACPI_TMP07:
2912 case TPACPI_THERMAL_ACPI_UPDT:
2913 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
2914 &thermal_temp_input16_group);
2916 case TPACPI_THERMAL_NONE:
2922 /* idx is zero-based */
2923 static int thermal_get_sensor(int idx, s32 *value)
2929 t = TP_EC_THERMAL_TMP0;
2931 switch (thermal_read_mode) {
2932 #if TPACPI_MAX_THERMAL_SENSORS >= 16
2933 case TPACPI_THERMAL_TPEC_16:
2934 if (idx >= 8 && idx <= 15) {
2935 t = TP_EC_THERMAL_TMP8;
2940 case TPACPI_THERMAL_TPEC_8:
2942 if (!acpi_ec_read(t + idx, &tmp))
2944 *value = tmp * 1000;
2949 case TPACPI_THERMAL_ACPI_UPDT:
2951 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
2952 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
2954 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
2956 *value = (t - 2732) * 100;
2961 case TPACPI_THERMAL_ACPI_TMP07:
2963 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
2964 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
2966 if (t > 127 || t < -127)
2967 t = TP_EC_THERMAL_TMP_NA;
2973 case TPACPI_THERMAL_NONE:
2981 static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
2992 if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
2995 for(i = 0 ; i < n; i++) {
2996 res = thermal_get_sensor(i, &s->temp[i]);
3004 static int thermal_read(char *p)
3008 struct ibm_thermal_sensors_struct t;
3010 n = thermal_get_sensors(&t);
3011 if (unlikely(n < 0))
3014 len += sprintf(p + len, "temperatures:\t");
3017 for (i = 0; i < (n - 1); i++)
3018 len += sprintf(p + len, "%d ", t.temp[i] / 1000);
3019 len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
3021 len += sprintf(p + len, "not supported\n");
3026 static struct ibm_struct thermal_driver_data = {
3028 .read = thermal_read,
3029 .exit = thermal_exit,
3032 /*************************************************************************
3036 static u8 ecdump_regs[256];
3038 static int ecdump_read(char *p)
3044 len += sprintf(p + len, "EC "
3045 " +00 +01 +02 +03 +04 +05 +06 +07"
3046 " +08 +09 +0a +0b +0c +0d +0e +0f\n");
3047 for (i = 0; i < 256; i += 16) {
3048 len += sprintf(p + len, "EC 0x%02x:", i);
3049 for (j = 0; j < 16; j++) {
3050 if (!acpi_ec_read(i + j, &v))
3052 if (v != ecdump_regs[i + j])
3053 len += sprintf(p + len, " *%02x", v);
3055 len += sprintf(p + len, " %02x", v);
3056 ecdump_regs[i + j] = v;
3058 len += sprintf(p + len, "\n");
3063 /* These are way too dangerous to advertise openly... */
3065 len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
3066 " (<offset> is 00-ff, <value> is 00-ff)\n");
3067 len += sprintf(p + len, "commands:\t0x<offset> <value> "
3068 " (<offset> is 00-ff, <value> is 0-255)\n");
3073 static int ecdump_write(char *buf)
3078 while ((cmd = next_cmd(&buf))) {
3079 if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
3081 } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
3085 if (i >= 0 && i < 256 && v >= 0 && v < 256) {
3086 if (!acpi_ec_write(i, v))
3095 static struct ibm_struct ecdump_driver_data = {
3097 .read = ecdump_read,
3098 .write = ecdump_write,
3099 .flags.experimental = 1,
3102 /*************************************************************************
3103 * Backlight/brightness subdriver
3106 static struct backlight_device *ibm_backlight_device;
3108 static struct backlight_ops ibm_backlight_data = {
3109 .get_brightness = brightness_get,
3110 .update_status = brightness_update_status,
3113 static struct mutex brightness_mutex;
3115 static int __init tpacpi_query_bcll_levels(acpi_handle handle)
3117 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
3118 union acpi_object *obj;
3121 if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
3122 obj = (union acpi_object *)buffer.pointer;
3123 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
3124 printk(IBM_ERR "Unknown BCLL data, "
3125 "please report this to %s\n", IBM_MAIL);
3128 rc = obj->package.count;
3134 kfree(buffer.pointer);