aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2007-07-22 02:28:06 -0400
committerLen Brown <len.brown@intel.com>2007-07-22 02:28:06 -0400
commit08e31686d6d119ba26bf0690f5f872f6f5bd1a97 (patch)
tree4568c690296eede145bdcc6555834b939d0a6c2c /drivers
parentd6da5ce8cc71a13e2f3671361c5a8bd9b82e014d (diff)
parentf432255e936a892a6896e5032e2b4897423076f2 (diff)
Pull thinkpad into release branch
Diffstat (limited to 'drivers')
-rw-r--r--drivers/misc/Kconfig14
-rw-r--r--drivers/misc/thinkpad_acpi.c602
-rw-r--r--drivers/misc/thinkpad_acpi.h42
3 files changed, 576 insertions, 82 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 1d516f24ba53..aaaa61ea4217 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -150,6 +150,7 @@ config THINKPAD_ACPI
150 depends on X86 && ACPI 150 depends on X86 && ACPI
151 select BACKLIGHT_CLASS_DEVICE 151 select BACKLIGHT_CLASS_DEVICE
152 select HWMON 152 select HWMON
153 select NVRAM
153 ---help--- 154 ---help---
154 This is a driver for the IBM and Lenovo ThinkPad laptops. It adds 155 This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
155 support for Fn-Fx key combinations, Bluetooth control, video 156 support for Fn-Fx key combinations, Bluetooth control, video
@@ -196,4 +197,17 @@ config THINKPAD_ACPI_BAY
196 197
197 If you are not sure, say Y here. 198 If you are not sure, say Y here.
198 199
200config THINKPAD_ACPI_INPUT_ENABLED
201 bool "Enable input layer support by default"
202 depends on THINKPAD_ACPI
203 default y
204 ---help---
205 Enables hot key handling over the input layer by default. If unset,
206 the driver does not enable any hot key handling by default, and also
207 starts up with a mostly empty keymap.
208
209 If you are not sure, say Y here. Say N to retain the deprecated
210 behavior of ibm-acpi, and thinkpad-acpi for kernels up to 2.6.21.
211
212
199endif # MISC_DEVICES 213endif # MISC_DEVICES
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 95c0b96e83f2..f15a58f7403f 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -21,8 +21,8 @@
21 * 02110-1301, USA. 21 * 02110-1301, USA.
22 */ 22 */
23 23
24#define IBM_VERSION "0.14" 24#define IBM_VERSION "0.15"
25#define TPACPI_SYSFS_VERSION 0x000100 25#define TPACPI_SYSFS_VERSION 0x010000
26 26
27/* 27/*
28 * Changelog: 28 * Changelog:
@@ -92,6 +92,29 @@ MODULE_LICENSE("GPL");
92/* Please remove this in year 2009 */ 92/* Please remove this in year 2009 */
93MODULE_ALIAS("ibm_acpi"); 93MODULE_ALIAS("ibm_acpi");
94 94
95/*
96 * DMI matching for module autoloading
97 *
98 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
99 * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
100 *
101 * Only models listed in thinkwiki will be supported, so add yours
102 * if it is not there yet.
103 */
104#define IBM_BIOS_MODULE_ALIAS(__type) \
105 MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
106
107/* Non-ancient thinkpads */
108MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
109MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
110
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... */
114IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
115IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
116IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
117
95#define __unused __attribute__ ((unused)) 118#define __unused __attribute__ ((unused))
96 119
97/**************************************************************************** 120/****************************************************************************
@@ -106,7 +129,7 @@ MODULE_ALIAS("ibm_acpi");
106 * ACPI basic handles 129 * ACPI basic handles
107 */ 130 */
108 131
109static acpi_handle root_handle = NULL; 132static acpi_handle root_handle;
110 133
111#define IBM_HANDLE(object, parent, paths...) \ 134#define IBM_HANDLE(object, parent, paths...) \
112 static acpi_handle object##_handle; \ 135 static acpi_handle object##_handle; \
@@ -487,19 +510,36 @@ static char *next_cmd(char **cmds)
487/**************************************************************************** 510/****************************************************************************
488 **************************************************************************** 511 ****************************************************************************
489 * 512 *
490 * Device model: hwmon and platform 513 * Device model: input, hwmon and platform
491 * 514 *
492 **************************************************************************** 515 ****************************************************************************
493 ****************************************************************************/ 516 ****************************************************************************/
494 517
495static struct platform_device *tpacpi_pdev = NULL; 518static struct platform_device *tpacpi_pdev;
496static struct class_device *tpacpi_hwmon = NULL; 519static struct class_device *tpacpi_hwmon;
520static struct input_dev *tpacpi_inputdev;
521
522
523static int tpacpi_resume_handler(struct platform_device *pdev)
524{
525 struct ibm_struct *ibm, *itmp;
526
527 list_for_each_entry_safe(ibm, itmp,
528 &tpacpi_all_drivers,
529 all_drivers) {
530 if (ibm->resume)
531 (ibm->resume)();
532 }
533
534 return 0;
535}
497 536
498static struct platform_driver tpacpi_pdriver = { 537static struct platform_driver tpacpi_pdriver = {
499 .driver = { 538 .driver = {
500 .name = IBM_DRVR_NAME, 539 .name = IBM_DRVR_NAME,
501 .owner = THIS_MODULE, 540 .owner = THIS_MODULE,
502 }, 541 },
542 .resume = tpacpi_resume_handler,
503}; 543};
504 544
505 545
@@ -677,9 +717,19 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
677 printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); 717 printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
678 printk(IBM_INFO "%s\n", IBM_URL); 718 printk(IBM_INFO "%s\n", IBM_URL);
679 719
680 if (ibm_thinkpad_ec_found) 720 printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n",
681 printk(IBM_INFO "ThinkPad EC firmware %s\n", 721 (thinkpad_id.bios_version_str) ?
682 ibm_thinkpad_ec_found); 722 thinkpad_id.bios_version_str : "unknown",
723 (thinkpad_id.ec_version_str) ?
724 thinkpad_id.ec_version_str : "unknown");
725
726 if (thinkpad_id.vendor && thinkpad_id.model_str)
727 printk(IBM_INFO "%s %s\n",
728 (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
729 "IBM" : ((thinkpad_id.vendor ==
730 PCI_VENDOR_ID_LENOVO) ?
731 "Lenovo" : "Unknown vendor"),
732 thinkpad_id.model_str);
683 733
684 return 0; 734 return 0;
685} 735}
@@ -704,16 +754,28 @@ static struct ibm_struct thinkpad_acpi_driver_data = {
704 */ 754 */
705 755
706static int hotkey_orig_status; 756static int hotkey_orig_status;
707static int hotkey_orig_mask; 757static u32 hotkey_orig_mask;
758static u32 hotkey_all_mask;
759static u32 hotkey_reserved_mask;
760
761static u16 *hotkey_keycode_map;
708 762
709static struct attribute_set *hotkey_dev_attributes = NULL; 763static struct attribute_set *hotkey_dev_attributes;
764
765static int hotkey_get_wlsw(int *status)
766{
767 if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
768 return -EIO;
769 return 0;
770}
710 771
711/* sysfs hotkey enable ------------------------------------------------- */ 772/* sysfs hotkey enable ------------------------------------------------- */
712static ssize_t hotkey_enable_show(struct device *dev, 773static ssize_t hotkey_enable_show(struct device *dev,
713 struct device_attribute *attr, 774 struct device_attribute *attr,
714 char *buf) 775 char *buf)
715{ 776{
716 int res, status, mask; 777 int res, status;
778 u32 mask;
717 779
718 res = hotkey_get(&status, &mask); 780 res = hotkey_get(&status, &mask);
719 if (res) 781 if (res)
@@ -727,7 +789,8 @@ static ssize_t hotkey_enable_store(struct device *dev,
727 const char *buf, size_t count) 789 const char *buf, size_t count)
728{ 790{
729 unsigned long t; 791 unsigned long t;
730 int res, status, mask; 792 int res, status;
793 u32 mask;
731 794
732 if (parse_strtoul(buf, 1, &t)) 795 if (parse_strtoul(buf, 1, &t))
733 return -EINVAL; 796 return -EINVAL;
@@ -748,13 +811,14 @@ static ssize_t hotkey_mask_show(struct device *dev,
748 struct device_attribute *attr, 811 struct device_attribute *attr,
749 char *buf) 812 char *buf)
750{ 813{
751 int res, status, mask; 814 int res, status;
815 u32 mask;
752 816
753 res = hotkey_get(&status, &mask); 817 res = hotkey_get(&status, &mask);
754 if (res) 818 if (res)
755 return res; 819 return res;
756 820
757 return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask); 821 return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask);
758} 822}
759 823
760static ssize_t hotkey_mask_store(struct device *dev, 824static ssize_t hotkey_mask_store(struct device *dev,
@@ -762,9 +826,10 @@ static ssize_t hotkey_mask_store(struct device *dev,
762 const char *buf, size_t count) 826 const char *buf, size_t count)
763{ 827{
764 unsigned long t; 828 unsigned long t;
765 int res, status, mask; 829 int res, status;
830 u32 mask;
766 831
767 if (parse_strtoul(buf, 0xffff, &t)) 832 if (parse_strtoul(buf, 0xffffffffUL, &t))
768 return -EINVAL; 833 return -EINVAL;
769 834
770 res = hotkey_get(&status, &mask); 835 res = hotkey_get(&status, &mask);
@@ -794,26 +859,123 @@ static ssize_t hotkey_bios_mask_show(struct device *dev,
794 struct device_attribute *attr, 859 struct device_attribute *attr,
795 char *buf) 860 char *buf)
796{ 861{
797 return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask); 862 return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask);
798} 863}
799 864
800static struct device_attribute dev_attr_hotkey_bios_mask = 865static struct device_attribute dev_attr_hotkey_bios_mask =
801 __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL); 866 __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
802 867
868/* sysfs hotkey all_mask ----------------------------------------------- */
869static ssize_t hotkey_all_mask_show(struct device *dev,
870 struct device_attribute *attr,
871 char *buf)
872{
873 return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask);
874}
875
876static struct device_attribute dev_attr_hotkey_all_mask =
877 __ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL);
878
879/* sysfs hotkey recommended_mask --------------------------------------- */
880static ssize_t hotkey_recommended_mask_show(struct device *dev,
881 struct device_attribute *attr,
882 char *buf)
883{
884 return snprintf(buf, PAGE_SIZE, "0x%08x\n",
885 hotkey_all_mask & ~hotkey_reserved_mask);
886}
887
888static struct device_attribute dev_attr_hotkey_recommended_mask =
889 __ATTR(hotkey_recommended_mask, S_IRUGO,
890 hotkey_recommended_mask_show, NULL);
891
892/* sysfs hotkey radio_sw ----------------------------------------------- */
893static ssize_t hotkey_radio_sw_show(struct device *dev,
894 struct device_attribute *attr,
895 char *buf)
896{
897 int res, s;
898 res = hotkey_get_wlsw(&s);
899 if (res < 0)
900 return res;
901
902 return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
903}
904
905static struct device_attribute dev_attr_hotkey_radio_sw =
906 __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
907
803/* --------------------------------------------------------------------- */ 908/* --------------------------------------------------------------------- */
804 909
805static struct attribute *hotkey_mask_attributes[] = { 910static struct attribute *hotkey_mask_attributes[] = {
806 &dev_attr_hotkey_mask.attr, 911 &dev_attr_hotkey_mask.attr,
807 &dev_attr_hotkey_bios_enabled.attr, 912 &dev_attr_hotkey_bios_enabled.attr,
808 &dev_attr_hotkey_bios_mask.attr, 913 &dev_attr_hotkey_bios_mask.attr,
914 &dev_attr_hotkey_all_mask.attr,
915 &dev_attr_hotkey_recommended_mask.attr,
809}; 916};
810 917
811static int __init hotkey_init(struct ibm_init_struct *iibm) 918static int __init hotkey_init(struct ibm_init_struct *iibm)
812{ 919{
813 int res; 920
921 static u16 ibm_keycode_map[] __initdata = {
922 /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
923 KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP,
924 KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
925 KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
926 /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
927 KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
928 KEY_UNKNOWN, /* 0x0D: FN+INSERT */
929 KEY_UNKNOWN, /* 0x0E: FN+DELETE */
930 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
931 /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
932 KEY_RESERVED, /* 0x10: FN+END (brightness down) */
933 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
934 KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
935 KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
936 KEY_RESERVED, /* 0x14: VOLUME UP */
937 KEY_RESERVED, /* 0x15: VOLUME DOWN */
938 KEY_RESERVED, /* 0x16: MUTE */
939 KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
940 /* (assignments unknown, please report if found) */
941 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
942 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
943 };
944 static u16 lenovo_keycode_map[] __initdata = {
945 /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
946 KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP,
947 KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
948 KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
949 /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
950 KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
951 KEY_UNKNOWN, /* 0x0D: FN+INSERT */
952 KEY_UNKNOWN, /* 0x0E: FN+DELETE */
953 KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */
954 /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
955 KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */
956 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
957 KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
958 KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
959 KEY_RESERVED, /* 0x14: VOLUME UP */
960 KEY_RESERVED, /* 0x15: VOLUME DOWN */
961 KEY_RESERVED, /* 0x16: MUTE */
962 KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
963 /* (assignments unknown, please report if found) */
964 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
965 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
966 };
967
968#define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map)
969#define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map)
970#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0])
971
972 int res, i;
973 int status;
814 974
815 vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); 975 vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
816 976
977 BUG_ON(!tpacpi_inputdev);
978
817 IBM_ACPIHANDLE_INIT(hkey); 979 IBM_ACPIHANDLE_INIT(hkey);
818 mutex_init(&hotkey_mutex); 980 mutex_init(&hotkey_mutex);
819 981
@@ -824,7 +986,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
824 str_supported(tp_features.hotkey)); 986 str_supported(tp_features.hotkey));
825 987
826 if (tp_features.hotkey) { 988 if (tp_features.hotkey) {
827 hotkey_dev_attributes = create_attr_set(4, NULL); 989 hotkey_dev_attributes = create_attr_set(7, NULL);
828 if (!hotkey_dev_attributes) 990 if (!hotkey_dev_attributes)
829 return -ENOMEM; 991 return -ENOMEM;
830 res = add_to_attr_set(hotkey_dev_attributes, 992 res = add_to_attr_set(hotkey_dev_attributes,
@@ -840,19 +1002,92 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
840 vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", 1002 vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
841 str_supported(tp_features.hotkey_mask)); 1003 str_supported(tp_features.hotkey_mask));
842 1004
1005 if (tp_features.hotkey_mask) {
1006 /* MHKA available in A31, R40, R40e, T4x, X31, and later */
1007 if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
1008 "MHKA", "qd"))
1009 hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
1010 }
1011
843 res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); 1012 res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
844 if (!res && tp_features.hotkey_mask) { 1013 if (!res && tp_features.hotkey_mask) {
845 res = add_many_to_attr_set(hotkey_dev_attributes, 1014 res = add_many_to_attr_set(hotkey_dev_attributes,
846 hotkey_mask_attributes, 1015 hotkey_mask_attributes,
847 ARRAY_SIZE(hotkey_mask_attributes)); 1016 ARRAY_SIZE(hotkey_mask_attributes));
848 } 1017 }
1018
1019 /* Not all thinkpads have a hardware radio switch */
1020 if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
1021 tp_features.hotkey_wlsw = 1;
1022 printk(IBM_INFO
1023 "radio switch found; radios are %s\n",
1024 enabled(status, 0));
1025 res = add_to_attr_set(hotkey_dev_attributes,
1026 &dev_attr_hotkey_radio_sw.attr);
1027 }
1028
849 if (!res) 1029 if (!res)
850 res = register_attr_set_with_sysfs( 1030 res = register_attr_set_with_sysfs(
851 hotkey_dev_attributes, 1031 hotkey_dev_attributes,
852 &tpacpi_pdev->dev.kobj); 1032 &tpacpi_pdev->dev.kobj);
1033 if (res)
1034 return res;
1035
1036 /* Set up key map */
1037
1038 hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
1039 GFP_KERNEL);
1040 if (!hotkey_keycode_map) {
1041 printk(IBM_ERR "failed to allocate memory for key map\n");
1042 return -ENOMEM;
1043 }
1044
1045 if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
1046 dbg_printk(TPACPI_DBG_INIT,
1047 "using Lenovo default hot key map\n");
1048 memcpy(hotkey_keycode_map, &lenovo_keycode_map,
1049 TPACPI_HOTKEY_MAP_SIZE);
1050 } else {
1051 dbg_printk(TPACPI_DBG_INIT,
1052 "using IBM default hot key map\n");
1053 memcpy(hotkey_keycode_map, &ibm_keycode_map,
1054 TPACPI_HOTKEY_MAP_SIZE);
1055 }
853 1056
1057#ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
1058 for (i = 0; i < 12; i++)
1059 hotkey_keycode_map[i] = KEY_UNKNOWN;
1060#endif /* ! CONFIG_THINKPAD_ACPI_INPUT_ENABLED */
1061
1062 set_bit(EV_KEY, tpacpi_inputdev->evbit);
1063 set_bit(EV_MSC, tpacpi_inputdev->evbit);
1064 set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
1065 tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
1066 tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
1067 tpacpi_inputdev->keycode = hotkey_keycode_map;
1068 for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
1069 if (hotkey_keycode_map[i] != KEY_RESERVED) {
1070 set_bit(hotkey_keycode_map[i],
1071 tpacpi_inputdev->keybit);
1072 } else {
1073 if (i < sizeof(hotkey_reserved_mask)*8)
1074 hotkey_reserved_mask |= 1 << i;
1075 }
1076 }
1077
1078 if (tp_features.hotkey_wlsw) {
1079 set_bit(EV_SW, tpacpi_inputdev->evbit);
1080 set_bit(SW_RADIO, tpacpi_inputdev->swbit);
1081 }
1082
1083#ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
1084 dbg_printk(TPACPI_DBG_INIT,
1085 "enabling hot key handling\n");
1086 res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask)
1087 | hotkey_orig_mask);
854 if (res) 1088 if (res)
855 return res; 1089 return res;
1090#endif /* CONFIG_THINKPAD_ACPI_INPUT_ENABLED */
856 } 1091 }
857 1092
858 return (tp_features.hotkey)? 0 : 1; 1093 return (tp_features.hotkey)? 0 : 1;
@@ -875,22 +1110,101 @@ static void hotkey_exit(void)
875 } 1110 }
876} 1111}
877 1112
1113static void tpacpi_input_send_key(unsigned int scancode,
1114 unsigned int keycode)
1115{
1116 if (keycode != KEY_RESERVED) {
1117 input_report_key(tpacpi_inputdev, keycode, 1);
1118 if (keycode == KEY_UNKNOWN)
1119 input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
1120 scancode);
1121 input_sync(tpacpi_inputdev);
1122
1123 input_report_key(tpacpi_inputdev, keycode, 0);
1124 if (keycode == KEY_UNKNOWN)
1125 input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
1126 scancode);
1127 input_sync(tpacpi_inputdev);
1128 }
1129}
1130
1131static void tpacpi_input_send_radiosw(void)
1132{
1133 int wlsw;
1134
1135 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw))
1136 input_report_switch(tpacpi_inputdev,
1137 SW_RADIO, !!wlsw);
1138}
1139
878static void hotkey_notify(struct ibm_struct *ibm, u32 event) 1140static void hotkey_notify(struct ibm_struct *ibm, u32 event)
879{ 1141{
880 int hkey; 1142 u32 hkey;
1143 unsigned int keycode, scancode;
1144 int sendacpi = 1;
1145
1146 if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
1147 if (tpacpi_inputdev->users > 0) {
1148 switch (hkey >> 12) {
1149 case 1:
1150 /* 0x1000-0x1FFF: key presses */
1151 scancode = hkey & 0xfff;
1152 if (scancode > 0 && scancode < 0x21) {
1153 scancode--;
1154 keycode = hotkey_keycode_map[scancode];
1155 tpacpi_input_send_key(scancode, keycode);
1156 sendacpi = (keycode == KEY_RESERVED
1157 || keycode == KEY_UNKNOWN);
1158 } else {
1159 printk(IBM_ERR
1160 "hotkey 0x%04x out of range for keyboard map\n",
1161 hkey);
1162 }
1163 break;
1164 case 5:
1165 /* 0x5000-0x5FFF: LID */
1166 /* we don't handle it through this path, just
1167 * eat up known LID events */
1168 if (hkey != 0x5001 && hkey != 0x5002) {
1169 printk(IBM_ERR
1170 "unknown LID-related hotkey event: 0x%04x\n",
1171 hkey);
1172 }
1173 break;
1174 case 7:
1175 /* 0x7000-0x7FFF: misc */
1176 if (tp_features.hotkey_wlsw && hkey == 0x7000) {
1177 tpacpi_input_send_radiosw();
1178 sendacpi = 0;
1179 break;
1180 }
1181 /* fallthrough to default */
1182 default:
1183 /* case 2: dock-related */
1184 /* 0x2305 - T43 waking up due to bay lever eject while aslept */
1185 /* case 3: ultra-bay related. maybe bay in dock? */
1186 /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */
1187 printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey);
1188 }
1189 }
881 1190
882 if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) 1191 if (sendacpi)
883 acpi_bus_generate_event(ibm->acpi->device, event, hkey); 1192 acpi_bus_generate_event(ibm->acpi->device, event, hkey);
884 else { 1193 } else {
885 printk(IBM_ERR "unknown hotkey event %d\n", event); 1194 printk(IBM_ERR "unknown hotkey notification event %d\n", event);
886 acpi_bus_generate_event(ibm->acpi->device, event, 0); 1195 acpi_bus_generate_event(ibm->acpi->device, event, 0);
887 } 1196 }
888} 1197}
889 1198
1199static void hotkey_resume(void)
1200{
1201 tpacpi_input_send_radiosw();
1202}
1203
890/* 1204/*
891 * Call with hotkey_mutex held 1205 * Call with hotkey_mutex held
892 */ 1206 */
893static int hotkey_get(int *status, int *mask) 1207static int hotkey_get(int *status, u32 *mask)
894{ 1208{
895 if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) 1209 if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
896 return -EIO; 1210 return -EIO;
@@ -905,7 +1219,7 @@ static int hotkey_get(int *status, int *mask)
905/* 1219/*
906 * Call with hotkey_mutex held 1220 * Call with hotkey_mutex held
907 */ 1221 */
908static int hotkey_set(int status, int mask) 1222static int hotkey_set(int status, u32 mask)
909{ 1223{
910 int i; 1224 int i;
911 1225
@@ -926,7 +1240,8 @@ static int hotkey_set(int status, int mask)
926/* procfs -------------------------------------------------------------- */ 1240/* procfs -------------------------------------------------------------- */
927static int hotkey_read(char *p) 1241static int hotkey_read(char *p)
928{ 1242{
929 int res, status, mask; 1243 int res, status;
1244 u32 mask;
930 int len = 0; 1245 int len = 0;
931 1246
932 if (!tp_features.hotkey) { 1247 if (!tp_features.hotkey) {
@@ -944,7 +1259,7 @@ static int hotkey_read(char *p)
944 1259
945 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); 1260 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
946 if (tp_features.hotkey_mask) { 1261 if (tp_features.hotkey_mask) {
947 len += sprintf(p + len, "mask:\t\t0x%04x\n", mask); 1262 len += sprintf(p + len, "mask:\t\t0x%08x\n", mask);
948 len += sprintf(p + len, 1263 len += sprintf(p + len,
949 "commands:\tenable, disable, reset, <mask>\n"); 1264 "commands:\tenable, disable, reset, <mask>\n");
950 } else { 1265 } else {
@@ -957,7 +1272,8 @@ static int hotkey_read(char *p)
957 1272
958static int hotkey_write(char *buf) 1273static int hotkey_write(char *buf)
959{ 1274{
960 int res, status, mask; 1275 int res, status;
1276 u32 mask;
961 char *cmd; 1277 char *cmd;
962 int do_cmd = 0; 1278 int do_cmd = 0;
963 1279
@@ -1012,6 +1328,7 @@ static struct ibm_struct hotkey_driver_data = {
1012 .read = hotkey_read, 1328 .read = hotkey_read,
1013 .write = hotkey_write, 1329 .write = hotkey_write,
1014 .exit = hotkey_exit, 1330 .exit = hotkey_exit,
1331 .resume = hotkey_resume,
1015 .acpi = &ibm_hotkey_acpidriver, 1332 .acpi = &ibm_hotkey_acpidriver,
1016}; 1333};
1017 1334
@@ -1770,7 +2087,10 @@ static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
1770 .type = ACPI_SYSTEM_NOTIFY, 2087 .type = ACPI_SYSTEM_NOTIFY,
1771 }, 2088 },
1772 { 2089 {
1773 .hid = IBM_PCI_HID, 2090 /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING.
2091 * We just use it to get notifications of dock hotplug
2092 * in very old thinkpads */
2093 .hid = PCI_ROOT_HID_STRING,
1774 .notify = dock_notify, 2094 .notify = dock_notify,
1775 .handle = &pci_handle, 2095 .handle = &pci_handle,
1776 .type = ACPI_SYSTEM_NOTIFY, 2096 .type = ACPI_SYSTEM_NOTIFY,
@@ -1829,7 +2149,7 @@ static int __init dock_init2(struct ibm_init_struct *iibm)
1829static void dock_notify(struct ibm_struct *ibm, u32 event) 2149static void dock_notify(struct ibm_struct *ibm, u32 event)
1830{ 2150{
1831 int docked = dock_docked(); 2151 int docked = dock_docked();
1832 int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID); 2152 int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, PCI_ROOT_HID_STRING);
1833 2153
1834 if (event == 1 && !pci) /* 570 */ 2154 if (event == 1 && !pci) /* 570 */
1835 acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ 2155 acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */
@@ -2389,7 +2709,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
2389 2709
2390 acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); 2710 acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
2391 2711
2392 if (ibm_thinkpad_ec_found && experimental) { 2712 if (thinkpad_id.ec_model) {
2393 /* 2713 /*
2394 * Direct EC access mode: sensors at registers 2714 * Direct EC access mode: sensors at registers
2395 * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for 2715 * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
@@ -2533,6 +2853,8 @@ static int thermal_get_sensor(int idx, s32 *value)
2533 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); 2853 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
2534 if (!acpi_evalf(ec_handle, &t, tmpi, "d")) 2854 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
2535 return -EIO; 2855 return -EIO;
2856 if (t > 127 || t < -127)
2857 t = TP_EC_THERMAL_TMP_NA;
2536 *value = t * 1000; 2858 *value = t * 1000;
2537 return 0; 2859 return 0;
2538 } 2860 }
@@ -2671,22 +2993,39 @@ static struct ibm_struct ecdump_driver_data = {
2671 * Backlight/brightness subdriver 2993 * Backlight/brightness subdriver
2672 */ 2994 */
2673 2995
2674static struct backlight_device *ibm_backlight_device = NULL; 2996static struct backlight_device *ibm_backlight_device;
2675 2997
2676static struct backlight_ops ibm_backlight_data = { 2998static struct backlight_ops ibm_backlight_data = {
2677 .get_brightness = brightness_get, 2999 .get_brightness = brightness_get,
2678 .update_status = brightness_update_status, 3000 .update_status = brightness_update_status,
2679}; 3001};
2680 3002
3003static struct mutex brightness_mutex;
3004
2681static int __init brightness_init(struct ibm_init_struct *iibm) 3005static int __init brightness_init(struct ibm_init_struct *iibm)
2682{ 3006{
2683 int b; 3007 int b;
2684 3008
2685 vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); 3009 vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
2686 3010
3011 mutex_init(&brightness_mutex);
3012
3013 if (!brightness_mode) {
3014 if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
3015 brightness_mode = 2;
3016 else
3017 brightness_mode = 3;
3018
3019 dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
3020 brightness_mode);
3021 }
3022
3023 if (brightness_mode > 3)
3024 return -EINVAL;
3025
2687 b = brightness_get(NULL); 3026 b = brightness_get(NULL);
2688 if (b < 0) 3027 if (b < 0)
2689 return b; 3028 return 1;
2690 3029
2691 ibm_backlight_device = backlight_device_register( 3030 ibm_backlight_device = backlight_device_register(
2692 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, 3031 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
@@ -2722,34 +3061,79 @@ static int brightness_update_status(struct backlight_device *bd)
2722 bd->props.brightness : 0); 3061 bd->props.brightness : 0);
2723} 3062}
2724 3063
3064/*
3065 * ThinkPads can read brightness from two places: EC 0x31, or
3066 * CMOS NVRAM byte 0x5E, bits 0-3.
3067 */
2725static int brightness_get(struct backlight_device *bd) 3068static int brightness_get(struct backlight_device *bd)
2726{ 3069{
2727 u8 level; 3070 u8 lec = 0, lcmos = 0, level = 0;
2728 if (!acpi_ec_read(brightness_offset, &level))
2729 return -EIO;
2730 3071
2731 level &= 0x7; 3072 if (brightness_mode & 1) {
3073 if (!acpi_ec_read(brightness_offset, &lec))
3074 return -EIO;
3075 lec &= 7;
3076 level = lec;
3077 };
3078 if (brightness_mode & 2) {
3079 lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
3080 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
3081 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
3082 level = lcmos;
3083 }
3084
3085 if (brightness_mode == 3 && lec != lcmos) {
3086 printk(IBM_ERR
3087 "CMOS NVRAM (%u) and EC (%u) do not agree "
3088 "on display brightness level\n",
3089 (unsigned int) lcmos,
3090 (unsigned int) lec);
3091 return -EIO;
3092 }
2732 3093
2733 return level; 3094 return level;
2734} 3095}
2735 3096
2736static int brightness_set(int value) 3097static int brightness_set(int value)
2737{ 3098{
2738 int cmos_cmd, inc, i; 3099 int cmos_cmd, inc, i, res;
2739 int current_value = brightness_get(NULL); 3100 int current_value;
3101
3102 if (value > 7)
3103 return -EINVAL;
2740 3104
2741 value &= 7; 3105 res = mutex_lock_interruptible(&brightness_mutex);
3106 if (res < 0)
3107 return res;
3108
3109 current_value = brightness_get(NULL);
3110 if (current_value < 0) {
3111 res = current_value;
3112 goto errout;
3113 }
2742 3114
2743 cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN; 3115 cmos_cmd = value > current_value ?
3116 TP_CMOS_BRIGHTNESS_UP :
3117 TP_CMOS_BRIGHTNESS_DOWN;
2744 inc = value > current_value ? 1 : -1; 3118 inc = value > current_value ? 1 : -1;
3119
3120 res = 0;
2745 for (i = current_value; i != value; i += inc) { 3121 for (i = current_value; i != value; i += inc) {
2746 if (issue_thinkpad_cmos_command(cmos_cmd)) 3122 if ((brightness_mode & 2) &&
2747 return -EIO; 3123 issue_thinkpad_cmos_command(cmos_cmd)) {
2748 if (!acpi_ec_write(brightness_offset, i + inc)) 3124 res = -EIO;
2749 return -EIO; 3125 goto errout;
3126 }
3127 if ((brightness_mode & 1) &&
3128 !acpi_ec_write(brightness_offset, i + inc)) {
3129 res = -EIO;
3130 goto errout;;
3131 }
2750 } 3132 }
2751 3133
2752 return 0; 3134errout:
3135 mutex_unlock(&brightness_mutex);
3136 return res;
2753} 3137}
2754 3138
2755static int brightness_read(char *p) 3139static int brightness_read(char *p)
@@ -3273,20 +3657,19 @@ static int __init fan_init(struct ibm_init_struct *iibm)
3273 * Enable for TP-1Y (T43), TP-78 (R51e), 3657 * Enable for TP-1Y (T43), TP-78 (R51e),
3274 * TP-76 (R52), TP-70 (T43, R52), which are known 3658 * TP-76 (R52), TP-70 (T43, R52), which are known
3275 * to be buggy. */ 3659 * to be buggy. */
3276 if (fan_control_initial_status == 0x07 && 3660 if (fan_control_initial_status == 0x07) {
3277 ibm_thinkpad_ec_found && 3661 switch (thinkpad_id.ec_model) {
3278 ((ibm_thinkpad_ec_found[0] == '1' && 3662 case 0x5931: /* TP-1Y */
3279 ibm_thinkpad_ec_found[1] == 'Y') || 3663 case 0x3837: /* TP-78 */
3280 (ibm_thinkpad_ec_found[0] == '7' && 3664 case 0x3637: /* TP-76 */
3281 (ibm_thinkpad_ec_found[1] == '6' || 3665 case 0x3037: /* TP-70 */
3282 ibm_thinkpad_ec_found[1] == '8' || 3666 printk(IBM_NOTICE
3283 ibm_thinkpad_ec_found[1] == '0')) 3667 "fan_init: initial fan status is "
3284 )) { 3668 "unknown, assuming it is in auto "
3285 printk(IBM_NOTICE 3669 "mode\n");
3286 "fan_init: initial fan status is " 3670 tp_features.fan_ctrl_status_undef = 1;
3287 "unknown, assuming it is in auto " 3671 ;;
3288 "mode\n"); 3672 }
3289 tp_features.fan_ctrl_status_undef = 1;
3290 } 3673 }
3291 } else { 3674 } else {
3292 printk(IBM_ERR 3675 printk(IBM_ERR
@@ -3474,7 +3857,7 @@ static void fan_watchdog_fire(struct work_struct *ignored)
3474 3857
3475static void fan_watchdog_reset(void) 3858static void fan_watchdog_reset(void)
3476{ 3859{
3477 static int fan_watchdog_active = 0; 3860 static int fan_watchdog_active;
3478 3861
3479 if (fan_control_access_mode == TPACPI_FAN_WR_NONE) 3862 if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
3480 return; 3863 return;
@@ -3877,7 +4260,7 @@ static struct ibm_struct fan_driver_data = {
3877 ****************************************************************************/ 4260 ****************************************************************************/
3878 4261
3879/* /proc support */ 4262/* /proc support */
3880static struct proc_dir_entry *proc_dir = NULL; 4263static struct proc_dir_entry *proc_dir;
3881 4264
3882/* Subdriver registry */ 4265/* Subdriver registry */
3883static LIST_HEAD(tpacpi_all_drivers); 4266static LIST_HEAD(tpacpi_all_drivers);
@@ -4020,13 +4403,30 @@ static void ibm_exit(struct ibm_struct *ibm)
4020 4403
4021/* Probing */ 4404/* Probing */
4022 4405
4023static char *ibm_thinkpad_ec_found = NULL; 4406static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
4024
4025static char* __init check_dmi_for_ec(void)
4026{ 4407{
4027 struct dmi_device *dev = NULL; 4408 struct dmi_device *dev = NULL;
4028 char ec_fw_string[18]; 4409 char ec_fw_string[18];
4029 4410
4411 if (!tp)
4412 return;
4413
4414 memset(tp, 0, sizeof(*tp));
4415
4416 if (dmi_name_in_vendors("IBM"))
4417 tp->vendor = PCI_VENDOR_ID_IBM;
4418 else if (dmi_name_in_vendors("LENOVO"))
4419 tp->vendor = PCI_VENDOR_ID_LENOVO;
4420 else
4421 return;
4422
4423 tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION),
4424 GFP_KERNEL);
4425 if (!tp->bios_version_str)
4426 return;
4427 tp->bios_model = tp->bios_version_str[0]
4428 | (tp->bios_version_str[1] << 8);
4429
4030 /* 4430 /*
4031 * ThinkPad T23 or newer, A31 or newer, R50e or newer, 4431 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
4032 * X32 or newer, all Z series; Some models must have an 4432 * X32 or newer, all Z series; Some models must have an
@@ -4040,10 +4440,20 @@ static char* __init check_dmi_for_ec(void)
4040 ec_fw_string) == 1) { 4440 ec_fw_string) == 1) {
4041 ec_fw_string[sizeof(ec_fw_string) - 1] = 0; 4441 ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
4042 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; 4442 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
4043 return kstrdup(ec_fw_string, GFP_KERNEL); 4443
4444 tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
4445 tp->ec_model = ec_fw_string[0]
4446 | (ec_fw_string[1] << 8);
4447 break;
4044 } 4448 }
4045 } 4449 }
4046 return NULL; 4450
4451 tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION),
4452 GFP_KERNEL);
4453 if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
4454 kfree(tp->model_str);
4455 tp->model_str = NULL;
4456 }
4047} 4457}
4048 4458
4049static int __init probe_for_thinkpad(void) 4459static int __init probe_for_thinkpad(void)
@@ -4057,7 +4467,7 @@ static int __init probe_for_thinkpad(void)
4057 * Non-ancient models have better DMI tagging, but very old models 4467 * Non-ancient models have better DMI tagging, but very old models
4058 * don't. 4468 * don't.
4059 */ 4469 */
4060 is_thinkpad = dmi_name_in_vendors("ThinkPad"); 4470 is_thinkpad = (thinkpad_id.model_str != NULL);
4061 4471
4062 /* ec is required because many other handles are relative to it */ 4472 /* ec is required because many other handles are relative to it */
4063 IBM_ACPIHANDLE_INIT(ec); 4473 IBM_ACPIHANDLE_INIT(ec);
@@ -4073,7 +4483,7 @@ static int __init probe_for_thinkpad(void)
4073 * false positives a damn great deal 4483 * false positives a damn great deal
4074 */ 4484 */
4075 if (!is_thinkpad) 4485 if (!is_thinkpad)
4076 is_thinkpad = dmi_name_in_vendors("IBM"); 4486 is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM);
4077 4487
4078 if (!is_thinkpad && !force_load) 4488 if (!is_thinkpad && !force_load)
4079 return -ENODEV; 4489 return -ENODEV;
@@ -4185,10 +4595,13 @@ static u32 dbg_level;
4185module_param_named(debug, dbg_level, uint, 0); 4595module_param_named(debug, dbg_level, uint, 0);
4186 4596
4187static int force_load; 4597static int force_load;
4188module_param(force_load, int, 0); 4598module_param(force_load, bool, 0);
4189 4599
4190static int fan_control_allowed; 4600static int fan_control_allowed;
4191module_param_named(fan_control, fan_control_allowed, int, 0); 4601module_param_named(fan_control, fan_control_allowed, bool, 0);
4602
4603static int brightness_mode;
4604module_param_named(brightness_mode, brightness_mode, int, 0);
4192 4605
4193#define IBM_PARAM(feature) \ 4606#define IBM_PARAM(feature) \
4194 module_param_call(feature, set_ibm_param, NULL, NULL, 0) 4607 module_param_call(feature, set_ibm_param, NULL, NULL, 0)
@@ -4216,12 +4629,16 @@ static int __init thinkpad_acpi_module_init(void)
4216 int ret, i; 4629 int ret, i;
4217 4630
4218 /* Driver-level probe */ 4631 /* Driver-level probe */
4632
4633 get_thinkpad_model_data(&thinkpad_id);
4219 ret = probe_for_thinkpad(); 4634 ret = probe_for_thinkpad();
4220 if (ret) 4635 if (ret) {
4636 thinkpad_acpi_module_exit();
4221 return ret; 4637 return ret;
4638 }
4222 4639
4223 /* Driver initialization */ 4640 /* Driver initialization */
4224 ibm_thinkpad_ec_found = check_dmi_for_ec(); 4641
4225 IBM_ACPIHANDLE_INIT(ecrd); 4642 IBM_ACPIHANDLE_INIT(ecrd);
4226 IBM_ACPIHANDLE_INIT(ecwr); 4643 IBM_ACPIHANDLE_INIT(ecwr);
4227 4644
@@ -4265,6 +4682,22 @@ static int __init thinkpad_acpi_module_init(void)
4265 thinkpad_acpi_module_exit(); 4682 thinkpad_acpi_module_exit();
4266 return ret; 4683 return ret;
4267 } 4684 }
4685 tpacpi_inputdev = input_allocate_device();
4686 if (!tpacpi_inputdev) {
4687 printk(IBM_ERR "unable to allocate input device\n");
4688 thinkpad_acpi_module_exit();
4689 return -ENOMEM;
4690 } else {
4691 /* Prepare input device, but don't register */
4692 tpacpi_inputdev->name = "ThinkPad Extra Buttons";
4693 tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0";
4694 tpacpi_inputdev->id.bustype = BUS_HOST;
4695 tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
4696 thinkpad_id.vendor :
4697 PCI_VENDOR_ID_IBM;
4698 tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
4699 tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
4700 }
4268 for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { 4701 for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
4269 ret = ibm_init(&ibms_init[i]); 4702 ret = ibm_init(&ibms_init[i]);
4270 if (ret >= 0 && *ibms_init[i].param) 4703 if (ret >= 0 && *ibms_init[i].param)
@@ -4274,6 +4707,14 @@ static int __init thinkpad_acpi_module_init(void)
4274 return ret; 4707 return ret;
4275 } 4708 }
4276 } 4709 }
4710 ret = input_register_device(tpacpi_inputdev);
4711 if (ret < 0) {
4712 printk(IBM_ERR "unable to register input device\n");
4713 thinkpad_acpi_module_exit();
4714 return ret;
4715 } else {
4716 tp_features.input_device_registered = 1;
4717 }
4277 4718
4278 return 0; 4719 return 0;
4279} 4720}
@@ -4290,6 +4731,13 @@ static void thinkpad_acpi_module_exit(void)
4290 4731
4291 dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); 4732 dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
4292 4733
4734 if (tpacpi_inputdev) {
4735 if (tp_features.input_device_registered)
4736 input_unregister_device(tpacpi_inputdev);
4737 else
4738 input_free_device(tpacpi_inputdev);
4739 }
4740
4293 if (tpacpi_hwmon) 4741 if (tpacpi_hwmon)
4294 hwmon_device_unregister(tpacpi_hwmon); 4742 hwmon_device_unregister(tpacpi_hwmon);
4295 4743
@@ -4302,7 +4750,9 @@ static void thinkpad_acpi_module_exit(void)
4302 if (proc_dir) 4750 if (proc_dir)
4303 remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); 4751 remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
4304 4752
4305 kfree(ibm_thinkpad_ec_found); 4753 kfree(thinkpad_id.bios_version_str);
4754 kfree(thinkpad_id.ec_version_str);
4755 kfree(thinkpad_id.model_str);
4306} 4756}
4307 4757
4308module_init(thinkpad_acpi_module_init); 4758module_init(thinkpad_acpi_module_init);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index 72d62f2dabb9..b7a4a888cc8b 100644
--- a/drivers/misc/thinkpad_acpi.h
+++ b/drivers/misc/thinkpad_acpi.h
@@ -32,6 +32,7 @@
32#include <linux/list.h> 32#include <linux/list.h>
33#include <linux/mutex.h> 33#include <linux/mutex.h>
34 34
35#include <linux/nvram.h>
35#include <linux/proc_fs.h> 36#include <linux/proc_fs.h>
36#include <linux/sysfs.h> 37#include <linux/sysfs.h>
37#include <linux/backlight.h> 38#include <linux/backlight.h>
@@ -39,6 +40,7 @@
39#include <linux/platform_device.h> 40#include <linux/platform_device.h>
40#include <linux/hwmon.h> 41#include <linux/hwmon.h>
41#include <linux/hwmon-sysfs.h> 42#include <linux/hwmon-sysfs.h>
43#include <linux/input.h>
42#include <asm/uaccess.h> 44#include <asm/uaccess.h>
43 45
44#include <linux/dmi.h> 46#include <linux/dmi.h>
@@ -48,6 +50,7 @@
48#include <acpi/acpi_drivers.h> 50#include <acpi/acpi_drivers.h>
49#include <acpi/acnamesp.h> 51#include <acpi/acnamesp.h>
50 52
53#include <linux/pci_ids.h>
51 54
52/**************************************************************************** 55/****************************************************************************
53 * Main driver 56 * Main driver
@@ -78,6 +81,11 @@
78#define TP_CMOS_BRIGHTNESS_UP 4 81#define TP_CMOS_BRIGHTNESS_UP 4
79#define TP_CMOS_BRIGHTNESS_DOWN 5 82#define TP_CMOS_BRIGHTNESS_DOWN 5
80 83
84/* ThinkPad CMOS NVRAM constants */
85#define TP_NVRAM_ADDR_BRIGHTNESS 0x5e
86#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07
87#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
88
81#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") 89#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
82#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") 90#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
83#define strlencmp(a,b) (strncmp((a), (b), strlen(b))) 91#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
@@ -98,9 +106,13 @@ static const char *str_supported(int is_supported);
98#define vdbg_printk(a_dbg_level, format, arg...) 106#define vdbg_printk(a_dbg_level, format, arg...)
99#endif 107#endif
100 108
109/* Input IDs */
110#define TPACPI_HKEY_INPUT_VENDOR PCI_VENDOR_ID_IBM
111#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */
112#define TPACPI_HKEY_INPUT_VERSION 0x4101
113
101/* ACPI HIDs */ 114/* ACPI HIDs */
102#define IBM_HKEY_HID "IBM0068" 115#define IBM_HKEY_HID "IBM0068"
103#define IBM_PCI_HID "PNP0A03"
104 116
105/* ACPI helpers */ 117/* ACPI helpers */
106static int __must_check acpi_evalf(acpi_handle handle, 118static int __must_check acpi_evalf(acpi_handle handle,
@@ -161,6 +173,7 @@ static int parse_strtoul(const char *buf, unsigned long max,
161static struct platform_device *tpacpi_pdev; 173static struct platform_device *tpacpi_pdev;
162static struct class_device *tpacpi_hwmon; 174static struct class_device *tpacpi_hwmon;
163static struct platform_driver tpacpi_pdriver; 175static struct platform_driver tpacpi_pdriver;
176static struct input_dev *tpacpi_inputdev;
164static int tpacpi_create_driver_attributes(struct device_driver *drv); 177static int tpacpi_create_driver_attributes(struct device_driver *drv);
165static void tpacpi_remove_driver_attributes(struct device_driver *drv); 178static void tpacpi_remove_driver_attributes(struct device_driver *drv);
166 179
@@ -168,9 +181,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv);
168static int experimental; 181static int experimental;
169static u32 dbg_level; 182static u32 dbg_level;
170static int force_load; 183static int force_load;
171static char *ibm_thinkpad_ec_found;
172 184
173static char* check_dmi_for_ec(void);
174static int thinkpad_acpi_module_init(void); 185static int thinkpad_acpi_module_init(void);
175static void thinkpad_acpi_module_exit(void); 186static void thinkpad_acpi_module_exit(void);
176 187
@@ -197,6 +208,7 @@ struct ibm_struct {
197 int (*read) (char *); 208 int (*read) (char *);
198 int (*write) (char *); 209 int (*write) (char *);
199 void (*exit) (void); 210 void (*exit) (void);
211 void (*resume) (void);
200 212
201 struct list_head all_drivers; 213 struct list_head all_drivers;
202 214
@@ -228,12 +240,29 @@ static struct {
228 u16 bluetooth:1; 240 u16 bluetooth:1;
229 u16 hotkey:1; 241 u16 hotkey:1;
230 u16 hotkey_mask:1; 242 u16 hotkey_mask:1;
243 u16 hotkey_wlsw:1;
231 u16 light:1; 244 u16 light:1;
232 u16 light_status:1; 245 u16 light_status:1;
233 u16 wan:1; 246 u16 wan:1;
234 u16 fan_ctrl_status_undef:1; 247 u16 fan_ctrl_status_undef:1;
248 u16 input_device_registered:1;
235} tp_features; 249} tp_features;
236 250
251struct thinkpad_id_data {
252 unsigned int vendor; /* ThinkPad vendor:
253 * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
254
255 char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
256 char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
257
258 u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
259 u16 ec_model;
260
261 char *model_str;
262};
263
264static struct thinkpad_id_data thinkpad_id;
265
237static struct list_head tpacpi_all_drivers; 266static struct list_head tpacpi_all_drivers;
238 267
239static struct ibm_init_struct ibms_init[]; 268static struct ibm_init_struct ibms_init[];
@@ -300,6 +329,7 @@ static int bluetooth_write(char *buf);
300 329
301static struct backlight_device *ibm_backlight_device; 330static struct backlight_device *ibm_backlight_device;
302static int brightness_offset = 0x31; 331static int brightness_offset = 0x31;
332static int brightness_mode;
303 333
304static int brightness_init(struct ibm_init_struct *iibm); 334static int brightness_init(struct ibm_init_struct *iibm);
305static void brightness_exit(void); 335static void brightness_exit(void);
@@ -415,14 +445,14 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc);
415 */ 445 */
416 446
417static int hotkey_orig_status; 447static int hotkey_orig_status;
418static int hotkey_orig_mask; 448static u32 hotkey_orig_mask;
419 449
420static struct mutex hotkey_mutex; 450static struct mutex hotkey_mutex;
421 451
422static int hotkey_init(struct ibm_init_struct *iibm); 452static int hotkey_init(struct ibm_init_struct *iibm);
423static void hotkey_exit(void); 453static void hotkey_exit(void);
424static int hotkey_get(int *status, int *mask); 454static int hotkey_get(int *status, u32 *mask);
425static int hotkey_set(int status, int mask); 455static int hotkey_set(int status, u32 mask);
426static void hotkey_notify(struct ibm_struct *ibm, u32 event); 456static void hotkey_notify(struct ibm_struct *ibm, u32 event);
427static int hotkey_read(char *p); 457static int hotkey_read(char *p);
428static int hotkey_write(char *buf); 458static int hotkey_write(char *buf);