diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2007-10-12 21:27:47 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2007-10-12 21:27:47 -0400 |
| commit | b981d8b3f5e008ff10d993be633ad00564fc22cd (patch) | |
| tree | e292dc07b22308912cf6a58354a608b9e5e8e1fd /drivers/misc | |
| parent | b11d2127c4893a7315d1e16273bc8560049fa3ca (diff) | |
| parent | 2b9e0aae1d50e880c58d46788e5e3ebd89d75d62 (diff) | |
Merge master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
drivers/macintosh/adbhid.c
Diffstat (limited to 'drivers/misc')
| -rw-r--r-- | drivers/misc/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/misc/asus-laptop.c | 45 | ||||
| -rw-r--r-- | drivers/misc/hdpuftrs/hdpu_cpustate.c | 107 | ||||
| -rw-r--r-- | drivers/misc/hdpuftrs/hdpu_nexus.c | 88 | ||||
| -rw-r--r-- | drivers/misc/ibmasm/command.c | 6 | ||||
| -rw-r--r-- | drivers/misc/ibmasm/ibmasmfs.c | 3 | ||||
| -rw-r--r-- | drivers/misc/ibmasm/module.c | 3 | ||||
| -rw-r--r-- | drivers/misc/msi-laptop.c | 4 | ||||
| -rw-r--r-- | drivers/misc/sony-laptop.c | 420 | ||||
| -rw-r--r-- | drivers/misc/thinkpad_acpi.c | 690 | ||||
| -rw-r--r-- | drivers/misc/thinkpad_acpi.h | 47 | ||||
| -rw-r--r-- | drivers/misc/tifm_core.c | 9 |
12 files changed, 1156 insertions, 273 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 1d516f24ba53..73e248fb2ff1 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
| @@ -5,6 +5,11 @@ | |||
| 5 | menuconfig MISC_DEVICES | 5 | menuconfig MISC_DEVICES |
| 6 | bool "Misc devices" | 6 | bool "Misc devices" |
| 7 | default y | 7 | default y |
| 8 | ---help--- | ||
| 9 | Say Y here to get to see options for device drivers from various | ||
| 10 | different categories. This option alone does not add any kernel code. | ||
| 11 | |||
| 12 | If you say N, all options in this submenu will be skipped and disabled. | ||
| 8 | 13 | ||
| 9 | if MISC_DEVICES | 14 | if MISC_DEVICES |
| 10 | 15 | ||
| @@ -150,6 +155,7 @@ config THINKPAD_ACPI | |||
| 150 | depends on X86 && ACPI | 155 | depends on X86 && ACPI |
| 151 | select BACKLIGHT_CLASS_DEVICE | 156 | select BACKLIGHT_CLASS_DEVICE |
| 152 | select HWMON | 157 | select HWMON |
| 158 | select NVRAM | ||
| 153 | ---help--- | 159 | ---help--- |
| 154 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds | 160 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds |
| 155 | support for Fn-Fx key combinations, Bluetooth control, video | 161 | support for Fn-Fx key combinations, Bluetooth control, video |
| @@ -196,4 +202,5 @@ config THINKPAD_ACPI_BAY | |||
| 196 | 202 | ||
| 197 | If you are not sure, say Y here. | 203 | If you are not sure, say Y here. |
| 198 | 204 | ||
| 205 | |||
| 199 | endif # MISC_DEVICES | 206 | endif # MISC_DEVICES |
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index 7798f590e5aa..7dce318df1bd 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c | |||
| @@ -53,7 +53,6 @@ | |||
| 53 | #define ASUS_HOTK_NAME "Asus Laptop Support" | 53 | #define ASUS_HOTK_NAME "Asus Laptop Support" |
| 54 | #define ASUS_HOTK_CLASS "hotkey" | 54 | #define ASUS_HOTK_CLASS "hotkey" |
| 55 | #define ASUS_HOTK_DEVICE_NAME "Hotkey" | 55 | #define ASUS_HOTK_DEVICE_NAME "Hotkey" |
| 56 | #define ASUS_HOTK_HID "ATK0100" | ||
| 57 | #define ASUS_HOTK_FILE "asus-laptop" | 56 | #define ASUS_HOTK_FILE "asus-laptop" |
| 58 | #define ASUS_HOTK_PREFIX "\\_SB.ATKD." | 57 | #define ASUS_HOTK_PREFIX "\\_SB.ATKD." |
| 59 | 58 | ||
| @@ -197,12 +196,18 @@ static struct asus_hotk *hotk; | |||
| 197 | /* | 196 | /* |
| 198 | * The hotkey driver declaration | 197 | * The hotkey driver declaration |
| 199 | */ | 198 | */ |
| 199 | static const struct acpi_device_id asus_device_ids[] = { | ||
| 200 | {"ATK0100", 0}, | ||
| 201 | {"", 0}, | ||
| 202 | }; | ||
| 203 | MODULE_DEVICE_TABLE(acpi, asus_device_ids); | ||
| 204 | |||
| 200 | static int asus_hotk_add(struct acpi_device *device); | 205 | static int asus_hotk_add(struct acpi_device *device); |
| 201 | static int asus_hotk_remove(struct acpi_device *device, int type); | 206 | static int asus_hotk_remove(struct acpi_device *device, int type); |
| 202 | static struct acpi_driver asus_hotk_driver = { | 207 | static struct acpi_driver asus_hotk_driver = { |
| 203 | .name = ASUS_HOTK_NAME, | 208 | .name = ASUS_HOTK_NAME, |
| 204 | .class = ASUS_HOTK_CLASS, | 209 | .class = ASUS_HOTK_CLASS, |
| 205 | .ids = ASUS_HOTK_HID, | 210 | .ids = asus_device_ids, |
| 206 | .ops = { | 211 | .ops = { |
| 207 | .add = asus_hotk_add, | 212 | .add = asus_hotk_add, |
| 208 | .remove = asus_hotk_remove, | 213 | .remove = asus_hotk_remove, |
| @@ -727,7 +732,7 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) | |||
| 727 | lcd_blank(FB_BLANK_POWERDOWN); | 732 | lcd_blank(FB_BLANK_POWERDOWN); |
| 728 | } | 733 | } |
| 729 | 734 | ||
| 730 | acpi_bus_generate_event(hotk->device, event, | 735 | acpi_bus_generate_proc_event(hotk->device, event, |
| 731 | hotk->event_count[event % 128]++); | 736 | hotk->event_count[event % 128]++); |
| 732 | 737 | ||
| 733 | return; | 738 | return; |
| @@ -979,10 +984,9 @@ static int asus_hotk_add(struct acpi_device *device) | |||
| 979 | printk(ASUS_NOTICE "Asus Laptop Support version %s\n", | 984 | printk(ASUS_NOTICE "Asus Laptop Support version %s\n", |
| 980 | ASUS_LAPTOP_VERSION); | 985 | ASUS_LAPTOP_VERSION); |
| 981 | 986 | ||
| 982 | hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL); | 987 | hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL); |
| 983 | if (!hotk) | 988 | if (!hotk) |
| 984 | return -ENOMEM; | 989 | return -ENOMEM; |
| 985 | memset(hotk, 0, sizeof(struct asus_hotk)); | ||
| 986 | 990 | ||
| 987 | hotk->handle = device->handle; | 991 | hotk->handle = device->handle; |
| 988 | strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME); | 992 | strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME); |
| @@ -1068,19 +1072,17 @@ static void asus_backlight_exit(void) | |||
| 1068 | } | 1072 | } |
| 1069 | 1073 | ||
| 1070 | #define ASUS_LED_UNREGISTER(object) \ | 1074 | #define ASUS_LED_UNREGISTER(object) \ |
| 1071 | if(object##_led.class_dev \ | 1075 | if (object##_led.dev) \ |
| 1072 | && !IS_ERR(object##_led.class_dev)) \ | ||
| 1073 | led_classdev_unregister(&object##_led) | 1076 | led_classdev_unregister(&object##_led) |
| 1074 | 1077 | ||
| 1075 | static void asus_led_exit(void) | 1078 | static void asus_led_exit(void) |
| 1076 | { | 1079 | { |
| 1080 | destroy_workqueue(led_workqueue); | ||
| 1077 | ASUS_LED_UNREGISTER(mled); | 1081 | ASUS_LED_UNREGISTER(mled); |
| 1078 | ASUS_LED_UNREGISTER(tled); | 1082 | ASUS_LED_UNREGISTER(tled); |
| 1079 | ASUS_LED_UNREGISTER(pled); | 1083 | ASUS_LED_UNREGISTER(pled); |
| 1080 | ASUS_LED_UNREGISTER(rled); | 1084 | ASUS_LED_UNREGISTER(rled); |
| 1081 | ASUS_LED_UNREGISTER(gled); | 1085 | ASUS_LED_UNREGISTER(gled); |
| 1082 | |||
| 1083 | destroy_workqueue(led_workqueue); | ||
| 1084 | } | 1086 | } |
| 1085 | 1087 | ||
| 1086 | static void __exit asus_laptop_exit(void) | 1088 | static void __exit asus_laptop_exit(void) |
| @@ -1136,29 +1138,42 @@ static int asus_led_init(struct device *dev) | |||
| 1136 | 1138 | ||
| 1137 | rv = ASUS_LED_REGISTER(mled, dev); | 1139 | rv = ASUS_LED_REGISTER(mled, dev); |
| 1138 | if (rv) | 1140 | if (rv) |
| 1139 | return rv; | 1141 | goto out; |
| 1140 | 1142 | ||
| 1141 | rv = ASUS_LED_REGISTER(tled, dev); | 1143 | rv = ASUS_LED_REGISTER(tled, dev); |
| 1142 | if (rv) | 1144 | if (rv) |
| 1143 | return rv; | 1145 | goto out1; |
| 1144 | 1146 | ||
| 1145 | rv = ASUS_LED_REGISTER(rled, dev); | 1147 | rv = ASUS_LED_REGISTER(rled, dev); |
| 1146 | if (rv) | 1148 | if (rv) |
| 1147 | return rv; | 1149 | goto out2; |
| 1148 | 1150 | ||
| 1149 | rv = ASUS_LED_REGISTER(pled, dev); | 1151 | rv = ASUS_LED_REGISTER(pled, dev); |
| 1150 | if (rv) | 1152 | if (rv) |
| 1151 | return rv; | 1153 | goto out3; |
| 1152 | 1154 | ||
| 1153 | rv = ASUS_LED_REGISTER(gled, dev); | 1155 | rv = ASUS_LED_REGISTER(gled, dev); |
| 1154 | if (rv) | 1156 | if (rv) |
| 1155 | return rv; | 1157 | goto out4; |
| 1156 | 1158 | ||
| 1157 | led_workqueue = create_singlethread_workqueue("led_workqueue"); | 1159 | led_workqueue = create_singlethread_workqueue("led_workqueue"); |
| 1158 | if (!led_workqueue) | 1160 | if (!led_workqueue) |
| 1159 | return -ENOMEM; | 1161 | goto out5; |
| 1160 | 1162 | ||
| 1161 | return 0; | 1163 | return 0; |
| 1164 | out5: | ||
| 1165 | rv = -ENOMEM; | ||
| 1166 | ASUS_LED_UNREGISTER(gled); | ||
| 1167 | out4: | ||
| 1168 | ASUS_LED_UNREGISTER(pled); | ||
| 1169 | out3: | ||
| 1170 | ASUS_LED_UNREGISTER(rled); | ||
| 1171 | out2: | ||
| 1172 | ASUS_LED_UNREGISTER(tled); | ||
| 1173 | out1: | ||
| 1174 | ASUS_LED_UNREGISTER(mled); | ||
| 1175 | out: | ||
| 1176 | return rv; | ||
| 1162 | } | 1177 | } |
| 1163 | 1178 | ||
| 1164 | static int __init asus_laptop_init(void) | 1179 | static int __init asus_laptop_init(void) |
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 276ba3c5143f..aa8ce7abe922 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c | |||
| @@ -19,16 +19,41 @@ | |||
| 19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
| 20 | #include <linux/miscdevice.h> | 20 | #include <linux/miscdevice.h> |
| 21 | #include <linux/proc_fs.h> | 21 | #include <linux/proc_fs.h> |
| 22 | #include <linux/hdpu_features.h> | ||
| 22 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
| 23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
| 24 | #include <linux/hdpu_features.h> | 25 | #include <linux/seq_file.h> |
| 26 | #include <asm/io.h> | ||
| 25 | 27 | ||
| 26 | #define SKY_CPUSTATE_VERSION "1.1" | 28 | #define SKY_CPUSTATE_VERSION "1.1" |
| 27 | 29 | ||
| 28 | static int hdpu_cpustate_probe(struct platform_device *pdev); | 30 | static int hdpu_cpustate_probe(struct platform_device *pdev); |
| 29 | static int hdpu_cpustate_remove(struct platform_device *pdev); | 31 | static int hdpu_cpustate_remove(struct platform_device *pdev); |
| 30 | 32 | ||
| 31 | struct cpustate_t cpustate; | 33 | static unsigned char cpustate_get_state(void); |
| 34 | static int cpustate_proc_open(struct inode *inode, struct file *file); | ||
| 35 | static int cpustate_proc_read(struct seq_file *seq, void *offset); | ||
| 36 | |||
| 37 | static struct cpustate_t cpustate; | ||
| 38 | |||
| 39 | static const struct file_operations proc_cpustate = { | ||
| 40 | .open = cpustate_proc_open, | ||
| 41 | .read = seq_read, | ||
| 42 | .llseek = seq_lseek, | ||
| 43 | .release = single_release, | ||
| 44 | .owner = THIS_MODULE, | ||
| 45 | }; | ||
| 46 | |||
| 47 | static int cpustate_proc_open(struct inode *inode, struct file *file) | ||
| 48 | { | ||
| 49 | return single_open(file, cpustate_proc_read, NULL); | ||
| 50 | } | ||
| 51 | |||
| 52 | static int cpustate_proc_read(struct seq_file *seq, void *offset) | ||
| 53 | { | ||
| 54 | seq_printf(seq, "CPU State: %04x\n", cpustate_get_state()); | ||
| 55 | return 0; | ||
| 56 | } | ||
| 32 | 57 | ||
| 33 | static int cpustate_get_ref(int excl) | 58 | static int cpustate_get_ref(int excl) |
| 34 | { | 59 | { |
| @@ -66,13 +91,13 @@ static int cpustate_free_ref(void) | |||
| 66 | return 0; | 91 | return 0; |
| 67 | } | 92 | } |
| 68 | 93 | ||
| 69 | unsigned char cpustate_get_state(void) | 94 | static unsigned char cpustate_get_state(void) |
| 70 | { | 95 | { |
| 71 | 96 | ||
| 72 | return cpustate.cached_val; | 97 | return cpustate.cached_val; |
| 73 | } | 98 | } |
| 74 | 99 | ||
| 75 | void cpustate_set_state(unsigned char new_state) | 100 | static void cpustate_set_state(unsigned char new_state) |
| 76 | { | 101 | { |
| 77 | unsigned int state = (new_state << 21); | 102 | unsigned int state = (new_state << 21); |
| 78 | 103 | ||
| @@ -134,29 +159,6 @@ static int cpustate_release(struct inode *inode, struct file *file) | |||
| 134 | return cpustate_free_ref(); | 159 | return cpustate_free_ref(); |
| 135 | } | 160 | } |
| 136 | 161 | ||
| 137 | /* | ||
| 138 | * Info exported via "/proc/sky_cpustate". | ||
| 139 | */ | ||
| 140 | static int cpustate_read_proc(char *page, char **start, off_t off, | ||
| 141 | int count, int *eof, void *data) | ||
| 142 | { | ||
| 143 | char *p = page; | ||
| 144 | int len = 0; | ||
| 145 | |||
| 146 | p += sprintf(p, "CPU State: %04x\n", cpustate_get_state()); | ||
| 147 | len = p - page; | ||
| 148 | |||
| 149 | if (len <= off + count) | ||
| 150 | *eof = 1; | ||
| 151 | *start = page + off; | ||
| 152 | len -= off; | ||
| 153 | if (len > count) | ||
| 154 | len = count; | ||
| 155 | if (len < 0) | ||
| 156 | len = 0; | ||
| 157 | return len; | ||
| 158 | } | ||
| 159 | |||
| 160 | static struct platform_driver hdpu_cpustate_driver = { | 162 | static struct platform_driver hdpu_cpustate_driver = { |
| 161 | .probe = hdpu_cpustate_probe, | 163 | .probe = hdpu_cpustate_probe, |
| 162 | .remove = hdpu_cpustate_remove, | 164 | .remove = hdpu_cpustate_remove, |
| @@ -169,22 +171,18 @@ static struct platform_driver hdpu_cpustate_driver = { | |||
| 169 | * The various file operations we support. | 171 | * The various file operations we support. |
| 170 | */ | 172 | */ |
| 171 | static const struct file_operations cpustate_fops = { | 173 | static const struct file_operations cpustate_fops = { |
| 172 | owner:THIS_MODULE, | 174 | .owner = THIS_MODULE, |
| 173 | open:cpustate_open, | 175 | .open = cpustate_open, |
| 174 | release:cpustate_release, | 176 | .release = cpustate_release, |
| 175 | read:cpustate_read, | 177 | .read = cpustate_read, |
| 176 | write:cpustate_write, | 178 | .write = cpustate_write, |
| 177 | fasync:NULL, | 179 | .llseek = no_llseek, |
| 178 | poll:NULL, | ||
| 179 | ioctl:NULL, | ||
| 180 | llseek:no_llseek, | ||
| 181 | |||
| 182 | }; | 180 | }; |
| 183 | 181 | ||
| 184 | static struct miscdevice cpustate_dev = { | 182 | static struct miscdevice cpustate_dev = { |
| 185 | MISC_DYNAMIC_MINOR, | 183 | .minor = MISC_DYNAMIC_MINOR, |
| 186 | "sky_cpustate", | 184 | .name = "sky_cpustate", |
| 187 | &cpustate_fops | 185 | .fops = &cpustate_fops, |
| 188 | }; | 186 | }; |
| 189 | 187 | ||
| 190 | static int hdpu_cpustate_probe(struct platform_device *pdev) | 188 | static int hdpu_cpustate_probe(struct platform_device *pdev) |
| @@ -194,23 +192,31 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) | |||
| 194 | int ret; | 192 | int ret; |
| 195 | 193 | ||
| 196 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 194 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 195 | if (!res) { | ||
| 196 | printk(KERN_ERR "sky_cpustate: " | ||
| 197 | "Invalid memory resource.\n"); | ||
| 198 | return -EINVAL; | ||
| 199 | } | ||
| 197 | cpustate.set_addr = (unsigned long *)res->start; | 200 | cpustate.set_addr = (unsigned long *)res->start; |
| 198 | cpustate.clr_addr = (unsigned long *)res->end - 1; | 201 | cpustate.clr_addr = (unsigned long *)res->end - 1; |
| 199 | 202 | ||
| 200 | ret = misc_register(&cpustate_dev); | 203 | ret = misc_register(&cpustate_dev); |
| 201 | if (ret) { | 204 | if (ret) { |
| 202 | printk(KERN_WARNING "sky_cpustate: Unable to register misc " | 205 | printk(KERN_WARNING "sky_cpustate: " |
| 203 | "device.\n"); | 206 | "Unable to register misc device.\n"); |
| 204 | cpustate.set_addr = NULL; | 207 | cpustate.set_addr = NULL; |
| 205 | cpustate.clr_addr = NULL; | 208 | cpustate.clr_addr = NULL; |
| 206 | return ret; | 209 | return ret; |
| 207 | } | 210 | } |
| 208 | 211 | ||
| 209 | proc_de = create_proc_read_entry("sky_cpustate", 0, 0, | 212 | proc_de = create_proc_entry("sky_cpustate", 0666, &proc_root); |
| 210 | cpustate_read_proc, NULL); | 213 | if (!proc_de) { |
| 211 | if (proc_de == NULL) | 214 | printk(KERN_WARNING "sky_cpustate: " |
| 212 | printk(KERN_WARNING "sky_cpustate: Unable to create proc " | 215 | "Unable to create proc entry\n"); |
| 213 | "dir entry\n"); | 216 | } else { |
| 217 | proc_de->proc_fops = &proc_cpustate; | ||
| 218 | proc_de->owner = THIS_MODULE; | ||
| 219 | } | ||
| 214 | 220 | ||
| 215 | printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); | 221 | printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); |
| 216 | return 0; | 222 | return 0; |
| @@ -218,21 +224,18 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) | |||
| 218 | 224 | ||
| 219 | static int hdpu_cpustate_remove(struct platform_device *pdev) | 225 | static int hdpu_cpustate_remove(struct platform_device *pdev) |
| 220 | { | 226 | { |
| 221 | |||
| 222 | cpustate.set_addr = NULL; | 227 | cpustate.set_addr = NULL; |
| 223 | cpustate.clr_addr = NULL; | 228 | cpustate.clr_addr = NULL; |
| 224 | 229 | ||
| 225 | remove_proc_entry("sky_cpustate", NULL); | 230 | remove_proc_entry("sky_cpustate", NULL); |
| 226 | misc_deregister(&cpustate_dev); | 231 | misc_deregister(&cpustate_dev); |
| 227 | return 0; | ||
| 228 | 232 | ||
| 233 | return 0; | ||
| 229 | } | 234 | } |
| 230 | 235 | ||
| 231 | static int __init cpustate_init(void) | 236 | static int __init cpustate_init(void) |
| 232 | { | 237 | { |
| 233 | int rc; | 238 | return platform_driver_register(&hdpu_cpustate_driver); |
| 234 | rc = platform_driver_register(&hdpu_cpustate_driver); | ||
| 235 | return rc; | ||
| 236 | } | 239 | } |
| 237 | 240 | ||
| 238 | static void __exit cpustate_exit(void) | 241 | static void __exit cpustate_exit(void) |
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index 60c8b26f0678..2887b2147980 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c | |||
| @@ -18,17 +18,38 @@ | |||
| 18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 19 | #include <linux/proc_fs.h> | 19 | #include <linux/proc_fs.h> |
| 20 | #include <linux/hdpu_features.h> | 20 | #include <linux/hdpu_features.h> |
| 21 | |||
| 22 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
| 22 | #include <linux/seq_file.h> | ||
| 23 | #include <asm/io.h> | ||
| 23 | 24 | ||
| 24 | static int hdpu_nexus_probe(struct platform_device *pdev); | 25 | static int hdpu_nexus_probe(struct platform_device *pdev); |
| 25 | static int hdpu_nexus_remove(struct platform_device *pdev); | 26 | static int hdpu_nexus_remove(struct platform_device *pdev); |
| 27 | static int hdpu_slot_id_open(struct inode *inode, struct file *file); | ||
| 28 | static int hdpu_slot_id_read(struct seq_file *seq, void *offset); | ||
| 29 | static int hdpu_chassis_id_open(struct inode *inode, struct file *file); | ||
| 30 | static int hdpu_chassis_id_read(struct seq_file *seq, void *offset); | ||
| 26 | 31 | ||
| 27 | static struct proc_dir_entry *hdpu_slot_id; | 32 | static struct proc_dir_entry *hdpu_slot_id; |
| 28 | static struct proc_dir_entry *hdpu_chassis_id; | 33 | static struct proc_dir_entry *hdpu_chassis_id; |
| 29 | static int slot_id = -1; | 34 | static int slot_id = -1; |
| 30 | static int chassis_id = -1; | 35 | static int chassis_id = -1; |
| 31 | 36 | ||
| 37 | static const struct file_operations proc_slot_id = { | ||
| 38 | .open = hdpu_slot_id_open, | ||
| 39 | .read = seq_read, | ||
| 40 | .llseek = seq_lseek, | ||
| 41 | .release = single_release, | ||
| 42 | .owner = THIS_MODULE, | ||
| 43 | }; | ||
| 44 | |||
| 45 | static const struct file_operations proc_chassis_id = { | ||
| 46 | .open = hdpu_chassis_id_open, | ||
| 47 | .read = seq_read, | ||
| 48 | .llseek = seq_lseek, | ||
| 49 | .release = single_release, | ||
| 50 | .owner = THIS_MODULE, | ||
| 51 | }; | ||
| 52 | |||
| 32 | static struct platform_driver hdpu_nexus_driver = { | 53 | static struct platform_driver hdpu_nexus_driver = { |
| 33 | .probe = hdpu_nexus_probe, | 54 | .probe = hdpu_nexus_probe, |
| 34 | .remove = hdpu_nexus_remove, | 55 | .remove = hdpu_nexus_remove, |
| @@ -37,43 +58,67 @@ static struct platform_driver hdpu_nexus_driver = { | |||
| 37 | }, | 58 | }, |
| 38 | }; | 59 | }; |
| 39 | 60 | ||
| 40 | int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset, | 61 | static int hdpu_slot_id_open(struct inode *inode, struct file *file) |
| 41 | int buffer_length, int *zero, void *ptr) | ||
| 42 | { | 62 | { |
| 63 | return single_open(file, hdpu_slot_id_read, NULL); | ||
| 64 | } | ||
| 43 | 65 | ||
| 44 | if (offset > 0) | 66 | static int hdpu_slot_id_read(struct seq_file *seq, void *offset) |
| 45 | return 0; | 67 | { |
| 46 | return sprintf(buffer, "%d\n", slot_id); | 68 | seq_printf(seq, "%d\n", slot_id); |
| 69 | return 0; | ||
| 47 | } | 70 | } |
| 48 | 71 | ||
| 49 | int hdpu_chassis_id_read(char *buffer, char **buffer_location, off_t offset, | 72 | static int hdpu_chassis_id_open(struct inode *inode, struct file *file) |
| 50 | int buffer_length, int *zero, void *ptr) | ||
| 51 | { | 73 | { |
| 74 | return single_open(file, hdpu_chassis_id_read, NULL); | ||
| 75 | } | ||
| 52 | 76 | ||
| 53 | if (offset > 0) | 77 | static int hdpu_chassis_id_read(struct seq_file *seq, void *offset) |
| 54 | return 0; | 78 | { |
| 55 | return sprintf(buffer, "%d\n", chassis_id); | 79 | seq_printf(seq, "%d\n", chassis_id); |
| 80 | return 0; | ||
| 56 | } | 81 | } |
| 57 | 82 | ||
| 58 | static int hdpu_nexus_probe(struct platform_device *pdev) | 83 | static int hdpu_nexus_probe(struct platform_device *pdev) |
| 59 | { | 84 | { |
| 60 | struct resource *res; | 85 | struct resource *res; |
| 86 | int *nexus_id_addr; | ||
| 61 | 87 | ||
| 62 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 88 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 63 | int *nexus_id_addr; | 89 | if (!res) { |
| 64 | nexus_id_addr = | 90 | printk(KERN_ERR "sky_nexus: " |
| 65 | ioremap(res->start, (unsigned long)(res->end - res->start)); | 91 | "Invalid memory resource.\n"); |
| 92 | return -EINVAL; | ||
| 93 | } | ||
| 94 | nexus_id_addr = ioremap(res->start, | ||
| 95 | (unsigned long)(res->end - res->start)); | ||
| 66 | if (nexus_id_addr) { | 96 | if (nexus_id_addr) { |
| 67 | slot_id = (*nexus_id_addr >> 8) & 0x1f; | 97 | slot_id = (*nexus_id_addr >> 8) & 0x1f; |
| 68 | chassis_id = *nexus_id_addr & 0xff; | 98 | chassis_id = *nexus_id_addr & 0xff; |
| 69 | iounmap(nexus_id_addr); | 99 | iounmap(nexus_id_addr); |
| 70 | } else | 100 | } else { |
| 71 | printk("Could not map slot id\n"); | 101 | printk(KERN_ERR "sky_nexus: Could not map slot id\n"); |
| 102 | } | ||
| 103 | |||
| 72 | hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); | 104 | hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); |
| 73 | hdpu_slot_id->read_proc = hdpu_slot_id_read; | 105 | if (!hdpu_slot_id) { |
| 106 | printk(KERN_WARNING "sky_nexus: " | ||
| 107 | "Unable to create proc dir entry: sky_slot_id\n"); | ||
| 108 | } else { | ||
| 109 | hdpu_slot_id->proc_fops = &proc_slot_id; | ||
| 110 | hdpu_slot_id->owner = THIS_MODULE; | ||
| 111 | } | ||
| 74 | 112 | ||
| 75 | hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); | 113 | hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); |
| 76 | hdpu_chassis_id->read_proc = hdpu_chassis_id_read; | 114 | if (!hdpu_chassis_id) { |
| 115 | printk(KERN_WARNING "sky_nexus: " | ||
| 116 | "Unable to create proc dir entry: sky_chassis_id\n"); | ||
| 117 | } else { | ||
| 118 | hdpu_chassis_id->proc_fops = &proc_chassis_id; | ||
| 119 | hdpu_chassis_id->owner = THIS_MODULE; | ||
| 120 | } | ||
| 121 | |||
| 77 | return 0; | 122 | return 0; |
| 78 | } | 123 | } |
| 79 | 124 | ||
| @@ -81,18 +126,19 @@ static int hdpu_nexus_remove(struct platform_device *pdev) | |||
| 81 | { | 126 | { |
| 82 | slot_id = -1; | 127 | slot_id = -1; |
| 83 | chassis_id = -1; | 128 | chassis_id = -1; |
| 129 | |||
| 84 | remove_proc_entry("sky_slot_id", &proc_root); | 130 | remove_proc_entry("sky_slot_id", &proc_root); |
| 85 | remove_proc_entry("sky_chassis_id", &proc_root); | 131 | remove_proc_entry("sky_chassis_id", &proc_root); |
| 132 | |||
| 86 | hdpu_slot_id = 0; | 133 | hdpu_slot_id = 0; |
| 87 | hdpu_chassis_id = 0; | 134 | hdpu_chassis_id = 0; |
| 135 | |||
| 88 | return 0; | 136 | return 0; |
| 89 | } | 137 | } |
| 90 | 138 | ||
| 91 | static int __init nexus_init(void) | 139 | static int __init nexus_init(void) |
| 92 | { | 140 | { |
| 93 | int rc; | 141 | return platform_driver_register(&hdpu_nexus_driver); |
| 94 | rc = platform_driver_register(&hdpu_nexus_driver); | ||
| 95 | return rc; | ||
| 96 | } | 142 | } |
| 97 | 143 | ||
| 98 | static void __exit nexus_exit(void) | 144 | static void __exit nexus_exit(void) |
diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c index b5df347c81b9..6497872df524 100644 --- a/drivers/misc/ibmasm/command.c +++ b/drivers/misc/ibmasm/command.c | |||
| @@ -41,18 +41,16 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s | |||
| 41 | if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE) | 41 | if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE) |
| 42 | return NULL; | 42 | return NULL; |
| 43 | 43 | ||
| 44 | cmd = kmalloc(sizeof(struct command), GFP_KERNEL); | 44 | cmd = kzalloc(sizeof(struct command), GFP_KERNEL); |
| 45 | if (cmd == NULL) | 45 | if (cmd == NULL) |
| 46 | return NULL; | 46 | return NULL; |
| 47 | 47 | ||
| 48 | memset(cmd, 0, sizeof(*cmd)); | ||
| 49 | 48 | ||
| 50 | cmd->buffer = kmalloc(buffer_size, GFP_KERNEL); | 49 | cmd->buffer = kzalloc(buffer_size, GFP_KERNEL); |
| 51 | if (cmd->buffer == NULL) { | 50 | if (cmd->buffer == NULL) { |
| 52 | kfree(cmd); | 51 | kfree(cmd); |
| 53 | return NULL; | 52 | return NULL; |
| 54 | } | 53 | } |
| 55 | memset(cmd->buffer, 0, buffer_size); | ||
| 56 | cmd->buffer_size = buffer_size; | 54 | cmd->buffer_size = buffer_size; |
| 57 | 55 | ||
| 58 | kobject_init(&cmd->kobj); | 56 | kobject_init(&cmd->kobj); |
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index eb7b073734b8..22a7e8ba211d 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c | |||
| @@ -563,11 +563,10 @@ static ssize_t remote_settings_file_write(struct file *file, const char __user * | |||
| 563 | if (*offset != 0) | 563 | if (*offset != 0) |
| 564 | return 0; | 564 | return 0; |
| 565 | 565 | ||
| 566 | buff = kmalloc (count + 1, GFP_KERNEL); | 566 | buff = kzalloc (count + 1, GFP_KERNEL); |
| 567 | if (!buff) | 567 | if (!buff) |
| 568 | return -ENOMEM; | 568 | return -ENOMEM; |
| 569 | 569 | ||
| 570 | memset(buff, 0x0, count + 1); | ||
| 571 | 570 | ||
| 572 | if (copy_from_user(buff, ubuff, count)) { | 571 | if (copy_from_user(buff, ubuff, count)) { |
| 573 | kfree(buff); | 572 | kfree(buff); |
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index fb03a853fac4..4f9d4a9da983 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c | |||
| @@ -77,13 +77,12 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi | |||
| 77 | /* vnc client won't work without bus-mastering */ | 77 | /* vnc client won't work without bus-mastering */ |
| 78 | pci_set_master(pdev); | 78 | pci_set_master(pdev); |
| 79 | 79 | ||
| 80 | sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL); | 80 | sp = kzalloc(sizeof(struct service_processor), GFP_KERNEL); |
| 81 | if (sp == NULL) { | 81 | if (sp == NULL) { |
| 82 | dev_err(&pdev->dev, "Failed to allocate memory\n"); | 82 | dev_err(&pdev->dev, "Failed to allocate memory\n"); |
| 83 | result = -ENOMEM; | 83 | result = -ENOMEM; |
| 84 | goto error_kmalloc; | 84 | goto error_kmalloc; |
| 85 | } | 85 | } |
| 86 | memset(sp, 0, sizeof(struct service_processor)); | ||
| 87 | 86 | ||
| 88 | spin_lock_init(&sp->lock); | 87 | spin_lock_init(&sp->lock); |
| 89 | INIT_LIST_HEAD(&sp->command_queue); | 88 | INIT_LIST_HEAD(&sp->command_queue); |
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c index 932a415197b3..83679c762925 100644 --- a/drivers/misc/msi-laptop.c +++ b/drivers/misc/msi-laptop.c | |||
| @@ -283,7 +283,7 @@ static struct platform_device *msipf_device; | |||
| 283 | 283 | ||
| 284 | /* Initialization */ | 284 | /* Initialization */ |
| 285 | 285 | ||
| 286 | static int dmi_check_cb(struct dmi_system_id *id) | 286 | static int dmi_check_cb(const struct dmi_system_id *id) |
| 287 | { | 287 | { |
| 288 | printk("msi-laptop: Identified laptop model '%s'.\n", id->ident); | 288 | printk("msi-laptop: Identified laptop model '%s'.\n", id->ident); |
| 289 | return 0; | 289 | return 0; |
| @@ -353,7 +353,7 @@ static int __init msi_init(void) | |||
| 353 | if (IS_ERR(msibl_device)) | 353 | if (IS_ERR(msibl_device)) |
| 354 | return PTR_ERR(msibl_device); | 354 | return PTR_ERR(msibl_device); |
| 355 | 355 | ||
| 356 | msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1, | 356 | msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1; |
| 357 | 357 | ||
| 358 | ret = platform_driver_register(&msipf_driver); | 358 | ret = platform_driver_register(&msipf_driver); |
| 359 | if (ret) | 359 | if (ret) |
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 9623eaf4f89f..e73a71f04bb4 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c | |||
| @@ -142,43 +142,124 @@ struct sony_laptop_keypress { | |||
| 142 | int key; | 142 | int key; |
| 143 | }; | 143 | }; |
| 144 | 144 | ||
| 145 | /* Correspondance table between sonypi events and input layer events */ | 145 | /* Correspondance table between sonypi events |
| 146 | static struct { | 146 | * and input layer indexes in the keymap |
| 147 | int sonypiev; | 147 | */ |
| 148 | int inputev; | 148 | static int sony_laptop_input_index[] = { |
| 149 | } sony_laptop_inputkeys[] = { | 149 | -1, /* no event */ |
| 150 | { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA }, | 150 | -1, /* SONYPI_EVENT_JOGDIAL_DOWN */ |
| 151 | { SONYPI_EVENT_FNKEY_ONLY, KEY_FN }, | 151 | -1, /* SONYPI_EVENT_JOGDIAL_UP */ |
| 152 | { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC }, | 152 | -1, /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */ |
| 153 | { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 }, | 153 | -1, /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */ |
| 154 | { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 }, | 154 | -1, /* SONYPI_EVENT_JOGDIAL_PRESSED */ |
| 155 | { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 }, | 155 | -1, /* SONYPI_EVENT_JOGDIAL_RELEASED */ |
| 156 | { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 }, | 156 | 0, /* SONYPI_EVENT_CAPTURE_PRESSED */ |
| 157 | { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 }, | 157 | 1, /* SONYPI_EVENT_CAPTURE_RELEASED */ |
| 158 | { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 }, | 158 | 2, /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ |
| 159 | { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 }, | 159 | 3, /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ |
| 160 | { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 }, | 160 | 4, /* SONYPI_EVENT_FNKEY_ESC */ |
| 161 | { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 }, | 161 | 5, /* SONYPI_EVENT_FNKEY_F1 */ |
| 162 | { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 }, | 162 | 6, /* SONYPI_EVENT_FNKEY_F2 */ |
| 163 | { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 }, | 163 | 7, /* SONYPI_EVENT_FNKEY_F3 */ |
| 164 | { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 }, | 164 | 8, /* SONYPI_EVENT_FNKEY_F4 */ |
| 165 | { SONYPI_EVENT_FNKEY_1, KEY_FN_1 }, | 165 | 9, /* SONYPI_EVENT_FNKEY_F5 */ |
| 166 | { SONYPI_EVENT_FNKEY_2, KEY_FN_2 }, | 166 | 10, /* SONYPI_EVENT_FNKEY_F6 */ |
| 167 | { SONYPI_EVENT_FNKEY_D, KEY_FN_D }, | 167 | 11, /* SONYPI_EVENT_FNKEY_F7 */ |
| 168 | { SONYPI_EVENT_FNKEY_E, KEY_FN_E }, | 168 | 12, /* SONYPI_EVENT_FNKEY_F8 */ |
| 169 | { SONYPI_EVENT_FNKEY_F, KEY_FN_F }, | 169 | 13, /* SONYPI_EVENT_FNKEY_F9 */ |
| 170 | { SONYPI_EVENT_FNKEY_S, KEY_FN_S }, | 170 | 14, /* SONYPI_EVENT_FNKEY_F10 */ |
| 171 | { SONYPI_EVENT_FNKEY_B, KEY_FN_B }, | 171 | 15, /* SONYPI_EVENT_FNKEY_F11 */ |
| 172 | { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE }, | 172 | 16, /* SONYPI_EVENT_FNKEY_F12 */ |
| 173 | { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE }, | 173 | 17, /* SONYPI_EVENT_FNKEY_1 */ |
| 174 | { SONYPI_EVENT_PKEY_P1, KEY_PROG1 }, | 174 | 18, /* SONYPI_EVENT_FNKEY_2 */ |
| 175 | { SONYPI_EVENT_PKEY_P2, KEY_PROG2 }, | 175 | 19, /* SONYPI_EVENT_FNKEY_D */ |
| 176 | { SONYPI_EVENT_PKEY_P3, KEY_PROG3 }, | 176 | 20, /* SONYPI_EVENT_FNKEY_E */ |
| 177 | { SONYPI_EVENT_BACK_PRESSED, KEY_BACK }, | 177 | 21, /* SONYPI_EVENT_FNKEY_F */ |
| 178 | { SONYPI_EVENT_HELP_PRESSED, KEY_HELP }, | 178 | 22, /* SONYPI_EVENT_FNKEY_S */ |
| 179 | { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM }, | 179 | 23, /* SONYPI_EVENT_FNKEY_B */ |
| 180 | { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB }, | 180 | 24, /* SONYPI_EVENT_BLUETOOTH_PRESSED */ |
| 181 | { 0, 0 }, | 181 | 25, /* SONYPI_EVENT_PKEY_P1 */ |
| 182 | 26, /* SONYPI_EVENT_PKEY_P2 */ | ||
| 183 | 27, /* SONYPI_EVENT_PKEY_P3 */ | ||
| 184 | 28, /* SONYPI_EVENT_BACK_PRESSED */ | ||
| 185 | -1, /* SONYPI_EVENT_LID_CLOSED */ | ||
| 186 | -1, /* SONYPI_EVENT_LID_OPENED */ | ||
| 187 | 29, /* SONYPI_EVENT_BLUETOOTH_ON */ | ||
| 188 | 30, /* SONYPI_EVENT_BLUETOOTH_OFF */ | ||
| 189 | 31, /* SONYPI_EVENT_HELP_PRESSED */ | ||
| 190 | 32, /* SONYPI_EVENT_FNKEY_ONLY */ | ||
| 191 | 33, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */ | ||
| 192 | 34, /* SONYPI_EVENT_JOGDIAL_FAST_UP */ | ||
| 193 | 35, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ | ||
| 194 | 36, /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ | ||
| 195 | 37, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ | ||
| 196 | 38, /* SONYPI_EVENT_JOGDIAL_VFAST_UP */ | ||
| 197 | 39, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ | ||
| 198 | 40, /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ | ||
| 199 | 41, /* SONYPI_EVENT_ZOOM_PRESSED */ | ||
| 200 | 42, /* SONYPI_EVENT_THUMBPHRASE_PRESSED */ | ||
| 201 | 43, /* SONYPI_EVENT_MEYE_FACE */ | ||
| 202 | 44, /* SONYPI_EVENT_MEYE_OPPOSITE */ | ||
| 203 | 45, /* SONYPI_EVENT_MEMORYSTICK_INSERT */ | ||
| 204 | 46, /* SONYPI_EVENT_MEMORYSTICK_EJECT */ | ||
| 205 | -1, /* SONYPI_EVENT_ANYBUTTON_RELEASED */ | ||
| 206 | -1, /* SONYPI_EVENT_BATTERY_INSERT */ | ||
| 207 | -1, /* SONYPI_EVENT_BATTERY_REMOVE */ | ||
| 208 | -1, /* SONYPI_EVENT_FNKEY_RELEASED */ | ||
| 209 | 47, /* SONYPI_EVENT_WIRELESS_ON */ | ||
| 210 | 48, /* SONYPI_EVENT_WIRELESS_OFF */ | ||
| 211 | }; | ||
| 212 | |||
| 213 | static int sony_laptop_input_keycode_map[] = { | ||
| 214 | KEY_CAMERA, /* 0 SONYPI_EVENT_CAPTURE_PRESSED */ | ||
| 215 | KEY_RESERVED, /* 1 SONYPI_EVENT_CAPTURE_RELEASED */ | ||
| 216 | KEY_RESERVED, /* 2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ | ||
| 217 | KEY_RESERVED, /* 3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ | ||
| 218 | KEY_FN_ESC, /* 4 SONYPI_EVENT_FNKEY_ESC */ | ||
| 219 | KEY_FN_F1, /* 5 SONYPI_EVENT_FNKEY_F1 */ | ||
| 220 | KEY_FN_F2, /* 6 SONYPI_EVENT_FNKEY_F2 */ | ||
| 221 | KEY_FN_F3, /* 7 SONYPI_EVENT_FNKEY_F3 */ | ||
| 222 | KEY_FN_F4, /* 8 SONYPI_EVENT_FNKEY_F4 */ | ||
| 223 | KEY_FN_F5, /* 9 SONYPI_EVENT_FNKEY_F5 */ | ||
| 224 | KEY_FN_F6, /* 10 SONYPI_EVENT_FNKEY_F6 */ | ||
| 225 | KEY_FN_F7, /* 11 SONYPI_EVENT_FNKEY_F7 */ | ||
| 226 | KEY_FN_F8, /* 12 SONYPI_EVENT_FNKEY_F8 */ | ||
| 227 | KEY_FN_F9, /* 13 SONYPI_EVENT_FNKEY_F9 */ | ||
| 228 | KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */ | ||
| 229 | KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */ | ||
| 230 | KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */ | ||
| 231 | KEY_FN_F1, /* 17 SONYPI_EVENT_FNKEY_1 */ | ||
| 232 | KEY_FN_F2, /* 18 SONYPI_EVENT_FNKEY_2 */ | ||
| 233 | KEY_FN_D, /* 19 SONYPI_EVENT_FNKEY_D */ | ||
| 234 | KEY_FN_E, /* 20 SONYPI_EVENT_FNKEY_E */ | ||
| 235 | KEY_FN_F, /* 21 SONYPI_EVENT_FNKEY_F */ | ||
| 236 | KEY_FN_S, /* 22 SONYPI_EVENT_FNKEY_S */ | ||
| 237 | KEY_FN_B, /* 23 SONYPI_EVENT_FNKEY_B */ | ||
| 238 | KEY_BLUETOOTH, /* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */ | ||
| 239 | KEY_PROG1, /* 25 SONYPI_EVENT_PKEY_P1 */ | ||
| 240 | KEY_PROG2, /* 26 SONYPI_EVENT_PKEY_P2 */ | ||
| 241 | KEY_PROG3, /* 27 SONYPI_EVENT_PKEY_P3 */ | ||
| 242 | KEY_BACK, /* 28 SONYPI_EVENT_BACK_PRESSED */ | ||
| 243 | KEY_BLUETOOTH, /* 29 SONYPI_EVENT_BLUETOOTH_ON */ | ||
| 244 | KEY_BLUETOOTH, /* 30 SONYPI_EVENT_BLUETOOTH_OFF */ | ||
| 245 | KEY_HELP, /* 31 SONYPI_EVENT_HELP_PRESSED */ | ||
| 246 | KEY_FN, /* 32 SONYPI_EVENT_FNKEY_ONLY */ | ||
| 247 | KEY_RESERVED, /* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */ | ||
| 248 | KEY_RESERVED, /* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */ | ||
| 249 | KEY_RESERVED, /* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ | ||
| 250 | KEY_RESERVED, /* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ | ||
| 251 | KEY_RESERVED, /* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ | ||
| 252 | KEY_RESERVED, /* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */ | ||
| 253 | KEY_RESERVED, /* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ | ||
| 254 | KEY_RESERVED, /* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ | ||
| 255 | KEY_ZOOM, /* 41 SONYPI_EVENT_ZOOM_PRESSED */ | ||
| 256 | BTN_THUMB, /* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */ | ||
| 257 | KEY_RESERVED, /* 43 SONYPI_EVENT_MEYE_FACE */ | ||
| 258 | KEY_RESERVED, /* 44 SONYPI_EVENT_MEYE_OPPOSITE */ | ||
| 259 | KEY_RESERVED, /* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */ | ||
| 260 | KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */ | ||
| 261 | KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */ | ||
| 262 | KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */ | ||
| 182 | }; | 263 | }; |
| 183 | 264 | ||
| 184 | /* release buttons after a short delay if pressed */ | 265 | /* release buttons after a short delay if pressed */ |
| @@ -202,7 +283,6 @@ static void sony_laptop_report_input_event(u8 event) | |||
| 202 | struct input_dev *jog_dev = sony_laptop_input.jog_dev; | 283 | struct input_dev *jog_dev = sony_laptop_input.jog_dev; |
| 203 | struct input_dev *key_dev = sony_laptop_input.key_dev; | 284 | struct input_dev *key_dev = sony_laptop_input.key_dev; |
| 204 | struct sony_laptop_keypress kp = { NULL }; | 285 | struct sony_laptop_keypress kp = { NULL }; |
| 205 | int i; | ||
| 206 | 286 | ||
| 207 | if (event == SONYPI_EVENT_FNKEY_RELEASED) { | 287 | if (event == SONYPI_EVENT_FNKEY_RELEASED) { |
| 208 | /* Nothing, not all VAIOs generate this event */ | 288 | /* Nothing, not all VAIOs generate this event */ |
| @@ -231,17 +311,22 @@ static void sony_laptop_report_input_event(u8 event) | |||
| 231 | break; | 311 | break; |
| 232 | 312 | ||
| 233 | default: | 313 | default: |
| 234 | for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++) | 314 | if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) { |
| 235 | if (event == sony_laptop_inputkeys[i].sonypiev) { | 315 | dprintk("sony_laptop_report_input_event, event not known: %d\n", event); |
| 316 | break; | ||
| 317 | } | ||
| 318 | if (sony_laptop_input_index[event] != -1) { | ||
| 319 | kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]]; | ||
| 320 | if (kp.key != KEY_UNKNOWN) | ||
| 236 | kp.dev = key_dev; | 321 | kp.dev = key_dev; |
| 237 | kp.key = sony_laptop_inputkeys[i].inputev; | 322 | } |
| 238 | break; | ||
| 239 | } | ||
| 240 | break; | 323 | break; |
| 241 | } | 324 | } |
| 242 | 325 | ||
| 243 | if (kp.dev) { | 326 | if (kp.dev) { |
| 244 | input_report_key(kp.dev, kp.key, 1); | 327 | input_report_key(kp.dev, kp.key, 1); |
| 328 | /* we emit the scancode so we can always remap the key */ | ||
| 329 | input_event(kp.dev, EV_MSC, MSC_SCAN, event); | ||
| 245 | input_sync(kp.dev); | 330 | input_sync(kp.dev); |
| 246 | kfifo_put(sony_laptop_input.fifo, | 331 | kfifo_put(sony_laptop_input.fifo, |
| 247 | (unsigned char *)&kp, sizeof(kp)); | 332 | (unsigned char *)&kp, sizeof(kp)); |
| @@ -296,11 +381,18 @@ static int sony_laptop_setup_input(void) | |||
| 296 | key_dev->id.vendor = PCI_VENDOR_ID_SONY; | 381 | key_dev->id.vendor = PCI_VENDOR_ID_SONY; |
| 297 | 382 | ||
| 298 | /* Initialize the Input Drivers: special keys */ | 383 | /* Initialize the Input Drivers: special keys */ |
| 299 | key_dev->evbit[0] = BIT(EV_KEY); | 384 | set_bit(EV_KEY, key_dev->evbit); |
| 300 | for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++) | 385 | set_bit(EV_MSC, key_dev->evbit); |
| 301 | if (sony_laptop_inputkeys[i].inputev) | 386 | set_bit(MSC_SCAN, key_dev->mscbit); |
| 302 | set_bit(sony_laptop_inputkeys[i].inputev, | 387 | key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]); |
| 303 | key_dev->keybit); | 388 | key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map); |
| 389 | key_dev->keycode = &sony_laptop_input_keycode_map; | ||
| 390 | for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) { | ||
| 391 | if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) { | ||
| 392 | set_bit(sony_laptop_input_keycode_map[i], | ||
| 393 | key_dev->keybit); | ||
| 394 | } | ||
| 395 | } | ||
| 304 | 396 | ||
| 305 | error = input_register_device(key_dev); | 397 | error = input_register_device(key_dev); |
| 306 | if (error) | 398 | if (error) |
| @@ -487,6 +579,14 @@ SNC_HANDLE_NAMES(audiopower_set, "AZPW"); | |||
| 487 | SNC_HANDLE_NAMES(lanpower_get, "GLNP"); | 579 | SNC_HANDLE_NAMES(lanpower_get, "GLNP"); |
| 488 | SNC_HANDLE_NAMES(lanpower_set, "LNPW"); | 580 | SNC_HANDLE_NAMES(lanpower_set, "LNPW"); |
| 489 | 581 | ||
| 582 | SNC_HANDLE_NAMES(lidstate_get, "GLID"); | ||
| 583 | |||
| 584 | SNC_HANDLE_NAMES(indicatorlamp_get, "GILS"); | ||
| 585 | SNC_HANDLE_NAMES(indicatorlamp_set, "SILS"); | ||
| 586 | |||
| 587 | SNC_HANDLE_NAMES(gainbass_get, "GMGB"); | ||
| 588 | SNC_HANDLE_NAMES(gainbass_set, "CMGB"); | ||
| 589 | |||
| 490 | SNC_HANDLE_NAMES(PID_get, "GPID"); | 590 | SNC_HANDLE_NAMES(PID_get, "GPID"); |
| 491 | 591 | ||
| 492 | SNC_HANDLE_NAMES(CTR_get, "GCTR"); | 592 | SNC_HANDLE_NAMES(CTR_get, "GCTR"); |
| @@ -507,6 +607,12 @@ static struct sony_nc_value sony_nc_values[] = { | |||
| 507 | boolean_validate, 0), | 607 | boolean_validate, 0), |
| 508 | SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set, | 608 | SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set, |
| 509 | boolean_validate, 1), | 609 | boolean_validate, 1), |
| 610 | SNC_HANDLE(lidstate, snc_lidstate_get, NULL, | ||
| 611 | boolean_validate, 0), | ||
| 612 | SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set, | ||
| 613 | boolean_validate, 0), | ||
| 614 | SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set, | ||
| 615 | boolean_validate, 0), | ||
| 510 | /* unknown methods */ | 616 | /* unknown methods */ |
| 511 | SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1), | 617 | SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1), |
| 512 | SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), | 618 | SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), |
| @@ -689,13 +795,125 @@ static struct backlight_ops sony_backlight_ops = { | |||
| 689 | }; | 795 | }; |
| 690 | 796 | ||
| 691 | /* | 797 | /* |
| 798 | * New SNC-only Vaios event mapping to driver known keys | ||
| 799 | */ | ||
| 800 | struct sony_nc_event { | ||
| 801 | u8 data; | ||
| 802 | u8 event; | ||
| 803 | }; | ||
| 804 | |||
| 805 | static struct sony_nc_event *sony_nc_events; | ||
| 806 | |||
| 807 | /* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence | ||
| 808 | * for Fn keys | ||
| 809 | */ | ||
| 810 | static int sony_nc_C_enable(const struct dmi_system_id *id) | ||
| 811 | { | ||
| 812 | int result = 0; | ||
| 813 | |||
| 814 | printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident); | ||
| 815 | |||
| 816 | sony_nc_events = id->driver_data; | ||
| 817 | |||
| 818 | if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0 | ||
| 819 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0 | ||
| 820 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0 | ||
| 821 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0 | ||
| 822 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0 | ||
| 823 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) { | ||
| 824 | printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some " | ||
| 825 | "functionalities may be missing\n"); | ||
| 826 | return 1; | ||
| 827 | } | ||
| 828 | return 0; | ||
| 829 | } | ||
| 830 | |||
| 831 | static struct sony_nc_event sony_C_events[] = { | ||
| 832 | { 0x81, SONYPI_EVENT_FNKEY_F1 }, | ||
| 833 | { 0x01, SONYPI_EVENT_FNKEY_RELEASED }, | ||
| 834 | { 0x85, SONYPI_EVENT_FNKEY_F5 }, | ||
| 835 | { 0x05, SONYPI_EVENT_FNKEY_RELEASED }, | ||
| 836 | { 0x86, SONYPI_EVENT_FNKEY_F6 }, | ||
| 837 | { 0x06, SONYPI_EVENT_FNKEY_RELEASED }, | ||
| 838 | { 0x87, SONYPI_EVENT_FNKEY_F7 }, | ||
| 839 | { 0x07, SONYPI_EVENT_FNKEY_RELEASED }, | ||
| 840 | { 0x8A, SONYPI_EVENT_FNKEY_F10 }, | ||
| 841 | { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, | ||
| 842 | { 0x8C, SONYPI_EVENT_FNKEY_F12 }, | ||
| 843 | { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, | ||
| 844 | { 0, 0 }, | ||
| 845 | }; | ||
| 846 | |||
| 847 | /* SNC-only model map */ | ||
| 848 | static const struct dmi_system_id sony_nc_ids[] = { | ||
| 849 | { | ||
| 850 | .ident = "Sony Vaio FE Series", | ||
| 851 | .callback = sony_nc_C_enable, | ||
| 852 | .driver_data = sony_C_events, | ||
| 853 | .matches = { | ||
| 854 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | ||
| 855 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"), | ||
| 856 | }, | ||
| 857 | }, | ||
| 858 | { | ||
| 859 | .ident = "Sony Vaio FZ Series", | ||
| 860 | .callback = sony_nc_C_enable, | ||
| 861 | .driver_data = sony_C_events, | ||
| 862 | .matches = { | ||
| 863 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | ||
| 864 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ"), | ||
| 865 | }, | ||
| 866 | }, | ||
| 867 | { | ||
| 868 | .ident = "Sony Vaio C Series", | ||
| 869 | .callback = sony_nc_C_enable, | ||
| 870 | .driver_data = sony_C_events, | ||
| 871 | .matches = { | ||
| 872 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | ||
| 873 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"), | ||
| 874 | }, | ||
| 875 | }, | ||
| 876 | { } | ||
| 877 | }; | ||
| 878 | |||
| 879 | /* | ||
| 692 | * ACPI callbacks | 880 | * ACPI callbacks |
| 693 | */ | 881 | */ |
| 694 | static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) | 882 | static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) |
| 695 | { | 883 | { |
| 696 | dprintk("sony_acpi_notify, event: %d\n", event); | 884 | struct sony_nc_event *evmap; |
| 697 | sony_laptop_report_input_event(event); | 885 | u32 ev = event; |
| 698 | acpi_bus_generate_event(sony_nc_acpi_device, 1, event); | 886 | int result; |
| 887 | |||
| 888 | if (ev == 0x92) { | ||
| 889 | /* read the key pressed from EC.GECR | ||
| 890 | * A call to SN07 with 0x0202 will do it as well respecting | ||
| 891 | * the current protocol on different OSes | ||
| 892 | * | ||
| 893 | * Note: the path for GECR may be | ||
| 894 | * \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends) | ||
| 895 | * \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR) | ||
| 896 | * | ||
| 897 | * TODO: we may want to do the same for the older GHKE -need | ||
| 898 | * dmi list- so this snippet may become one more callback. | ||
| 899 | */ | ||
| 900 | if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0) | ||
| 901 | dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev); | ||
| 902 | else | ||
| 903 | ev = result & 0xFF; | ||
| 904 | } | ||
| 905 | |||
| 906 | if (sony_nc_events) | ||
| 907 | for (evmap = sony_nc_events; evmap->event; evmap++) { | ||
| 908 | if (evmap->data == ev) { | ||
| 909 | ev = evmap->event; | ||
| 910 | break; | ||
| 911 | } | ||
| 912 | } | ||
| 913 | |||
| 914 | dprintk("sony_acpi_notify, event: 0x%.2x\n", ev); | ||
| 915 | sony_laptop_report_input_event(ev); | ||
| 916 | acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev); | ||
| 699 | } | 917 | } |
| 700 | 918 | ||
| 701 | static acpi_status sony_walk_callback(acpi_handle handle, u32 level, | 919 | static acpi_status sony_walk_callback(acpi_handle handle, u32 level, |
| @@ -732,6 +950,15 @@ static int sony_nc_resume(struct acpi_device *device) | |||
| 732 | break; | 950 | break; |
| 733 | } | 951 | } |
| 734 | } | 952 | } |
| 953 | |||
| 954 | /* set the last requested brightness level */ | ||
| 955 | if (sony_backlight_device && | ||
| 956 | !sony_backlight_update_status(sony_backlight_device)) | ||
| 957 | printk(KERN_WARNING DRV_PFX "unable to restore brightness level"); | ||
| 958 | |||
| 959 | /* re-initialize models with specific requirements */ | ||
| 960 | dmi_check_system(sony_nc_ids); | ||
| 961 | |||
| 735 | return 0; | 962 | return 0; |
| 736 | } | 963 | } |
| 737 | 964 | ||
| @@ -750,6 +977,15 @@ static int sony_nc_add(struct acpi_device *device) | |||
| 750 | 977 | ||
| 751 | sony_nc_acpi_handle = device->handle; | 978 | sony_nc_acpi_handle = device->handle; |
| 752 | 979 | ||
| 980 | /* read device status */ | ||
| 981 | result = acpi_bus_get_status(device); | ||
| 982 | /* bail IFF the above call was successful and the device is not present */ | ||
| 983 | if (!result && !device->status.present) { | ||
| 984 | dprintk("Device not present\n"); | ||
| 985 | result = -ENODEV; | ||
| 986 | goto outwalk; | ||
| 987 | } | ||
| 988 | |||
| 753 | if (debug) { | 989 | if (debug) { |
| 754 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, | 990 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, |
| 755 | 1, sony_walk_callback, NULL, NULL); | 991 | 1, sony_walk_callback, NULL, NULL); |
| @@ -760,6 +996,15 @@ static int sony_nc_add(struct acpi_device *device) | |||
| 760 | } | 996 | } |
| 761 | } | 997 | } |
| 762 | 998 | ||
| 999 | /* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1 | ||
| 1000 | * should be respected as we already checked for the device presence above */ | ||
| 1001 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) { | ||
| 1002 | dprintk("Invoking _INI\n"); | ||
| 1003 | if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI, | ||
| 1004 | NULL, NULL))) | ||
| 1005 | dprintk("_INI Method failed\n"); | ||
| 1006 | } | ||
| 1007 | |||
| 763 | /* setup input devices and helper fifo */ | 1008 | /* setup input devices and helper fifo */ |
| 764 | result = sony_laptop_setup_input(); | 1009 | result = sony_laptop_setup_input(); |
| 765 | if (result) { | 1010 | if (result) { |
| @@ -772,7 +1017,7 @@ static int sony_nc_add(struct acpi_device *device) | |||
| 772 | ACPI_DEVICE_NOTIFY, | 1017 | ACPI_DEVICE_NOTIFY, |
| 773 | sony_acpi_notify, NULL); | 1018 | sony_acpi_notify, NULL); |
| 774 | if (ACPI_FAILURE(status)) { | 1019 | if (ACPI_FAILURE(status)) { |
| 775 | printk(KERN_WARNING DRV_PFX "unable to install notify handler\n"); | 1020 | printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status); |
| 776 | result = -ENODEV; | 1021 | result = -ENODEV; |
| 777 | goto outinput; | 1022 | goto outinput; |
| 778 | } | 1023 | } |
| @@ -795,6 +1040,9 @@ static int sony_nc_add(struct acpi_device *device) | |||
| 795 | 1040 | ||
| 796 | } | 1041 | } |
| 797 | 1042 | ||
| 1043 | /* initialize models with specific requirements */ | ||
| 1044 | dmi_check_system(sony_nc_ids); | ||
| 1045 | |||
| 798 | result = sony_pf_add(); | 1046 | result = sony_pf_add(); |
| 799 | if (result) | 1047 | if (result) |
| 800 | goto outbacklight; | 1048 | goto outbacklight; |
| @@ -890,10 +1138,22 @@ static int sony_nc_remove(struct acpi_device *device, int type) | |||
| 890 | return 0; | 1138 | return 0; |
| 891 | } | 1139 | } |
| 892 | 1140 | ||
| 1141 | static const struct acpi_device_id sony_device_ids[] = { | ||
| 1142 | {SONY_NC_HID, 0}, | ||
| 1143 | {SONY_PIC_HID, 0}, | ||
| 1144 | {"", 0}, | ||
| 1145 | }; | ||
| 1146 | MODULE_DEVICE_TABLE(acpi, sony_device_ids); | ||
| 1147 | |||
| 1148 | static const struct acpi_device_id sony_nc_device_ids[] = { | ||
| 1149 | {SONY_NC_HID, 0}, | ||
| 1150 | {"", 0}, | ||
| 1151 | }; | ||
| 1152 | |||
| 893 | static struct acpi_driver sony_nc_driver = { | 1153 | static struct acpi_driver sony_nc_driver = { |
| 894 | .name = SONY_NC_DRIVER_NAME, | 1154 | .name = SONY_NC_DRIVER_NAME, |
| 895 | .class = SONY_NC_CLASS, | 1155 | .class = SONY_NC_CLASS, |
| 896 | .ids = SONY_NC_HID, | 1156 | .ids = sony_nc_device_ids, |
| 897 | .owner = THIS_MODULE, | 1157 | .owner = THIS_MODULE, |
| 898 | .ops = { | 1158 | .ops = { |
| 899 | .add = sony_nc_add, | 1159 | .add = sony_nc_add, |
| @@ -908,7 +1168,9 @@ static struct acpi_driver sony_nc_driver = { | |||
| 908 | #define SONYPI_DEVICE_TYPE2 0x00000002 | 1168 | #define SONYPI_DEVICE_TYPE2 0x00000002 |
| 909 | #define SONYPI_DEVICE_TYPE3 0x00000004 | 1169 | #define SONYPI_DEVICE_TYPE3 0x00000004 |
| 910 | 1170 | ||
| 911 | #define SONY_PIC_EV_MASK 0xff | 1171 | #define SONYPI_TYPE1_OFFSET 0x04 |
| 1172 | #define SONYPI_TYPE2_OFFSET 0x12 | ||
| 1173 | #define SONYPI_TYPE3_OFFSET 0x12 | ||
| 912 | 1174 | ||
| 913 | struct sony_pic_ioport { | 1175 | struct sony_pic_ioport { |
| 914 | struct acpi_resource_io io; | 1176 | struct acpi_resource_io io; |
| @@ -922,6 +1184,7 @@ struct sony_pic_irq { | |||
| 922 | 1184 | ||
| 923 | struct sony_pic_dev { | 1185 | struct sony_pic_dev { |
| 924 | int model; | 1186 | int model; |
| 1187 | u16 evport_offset; | ||
| 925 | u8 camera_power; | 1188 | u8 camera_power; |
| 926 | u8 bluetooth_power; | 1189 | u8 bluetooth_power; |
| 927 | u8 wwan_power; | 1190 | u8 wwan_power; |
| @@ -1999,20 +2262,17 @@ end: | |||
| 1999 | static irqreturn_t sony_pic_irq(int irq, void *dev_id) | 2262 | static irqreturn_t sony_pic_irq(int irq, void *dev_id) |
| 2000 | { | 2263 | { |
| 2001 | int i, j; | 2264 | int i, j; |
| 2002 | u32 port_val = 0; | ||
| 2003 | u8 ev = 0; | 2265 | u8 ev = 0; |
| 2004 | u8 data_mask = 0; | 2266 | u8 data_mask = 0; |
| 2005 | u8 device_event = 0; | 2267 | u8 device_event = 0; |
| 2006 | 2268 | ||
| 2007 | struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; | 2269 | struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; |
| 2008 | 2270 | ||
| 2009 | acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val, | 2271 | ev = inb_p(dev->cur_ioport->io.minimum); |
| 2010 | dev->cur_ioport->io.address_length); | 2272 | data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset); |
| 2011 | ev = port_val & SONY_PIC_EV_MASK; | ||
| 2012 | data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8)); | ||
| 2013 | 2273 | ||
| 2014 | dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n", | 2274 | dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", |
| 2015 | port_val, ev, data_mask, dev->cur_ioport->io.minimum); | 2275 | ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset); |
| 2016 | 2276 | ||
| 2017 | if (ev == 0x00 || ev == 0xff) | 2277 | if (ev == 0x00 || ev == 0xff) |
| 2018 | return IRQ_HANDLED; | 2278 | return IRQ_HANDLED; |
| @@ -2041,7 +2301,7 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id) | |||
| 2041 | 2301 | ||
| 2042 | found: | 2302 | found: |
| 2043 | sony_laptop_report_input_event(device_event); | 2303 | sony_laptop_report_input_event(device_event); |
| 2044 | acpi_bus_generate_event(spic_dev.acpi_dev, 1, device_event); | 2304 | acpi_bus_generate_proc_event(spic_dev.acpi_dev, 1, device_event); |
| 2045 | sonypi_compat_report_event(device_event); | 2305 | sonypi_compat_report_event(device_event); |
| 2046 | 2306 | ||
| 2047 | return IRQ_HANDLED; | 2307 | return IRQ_HANDLED; |
| @@ -2057,8 +2317,6 @@ static int sony_pic_remove(struct acpi_device *device, int type) | |||
| 2057 | struct sony_pic_ioport *io, *tmp_io; | 2317 | struct sony_pic_ioport *io, *tmp_io; |
| 2058 | struct sony_pic_irq *irq, *tmp_irq; | 2318 | struct sony_pic_irq *irq, *tmp_irq; |
| 2059 | 2319 | ||
| 2060 | sonypi_compat_exit(); | ||
| 2061 | |||
| 2062 | if (sony_pic_disable(device)) { | 2320 | if (sony_pic_disable(device)) { |
| 2063 | printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); | 2321 | printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); |
| 2064 | return -ENXIO; | 2322 | return -ENXIO; |
| @@ -2068,6 +2326,8 @@ static int sony_pic_remove(struct acpi_device *device, int type) | |||
| 2068 | release_region(spic_dev.cur_ioport->io.minimum, | 2326 | release_region(spic_dev.cur_ioport->io.minimum, |
| 2069 | spic_dev.cur_ioport->io.address_length); | 2327 | spic_dev.cur_ioport->io.address_length); |
| 2070 | 2328 | ||
| 2329 | sonypi_compat_exit(); | ||
| 2330 | |||
| 2071 | sony_laptop_remove_input(); | 2331 | sony_laptop_remove_input(); |
| 2072 | 2332 | ||
| 2073 | /* pf attrs */ | 2333 | /* pf attrs */ |
| @@ -2103,6 +2363,20 @@ static int sony_pic_add(struct acpi_device *device) | |||
| 2103 | spic_dev.model = sony_pic_detect_device_type(); | 2363 | spic_dev.model = sony_pic_detect_device_type(); |
| 2104 | mutex_init(&spic_dev.lock); | 2364 | mutex_init(&spic_dev.lock); |
| 2105 | 2365 | ||
| 2366 | /* model specific characteristics */ | ||
| 2367 | switch(spic_dev.model) { | ||
| 2368 | case SONYPI_DEVICE_TYPE1: | ||
| 2369 | spic_dev.evport_offset = SONYPI_TYPE1_OFFSET; | ||
| 2370 | break; | ||
| 2371 | case SONYPI_DEVICE_TYPE3: | ||
| 2372 | spic_dev.evport_offset = SONYPI_TYPE3_OFFSET; | ||
| 2373 | break; | ||
| 2374 | case SONYPI_DEVICE_TYPE2: | ||
| 2375 | default: | ||
| 2376 | spic_dev.evport_offset = SONYPI_TYPE2_OFFSET; | ||
| 2377 | break; | ||
| 2378 | } | ||
| 2379 | |||
| 2106 | /* read _PRS resources */ | 2380 | /* read _PRS resources */ |
| 2107 | result = sony_pic_possible_resources(device); | 2381 | result = sony_pic_possible_resources(device); |
| 2108 | if (result) { | 2382 | if (result) { |
| @@ -2119,6 +2393,9 @@ static int sony_pic_add(struct acpi_device *device) | |||
| 2119 | goto err_free_resources; | 2393 | goto err_free_resources; |
| 2120 | } | 2394 | } |
| 2121 | 2395 | ||
| 2396 | if (sonypi_compat_init()) | ||
| 2397 | goto err_remove_input; | ||
| 2398 | |||
| 2122 | /* request io port */ | 2399 | /* request io port */ |
| 2123 | list_for_each_entry(io, &spic_dev.ioports, list) { | 2400 | list_for_each_entry(io, &spic_dev.ioports, list) { |
| 2124 | if (request_region(io->io.minimum, io->io.address_length, | 2401 | if (request_region(io->io.minimum, io->io.address_length, |
| @@ -2133,7 +2410,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
| 2133 | if (!spic_dev.cur_ioport) { | 2410 | if (!spic_dev.cur_ioport) { |
| 2134 | printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); | 2411 | printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); |
| 2135 | result = -ENODEV; | 2412 | result = -ENODEV; |
| 2136 | goto err_remove_input; | 2413 | goto err_remove_compat; |
| 2137 | } | 2414 | } |
| 2138 | 2415 | ||
| 2139 | /* request IRQ */ | 2416 | /* request IRQ */ |
| @@ -2173,9 +2450,6 @@ static int sony_pic_add(struct acpi_device *device) | |||
| 2173 | if (result) | 2450 | if (result) |
| 2174 | goto err_remove_pf; | 2451 | goto err_remove_pf; |
| 2175 | 2452 | ||
| 2176 | if (sonypi_compat_init()) | ||
| 2177 | goto err_remove_pf; | ||
| 2178 | |||
| 2179 | return 0; | 2453 | return 0; |
| 2180 | 2454 | ||
| 2181 | err_remove_pf: | 2455 | err_remove_pf: |
| @@ -2191,6 +2465,9 @@ err_release_region: | |||
| 2191 | release_region(spic_dev.cur_ioport->io.minimum, | 2465 | release_region(spic_dev.cur_ioport->io.minimum, |
| 2192 | spic_dev.cur_ioport->io.address_length); | 2466 | spic_dev.cur_ioport->io.address_length); |
| 2193 | 2467 | ||
| 2468 | err_remove_compat: | ||
| 2469 | sonypi_compat_exit(); | ||
| 2470 | |||
| 2194 | err_remove_input: | 2471 | err_remove_input: |
| 2195 | sony_laptop_remove_input(); | 2472 | sony_laptop_remove_input(); |
| 2196 | 2473 | ||
| @@ -2222,10 +2499,15 @@ static int sony_pic_resume(struct acpi_device *device) | |||
| 2222 | return 0; | 2499 | return 0; |
| 2223 | } | 2500 | } |
| 2224 | 2501 | ||
| 2502 | static const struct acpi_device_id sony_pic_device_ids[] = { | ||
| 2503 | {SONY_PIC_HID, 0}, | ||
| 2504 | {"", 0}, | ||
| 2505 | }; | ||
| 2506 | |||
| 2225 | static struct acpi_driver sony_pic_driver = { | 2507 | static struct acpi_driver sony_pic_driver = { |
| 2226 | .name = SONY_PIC_DRIVER_NAME, | 2508 | .name = SONY_PIC_DRIVER_NAME, |
| 2227 | .class = SONY_PIC_CLASS, | 2509 | .class = SONY_PIC_CLASS, |
| 2228 | .ids = SONY_PIC_HID, | 2510 | .ids = sony_pic_device_ids, |
| 2229 | .owner = THIS_MODULE, | 2511 | .owner = THIS_MODULE, |
| 2230 | .ops = { | 2512 | .ops = { |
| 2231 | .add = sony_pic_add, | 2513 | .add = sony_pic_add, |
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 95c0b96e83f2..6c0b2f0a51ab 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.16" |
| 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 */ |
| 93 | MODULE_ALIAS("ibm_acpi"); | 93 | MODULE_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 */ | ||
| 108 | MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); | ||
| 109 | MODULE_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... */ | ||
| 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]"); | ||
| 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 | ||
| 109 | static acpi_handle root_handle = NULL; | 132 | static 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; \ |
| @@ -388,12 +411,13 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) | |||
| 388 | 411 | ||
| 389 | sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name); | 412 | sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name); |
| 390 | ibm->acpi->driver->ids = ibm->acpi->hid; | 413 | ibm->acpi->driver->ids = ibm->acpi->hid; |
| 414 | |||
| 391 | ibm->acpi->driver->ops.add = &tpacpi_device_add; | 415 | ibm->acpi->driver->ops.add = &tpacpi_device_add; |
| 392 | 416 | ||
| 393 | rc = acpi_bus_register_driver(ibm->acpi->driver); | 417 | rc = acpi_bus_register_driver(ibm->acpi->driver); |
| 394 | if (rc < 0) { | 418 | if (rc < 0) { |
| 395 | printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n", | 419 | printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n", |
| 396 | ibm->acpi->hid, rc); | 420 | ibm->name, rc); |
| 397 | kfree(ibm->acpi->driver); | 421 | kfree(ibm->acpi->driver); |
| 398 | ibm->acpi->driver = NULL; | 422 | ibm->acpi->driver = NULL; |
| 399 | } else if (!rc) | 423 | } else if (!rc) |
| @@ -487,19 +511,36 @@ static char *next_cmd(char **cmds) | |||
| 487 | /**************************************************************************** | 511 | /**************************************************************************** |
| 488 | **************************************************************************** | 512 | **************************************************************************** |
| 489 | * | 513 | * |
| 490 | * Device model: hwmon and platform | 514 | * Device model: input, hwmon and platform |
| 491 | * | 515 | * |
| 492 | **************************************************************************** | 516 | **************************************************************************** |
| 493 | ****************************************************************************/ | 517 | ****************************************************************************/ |
| 494 | 518 | ||
| 495 | static struct platform_device *tpacpi_pdev = NULL; | 519 | static struct platform_device *tpacpi_pdev; |
| 496 | static struct class_device *tpacpi_hwmon = NULL; | 520 | static struct class_device *tpacpi_hwmon; |
| 521 | static struct input_dev *tpacpi_inputdev; | ||
| 522 | |||
| 523 | |||
| 524 | static int tpacpi_resume_handler(struct platform_device *pdev) | ||
| 525 | { | ||
| 526 | struct ibm_struct *ibm, *itmp; | ||
| 527 | |||
| 528 | list_for_each_entry_safe(ibm, itmp, | ||
| 529 | &tpacpi_all_drivers, | ||
| 530 | all_drivers) { | ||
| 531 | if (ibm->resume) | ||
| 532 | (ibm->resume)(); | ||
| 533 | } | ||
| 534 | |||
| 535 | return 0; | ||
| 536 | } | ||
| 497 | 537 | ||
| 498 | static struct platform_driver tpacpi_pdriver = { | 538 | static struct platform_driver tpacpi_pdriver = { |
| 499 | .driver = { | 539 | .driver = { |
| 500 | .name = IBM_DRVR_NAME, | 540 | .name = IBM_DRVR_NAME, |
| 501 | .owner = THIS_MODULE, | 541 | .owner = THIS_MODULE, |
| 502 | }, | 542 | }, |
| 543 | .resume = tpacpi_resume_handler, | ||
| 503 | }; | 544 | }; |
| 504 | 545 | ||
| 505 | 546 | ||
| @@ -677,9 +718,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); | 718 | printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); |
| 678 | printk(IBM_INFO "%s\n", IBM_URL); | 719 | printk(IBM_INFO "%s\n", IBM_URL); |
| 679 | 720 | ||
| 680 | if (ibm_thinkpad_ec_found) | 721 | printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n", |
| 681 | printk(IBM_INFO "ThinkPad EC firmware %s\n", | 722 | (thinkpad_id.bios_version_str) ? |
| 682 | ibm_thinkpad_ec_found); | 723 | thinkpad_id.bios_version_str : "unknown", |
| 724 | (thinkpad_id.ec_version_str) ? | ||
| 725 | thinkpad_id.ec_version_str : "unknown"); | ||
| 726 | |||
| 727 | if (thinkpad_id.vendor && thinkpad_id.model_str) | ||
| 728 | printk(IBM_INFO "%s %s\n", | ||
| 729 | (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? | ||
| 730 | "IBM" : ((thinkpad_id.vendor == | ||
| 731 | PCI_VENDOR_ID_LENOVO) ? | ||
| 732 | "Lenovo" : "Unknown vendor"), | ||
| 733 | thinkpad_id.model_str); | ||
| 683 | 734 | ||
| 684 | return 0; | 735 | return 0; |
| 685 | } | 736 | } |
| @@ -704,16 +755,28 @@ static struct ibm_struct thinkpad_acpi_driver_data = { | |||
| 704 | */ | 755 | */ |
| 705 | 756 | ||
| 706 | static int hotkey_orig_status; | 757 | static int hotkey_orig_status; |
| 707 | static int hotkey_orig_mask; | 758 | static u32 hotkey_orig_mask; |
| 759 | static u32 hotkey_all_mask; | ||
| 760 | static u32 hotkey_reserved_mask; | ||
| 708 | 761 | ||
| 709 | static struct attribute_set *hotkey_dev_attributes = NULL; | 762 | static u16 *hotkey_keycode_map; |
| 763 | |||
| 764 | static struct attribute_set *hotkey_dev_attributes; | ||
| 765 | |||
| 766 | static int hotkey_get_wlsw(int *status) | ||
| 767 | { | ||
| 768 | if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) | ||
| 769 | return -EIO; | ||
| 770 | return 0; | ||
| 771 | } | ||
| 710 | 772 | ||
| 711 | /* sysfs hotkey enable ------------------------------------------------- */ | 773 | /* sysfs hotkey enable ------------------------------------------------- */ |
| 712 | static ssize_t hotkey_enable_show(struct device *dev, | 774 | static ssize_t hotkey_enable_show(struct device *dev, |
| 713 | struct device_attribute *attr, | 775 | struct device_attribute *attr, |
| 714 | char *buf) | 776 | char *buf) |
| 715 | { | 777 | { |
| 716 | int res, status, mask; | 778 | int res, status; |
| 779 | u32 mask; | ||
| 717 | 780 | ||
| 718 | res = hotkey_get(&status, &mask); | 781 | res = hotkey_get(&status, &mask); |
| 719 | if (res) | 782 | if (res) |
| @@ -727,7 +790,8 @@ static ssize_t hotkey_enable_store(struct device *dev, | |||
| 727 | const char *buf, size_t count) | 790 | const char *buf, size_t count) |
| 728 | { | 791 | { |
| 729 | unsigned long t; | 792 | unsigned long t; |
| 730 | int res, status, mask; | 793 | int res, status; |
| 794 | u32 mask; | ||
| 731 | 795 | ||
| 732 | if (parse_strtoul(buf, 1, &t)) | 796 | if (parse_strtoul(buf, 1, &t)) |
| 733 | return -EINVAL; | 797 | return -EINVAL; |
| @@ -748,13 +812,14 @@ static ssize_t hotkey_mask_show(struct device *dev, | |||
| 748 | struct device_attribute *attr, | 812 | struct device_attribute *attr, |
| 749 | char *buf) | 813 | char *buf) |
| 750 | { | 814 | { |
| 751 | int res, status, mask; | 815 | int res, status; |
| 816 | u32 mask; | ||
| 752 | 817 | ||
| 753 | res = hotkey_get(&status, &mask); | 818 | res = hotkey_get(&status, &mask); |
| 754 | if (res) | 819 | if (res) |
| 755 | return res; | 820 | return res; |
| 756 | 821 | ||
| 757 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask); | 822 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask); |
| 758 | } | 823 | } |
| 759 | 824 | ||
| 760 | static ssize_t hotkey_mask_store(struct device *dev, | 825 | static ssize_t hotkey_mask_store(struct device *dev, |
| @@ -762,9 +827,10 @@ static ssize_t hotkey_mask_store(struct device *dev, | |||
| 762 | const char *buf, size_t count) | 827 | const char *buf, size_t count) |
| 763 | { | 828 | { |
| 764 | unsigned long t; | 829 | unsigned long t; |
| 765 | int res, status, mask; | 830 | int res, status; |
| 831 | u32 mask; | ||
| 766 | 832 | ||
| 767 | if (parse_strtoul(buf, 0xffff, &t)) | 833 | if (parse_strtoul(buf, 0xffffffffUL, &t)) |
| 768 | return -EINVAL; | 834 | return -EINVAL; |
| 769 | 835 | ||
| 770 | res = hotkey_get(&status, &mask); | 836 | res = hotkey_get(&status, &mask); |
| @@ -794,26 +860,140 @@ static ssize_t hotkey_bios_mask_show(struct device *dev, | |||
| 794 | struct device_attribute *attr, | 860 | struct device_attribute *attr, |
| 795 | char *buf) | 861 | char *buf) |
| 796 | { | 862 | { |
| 797 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask); | 863 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); |
| 798 | } | 864 | } |
| 799 | 865 | ||
| 800 | static struct device_attribute dev_attr_hotkey_bios_mask = | 866 | static struct device_attribute dev_attr_hotkey_bios_mask = |
| 801 | __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL); | 867 | __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL); |
| 802 | 868 | ||
| 869 | /* sysfs hotkey all_mask ----------------------------------------------- */ | ||
| 870 | static ssize_t hotkey_all_mask_show(struct device *dev, | ||
| 871 | struct device_attribute *attr, | ||
| 872 | char *buf) | ||
| 873 | { | ||
| 874 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask); | ||
| 875 | } | ||
| 876 | |||
| 877 | static struct device_attribute dev_attr_hotkey_all_mask = | ||
| 878 | __ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL); | ||
| 879 | |||
| 880 | /* sysfs hotkey recommended_mask --------------------------------------- */ | ||
| 881 | static ssize_t hotkey_recommended_mask_show(struct device *dev, | ||
| 882 | struct device_attribute *attr, | ||
| 883 | char *buf) | ||
| 884 | { | ||
| 885 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", | ||
| 886 | hotkey_all_mask & ~hotkey_reserved_mask); | ||
| 887 | } | ||
| 888 | |||
| 889 | static struct device_attribute dev_attr_hotkey_recommended_mask = | ||
| 890 | __ATTR(hotkey_recommended_mask, S_IRUGO, | ||
| 891 | hotkey_recommended_mask_show, NULL); | ||
| 892 | |||
| 893 | /* sysfs hotkey radio_sw ----------------------------------------------- */ | ||
| 894 | static ssize_t hotkey_radio_sw_show(struct device *dev, | ||
| 895 | struct device_attribute *attr, | ||
| 896 | char *buf) | ||
| 897 | { | ||
| 898 | int res, s; | ||
| 899 | res = hotkey_get_wlsw(&s); | ||
| 900 | if (res < 0) | ||
| 901 | return res; | ||
| 902 | |||
| 903 | return snprintf(buf, PAGE_SIZE, "%d\n", !!s); | ||
| 904 | } | ||
| 905 | |||
| 906 | static struct device_attribute dev_attr_hotkey_radio_sw = | ||
| 907 | __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); | ||
| 908 | |||
| 909 | /* sysfs hotkey report_mode -------------------------------------------- */ | ||
| 910 | static ssize_t hotkey_report_mode_show(struct device *dev, | ||
| 911 | struct device_attribute *attr, | ||
| 912 | char *buf) | ||
| 913 | { | ||
| 914 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
| 915 | (hotkey_report_mode != 0) ? hotkey_report_mode : 1); | ||
| 916 | } | ||
| 917 | |||
| 918 | static struct device_attribute dev_attr_hotkey_report_mode = | ||
| 919 | __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); | ||
| 920 | |||
| 803 | /* --------------------------------------------------------------------- */ | 921 | /* --------------------------------------------------------------------- */ |
| 804 | 922 | ||
| 805 | static struct attribute *hotkey_mask_attributes[] = { | 923 | static struct attribute *hotkey_attributes[] __initdata = { |
| 924 | &dev_attr_hotkey_enable.attr, | ||
| 925 | &dev_attr_hotkey_report_mode.attr, | ||
| 926 | }; | ||
| 927 | |||
| 928 | static struct attribute *hotkey_mask_attributes[] __initdata = { | ||
| 806 | &dev_attr_hotkey_mask.attr, | 929 | &dev_attr_hotkey_mask.attr, |
| 807 | &dev_attr_hotkey_bios_enabled.attr, | 930 | &dev_attr_hotkey_bios_enabled.attr, |
| 808 | &dev_attr_hotkey_bios_mask.attr, | 931 | &dev_attr_hotkey_bios_mask.attr, |
| 932 | &dev_attr_hotkey_all_mask.attr, | ||
| 933 | &dev_attr_hotkey_recommended_mask.attr, | ||
| 809 | }; | 934 | }; |
| 810 | 935 | ||
| 811 | static int __init hotkey_init(struct ibm_init_struct *iibm) | 936 | static int __init hotkey_init(struct ibm_init_struct *iibm) |
| 812 | { | 937 | { |
| 813 | int res; | 938 | |
| 939 | static u16 ibm_keycode_map[] __initdata = { | ||
| 940 | /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ | ||
| 941 | KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP, | ||
| 942 | KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, | ||
| 943 | KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, | ||
| 944 | /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ | ||
| 945 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ | ||
| 946 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ | ||
| 947 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ | ||
| 948 | KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ | ||
| 949 | /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ | ||
| 950 | KEY_RESERVED, /* 0x10: FN+END (brightness down) */ | ||
| 951 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ | ||
| 952 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ | ||
| 953 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ | ||
| 954 | KEY_RESERVED, /* 0x14: VOLUME UP */ | ||
| 955 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ | ||
| 956 | KEY_RESERVED, /* 0x16: MUTE */ | ||
| 957 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ | ||
| 958 | /* (assignments unknown, please report if found) */ | ||
| 959 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
| 960 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
| 961 | }; | ||
| 962 | static u16 lenovo_keycode_map[] __initdata = { | ||
| 963 | /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ | ||
| 964 | KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, | ||
| 965 | KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, | ||
| 966 | KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, | ||
| 967 | /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ | ||
| 968 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ | ||
| 969 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ | ||
| 970 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ | ||
| 971 | KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */ | ||
| 972 | /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ | ||
| 973 | KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */ | ||
| 974 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ | ||
| 975 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ | ||
| 976 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ | ||
| 977 | KEY_RESERVED, /* 0x14: VOLUME UP */ | ||
| 978 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ | ||
| 979 | KEY_RESERVED, /* 0x16: MUTE */ | ||
| 980 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ | ||
| 981 | /* (assignments unknown, please report if found) */ | ||
| 982 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
| 983 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
| 984 | }; | ||
| 985 | |||
| 986 | #define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map) | ||
| 987 | #define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map) | ||
| 988 | #define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0]) | ||
| 989 | |||
| 990 | int res, i; | ||
| 991 | int status; | ||
| 814 | 992 | ||
| 815 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); | 993 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); |
| 816 | 994 | ||
| 995 | BUG_ON(!tpacpi_inputdev); | ||
| 996 | |||
| 817 | IBM_ACPIHANDLE_INIT(hkey); | 997 | IBM_ACPIHANDLE_INIT(hkey); |
| 818 | mutex_init(&hotkey_mutex); | 998 | mutex_init(&hotkey_mutex); |
| 819 | 999 | ||
| @@ -824,11 +1004,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 824 | str_supported(tp_features.hotkey)); | 1004 | str_supported(tp_features.hotkey)); |
| 825 | 1005 | ||
| 826 | if (tp_features.hotkey) { | 1006 | if (tp_features.hotkey) { |
| 827 | hotkey_dev_attributes = create_attr_set(4, NULL); | 1007 | hotkey_dev_attributes = create_attr_set(8, NULL); |
| 828 | if (!hotkey_dev_attributes) | 1008 | if (!hotkey_dev_attributes) |
| 829 | return -ENOMEM; | 1009 | return -ENOMEM; |
| 830 | res = add_to_attr_set(hotkey_dev_attributes, | 1010 | res = add_many_to_attr_set(hotkey_dev_attributes, |
| 831 | &dev_attr_hotkey_enable.attr); | 1011 | hotkey_attributes, |
| 1012 | ARRAY_SIZE(hotkey_attributes)); | ||
| 832 | if (res) | 1013 | if (res) |
| 833 | return res; | 1014 | return res; |
| 834 | 1015 | ||
| @@ -840,19 +1021,90 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 840 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", | 1021 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", |
| 841 | str_supported(tp_features.hotkey_mask)); | 1022 | str_supported(tp_features.hotkey_mask)); |
| 842 | 1023 | ||
| 1024 | if (tp_features.hotkey_mask) { | ||
| 1025 | /* MHKA available in A31, R40, R40e, T4x, X31, and later */ | ||
| 1026 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, | ||
| 1027 | "MHKA", "qd")) | ||
| 1028 | hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ | ||
| 1029 | } | ||
| 1030 | |||
| 843 | res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); | 1031 | res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); |
| 844 | if (!res && tp_features.hotkey_mask) { | 1032 | if (!res && tp_features.hotkey_mask) { |
| 845 | res = add_many_to_attr_set(hotkey_dev_attributes, | 1033 | res = add_many_to_attr_set(hotkey_dev_attributes, |
| 846 | hotkey_mask_attributes, | 1034 | hotkey_mask_attributes, |
| 847 | ARRAY_SIZE(hotkey_mask_attributes)); | 1035 | ARRAY_SIZE(hotkey_mask_attributes)); |
| 848 | } | 1036 | } |
| 1037 | |||
| 1038 | /* Not all thinkpads have a hardware radio switch */ | ||
| 1039 | if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { | ||
| 1040 | tp_features.hotkey_wlsw = 1; | ||
| 1041 | printk(IBM_INFO | ||
| 1042 | "radio switch found; radios are %s\n", | ||
| 1043 | enabled(status, 0)); | ||
| 1044 | res = add_to_attr_set(hotkey_dev_attributes, | ||
| 1045 | &dev_attr_hotkey_radio_sw.attr); | ||
| 1046 | } | ||
| 1047 | |||
| 849 | if (!res) | 1048 | if (!res) |
| 850 | res = register_attr_set_with_sysfs( | 1049 | res = register_attr_set_with_sysfs( |
| 851 | hotkey_dev_attributes, | 1050 | hotkey_dev_attributes, |
| 852 | &tpacpi_pdev->dev.kobj); | 1051 | &tpacpi_pdev->dev.kobj); |
| 1052 | if (res) | ||
| 1053 | return res; | ||
| 1054 | |||
| 1055 | /* Set up key map */ | ||
| 1056 | |||
| 1057 | hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, | ||
| 1058 | GFP_KERNEL); | ||
| 1059 | if (!hotkey_keycode_map) { | ||
| 1060 | printk(IBM_ERR "failed to allocate memory for key map\n"); | ||
| 1061 | return -ENOMEM; | ||
| 1062 | } | ||
| 853 | 1063 | ||
| 1064 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { | ||
| 1065 | dbg_printk(TPACPI_DBG_INIT, | ||
| 1066 | "using Lenovo default hot key map\n"); | ||
| 1067 | memcpy(hotkey_keycode_map, &lenovo_keycode_map, | ||
| 1068 | TPACPI_HOTKEY_MAP_SIZE); | ||
| 1069 | } else { | ||
| 1070 | dbg_printk(TPACPI_DBG_INIT, | ||
| 1071 | "using IBM default hot key map\n"); | ||
| 1072 | memcpy(hotkey_keycode_map, &ibm_keycode_map, | ||
| 1073 | TPACPI_HOTKEY_MAP_SIZE); | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | set_bit(EV_KEY, tpacpi_inputdev->evbit); | ||
| 1077 | set_bit(EV_MSC, tpacpi_inputdev->evbit); | ||
| 1078 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); | ||
| 1079 | tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; | ||
| 1080 | tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; | ||
| 1081 | tpacpi_inputdev->keycode = hotkey_keycode_map; | ||
| 1082 | for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { | ||
| 1083 | if (hotkey_keycode_map[i] != KEY_RESERVED) { | ||
| 1084 | set_bit(hotkey_keycode_map[i], | ||
| 1085 | tpacpi_inputdev->keybit); | ||
| 1086 | } else { | ||
| 1087 | if (i < sizeof(hotkey_reserved_mask)*8) | ||
| 1088 | hotkey_reserved_mask |= 1 << i; | ||
| 1089 | } | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | if (tp_features.hotkey_wlsw) { | ||
| 1093 | set_bit(EV_SW, tpacpi_inputdev->evbit); | ||
| 1094 | set_bit(SW_RADIO, tpacpi_inputdev->swbit); | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | dbg_printk(TPACPI_DBG_INIT, | ||
| 1098 | "enabling hot key handling\n"); | ||
| 1099 | res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) | ||
| 1100 | | hotkey_orig_mask); | ||
| 854 | if (res) | 1101 | if (res) |
| 855 | return res; | 1102 | return res; |
| 1103 | |||
| 1104 | dbg_printk(TPACPI_DBG_INIT, | ||
| 1105 | "legacy hot key reporting over procfs %s\n", | ||
| 1106 | (hotkey_report_mode < 2) ? | ||
| 1107 | "enabled" : "disabled"); | ||
| 856 | } | 1108 | } |
| 857 | 1109 | ||
| 858 | return (tp_features.hotkey)? 0 : 1; | 1110 | return (tp_features.hotkey)? 0 : 1; |
| @@ -875,22 +1127,108 @@ static void hotkey_exit(void) | |||
| 875 | } | 1127 | } |
| 876 | } | 1128 | } |
| 877 | 1129 | ||
| 1130 | static void tpacpi_input_send_key(unsigned int scancode, | ||
| 1131 | unsigned int keycode) | ||
| 1132 | { | ||
| 1133 | if (keycode != KEY_RESERVED) { | ||
| 1134 | input_report_key(tpacpi_inputdev, keycode, 1); | ||
| 1135 | if (keycode == KEY_UNKNOWN) | ||
| 1136 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | ||
| 1137 | scancode); | ||
| 1138 | input_sync(tpacpi_inputdev); | ||
| 1139 | |||
| 1140 | input_report_key(tpacpi_inputdev, keycode, 0); | ||
| 1141 | if (keycode == KEY_UNKNOWN) | ||
| 1142 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | ||
| 1143 | scancode); | ||
| 1144 | input_sync(tpacpi_inputdev); | ||
| 1145 | } | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | static void tpacpi_input_send_radiosw(void) | ||
| 1149 | { | ||
| 1150 | int wlsw; | ||
| 1151 | |||
| 1152 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) | ||
| 1153 | input_report_switch(tpacpi_inputdev, | ||
| 1154 | SW_RADIO, !!wlsw); | ||
| 1155 | } | ||
| 1156 | |||
| 878 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) | 1157 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) |
| 879 | { | 1158 | { |
| 880 | int hkey; | 1159 | u32 hkey; |
| 1160 | unsigned int keycode, scancode; | ||
| 1161 | int send_acpi_ev = 0; | ||
| 1162 | |||
| 1163 | if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { | ||
| 1164 | switch (hkey >> 12) { | ||
| 1165 | case 1: | ||
| 1166 | /* 0x1000-0x1FFF: key presses */ | ||
| 1167 | scancode = hkey & 0xfff; | ||
| 1168 | if (scancode > 0 && scancode < 0x21) { | ||
| 1169 | scancode--; | ||
| 1170 | keycode = hotkey_keycode_map[scancode]; | ||
| 1171 | tpacpi_input_send_key(scancode, keycode); | ||
| 1172 | } else { | ||
| 1173 | printk(IBM_ERR | ||
| 1174 | "hotkey 0x%04x out of range for keyboard map\n", | ||
| 1175 | hkey); | ||
| 1176 | send_acpi_ev = 1; | ||
| 1177 | } | ||
| 1178 | break; | ||
| 1179 | case 5: | ||
| 1180 | /* 0x5000-0x5FFF: LID */ | ||
| 1181 | /* we don't handle it through this path, just | ||
| 1182 | * eat up known LID events */ | ||
| 1183 | if (hkey != 0x5001 && hkey != 0x5002) { | ||
| 1184 | printk(IBM_ERR | ||
| 1185 | "unknown LID-related hotkey event: 0x%04x\n", | ||
| 1186 | hkey); | ||
| 1187 | send_acpi_ev = 1; | ||
| 1188 | } | ||
| 1189 | break; | ||
| 1190 | case 7: | ||
| 1191 | /* 0x7000-0x7FFF: misc */ | ||
| 1192 | if (tp_features.hotkey_wlsw && hkey == 0x7000) { | ||
| 1193 | tpacpi_input_send_radiosw(); | ||
| 1194 | break; | ||
| 1195 | } | ||
| 1196 | /* fallthrough to default */ | ||
| 1197 | default: | ||
| 1198 | /* case 2: dock-related */ | ||
| 1199 | /* 0x2305 - T43 waking up due to bay lever eject while aslept */ | ||
| 1200 | /* case 3: ultra-bay related. maybe bay in dock? */ | ||
| 1201 | /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ | ||
| 1202 | printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); | ||
| 1203 | send_acpi_ev = 1; | ||
| 1204 | } | ||
| 1205 | } else { | ||
| 1206 | printk(IBM_ERR "unknown hotkey notification event %d\n", event); | ||
| 1207 | hkey = 0; | ||
| 1208 | send_acpi_ev = 1; | ||
| 1209 | } | ||
| 881 | 1210 | ||
| 882 | if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) | 1211 | /* Legacy events */ |
| 883 | acpi_bus_generate_event(ibm->acpi->device, event, hkey); | 1212 | if (send_acpi_ev || hotkey_report_mode < 2) |
| 884 | else { | 1213 | acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); |
| 885 | printk(IBM_ERR "unknown hotkey event %d\n", event); | 1214 | |
| 886 | acpi_bus_generate_event(ibm->acpi->device, event, 0); | 1215 | /* netlink events */ |
| 1216 | if (send_acpi_ev) { | ||
| 1217 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, | ||
| 1218 | ibm->acpi->device->dev.bus_id, | ||
| 1219 | event, hkey); | ||
| 887 | } | 1220 | } |
| 888 | } | 1221 | } |
| 889 | 1222 | ||
| 1223 | static void hotkey_resume(void) | ||
| 1224 | { | ||
| 1225 | tpacpi_input_send_radiosw(); | ||
| 1226 | } | ||
| 1227 | |||
| 890 | /* | 1228 | /* |
| 891 | * Call with hotkey_mutex held | 1229 | * Call with hotkey_mutex held |
| 892 | */ | 1230 | */ |
| 893 | static int hotkey_get(int *status, int *mask) | 1231 | static int hotkey_get(int *status, u32 *mask) |
| 894 | { | 1232 | { |
| 895 | if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) | 1233 | if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) |
| 896 | return -EIO; | 1234 | return -EIO; |
| @@ -905,7 +1243,7 @@ static int hotkey_get(int *status, int *mask) | |||
| 905 | /* | 1243 | /* |
| 906 | * Call with hotkey_mutex held | 1244 | * Call with hotkey_mutex held |
| 907 | */ | 1245 | */ |
| 908 | static int hotkey_set(int status, int mask) | 1246 | static int hotkey_set(int status, u32 mask) |
| 909 | { | 1247 | { |
| 910 | int i; | 1248 | int i; |
| 911 | 1249 | ||
| @@ -926,7 +1264,8 @@ static int hotkey_set(int status, int mask) | |||
| 926 | /* procfs -------------------------------------------------------------- */ | 1264 | /* procfs -------------------------------------------------------------- */ |
| 927 | static int hotkey_read(char *p) | 1265 | static int hotkey_read(char *p) |
| 928 | { | 1266 | { |
| 929 | int res, status, mask; | 1267 | int res, status; |
| 1268 | u32 mask; | ||
| 930 | int len = 0; | 1269 | int len = 0; |
| 931 | 1270 | ||
| 932 | if (!tp_features.hotkey) { | 1271 | if (!tp_features.hotkey) { |
| @@ -944,7 +1283,7 @@ static int hotkey_read(char *p) | |||
| 944 | 1283 | ||
| 945 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); | 1284 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); |
| 946 | if (tp_features.hotkey_mask) { | 1285 | if (tp_features.hotkey_mask) { |
| 947 | len += sprintf(p + len, "mask:\t\t0x%04x\n", mask); | 1286 | len += sprintf(p + len, "mask:\t\t0x%08x\n", mask); |
| 948 | len += sprintf(p + len, | 1287 | len += sprintf(p + len, |
| 949 | "commands:\tenable, disable, reset, <mask>\n"); | 1288 | "commands:\tenable, disable, reset, <mask>\n"); |
| 950 | } else { | 1289 | } else { |
| @@ -957,7 +1296,8 @@ static int hotkey_read(char *p) | |||
| 957 | 1296 | ||
| 958 | static int hotkey_write(char *buf) | 1297 | static int hotkey_write(char *buf) |
| 959 | { | 1298 | { |
| 960 | int res, status, mask; | 1299 | int res, status; |
| 1300 | u32 mask; | ||
| 961 | char *cmd; | 1301 | char *cmd; |
| 962 | int do_cmd = 0; | 1302 | int do_cmd = 0; |
| 963 | 1303 | ||
| @@ -1000,8 +1340,13 @@ errexit: | |||
| 1000 | return res; | 1340 | return res; |
| 1001 | } | 1341 | } |
| 1002 | 1342 | ||
| 1343 | static const struct acpi_device_id ibm_htk_device_ids[] = { | ||
| 1344 | {IBM_HKEY_HID, 0}, | ||
| 1345 | {"", 0}, | ||
| 1346 | }; | ||
| 1347 | |||
| 1003 | static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = { | 1348 | static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = { |
| 1004 | .hid = IBM_HKEY_HID, | 1349 | .hid = ibm_htk_device_ids, |
| 1005 | .notify = hotkey_notify, | 1350 | .notify = hotkey_notify, |
| 1006 | .handle = &hkey_handle, | 1351 | .handle = &hkey_handle, |
| 1007 | .type = ACPI_DEVICE_NOTIFY, | 1352 | .type = ACPI_DEVICE_NOTIFY, |
| @@ -1012,6 +1357,7 @@ static struct ibm_struct hotkey_driver_data = { | |||
| 1012 | .read = hotkey_read, | 1357 | .read = hotkey_read, |
| 1013 | .write = hotkey_write, | 1358 | .write = hotkey_write, |
| 1014 | .exit = hotkey_exit, | 1359 | .exit = hotkey_exit, |
| 1360 | .resume = hotkey_resume, | ||
| 1015 | .acpi = &ibm_hotkey_acpidriver, | 1361 | .acpi = &ibm_hotkey_acpidriver, |
| 1016 | }; | 1362 | }; |
| 1017 | 1363 | ||
| @@ -1763,6 +2109,11 @@ IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ | |||
| 1763 | /* don't list other alternatives as we install a notify handler on the 570 */ | 2109 | /* don't list other alternatives as we install a notify handler on the 570 */ |
| 1764 | IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ | 2110 | IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ |
| 1765 | 2111 | ||
| 2112 | static const struct acpi_device_id ibm_pci_device_ids[] = { | ||
| 2113 | {PCI_ROOT_HID_STRING, 0}, | ||
| 2114 | {"", 0}, | ||
| 2115 | }; | ||
| 2116 | |||
| 1766 | static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = { | 2117 | static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = { |
| 1767 | { | 2118 | { |
| 1768 | .notify = dock_notify, | 2119 | .notify = dock_notify, |
| @@ -1770,7 +2121,10 @@ static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = { | |||
| 1770 | .type = ACPI_SYSTEM_NOTIFY, | 2121 | .type = ACPI_SYSTEM_NOTIFY, |
| 1771 | }, | 2122 | }, |
| 1772 | { | 2123 | { |
| 1773 | .hid = IBM_PCI_HID, | 2124 | /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING. |
| 2125 | * We just use it to get notifications of dock hotplug | ||
| 2126 | * in very old thinkpads */ | ||
| 2127 | .hid = ibm_pci_device_ids, | ||
| 1774 | .notify = dock_notify, | 2128 | .notify = dock_notify, |
| 1775 | .handle = &pci_handle, | 2129 | .handle = &pci_handle, |
| 1776 | .type = ACPI_SYSTEM_NOTIFY, | 2130 | .type = ACPI_SYSTEM_NOTIFY, |
| @@ -1829,23 +2183,29 @@ static int __init dock_init2(struct ibm_init_struct *iibm) | |||
| 1829 | static void dock_notify(struct ibm_struct *ibm, u32 event) | 2183 | static void dock_notify(struct ibm_struct *ibm, u32 event) |
| 1830 | { | 2184 | { |
| 1831 | int docked = dock_docked(); | 2185 | int docked = dock_docked(); |
| 1832 | int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID); | 2186 | int pci = ibm->acpi->hid && ibm->acpi->device && |
| 2187 | acpi_match_device_ids(ibm->acpi->device, ibm_pci_device_ids); | ||
| 2188 | int data; | ||
| 1833 | 2189 | ||
| 1834 | if (event == 1 && !pci) /* 570 */ | 2190 | if (event == 1 && !pci) /* 570 */ |
| 1835 | acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ | 2191 | data = 1; /* button */ |
| 1836 | else if (event == 1 && pci) /* 570 */ | 2192 | else if (event == 1 && pci) /* 570 */ |
| 1837 | acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */ | 2193 | data = 3; /* dock */ |
| 1838 | else if (event == 3 && docked) | 2194 | else if (event == 3 && docked) |
| 1839 | acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ | 2195 | data = 1; /* button */ |
| 1840 | else if (event == 3 && !docked) | 2196 | else if (event == 3 && !docked) |
| 1841 | acpi_bus_generate_event(ibm->acpi->device, event, 2); /* undock */ | 2197 | data = 2; /* undock */ |
| 1842 | else if (event == 0 && docked) | 2198 | else if (event == 0 && docked) |
| 1843 | acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */ | 2199 | data = 3; /* dock */ |
| 1844 | else { | 2200 | else { |
| 1845 | printk(IBM_ERR "unknown dock event %d, status %d\n", | 2201 | printk(IBM_ERR "unknown dock event %d, status %d\n", |
| 1846 | event, _sta(dock_handle)); | 2202 | event, _sta(dock_handle)); |
| 1847 | acpi_bus_generate_event(ibm->acpi->device, event, 0); /* unknown */ | 2203 | data = 0; /* unknown */ |
| 1848 | } | 2204 | } |
| 2205 | acpi_bus_generate_proc_event(ibm->acpi->device, event, data); | ||
| 2206 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, | ||
| 2207 | ibm->acpi->device->dev.bus_id, | ||
| 2208 | event, data); | ||
| 1849 | } | 2209 | } |
| 1850 | 2210 | ||
| 1851 | static int dock_read(char *p) | 2211 | static int dock_read(char *p) |
| @@ -1943,7 +2303,10 @@ static int __init bay_init(struct ibm_init_struct *iibm) | |||
| 1943 | 2303 | ||
| 1944 | static void bay_notify(struct ibm_struct *ibm, u32 event) | 2304 | static void bay_notify(struct ibm_struct *ibm, u32 event) |
| 1945 | { | 2305 | { |
| 1946 | acpi_bus_generate_event(ibm->acpi->device, event, 0); | 2306 | acpi_bus_generate_proc_event(ibm->acpi->device, event, 0); |
| 2307 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, | ||
| 2308 | ibm->acpi->device->dev.bus_id, | ||
| 2309 | event, 0); | ||
| 1947 | } | 2310 | } |
| 1948 | 2311 | ||
| 1949 | #define bay_occupied(b) (_sta(b##_handle) & 1) | 2312 | #define bay_occupied(b) (_sta(b##_handle) & 1) |
| @@ -2389,7 +2752,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) | |||
| 2389 | 2752 | ||
| 2390 | acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); | 2753 | acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); |
| 2391 | 2754 | ||
| 2392 | if (ibm_thinkpad_ec_found && experimental) { | 2755 | if (thinkpad_id.ec_model) { |
| 2393 | /* | 2756 | /* |
| 2394 | * Direct EC access mode: sensors at registers | 2757 | * Direct EC access mode: sensors at registers |
| 2395 | * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for | 2758 | * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for |
| @@ -2533,6 +2896,8 @@ static int thermal_get_sensor(int idx, s32 *value) | |||
| 2533 | snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); | 2896 | snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); |
| 2534 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) | 2897 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) |
| 2535 | return -EIO; | 2898 | return -EIO; |
| 2899 | if (t > 127 || t < -127) | ||
| 2900 | t = TP_EC_THERMAL_TMP_NA; | ||
| 2536 | *value = t * 1000; | 2901 | *value = t * 1000; |
| 2537 | return 0; | 2902 | return 0; |
| 2538 | } | 2903 | } |
| @@ -2671,22 +3036,39 @@ static struct ibm_struct ecdump_driver_data = { | |||
| 2671 | * Backlight/brightness subdriver | 3036 | * Backlight/brightness subdriver |
| 2672 | */ | 3037 | */ |
| 2673 | 3038 | ||
| 2674 | static struct backlight_device *ibm_backlight_device = NULL; | 3039 | static struct backlight_device *ibm_backlight_device; |
| 2675 | 3040 | ||
| 2676 | static struct backlight_ops ibm_backlight_data = { | 3041 | static struct backlight_ops ibm_backlight_data = { |
| 2677 | .get_brightness = brightness_get, | 3042 | .get_brightness = brightness_get, |
| 2678 | .update_status = brightness_update_status, | 3043 | .update_status = brightness_update_status, |
| 2679 | }; | 3044 | }; |
| 2680 | 3045 | ||
| 3046 | static struct mutex brightness_mutex; | ||
| 3047 | |||
| 2681 | static int __init brightness_init(struct ibm_init_struct *iibm) | 3048 | static int __init brightness_init(struct ibm_init_struct *iibm) |
| 2682 | { | 3049 | { |
| 2683 | int b; | 3050 | int b; |
| 2684 | 3051 | ||
| 2685 | vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); | 3052 | vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); |
| 2686 | 3053 | ||
| 3054 | mutex_init(&brightness_mutex); | ||
| 3055 | |||
| 3056 | if (!brightness_mode) { | ||
| 3057 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) | ||
| 3058 | brightness_mode = 2; | ||
| 3059 | else | ||
| 3060 | brightness_mode = 3; | ||
| 3061 | |||
| 3062 | dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n", | ||
| 3063 | brightness_mode); | ||
| 3064 | } | ||
| 3065 | |||
| 3066 | if (brightness_mode > 3) | ||
| 3067 | return -EINVAL; | ||
| 3068 | |||
| 2687 | b = brightness_get(NULL); | 3069 | b = brightness_get(NULL); |
| 2688 | if (b < 0) | 3070 | if (b < 0) |
| 2689 | return b; | 3071 | return 1; |
| 2690 | 3072 | ||
| 2691 | ibm_backlight_device = backlight_device_register( | 3073 | ibm_backlight_device = backlight_device_register( |
| 2692 | TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, | 3074 | TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, |
| @@ -2722,34 +3104,79 @@ static int brightness_update_status(struct backlight_device *bd) | |||
| 2722 | bd->props.brightness : 0); | 3104 | bd->props.brightness : 0); |
| 2723 | } | 3105 | } |
| 2724 | 3106 | ||
| 3107 | /* | ||
| 3108 | * ThinkPads can read brightness from two places: EC 0x31, or | ||
| 3109 | * CMOS NVRAM byte 0x5E, bits 0-3. | ||
| 3110 | */ | ||
| 2725 | static int brightness_get(struct backlight_device *bd) | 3111 | static int brightness_get(struct backlight_device *bd) |
| 2726 | { | 3112 | { |
| 2727 | u8 level; | 3113 | u8 lec = 0, lcmos = 0, level = 0; |
| 2728 | if (!acpi_ec_read(brightness_offset, &level)) | 3114 | |
| 2729 | return -EIO; | 3115 | if (brightness_mode & 1) { |
| 3116 | if (!acpi_ec_read(brightness_offset, &lec)) | ||
| 3117 | return -EIO; | ||
| 3118 | lec &= 7; | ||
| 3119 | level = lec; | ||
| 3120 | }; | ||
| 3121 | if (brightness_mode & 2) { | ||
| 3122 | lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) | ||
| 3123 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) | ||
| 3124 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; | ||
| 3125 | level = lcmos; | ||
| 3126 | } | ||
| 2730 | 3127 | ||
| 2731 | level &= 0x7; | 3128 | if (brightness_mode == 3 && lec != lcmos) { |
| 3129 | printk(IBM_ERR | ||
| 3130 | "CMOS NVRAM (%u) and EC (%u) do not agree " | ||
| 3131 | "on display brightness level\n", | ||
| 3132 | (unsigned int) lcmos, | ||
| 3133 | (unsigned int) lec); | ||
| 3134 | return -EIO; | ||
| 3135 | } | ||
| 2732 | 3136 | ||
| 2733 | return level; | 3137 | return level; |
| 2734 | } | 3138 | } |
| 2735 | 3139 | ||
| 2736 | static int brightness_set(int value) | 3140 | static int brightness_set(int value) |
| 2737 | { | 3141 | { |
| 2738 | int cmos_cmd, inc, i; | 3142 | int cmos_cmd, inc, i, res; |
| 2739 | int current_value = brightness_get(NULL); | 3143 | int current_value; |
| 3144 | |||
| 3145 | if (value > 7) | ||
| 3146 | return -EINVAL; | ||
| 2740 | 3147 | ||
| 2741 | value &= 7; | 3148 | res = mutex_lock_interruptible(&brightness_mutex); |
| 3149 | if (res < 0) | ||
| 3150 | return res; | ||
| 2742 | 3151 | ||
| 2743 | cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN; | 3152 | current_value = brightness_get(NULL); |
| 3153 | if (current_value < 0) { | ||
| 3154 | res = current_value; | ||
| 3155 | goto errout; | ||
| 3156 | } | ||
| 3157 | |||
| 3158 | cmos_cmd = value > current_value ? | ||
| 3159 | TP_CMOS_BRIGHTNESS_UP : | ||
| 3160 | TP_CMOS_BRIGHTNESS_DOWN; | ||
| 2744 | inc = value > current_value ? 1 : -1; | 3161 | inc = value > current_value ? 1 : -1; |
| 3162 | |||
| 3163 | res = 0; | ||
| 2745 | for (i = current_value; i != value; i += inc) { | 3164 | for (i = current_value; i != value; i += inc) { |
| 2746 | if (issue_thinkpad_cmos_command(cmos_cmd)) | 3165 | if ((brightness_mode & 2) && |
| 2747 | return -EIO; | 3166 | issue_thinkpad_cmos_command(cmos_cmd)) { |
| 2748 | if (!acpi_ec_write(brightness_offset, i + inc)) | 3167 | res = -EIO; |
| 2749 | return -EIO; | 3168 | goto errout; |
| 3169 | } | ||
| 3170 | if ((brightness_mode & 1) && | ||
| 3171 | !acpi_ec_write(brightness_offset, i + inc)) { | ||
| 3172 | res = -EIO; | ||
| 3173 | goto errout;; | ||
| 3174 | } | ||
| 2750 | } | 3175 | } |
| 2751 | 3176 | ||
| 2752 | return 0; | 3177 | errout: |
| 3178 | mutex_unlock(&brightness_mutex); | ||
| 3179 | return res; | ||
| 2753 | } | 3180 | } |
| 2754 | 3181 | ||
| 2755 | static int brightness_read(char *p) | 3182 | static int brightness_read(char *p) |
| @@ -3273,20 +3700,19 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
| 3273 | * Enable for TP-1Y (T43), TP-78 (R51e), | 3700 | * Enable for TP-1Y (T43), TP-78 (R51e), |
| 3274 | * TP-76 (R52), TP-70 (T43, R52), which are known | 3701 | * TP-76 (R52), TP-70 (T43, R52), which are known |
| 3275 | * to be buggy. */ | 3702 | * to be buggy. */ |
| 3276 | if (fan_control_initial_status == 0x07 && | 3703 | if (fan_control_initial_status == 0x07) { |
| 3277 | ibm_thinkpad_ec_found && | 3704 | switch (thinkpad_id.ec_model) { |
| 3278 | ((ibm_thinkpad_ec_found[0] == '1' && | 3705 | case 0x5931: /* TP-1Y */ |
| 3279 | ibm_thinkpad_ec_found[1] == 'Y') || | 3706 | case 0x3837: /* TP-78 */ |
| 3280 | (ibm_thinkpad_ec_found[0] == '7' && | 3707 | case 0x3637: /* TP-76 */ |
| 3281 | (ibm_thinkpad_ec_found[1] == '6' || | 3708 | case 0x3037: /* TP-70 */ |
| 3282 | ibm_thinkpad_ec_found[1] == '8' || | 3709 | printk(IBM_NOTICE |
| 3283 | ibm_thinkpad_ec_found[1] == '0')) | 3710 | "fan_init: initial fan status is " |
| 3284 | )) { | 3711 | "unknown, assuming it is in auto " |
| 3285 | printk(IBM_NOTICE | 3712 | "mode\n"); |
| 3286 | "fan_init: initial fan status is " | 3713 | tp_features.fan_ctrl_status_undef = 1; |
| 3287 | "unknown, assuming it is in auto " | 3714 | ;; |
| 3288 | "mode\n"); | 3715 | } |
| 3289 | tp_features.fan_ctrl_status_undef = 1; | ||
| 3290 | } | 3716 | } |
| 3291 | } else { | 3717 | } else { |
| 3292 | printk(IBM_ERR | 3718 | printk(IBM_ERR |
| @@ -3474,7 +3900,7 @@ static void fan_watchdog_fire(struct work_struct *ignored) | |||
| 3474 | 3900 | ||
| 3475 | static void fan_watchdog_reset(void) | 3901 | static void fan_watchdog_reset(void) |
| 3476 | { | 3902 | { |
| 3477 | static int fan_watchdog_active = 0; | 3903 | static int fan_watchdog_active; |
| 3478 | 3904 | ||
| 3479 | if (fan_control_access_mode == TPACPI_FAN_WR_NONE) | 3905 | if (fan_control_access_mode == TPACPI_FAN_WR_NONE) |
| 3480 | return; | 3906 | return; |
| @@ -3877,7 +4303,7 @@ static struct ibm_struct fan_driver_data = { | |||
| 3877 | ****************************************************************************/ | 4303 | ****************************************************************************/ |
| 3878 | 4304 | ||
| 3879 | /* /proc support */ | 4305 | /* /proc support */ |
| 3880 | static struct proc_dir_entry *proc_dir = NULL; | 4306 | static struct proc_dir_entry *proc_dir; |
| 3881 | 4307 | ||
| 3882 | /* Subdriver registry */ | 4308 | /* Subdriver registry */ |
| 3883 | static LIST_HEAD(tpacpi_all_drivers); | 4309 | static LIST_HEAD(tpacpi_all_drivers); |
| @@ -4020,13 +4446,30 @@ static void ibm_exit(struct ibm_struct *ibm) | |||
| 4020 | 4446 | ||
| 4021 | /* Probing */ | 4447 | /* Probing */ |
| 4022 | 4448 | ||
| 4023 | static char *ibm_thinkpad_ec_found = NULL; | 4449 | static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) |
| 4024 | |||
| 4025 | static char* __init check_dmi_for_ec(void) | ||
| 4026 | { | 4450 | { |
| 4027 | struct dmi_device *dev = NULL; | 4451 | const struct dmi_device *dev = NULL; |
| 4028 | char ec_fw_string[18]; | 4452 | char ec_fw_string[18]; |
| 4029 | 4453 | ||
| 4454 | if (!tp) | ||
| 4455 | return; | ||
| 4456 | |||
| 4457 | memset(tp, 0, sizeof(*tp)); | ||
| 4458 | |||
| 4459 | if (dmi_name_in_vendors("IBM")) | ||
| 4460 | tp->vendor = PCI_VENDOR_ID_IBM; | ||
| 4461 | else if (dmi_name_in_vendors("LENOVO")) | ||
| 4462 | tp->vendor = PCI_VENDOR_ID_LENOVO; | ||
| 4463 | else | ||
| 4464 | return; | ||
| 4465 | |||
| 4466 | tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION), | ||
| 4467 | GFP_KERNEL); | ||
| 4468 | if (!tp->bios_version_str) | ||
| 4469 | return; | ||
| 4470 | tp->bios_model = tp->bios_version_str[0] | ||
| 4471 | | (tp->bios_version_str[1] << 8); | ||
| 4472 | |||
| 4030 | /* | 4473 | /* |
| 4031 | * ThinkPad T23 or newer, A31 or newer, R50e or newer, | 4474 | * ThinkPad T23 or newer, A31 or newer, R50e or newer, |
| 4032 | * X32 or newer, all Z series; Some models must have an | 4475 | * X32 or newer, all Z series; Some models must have an |
| @@ -4040,10 +4483,20 @@ static char* __init check_dmi_for_ec(void) | |||
| 4040 | ec_fw_string) == 1) { | 4483 | ec_fw_string) == 1) { |
| 4041 | ec_fw_string[sizeof(ec_fw_string) - 1] = 0; | 4484 | ec_fw_string[sizeof(ec_fw_string) - 1] = 0; |
| 4042 | ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; | 4485 | ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; |
| 4043 | return kstrdup(ec_fw_string, GFP_KERNEL); | 4486 | |
| 4487 | tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); | ||
| 4488 | tp->ec_model = ec_fw_string[0] | ||
| 4489 | | (ec_fw_string[1] << 8); | ||
| 4490 | break; | ||
| 4044 | } | 4491 | } |
| 4045 | } | 4492 | } |
| 4046 | return NULL; | 4493 | |
| 4494 | tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION), | ||
| 4495 | GFP_KERNEL); | ||
| 4496 | if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) { | ||
| 4497 | kfree(tp->model_str); | ||
| 4498 | tp->model_str = NULL; | ||
| 4499 | } | ||
| 4047 | } | 4500 | } |
| 4048 | 4501 | ||
| 4049 | static int __init probe_for_thinkpad(void) | 4502 | static int __init probe_for_thinkpad(void) |
| @@ -4057,7 +4510,7 @@ static int __init probe_for_thinkpad(void) | |||
| 4057 | * Non-ancient models have better DMI tagging, but very old models | 4510 | * Non-ancient models have better DMI tagging, but very old models |
| 4058 | * don't. | 4511 | * don't. |
| 4059 | */ | 4512 | */ |
| 4060 | is_thinkpad = dmi_name_in_vendors("ThinkPad"); | 4513 | is_thinkpad = (thinkpad_id.model_str != NULL); |
| 4061 | 4514 | ||
| 4062 | /* ec is required because many other handles are relative to it */ | 4515 | /* ec is required because many other handles are relative to it */ |
| 4063 | IBM_ACPIHANDLE_INIT(ec); | 4516 | IBM_ACPIHANDLE_INIT(ec); |
| @@ -4073,7 +4526,7 @@ static int __init probe_for_thinkpad(void) | |||
| 4073 | * false positives a damn great deal | 4526 | * false positives a damn great deal |
| 4074 | */ | 4527 | */ |
| 4075 | if (!is_thinkpad) | 4528 | if (!is_thinkpad) |
| 4076 | is_thinkpad = dmi_name_in_vendors("IBM"); | 4529 | is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM); |
| 4077 | 4530 | ||
| 4078 | if (!is_thinkpad && !force_load) | 4531 | if (!is_thinkpad && !force_load) |
| 4079 | return -ENODEV; | 4532 | return -ENODEV; |
| @@ -4185,10 +4638,16 @@ static u32 dbg_level; | |||
| 4185 | module_param_named(debug, dbg_level, uint, 0); | 4638 | module_param_named(debug, dbg_level, uint, 0); |
| 4186 | 4639 | ||
| 4187 | static int force_load; | 4640 | static int force_load; |
| 4188 | module_param(force_load, int, 0); | 4641 | module_param(force_load, bool, 0); |
| 4189 | 4642 | ||
| 4190 | static int fan_control_allowed; | 4643 | static int fan_control_allowed; |
| 4191 | module_param_named(fan_control, fan_control_allowed, int, 0); | 4644 | module_param_named(fan_control, fan_control_allowed, bool, 0); |
| 4645 | |||
| 4646 | static int brightness_mode; | ||
| 4647 | module_param_named(brightness_mode, brightness_mode, int, 0); | ||
| 4648 | |||
| 4649 | static unsigned int hotkey_report_mode; | ||
| 4650 | module_param(hotkey_report_mode, uint, 0); | ||
| 4192 | 4651 | ||
| 4193 | #define IBM_PARAM(feature) \ | 4652 | #define IBM_PARAM(feature) \ |
| 4194 | module_param_call(feature, set_ibm_param, NULL, NULL, 0) | 4653 | module_param_call(feature, set_ibm_param, NULL, NULL, 0) |
| @@ -4215,13 +4674,21 @@ static int __init thinkpad_acpi_module_init(void) | |||
| 4215 | { | 4674 | { |
| 4216 | int ret, i; | 4675 | int ret, i; |
| 4217 | 4676 | ||
| 4677 | /* Parameter checking */ | ||
| 4678 | if (hotkey_report_mode > 2) | ||
| 4679 | return -EINVAL; | ||
| 4680 | |||
| 4218 | /* Driver-level probe */ | 4681 | /* Driver-level probe */ |
| 4682 | |||
| 4683 | get_thinkpad_model_data(&thinkpad_id); | ||
| 4219 | ret = probe_for_thinkpad(); | 4684 | ret = probe_for_thinkpad(); |
| 4220 | if (ret) | 4685 | if (ret) { |
| 4686 | thinkpad_acpi_module_exit(); | ||
| 4221 | return ret; | 4687 | return ret; |
| 4688 | } | ||
| 4222 | 4689 | ||
| 4223 | /* Driver initialization */ | 4690 | /* Driver initialization */ |
| 4224 | ibm_thinkpad_ec_found = check_dmi_for_ec(); | 4691 | |
| 4225 | IBM_ACPIHANDLE_INIT(ecrd); | 4692 | IBM_ACPIHANDLE_INIT(ecrd); |
| 4226 | IBM_ACPIHANDLE_INIT(ecwr); | 4693 | IBM_ACPIHANDLE_INIT(ecwr); |
| 4227 | 4694 | ||
| @@ -4239,12 +4706,15 @@ static int __init thinkpad_acpi_module_init(void) | |||
| 4239 | thinkpad_acpi_module_exit(); | 4706 | thinkpad_acpi_module_exit(); |
| 4240 | return ret; | 4707 | return ret; |
| 4241 | } | 4708 | } |
| 4709 | tp_features.platform_drv_registered = 1; | ||
| 4710 | |||
| 4242 | ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); | 4711 | ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); |
| 4243 | if (ret) { | 4712 | if (ret) { |
| 4244 | printk(IBM_ERR "unable to create sysfs driver attributes\n"); | 4713 | printk(IBM_ERR "unable to create sysfs driver attributes\n"); |
| 4245 | thinkpad_acpi_module_exit(); | 4714 | thinkpad_acpi_module_exit(); |
| 4246 | return ret; | 4715 | return ret; |
| 4247 | } | 4716 | } |
| 4717 | tp_features.platform_drv_attrs_registered = 1; | ||
| 4248 | 4718 | ||
| 4249 | 4719 | ||
| 4250 | /* Device initialization */ | 4720 | /* Device initialization */ |
| @@ -4265,6 +4735,22 @@ static int __init thinkpad_acpi_module_init(void) | |||
| 4265 | thinkpad_acpi_module_exit(); | 4735 | thinkpad_acpi_module_exit(); |
| 4266 | return ret; | 4736 | return ret; |
| 4267 | } | 4737 | } |
| 4738 | tpacpi_inputdev = input_allocate_device(); | ||
| 4739 | if (!tpacpi_inputdev) { | ||
| 4740 | printk(IBM_ERR "unable to allocate input device\n"); | ||
| 4741 | thinkpad_acpi_module_exit(); | ||
| 4742 | return -ENOMEM; | ||
| 4743 | } else { | ||
| 4744 | /* Prepare input device, but don't register */ | ||
| 4745 | tpacpi_inputdev->name = "ThinkPad Extra Buttons"; | ||
| 4746 | tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0"; | ||
| 4747 | tpacpi_inputdev->id.bustype = BUS_HOST; | ||
| 4748 | tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ? | ||
| 4749 | thinkpad_id.vendor : | ||
| 4750 | PCI_VENDOR_ID_IBM; | ||
| 4751 | tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; | ||
| 4752 | tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; | ||
| 4753 | } | ||
| 4268 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { | 4754 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { |
| 4269 | ret = ibm_init(&ibms_init[i]); | 4755 | ret = ibm_init(&ibms_init[i]); |
| 4270 | if (ret >= 0 && *ibms_init[i].param) | 4756 | if (ret >= 0 && *ibms_init[i].param) |
| @@ -4274,6 +4760,14 @@ static int __init thinkpad_acpi_module_init(void) | |||
| 4274 | return ret; | 4760 | return ret; |
| 4275 | } | 4761 | } |
| 4276 | } | 4762 | } |
| 4763 | ret = input_register_device(tpacpi_inputdev); | ||
| 4764 | if (ret < 0) { | ||
| 4765 | printk(IBM_ERR "unable to register input device\n"); | ||
| 4766 | thinkpad_acpi_module_exit(); | ||
| 4767 | return ret; | ||
| 4768 | } else { | ||
| 4769 | tp_features.input_device_registered = 1; | ||
| 4770 | } | ||
| 4277 | 4771 | ||
| 4278 | return 0; | 4772 | return 0; |
| 4279 | } | 4773 | } |
| @@ -4290,19 +4784,31 @@ static void thinkpad_acpi_module_exit(void) | |||
| 4290 | 4784 | ||
| 4291 | dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); | 4785 | dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); |
| 4292 | 4786 | ||
| 4787 | if (tpacpi_inputdev) { | ||
| 4788 | if (tp_features.input_device_registered) | ||
| 4789 | input_unregister_device(tpacpi_inputdev); | ||
| 4790 | else | ||
| 4791 | input_free_device(tpacpi_inputdev); | ||
| 4792 | } | ||
| 4793 | |||
| 4293 | if (tpacpi_hwmon) | 4794 | if (tpacpi_hwmon) |
| 4294 | hwmon_device_unregister(tpacpi_hwmon); | 4795 | hwmon_device_unregister(tpacpi_hwmon); |
| 4295 | 4796 | ||
| 4296 | if (tpacpi_pdev) | 4797 | if (tpacpi_pdev) |
| 4297 | platform_device_unregister(tpacpi_pdev); | 4798 | platform_device_unregister(tpacpi_pdev); |
| 4298 | 4799 | ||
| 4299 | tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); | 4800 | if (tp_features.platform_drv_attrs_registered) |
| 4300 | platform_driver_unregister(&tpacpi_pdriver); | 4801 | tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); |
| 4802 | |||
| 4803 | if (tp_features.platform_drv_registered) | ||
| 4804 | platform_driver_unregister(&tpacpi_pdriver); | ||
| 4301 | 4805 | ||
| 4302 | if (proc_dir) | 4806 | if (proc_dir) |
| 4303 | remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); | 4807 | remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); |
| 4304 | 4808 | ||
| 4305 | kfree(ibm_thinkpad_ec_found); | 4809 | kfree(thinkpad_id.bios_version_str); |
| 4810 | kfree(thinkpad_id.ec_version_str); | ||
| 4811 | kfree(thinkpad_id.model_str); | ||
| 4306 | } | 4812 | } |
| 4307 | 4813 | ||
| 4308 | module_init(thinkpad_acpi_module_init); | 4814 | module_init(thinkpad_acpi_module_init); |
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 72d62f2dabb9..082a1cbc16c0 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 */ |
| 106 | static int __must_check acpi_evalf(acpi_handle handle, | 118 | static int __must_check acpi_evalf(acpi_handle handle, |
| @@ -161,6 +173,7 @@ static int parse_strtoul(const char *buf, unsigned long max, | |||
| 161 | static struct platform_device *tpacpi_pdev; | 173 | static struct platform_device *tpacpi_pdev; |
| 162 | static struct class_device *tpacpi_hwmon; | 174 | static struct class_device *tpacpi_hwmon; |
| 163 | static struct platform_driver tpacpi_pdriver; | 175 | static struct platform_driver tpacpi_pdriver; |
| 176 | static struct input_dev *tpacpi_inputdev; | ||
| 164 | static int tpacpi_create_driver_attributes(struct device_driver *drv); | 177 | static int tpacpi_create_driver_attributes(struct device_driver *drv); |
| 165 | static void tpacpi_remove_driver_attributes(struct device_driver *drv); | 178 | static void tpacpi_remove_driver_attributes(struct device_driver *drv); |
| 166 | 179 | ||
| @@ -168,9 +181,8 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv); | |||
| 168 | static int experimental; | 181 | static int experimental; |
| 169 | static u32 dbg_level; | 182 | static u32 dbg_level; |
| 170 | static int force_load; | 183 | static int force_load; |
| 171 | static char *ibm_thinkpad_ec_found; | 184 | static unsigned int hotkey_report_mode; |
| 172 | 185 | ||
| 173 | static char* check_dmi_for_ec(void); | ||
| 174 | static int thinkpad_acpi_module_init(void); | 186 | static int thinkpad_acpi_module_init(void); |
| 175 | static void thinkpad_acpi_module_exit(void); | 187 | static void thinkpad_acpi_module_exit(void); |
| 176 | 188 | ||
| @@ -182,7 +194,7 @@ static void thinkpad_acpi_module_exit(void); | |||
| 182 | struct ibm_struct; | 194 | struct ibm_struct; |
| 183 | 195 | ||
| 184 | struct tp_acpi_drv_struct { | 196 | struct tp_acpi_drv_struct { |
| 185 | char *hid; | 197 | const struct acpi_device_id *hid; |
| 186 | struct acpi_driver *driver; | 198 | struct acpi_driver *driver; |
| 187 | 199 | ||
| 188 | void (*notify) (struct ibm_struct *, u32); | 200 | void (*notify) (struct ibm_struct *, u32); |
| @@ -197,6 +209,7 @@ struct ibm_struct { | |||
| 197 | int (*read) (char *); | 209 | int (*read) (char *); |
| 198 | int (*write) (char *); | 210 | int (*write) (char *); |
| 199 | void (*exit) (void); | 211 | void (*exit) (void); |
| 212 | void (*resume) (void); | ||
| 200 | 213 | ||
| 201 | struct list_head all_drivers; | 214 | struct list_head all_drivers; |
| 202 | 215 | ||
| @@ -228,12 +241,31 @@ static struct { | |||
| 228 | u16 bluetooth:1; | 241 | u16 bluetooth:1; |
| 229 | u16 hotkey:1; | 242 | u16 hotkey:1; |
| 230 | u16 hotkey_mask:1; | 243 | u16 hotkey_mask:1; |
| 244 | u16 hotkey_wlsw:1; | ||
| 231 | u16 light:1; | 245 | u16 light:1; |
| 232 | u16 light_status:1; | 246 | u16 light_status:1; |
| 233 | u16 wan:1; | 247 | u16 wan:1; |
| 234 | u16 fan_ctrl_status_undef:1; | 248 | u16 fan_ctrl_status_undef:1; |
| 249 | u16 input_device_registered:1; | ||
| 250 | u16 platform_drv_registered:1; | ||
| 251 | u16 platform_drv_attrs_registered:1; | ||
| 235 | } tp_features; | 252 | } tp_features; |
| 236 | 253 | ||
| 254 | struct thinkpad_id_data { | ||
| 255 | unsigned int vendor; /* ThinkPad vendor: | ||
| 256 | * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */ | ||
| 257 | |||
| 258 | char *bios_version_str; /* Something like 1ZET51WW (1.03z) */ | ||
| 259 | char *ec_version_str; /* Something like 1ZHT51WW-1.04a */ | ||
| 260 | |||
| 261 | u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */ | ||
| 262 | u16 ec_model; | ||
| 263 | |||
| 264 | char *model_str; | ||
| 265 | }; | ||
| 266 | |||
| 267 | static struct thinkpad_id_data thinkpad_id; | ||
| 268 | |||
| 237 | static struct list_head tpacpi_all_drivers; | 269 | static struct list_head tpacpi_all_drivers; |
| 238 | 270 | ||
| 239 | static struct ibm_init_struct ibms_init[]; | 271 | static struct ibm_init_struct ibms_init[]; |
| @@ -300,6 +332,7 @@ static int bluetooth_write(char *buf); | |||
| 300 | 332 | ||
| 301 | static struct backlight_device *ibm_backlight_device; | 333 | static struct backlight_device *ibm_backlight_device; |
| 302 | static int brightness_offset = 0x31; | 334 | static int brightness_offset = 0x31; |
| 335 | static int brightness_mode; | ||
| 303 | 336 | ||
| 304 | static int brightness_init(struct ibm_init_struct *iibm); | 337 | static int brightness_init(struct ibm_init_struct *iibm); |
| 305 | static void brightness_exit(void); | 338 | static void brightness_exit(void); |
| @@ -415,14 +448,14 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc); | |||
| 415 | */ | 448 | */ |
| 416 | 449 | ||
| 417 | static int hotkey_orig_status; | 450 | static int hotkey_orig_status; |
| 418 | static int hotkey_orig_mask; | 451 | static u32 hotkey_orig_mask; |
| 419 | 452 | ||
| 420 | static struct mutex hotkey_mutex; | 453 | static struct mutex hotkey_mutex; |
| 421 | 454 | ||
| 422 | static int hotkey_init(struct ibm_init_struct *iibm); | 455 | static int hotkey_init(struct ibm_init_struct *iibm); |
| 423 | static void hotkey_exit(void); | 456 | static void hotkey_exit(void); |
| 424 | static int hotkey_get(int *status, int *mask); | 457 | static int hotkey_get(int *status, u32 *mask); |
| 425 | static int hotkey_set(int status, int mask); | 458 | static int hotkey_set(int status, u32 mask); |
| 426 | static void hotkey_notify(struct ibm_struct *ibm, u32 event); | 459 | static void hotkey_notify(struct ibm_struct *ibm, u32 event); |
| 427 | static int hotkey_read(char *p); | 460 | static int hotkey_read(char *p); |
| 428 | static int hotkey_write(char *buf); | 461 | static int hotkey_write(char *buf); |
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index d195fb088f4a..8f77949f93dd 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c | |||
| @@ -57,16 +57,11 @@ static int tifm_bus_match(struct device *dev, struct device_driver *drv) | |||
| 57 | return 0; | 57 | return 0; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | static int tifm_uevent(struct device *dev, char **envp, int num_envp, | 60 | static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env) |
| 61 | char *buffer, int buffer_size) | ||
| 62 | { | 61 | { |
| 63 | struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); | 62 | struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); |
| 64 | int i = 0; | ||
| 65 | int length = 0; | ||
| 66 | 63 | ||
| 67 | if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, | 64 | if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1))) |
| 68 | "TIFM_CARD_TYPE=%s", | ||
| 69 | tifm_media_type_name(sock->type, 1))) | ||
| 70 | return -ENOMEM; | 65 | return -ENOMEM; |
| 71 | 66 | ||
| 72 | return 0; | 67 | return 0; |
