aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig63
-rw-r--r--drivers/misc/Makefile7
-rw-r--r--drivers/misc/acer-wmi.c145
-rw-r--r--drivers/misc/atmel_pwm.c5
-rw-r--r--drivers/misc/compal-laptop.c404
-rw-r--r--drivers/misc/eeepc-laptop.c4
-rw-r--r--drivers/misc/fujitsu-laptop.c831
-rw-r--r--drivers/misc/hdpuftrs/hdpu_cpustate.c9
-rw-r--r--drivers/misc/hp-wmi.c494
-rw-r--r--drivers/misc/hpilo.c768
-rw-r--r--drivers/misc/hpilo.h189
-rw-r--r--drivers/misc/kgdbts.c33
-rw-r--r--drivers/misc/phantom.c16
-rw-r--r--drivers/misc/sgi-xp/xpc_main.c3
-rw-r--r--drivers/misc/sony-laptop.c3
-rw-r--r--drivers/misc/thinkpad_acpi.c963
16 files changed, 3479 insertions, 458 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 636af2862308..321eb9134635 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -77,11 +77,13 @@ config IBM_ASM
77 for your IBM server. 77 for your IBM server.
78 78
79config PHANTOM 79config PHANTOM
80 tristate "Sensable PHANToM" 80 tristate "Sensable PHANToM (PCI)"
81 depends on PCI 81 depends on PCI
82 help 82 help
83 Say Y here if you want to build a driver for Sensable PHANToM device. 83 Say Y here if you want to build a driver for Sensable PHANToM device.
84 84
85 This driver is only for PCI PHANToMs.
86
85 If you choose to build module, its name will be phantom. If unsure, 87 If you choose to build module, its name will be phantom. If unsure,
86 say N here. 88 say N here.
87 89
@@ -179,17 +181,29 @@ config FUJITSU_LAPTOP
179 tristate "Fujitsu Laptop Extras" 181 tristate "Fujitsu Laptop Extras"
180 depends on X86 182 depends on X86
181 depends on ACPI 183 depends on ACPI
184 depends on INPUT
182 depends on BACKLIGHT_CLASS_DEVICE 185 depends on BACKLIGHT_CLASS_DEVICE
183 ---help--- 186 ---help---
184 This is a driver for laptops built by Fujitsu: 187 This is a driver for laptops built by Fujitsu:
185 188
186 * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks 189 * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks
187 * Possibly other Fujitsu laptop models 190 * Possibly other Fujitsu laptop models
191 * Tested with S6410 and S7020
188 192
189 It adds support for LCD brightness control. 193 It adds support for LCD brightness control and some hotkeys.
190 194
191 If you have a Fujitsu laptop, say Y or M here. 195 If you have a Fujitsu laptop, say Y or M here.
192 196
197config FUJITSU_LAPTOP_DEBUG
198 bool "Verbose debug mode for Fujitsu Laptop Extras"
199 depends on FUJITSU_LAPTOP
200 default n
201 ---help---
202 Enables extra debug output from the fujitsu extras driver, at the
203 expense of a slight increase in driver size.
204
205 If you are not sure, say N here.
206
193config TC1100_WMI 207config TC1100_WMI
194 tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)" 208 tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)"
195 depends on X86 && !X86_64 209 depends on X86 && !X86_64
@@ -200,6 +214,18 @@ config TC1100_WMI
200 This is a driver for the WMI extensions (wireless and bluetooth power 214 This is a driver for the WMI extensions (wireless and bluetooth power
201 control) of the HP Compaq TC1100 tablet. 215 control) of the HP Compaq TC1100 tablet.
202 216
217config HP_WMI
218 tristate "HP WMI extras"
219 depends on ACPI_WMI
220 depends on INPUT
221 depends on RFKILL
222 help
223 Say Y here if you want to support WMI-based hotkeys on HP laptops and
224 to read data from WMI such as docking or ambient light sensor state.
225
226 To compile this driver as a module, choose M here: the module will
227 be called hp-wmi.
228
203config MSI_LAPTOP 229config MSI_LAPTOP
204 tristate "MSI Laptop Extras" 230 tristate "MSI Laptop Extras"
205 depends on X86 231 depends on X86
@@ -219,6 +245,23 @@ config MSI_LAPTOP
219 245
220 If you have an MSI S270 laptop, say Y or M here. 246 If you have an MSI S270 laptop, say Y or M here.
221 247
248config COMPAL_LAPTOP
249 tristate "Compal Laptop Extras"
250 depends on X86
251 depends on ACPI_EC
252 depends on BACKLIGHT_CLASS_DEVICE
253 ---help---
254 This is a driver for laptops built by Compal:
255
256 Compal FL90/IFL90
257 Compal FL91/IFL91
258 Compal FL92/JFL92
259 Compal FT00/IFT00
260
261 It adds support for Bluetooth, WLAN and LCD brightness control.
262
263 If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here.
264
222config SONY_LAPTOP 265config SONY_LAPTOP
223 tristate "Sony Laptop Extras" 266 tristate "Sony Laptop Extras"
224 depends on X86 && ACPI 267 depends on X86 && ACPI
@@ -250,6 +293,8 @@ config THINKPAD_ACPI
250 select INPUT 293 select INPUT
251 select NEW_LEDS 294 select NEW_LEDS
252 select LEDS_CLASS 295 select LEDS_CLASS
296 select NET
297 select RFKILL
253 ---help--- 298 ---help---
254 This is a driver for the IBM and Lenovo ThinkPad laptops. It adds 299 This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
255 support for Fn-Fx key combinations, Bluetooth control, video 300 support for Fn-Fx key combinations, Bluetooth control, video
@@ -391,4 +436,18 @@ config SGI_XP
391 this feature will allow for direct communication between SSIs 436 this feature will allow for direct communication between SSIs
392 based on a network adapter and DMA messaging. 437 based on a network adapter and DMA messaging.
393 438
439config HP_ILO
440 tristate "Channel interface driver for HP iLO/iLO2 processor"
441 depends on PCI
442 default n
443 help
444 The channel interface driver allows applications to communicate
445 with iLO/iLO2 management processors present on HP ProLiant
446 servers. Upon loading, the driver creates /dev/hpilo/dXccbN files,
447 which can be used to gather data from the management processor,
448 via read and write system calls.
449
450 To compile this driver as a module, choose M here: the
451 module will be called hpilo.
452
394endif # MISC_DEVICES 453endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 1952875a272e..f5e273420c09 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -5,13 +5,15 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
5 5
6obj-$(CONFIG_IBM_ASM) += ibmasm/ 6obj-$(CONFIG_IBM_ASM) += ibmasm/
7obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ 7obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
8obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
9obj-$(CONFIG_ACER_WMI) += acer-wmi.o
10obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o 8obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
11obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o 9obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
10obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
11obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
12obj-$(CONFIG_ACER_WMI) += acer-wmi.o
12obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o 13obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
13obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o 14obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
14obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o 15obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
16obj-$(CONFIG_HP_WMI) += hp-wmi.o
15obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o 17obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
16obj-$(CONFIG_LKDTM) += lkdtm.o 18obj-$(CONFIG_LKDTM) += lkdtm.o
17obj-$(CONFIG_TIFM_CORE) += tifm_core.o 19obj-$(CONFIG_TIFM_CORE) += tifm_core.o
@@ -26,3 +28,4 @@ obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
26obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o 28obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
27obj-$(CONFIG_KGDB_TESTS) += kgdbts.o 29obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
28obj-$(CONFIG_SGI_XP) += sgi-xp/ 30obj-$(CONFIG_SGI_XP) += sgi-xp/
31obj-$(CONFIG_HP_ILO) += hpilo.o
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
index dd13a3749927..e7a3fe508dff 100644
--- a/drivers/misc/acer-wmi.c
+++ b/drivers/misc/acer-wmi.c
@@ -22,18 +22,18 @@
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */ 23 */
24 24
25#define ACER_WMI_VERSION "0.1"
26
27#include <linux/kernel.h> 25#include <linux/kernel.h>
28#include <linux/module.h> 26#include <linux/module.h>
29#include <linux/init.h> 27#include <linux/init.h>
30#include <linux/types.h> 28#include <linux/types.h>
31#include <linux/dmi.h> 29#include <linux/dmi.h>
30#include <linux/fb.h>
32#include <linux/backlight.h> 31#include <linux/backlight.h>
33#include <linux/leds.h> 32#include <linux/leds.h>
34#include <linux/platform_device.h> 33#include <linux/platform_device.h>
35#include <linux/acpi.h> 34#include <linux/acpi.h>
36#include <linux/i8042.h> 35#include <linux/i8042.h>
36#include <linux/debugfs.h>
37 37
38#include <acpi/acpi_drivers.h> 38#include <acpi/acpi_drivers.h>
39 39
@@ -87,6 +87,7 @@ struct acer_quirks {
87 * Acer ACPI method GUIDs 87 * Acer ACPI method GUIDs
88 */ 88 */
89#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" 89#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
90#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C"
90#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" 91#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
91#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" 92#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
92 93
@@ -150,6 +151,12 @@ struct acer_data {
150 int brightness; 151 int brightness;
151}; 152};
152 153
154struct acer_debug {
155 struct dentry *root;
156 struct dentry *devices;
157 u32 wmid_devices;
158};
159
153/* Each low-level interface must define at least some of the following */ 160/* Each low-level interface must define at least some of the following */
154struct wmi_interface { 161struct wmi_interface {
155 /* The WMI device type */ 162 /* The WMI device type */
@@ -160,6 +167,9 @@ struct wmi_interface {
160 167
161 /* Private data for the current interface */ 168 /* Private data for the current interface */
162 struct acer_data data; 169 struct acer_data data;
170
171 /* debugfs entries associated with this interface */
172 struct acer_debug debug;
163}; 173};
164 174
165/* The static interface pointer, points to the currently detected interface */ 175/* The static interface pointer, points to the currently detected interface */
@@ -174,7 +184,7 @@ static struct wmi_interface *interface;
174struct quirk_entry { 184struct quirk_entry {
175 u8 wireless; 185 u8 wireless;
176 u8 mailled; 186 u8 mailled;
177 u8 brightness; 187 s8 brightness;
178 u8 bluetooth; 188 u8 bluetooth;
179}; 189};
180 190
@@ -198,6 +208,10 @@ static int dmi_matched(const struct dmi_system_id *dmi)
198static struct quirk_entry quirk_unknown = { 208static struct quirk_entry quirk_unknown = {
199}; 209};
200 210
211static struct quirk_entry quirk_acer_aspire_1520 = {
212 .brightness = -1,
213};
214
201static struct quirk_entry quirk_acer_travelmate_2490 = { 215static struct quirk_entry quirk_acer_travelmate_2490 = {
202 .mailled = 1, 216 .mailled = 1,
203}; 217};
@@ -207,9 +221,31 @@ static struct quirk_entry quirk_medion_md_98300 = {
207 .wireless = 1, 221 .wireless = 1,
208}; 222};
209 223
224static struct quirk_entry quirk_fujitsu_amilo_li_1718 = {
225 .wireless = 2,
226};
227
210static struct dmi_system_id acer_quirks[] = { 228static struct dmi_system_id acer_quirks[] = {
211 { 229 {
212 .callback = dmi_matched, 230 .callback = dmi_matched,
231 .ident = "Acer Aspire 1360",
232 .matches = {
233 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
234 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
235 },
236 .driver_data = &quirk_acer_aspire_1520,
237 },
238 {
239 .callback = dmi_matched,
240 .ident = "Acer Aspire 1520",
241 .matches = {
242 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
243 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"),
244 },
245 .driver_data = &quirk_acer_aspire_1520,
246 },
247 {
248 .callback = dmi_matched,
213 .ident = "Acer Aspire 3100", 249 .ident = "Acer Aspire 3100",
214 .matches = { 250 .matches = {
215 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 251 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -300,6 +336,15 @@ static struct dmi_system_id acer_quirks[] = {
300 }, 336 },
301 { 337 {
302 .callback = dmi_matched, 338 .callback = dmi_matched,
339 .ident = "Fujitsu Siemens Amilo Li 1718",
340 .matches = {
341 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
342 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"),
343 },
344 .driver_data = &quirk_fujitsu_amilo_li_1718,
345 },
346 {
347 .callback = dmi_matched,
303 .ident = "Medion MD 98300", 348 .ident = "Medion MD 98300",
304 .matches = { 349 .matches = {
305 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), 350 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
@@ -393,6 +438,12 @@ struct wmi_interface *iface)
393 return AE_ERROR; 438 return AE_ERROR;
394 *value = result & 0x1; 439 *value = result & 0x1;
395 return AE_OK; 440 return AE_OK;
441 case 2:
442 err = ec_read(0x71, &result);
443 if (err)
444 return AE_ERROR;
445 *value = result & 0x1;
446 return AE_OK;
396 default: 447 default:
397 err = ec_read(0xA, &result); 448 err = ec_read(0xA, &result);
398 if (err) 449 if (err)
@@ -506,6 +557,15 @@ static acpi_status AMW0_set_capabilities(void)
506 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 557 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
507 union acpi_object *obj; 558 union acpi_object *obj;
508 559
560 /*
561 * On laptops with this strange GUID (non Acer), normal probing doesn't
562 * work.
563 */
564 if (wmi_has_guid(AMW0_GUID2)) {
565 interface->capability |= ACER_CAP_WIRELESS;
566 return AE_OK;
567 }
568
509 args.eax = ACER_AMW0_WRITE; 569 args.eax = ACER_AMW0_WRITE;
510 args.ecx = args.edx = 0; 570 args.ecx = args.edx = 0;
511 571
@@ -552,7 +612,8 @@ static acpi_status AMW0_set_capabilities(void)
552 * appear to use the same EC register for brightness, even if they 612 * appear to use the same EC register for brightness, even if they
553 * differ for wireless, etc 613 * differ for wireless, etc
554 */ 614 */
555 interface->capability |= ACER_CAP_BRIGHTNESS; 615 if (quirks->brightness >= 0)
616 interface->capability |= ACER_CAP_BRIGHTNESS;
556 617
557 return AE_OK; 618 return AE_OK;
558} 619}
@@ -807,7 +868,15 @@ static int read_brightness(struct backlight_device *bd)
807 868
808static int update_bl_status(struct backlight_device *bd) 869static int update_bl_status(struct backlight_device *bd)
809{ 870{
810 set_u32(bd->props.brightness, ACER_CAP_BRIGHTNESS); 871 int intensity = bd->props.brightness;
872
873 if (bd->props.power != FB_BLANK_UNBLANK)
874 intensity = 0;
875 if (bd->props.fb_blank != FB_BLANK_UNBLANK)
876 intensity = 0;
877
878 set_u32(intensity, ACER_CAP_BRIGHTNESS);
879
811 return 0; 880 return 0;
812} 881}
813 882
@@ -829,8 +898,9 @@ static int __devinit acer_backlight_init(struct device *dev)
829 898
830 acer_backlight_device = bd; 899 acer_backlight_device = bd;
831 900
901 bd->props.power = FB_BLANK_UNBLANK;
902 bd->props.brightness = max_brightness;
832 bd->props.max_brightness = max_brightness; 903 bd->props.max_brightness = max_brightness;
833 bd->props.brightness = read_brightness(NULL);
834 backlight_update_status(bd); 904 backlight_update_status(bd);
835 return 0; 905 return 0;
836} 906}
@@ -894,6 +964,28 @@ static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR,
894 show_interface, NULL); 964 show_interface, NULL);
895 965
896/* 966/*
967 * debugfs functions
968 */
969static u32 get_wmid_devices(void)
970{
971 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
972 union acpi_object *obj;
973 acpi_status status;
974
975 status = wmi_query_block(WMID_GUID2, 1, &out);
976 if (ACPI_FAILURE(status))
977 return 0;
978
979 obj = (union acpi_object *) out.pointer;
980 if (obj && obj->type == ACPI_TYPE_BUFFER &&
981 obj->buffer.length == sizeof(u32)) {
982 return *((u32 *) obj->buffer.pointer);
983 } else {
984 return 0;
985 }
986}
987
988/*
897 * Platform device 989 * Platform device
898 */ 990 */
899static int __devinit acer_platform_probe(struct platform_device *device) 991static int __devinit acer_platform_probe(struct platform_device *device)
@@ -1052,12 +1144,40 @@ error_sysfs:
1052 return retval; 1144 return retval;
1053} 1145}
1054 1146
1147static void remove_debugfs(void)
1148{
1149 debugfs_remove(interface->debug.devices);
1150 debugfs_remove(interface->debug.root);
1151}
1152
1153static int create_debugfs(void)
1154{
1155 interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
1156 if (!interface->debug.root) {
1157 printk(ACER_ERR "Failed to create debugfs directory");
1158 return -ENOMEM;
1159 }
1160
1161 interface->debug.devices = debugfs_create_u32("devices", S_IRUGO,
1162 interface->debug.root,
1163 &interface->debug.wmid_devices);
1164 if (!interface->debug.devices)
1165 goto error_debugfs;
1166
1167 return 0;
1168
1169error_debugfs:
1170 remove_debugfs();
1171 return -ENOMEM;
1172}
1173
1055static int __init acer_wmi_init(void) 1174static int __init acer_wmi_init(void)
1056{ 1175{
1057 int err; 1176 int err;
1058 1177
1059 printk(ACER_INFO "Acer Laptop ACPI-WMI Extras version %s\n", 1178 printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n");
1060 ACER_WMI_VERSION); 1179
1180 find_quirks();
1061 1181
1062 /* 1182 /*
1063 * Detect which ACPI-WMI interface we're using. 1183 * Detect which ACPI-WMI interface we're using.
@@ -1092,8 +1212,6 @@ static int __init acer_wmi_init(void)
1092 if (wmi_has_guid(AMW0_GUID1)) 1212 if (wmi_has_guid(AMW0_GUID1))
1093 AMW0_find_mailled(); 1213 AMW0_find_mailled();
1094 1214
1095 find_quirks();
1096
1097 if (!interface) { 1215 if (!interface) {
1098 printk(ACER_ERR "No or unsupported WMI interface, unable to " 1216 printk(ACER_ERR "No or unsupported WMI interface, unable to "
1099 "load\n"); 1217 "load\n");
@@ -1111,6 +1229,13 @@ static int __init acer_wmi_init(void)
1111 if (err) 1229 if (err)
1112 return err; 1230 return err;
1113 1231
1232 if (wmi_has_guid(WMID_GUID2)) {
1233 interface->debug.wmid_devices = get_wmid_devices();
1234 err = create_debugfs();
1235 if (err)
1236 return err;
1237 }
1238
1114 /* Override any initial settings with values from the commandline */ 1239 /* Override any initial settings with values from the commandline */
1115 acer_commandline_init(); 1240 acer_commandline_init();
1116 1241
diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c
index 0d5ce03cdff2..6aa5294dfec4 100644
--- a/drivers/misc/atmel_pwm.c
+++ b/drivers/misc/atmel_pwm.c
@@ -211,8 +211,7 @@ int pwm_clk_alloc(unsigned prescale, unsigned div)
211 if ((mr & 0xffff) == 0) { 211 if ((mr & 0xffff) == 0) {
212 mr |= val; 212 mr |= val;
213 ret = PWM_CPR_CLKA; 213 ret = PWM_CPR_CLKA;
214 } 214 } else if ((mr & (0xffff << 16)) == 0) {
215 if ((mr & (0xffff << 16)) == 0) {
216 mr |= val << 16; 215 mr |= val << 16;
217 ret = PWM_CPR_CLKB; 216 ret = PWM_CPR_CLKB;
218 } 217 }
@@ -332,7 +331,7 @@ static int __init pwm_probe(struct platform_device *pdev)
332 p->base = ioremap(r->start, r->end - r->start + 1); 331 p->base = ioremap(r->start, r->end - r->start + 1);
333 if (!p->base) 332 if (!p->base)
334 goto fail; 333 goto fail;
335 p->clk = clk_get(&pdev->dev, "mck"); 334 p->clk = clk_get(&pdev->dev, "pwm_clk");
336 if (IS_ERR(p->clk)) { 335 if (IS_ERR(p->clk)) {
337 status = PTR_ERR(p->clk); 336 status = PTR_ERR(p->clk);
338 p->clk = NULL; 337 p->clk = NULL;
diff --git a/drivers/misc/compal-laptop.c b/drivers/misc/compal-laptop.c
new file mode 100644
index 000000000000..344b790a6253
--- /dev/null
+++ b/drivers/misc/compal-laptop.c
@@ -0,0 +1,404 @@
1/*-*-linux-c-*-*/
2
3/*
4 Copyright (C) 2008 Cezary Jackiewicz <cezary.jackiewicz (at) gmail.com>
5
6 based on MSI driver
7
8 Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 02110-1301, USA.
24 */
25
26/*
27 * comapl-laptop.c - Compal laptop support.
28 *
29 * This driver exports a few files in /sys/devices/platform/compal-laptop/:
30 *
31 * wlan - wlan subsystem state: contains 0 or 1 (rw)
32 *
33 * bluetooth - Bluetooth subsystem state: contains 0 or 1 (rw)
34 *
35 * raw - raw value taken from embedded controller register (ro)
36 *
37 * In addition to these platform device attributes the driver
38 * registers itself in the Linux backlight control subsystem and is
39 * available to userspace under /sys/class/backlight/compal-laptop/.
40 *
41 * This driver might work on other laptops produced by Compal. If you
42 * want to try it you can pass force=1 as argument to the module which
43 * will force it to load even when the DMI data doesn't identify the
44 * laptop as FL9x.
45 */
46
47#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/acpi.h>
51#include <linux/dmi.h>
52#include <linux/backlight.h>
53#include <linux/platform_device.h>
54#include <linux/autoconf.h>
55
56#define COMPAL_DRIVER_VERSION "0.2.6"
57
58#define COMPAL_LCD_LEVEL_MAX 8
59
60#define COMPAL_EC_COMMAND_WIRELESS 0xBB
61#define COMPAL_EC_COMMAND_LCD_LEVEL 0xB9
62
63#define KILLSWITCH_MASK 0x10
64#define WLAN_MASK 0x01
65#define BT_MASK 0x02
66
67static int force;
68module_param(force, bool, 0);
69MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
70
71/* Hardware access */
72
73static int set_lcd_level(int level)
74{
75 if (level < 0 || level >= COMPAL_LCD_LEVEL_MAX)
76 return -EINVAL;
77
78 ec_write(COMPAL_EC_COMMAND_LCD_LEVEL, level);
79
80 return 0;
81}
82
83static int get_lcd_level(void)
84{
85 u8 result;
86
87 ec_read(COMPAL_EC_COMMAND_LCD_LEVEL, &result);
88
89 return (int) result;
90}
91
92static int set_wlan_state(int state)
93{
94 u8 result, value;
95
96 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
97
98 if ((result & KILLSWITCH_MASK) == 0)
99 return -EINVAL;
100 else {
101 if (state)
102 value = (u8) (result | WLAN_MASK);
103 else
104 value = (u8) (result & ~WLAN_MASK);
105 ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
106 }
107
108 return 0;
109}
110
111static int set_bluetooth_state(int state)
112{
113 u8 result, value;
114
115 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
116
117 if ((result & KILLSWITCH_MASK) == 0)
118 return -EINVAL;
119 else {
120 if (state)
121 value = (u8) (result | BT_MASK);
122 else
123 value = (u8) (result & ~BT_MASK);
124 ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
125 }
126
127 return 0;
128}
129
130static int get_wireless_state(int *wlan, int *bluetooth)
131{
132 u8 result;
133
134 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
135
136 if (wlan) {
137 if ((result & KILLSWITCH_MASK) == 0)
138 *wlan = 0;
139 else
140 *wlan = result & WLAN_MASK;
141 }
142
143 if (bluetooth) {
144 if ((result & KILLSWITCH_MASK) == 0)
145 *bluetooth = 0;
146 else
147 *bluetooth = (result & BT_MASK) >> 1;
148 }
149
150 return 0;
151}
152
153/* Backlight device stuff */
154
155static int bl_get_brightness(struct backlight_device *b)
156{
157 return get_lcd_level();
158}
159
160
161static int bl_update_status(struct backlight_device *b)
162{
163 return set_lcd_level(b->props.brightness);
164}
165
166static struct backlight_ops compalbl_ops = {
167 .get_brightness = bl_get_brightness,
168 .update_status = bl_update_status,
169};
170
171static struct backlight_device *compalbl_device;
172
173/* Platform device */
174
175static ssize_t show_wlan(struct device *dev,
176 struct device_attribute *attr, char *buf)
177{
178 int ret, enabled;
179
180 ret = get_wireless_state(&enabled, NULL);
181 if (ret < 0)
182 return ret;
183
184 return sprintf(buf, "%i\n", enabled);
185}
186
187static ssize_t show_raw(struct device *dev,
188 struct device_attribute *attr, char *buf)
189{
190 u8 result;
191
192 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
193
194 return sprintf(buf, "%i\n", result);
195}
196
197static ssize_t show_bluetooth(struct device *dev,
198 struct device_attribute *attr, char *buf)
199{
200 int ret, enabled;
201
202 ret = get_wireless_state(NULL, &enabled);
203 if (ret < 0)
204 return ret;
205
206 return sprintf(buf, "%i\n", enabled);
207}
208
209static ssize_t store_wlan_state(struct device *dev,
210 struct device_attribute *attr, const char *buf, size_t count)
211{
212 int state, ret;
213
214 if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
215 return -EINVAL;
216
217 ret = set_wlan_state(state);
218 if (ret < 0)
219 return ret;
220
221 return count;
222}
223
224static ssize_t store_bluetooth_state(struct device *dev,
225 struct device_attribute *attr, const char *buf, size_t count)
226{
227 int state, ret;
228
229 if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
230 return -EINVAL;
231
232 ret = set_bluetooth_state(state);
233 if (ret < 0)
234 return ret;
235
236 return count;
237}
238
239static DEVICE_ATTR(bluetooth, 0644, show_bluetooth, store_bluetooth_state);
240static DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan_state);
241static DEVICE_ATTR(raw, 0444, show_raw, NULL);
242
243static struct attribute *compal_attributes[] = {
244 &dev_attr_bluetooth.attr,
245 &dev_attr_wlan.attr,
246 &dev_attr_raw.attr,
247 NULL
248};
249
250static struct attribute_group compal_attribute_group = {
251 .attrs = compal_attributes
252};
253
254static struct platform_driver compal_driver = {
255 .driver = {
256 .name = "compal-laptop",
257 .owner = THIS_MODULE,
258 }
259};
260
261static struct platform_device *compal_device;
262
263/* Initialization */
264
265static int dmi_check_cb(const struct dmi_system_id *id)
266{
267 printk(KERN_INFO "compal-laptop: Identified laptop model '%s'.\n",
268 id->ident);
269
270 return 0;
271}
272
273static struct dmi_system_id __initdata compal_dmi_table[] = {
274 {
275 .ident = "FL90/IFL90",
276 .matches = {
277 DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
278 DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
279 },
280 .callback = dmi_check_cb
281 },
282 {
283 .ident = "FL90/IFL90",
284 .matches = {
285 DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
286 DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
287 },
288 .callback = dmi_check_cb
289 },
290 {
291 .ident = "FL91/IFL91",
292 .matches = {
293 DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
294 DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
295 },
296 .callback = dmi_check_cb
297 },
298 {
299 .ident = "FL92/JFL92",
300 .matches = {
301 DMI_MATCH(DMI_BOARD_NAME, "JFL92"),
302 DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
303 },
304 .callback = dmi_check_cb
305 },
306 {
307 .ident = "FT00/IFT00",
308 .matches = {
309 DMI_MATCH(DMI_BOARD_NAME, "IFT00"),
310 DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
311 },
312 .callback = dmi_check_cb
313 },
314 { }
315};
316
317static int __init compal_init(void)
318{
319 int ret;
320
321 if (acpi_disabled)
322 return -ENODEV;
323
324 if (!force && !dmi_check_system(compal_dmi_table))
325 return -ENODEV;
326
327 /* Register backlight stuff */
328
329 compalbl_device = backlight_device_register("compal-laptop", NULL, NULL,
330 &compalbl_ops);
331 if (IS_ERR(compalbl_device))
332 return PTR_ERR(compalbl_device);
333
334 compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1;
335
336 ret = platform_driver_register(&compal_driver);
337 if (ret)
338 goto fail_backlight;
339
340 /* Register platform stuff */
341
342 compal_device = platform_device_alloc("compal-laptop", -1);
343 if (!compal_device) {
344 ret = -ENOMEM;
345 goto fail_platform_driver;
346 }
347
348 ret = platform_device_add(compal_device);
349 if (ret)
350 goto fail_platform_device1;
351
352 ret = sysfs_create_group(&compal_device->dev.kobj,
353 &compal_attribute_group);
354 if (ret)
355 goto fail_platform_device2;
356
357 printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION
358 " successfully loaded.\n");
359
360 return 0;
361
362fail_platform_device2:
363
364 platform_device_del(compal_device);
365
366fail_platform_device1:
367
368 platform_device_put(compal_device);
369
370fail_platform_driver:
371
372 platform_driver_unregister(&compal_driver);
373
374fail_backlight:
375
376 backlight_device_unregister(compalbl_device);
377
378 return ret;
379}
380
381static void __exit compal_cleanup(void)
382{
383
384 sysfs_remove_group(&compal_device->dev.kobj, &compal_attribute_group);
385 platform_device_unregister(compal_device);
386 platform_driver_unregister(&compal_driver);
387 backlight_device_unregister(compalbl_device);
388
389 printk(KERN_INFO "compal-laptop: driver unloaded.\n");
390}
391
392module_init(compal_init);
393module_exit(compal_cleanup);
394
395MODULE_AUTHOR("Cezary Jackiewicz");
396MODULE_DESCRIPTION("Compal Laptop Support");
397MODULE_VERSION(COMPAL_DRIVER_VERSION);
398MODULE_LICENSE("GPL");
399
400MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*");
401MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
402MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
403MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
404MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
index 6d727609097f..9e8d79e7e9f4 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/misc/eeepc-laptop.c
@@ -87,7 +87,7 @@ enum {
87 CM_ASL_LID 87 CM_ASL_LID
88}; 88};
89 89
90const char *cm_getv[] = { 90static const char *cm_getv[] = {
91 "WLDG", NULL, NULL, NULL, 91 "WLDG", NULL, NULL, NULL,
92 "CAMG", NULL, NULL, NULL, 92 "CAMG", NULL, NULL, NULL,
93 NULL, "PBLG", NULL, NULL, 93 NULL, "PBLG", NULL, NULL,
@@ -96,7 +96,7 @@ const char *cm_getv[] = {
96 "CRDG", "LIDG" 96 "CRDG", "LIDG"
97}; 97};
98 98
99const char *cm_setv[] = { 99static const char *cm_setv[] = {
100 "WLDS", NULL, NULL, NULL, 100 "WLDS", NULL, NULL, NULL,
101 "CAMS", NULL, NULL, NULL, 101 "CAMS", NULL, NULL, NULL,
102 "SDSP", "PBLS", "HDPS", NULL, 102 "SDSP", "PBLS", "HDPS", NULL,
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c
index e2e7c05a147b..7a1ef6c262de 100644
--- a/drivers/misc/fujitsu-laptop.c
+++ b/drivers/misc/fujitsu-laptop.c
@@ -1,12 +1,14 @@
1/*-*-linux-c-*-*/ 1/*-*-linux-c-*-*/
2 2
3/* 3/*
4 Copyright (C) 2007 Jonathan Woithe <jwoithe@physics.adelaide.edu.au> 4 Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
5 Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
5 Based on earlier work: 6 Based on earlier work:
6 Copyright (C) 2003 Shane Spencer <shane@bogomip.com> 7 Copyright (C) 2003 Shane Spencer <shane@bogomip.com>
7 Adrian Yee <brewt-fujitsu@brewt.org> 8 Adrian Yee <brewt-fujitsu@brewt.org>
8 9
9 Templated from msi-laptop.c which is copyright by its respective authors. 10 Templated from msi-laptop.c and thinkpad_acpi.c which is copyright
11 by its respective authors.
10 12
11 This program is free software; you can redistribute it and/or modify 13 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by 14 it under the terms of the GNU General Public License as published by
@@ -39,8 +41,17 @@
39 * registers itself in the Linux backlight control subsystem and is 41 * registers itself in the Linux backlight control subsystem and is
40 * available to userspace under /sys/class/backlight/fujitsu-laptop/. 42 * available to userspace under /sys/class/backlight/fujitsu-laptop/.
41 * 43 *
42 * This driver has been tested on a Fujitsu Lifebook S7020. It should 44 * Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are
43 * work on most P-series and S-series Lifebooks, but YMMV. 45 * also supported by this driver.
46 *
47 * This driver has been tested on a Fujitsu Lifebook S6410 and S7020. It
48 * should work on most P-series and S-series Lifebooks, but YMMV.
49 *
50 * The module parameter use_alt_lcd_levels switches between different ACPI
51 * brightness controls which are used by different Fujitsu laptops. In most
52 * cases the correct method is automatically detected. "use_alt_lcd_levels=1"
53 * is applicable for a Fujitsu Lifebook S6410 if autodetection fails.
54 *
44 */ 55 */
45 56
46#include <linux/module.h> 57#include <linux/module.h>
@@ -49,30 +60,105 @@
49#include <linux/acpi.h> 60#include <linux/acpi.h>
50#include <linux/dmi.h> 61#include <linux/dmi.h>
51#include <linux/backlight.h> 62#include <linux/backlight.h>
63#include <linux/input.h>
64#include <linux/kfifo.h>
65#include <linux/video_output.h>
52#include <linux/platform_device.h> 66#include <linux/platform_device.h>
53 67
54#define FUJITSU_DRIVER_VERSION "0.3" 68#define FUJITSU_DRIVER_VERSION "0.4.2"
55 69
56#define FUJITSU_LCD_N_LEVELS 8 70#define FUJITSU_LCD_N_LEVELS 8
57 71
58#define ACPI_FUJITSU_CLASS "fujitsu" 72#define ACPI_FUJITSU_CLASS "fujitsu"
59#define ACPI_FUJITSU_HID "FUJ02B1" 73#define ACPI_FUJITSU_HID "FUJ02B1"
60#define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI extras driver" 74#define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver"
61#define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1" 75#define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1"
62 76#define ACPI_FUJITSU_HOTKEY_HID "FUJ02E3"
77#define ACPI_FUJITSU_HOTKEY_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver"
78#define ACPI_FUJITSU_HOTKEY_DEVICE_NAME "Fujitsu FUJ02E3"
79
80#define ACPI_FUJITSU_NOTIFY_CODE1 0x80
81
82#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86
83#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
84
85/* Hotkey details */
86#define LOCK_KEY 0x410 /* codes for the keys in the GIRB register */
87#define DISPLAY_KEY 0x411 /* keys are mapped to KEY_SCREENLOCK (the key with the key symbol) */
88#define ENERGY_KEY 0x412 /* KEY_MEDIA (the key with the laptop symbol, KEY_EMAIL (E key)) */
89#define REST_KEY 0x413 /* KEY_SUSPEND (R key) */
90
91#define MAX_HOTKEY_RINGBUFFER_SIZE 100
92#define RINGBUFFERSIZE 40
93
94/* Debugging */
95#define FUJLAPTOP_LOG ACPI_FUJITSU_HID ": "
96#define FUJLAPTOP_ERR KERN_ERR FUJLAPTOP_LOG
97#define FUJLAPTOP_NOTICE KERN_NOTICE FUJLAPTOP_LOG
98#define FUJLAPTOP_INFO KERN_INFO FUJLAPTOP_LOG
99#define FUJLAPTOP_DEBUG KERN_DEBUG FUJLAPTOP_LOG
100
101#define FUJLAPTOP_DBG_ALL 0xffff
102#define FUJLAPTOP_DBG_ERROR 0x0001
103#define FUJLAPTOP_DBG_WARN 0x0002
104#define FUJLAPTOP_DBG_INFO 0x0004
105#define FUJLAPTOP_DBG_TRACE 0x0008
106
107#define dbg_printk(a_dbg_level, format, arg...) \
108 do { if (dbg_level & a_dbg_level) \
109 printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \
110 } while (0)
111#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
112#define vdbg_printk(a_dbg_level, format, arg...) \
113 dbg_printk(a_dbg_level, format, ## arg)
114#else
115#define vdbg_printk(a_dbg_level, format, arg...)
116#endif
117
118/* Device controlling the backlight and associated keys */
63struct fujitsu_t { 119struct fujitsu_t {
64 acpi_handle acpi_handle; 120 acpi_handle acpi_handle;
121 struct acpi_device *dev;
122 struct input_dev *input;
123 char phys[32];
65 struct backlight_device *bl_device; 124 struct backlight_device *bl_device;
66 struct platform_device *pf_device; 125 struct platform_device *pf_device;
67 126
68 unsigned long fuj02b1_state; 127 unsigned int max_brightness;
69 unsigned int brightness_changed; 128 unsigned int brightness_changed;
70 unsigned int brightness_level; 129 unsigned int brightness_level;
71}; 130};
72 131
73static struct fujitsu_t *fujitsu; 132static struct fujitsu_t *fujitsu;
133static int use_alt_lcd_levels = -1;
134static int disable_brightness_keys = -1;
135static int disable_brightness_adjust = -1;
136
137/* Device used to access other hotkeys on the laptop */
138struct fujitsu_hotkey_t {
139 acpi_handle acpi_handle;
140 struct acpi_device *dev;
141 struct input_dev *input;
142 char phys[32];
143 struct platform_device *pf_device;
144 struct kfifo *fifo;
145 spinlock_t fifo_lock;
146
147 unsigned int irb; /* info about the pressed buttons */
148};
74 149
75/* Hardware access */ 150static struct fujitsu_hotkey_t *fujitsu_hotkey;
151
152static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
153 void *data);
154
155#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
156static u32 dbg_level = 0x03;
157#endif
158
159static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data);
160
161/* Hardware access for LCD brightness control */
76 162
77static int set_lcd_level(int level) 163static int set_lcd_level(int level)
78{ 164{
@@ -81,7 +167,10 @@ static int set_lcd_level(int level)
81 struct acpi_object_list arg_list = { 1, &arg0 }; 167 struct acpi_object_list arg_list = { 1, &arg0 };
82 acpi_handle handle = NULL; 168 acpi_handle handle = NULL;
83 169
84 if (level < 0 || level >= FUJITSU_LCD_N_LEVELS) 170 vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n",
171 level);
172
173 if (level < 0 || level >= fujitsu->max_brightness)
85 return -EINVAL; 174 return -EINVAL;
86 175
87 if (!fujitsu) 176 if (!fujitsu)
@@ -89,7 +178,38 @@ static int set_lcd_level(int level)
89 178
90 status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle); 179 status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle);
91 if (ACPI_FAILURE(status)) { 180 if (ACPI_FAILURE(status)) {
92 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SBLL not present\n")); 181 vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n");
182 return -ENODEV;
183 }
184
185 arg0.integer.value = level;
186
187 status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
188 if (ACPI_FAILURE(status))
189 return -ENODEV;
190
191 return 0;
192}
193
194static int set_lcd_level_alt(int level)
195{
196 acpi_status status = AE_OK;
197 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
198 struct acpi_object_list arg_list = { 1, &arg0 };
199 acpi_handle handle = NULL;
200
201 vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n",
202 level);
203
204 if (level < 0 || level >= fujitsu->max_brightness)
205 return -EINVAL;
206
207 if (!fujitsu)
208 return -EINVAL;
209
210 status = acpi_get_handle(fujitsu->acpi_handle, "SBL2", &handle);
211 if (ACPI_FAILURE(status)) {
212 vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n");
93 return -ENODEV; 213 return -ENODEV;
94 } 214 }
95 215
@@ -107,13 +227,52 @@ static int get_lcd_level(void)
107 unsigned long state = 0; 227 unsigned long state = 0;
108 acpi_status status = AE_OK; 228 acpi_status status = AE_OK;
109 229
110 // Get the Brightness 230 vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n");
231
111 status = 232 status =
112 acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state); 233 acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state);
113 if (status < 0) 234 if (status < 0)
114 return status; 235 return status;
115 236
116 fujitsu->fuj02b1_state = state; 237 fujitsu->brightness_level = state & 0x0fffffff;
238
239 if (state & 0x80000000)
240 fujitsu->brightness_changed = 1;
241 else
242 fujitsu->brightness_changed = 0;
243
244 return fujitsu->brightness_level;
245}
246
247static int get_max_brightness(void)
248{
249 unsigned long state = 0;
250 acpi_status status = AE_OK;
251
252 vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n");
253
254 status =
255 acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state);
256 if (status < 0)
257 return status;
258
259 fujitsu->max_brightness = state;
260
261 return fujitsu->max_brightness;
262}
263
264static int get_lcd_level_alt(void)
265{
266 unsigned long state = 0;
267 acpi_status status = AE_OK;
268
269 vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLS\n");
270
271 status =
272 acpi_evaluate_integer(fujitsu->acpi_handle, "GBLS", NULL, &state);
273 if (status < 0)
274 return status;
275
117 fujitsu->brightness_level = state & 0x0fffffff; 276 fujitsu->brightness_level = state & 0x0fffffff;
118 277
119 if (state & 0x80000000) 278 if (state & 0x80000000)
@@ -128,12 +287,18 @@ static int get_lcd_level(void)
128 287
129static int bl_get_brightness(struct backlight_device *b) 288static int bl_get_brightness(struct backlight_device *b)
130{ 289{
131 return get_lcd_level(); 290 if (use_alt_lcd_levels)
291 return get_lcd_level_alt();
292 else
293 return get_lcd_level();
132} 294}
133 295
134static int bl_update_status(struct backlight_device *b) 296static int bl_update_status(struct backlight_device *b)
135{ 297{
136 return set_lcd_level(b->props.brightness); 298 if (use_alt_lcd_levels)
299 return set_lcd_level_alt(b->props.brightness);
300 else
301 return set_lcd_level(b->props.brightness);
137} 302}
138 303
139static struct backlight_ops fujitsubl_ops = { 304static struct backlight_ops fujitsubl_ops = {
@@ -141,7 +306,35 @@ static struct backlight_ops fujitsubl_ops = {
141 .update_status = bl_update_status, 306 .update_status = bl_update_status,
142}; 307};
143 308
144/* Platform device */ 309/* Platform LCD brightness device */
310
311static ssize_t
312show_max_brightness(struct device *dev,
313 struct device_attribute *attr, char *buf)
314{
315
316 int ret;
317
318 ret = get_max_brightness();
319 if (ret < 0)
320 return ret;
321
322 return sprintf(buf, "%i\n", ret);
323}
324
325static ssize_t
326show_brightness_changed(struct device *dev,
327 struct device_attribute *attr, char *buf)
328{
329
330 int ret;
331
332 ret = fujitsu->brightness_changed;
333 if (ret < 0)
334 return ret;
335
336 return sprintf(buf, "%i\n", ret);
337}
145 338
146static ssize_t show_lcd_level(struct device *dev, 339static ssize_t show_lcd_level(struct device *dev,
147 struct device_attribute *attr, char *buf) 340 struct device_attribute *attr, char *buf)
@@ -149,7 +342,10 @@ static ssize_t show_lcd_level(struct device *dev,
149 342
150 int ret; 343 int ret;
151 344
152 ret = get_lcd_level(); 345 if (use_alt_lcd_levels)
346 ret = get_lcd_level_alt();
347 else
348 ret = get_lcd_level();
153 if (ret < 0) 349 if (ret < 0)
154 return ret; 350 return ret;
155 351
@@ -164,19 +360,61 @@ static ssize_t store_lcd_level(struct device *dev,
164 int level, ret; 360 int level, ret;
165 361
166 if (sscanf(buf, "%i", &level) != 1 362 if (sscanf(buf, "%i", &level) != 1
167 || (level < 0 || level >= FUJITSU_LCD_N_LEVELS)) 363 || (level < 0 || level >= fujitsu->max_brightness))
168 return -EINVAL; 364 return -EINVAL;
169 365
170 ret = set_lcd_level(level); 366 if (use_alt_lcd_levels)
367 ret = set_lcd_level_alt(level);
368 else
369 ret = set_lcd_level(level);
370 if (ret < 0)
371 return ret;
372
373 if (use_alt_lcd_levels)
374 ret = get_lcd_level_alt();
375 else
376 ret = get_lcd_level();
171 if (ret < 0) 377 if (ret < 0)
172 return ret; 378 return ret;
173 379
174 return count; 380 return count;
175} 381}
176 382
383/* Hardware access for hotkey device */
384
385static int get_irb(void)
386{
387 unsigned long state = 0;
388 acpi_status status = AE_OK;
389
390 vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n");
391
392 status =
393 acpi_evaluate_integer(fujitsu_hotkey->acpi_handle, "GIRB", NULL,
394 &state);
395 if (status < 0)
396 return status;
397
398 fujitsu_hotkey->irb = state;
399
400 return fujitsu_hotkey->irb;
401}
402
403static ssize_t
404ignore_store(struct device *dev,
405 struct device_attribute *attr, const char *buf, size_t count)
406{
407 return count;
408}
409
410static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store);
411static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed,
412 ignore_store);
177static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); 413static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
178 414
179static struct attribute *fujitsupf_attributes[] = { 415static struct attribute *fujitsupf_attributes[] = {
416 &dev_attr_brightness_changed.attr,
417 &dev_attr_max_brightness.attr,
180 &dev_attr_lcd_level.attr, 418 &dev_attr_lcd_level.attr,
181 NULL 419 NULL
182}; 420};
@@ -192,14 +430,52 @@ static struct platform_driver fujitsupf_driver = {
192 } 430 }
193}; 431};
194 432
195/* ACPI device */ 433static int dmi_check_cb_s6410(const struct dmi_system_id *id)
434{
435 acpi_handle handle;
436 int have_blnf;
437 printk(KERN_INFO "fujitsu-laptop: Identified laptop model '%s'.\n",
438 id->ident);
439 have_blnf = ACPI_SUCCESS
440 (acpi_get_handle(NULL, "\\_SB.PCI0.GFX0.LCD.BLNF", &handle));
441 if (use_alt_lcd_levels == -1) {
442 vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detecting usealt\n");
443 use_alt_lcd_levels = 1;
444 }
445 if (disable_brightness_keys == -1) {
446 vdbg_printk(FUJLAPTOP_DBG_TRACE,
447 "auto-detecting disable_keys\n");
448 disable_brightness_keys = have_blnf ? 1 : 0;
449 }
450 if (disable_brightness_adjust == -1) {
451 vdbg_printk(FUJLAPTOP_DBG_TRACE,
452 "auto-detecting disable_adjust\n");
453 disable_brightness_adjust = have_blnf ? 0 : 1;
454 }
455 return 0;
456}
457
458static struct dmi_system_id __initdata fujitsu_dmi_table[] = {
459 {
460 .ident = "Fujitsu Siemens",
461 .matches = {
462 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
463 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
464 },
465 .callback = dmi_check_cb_s6410},
466 {}
467};
468
469/* ACPI device for LCD brightness control */
196 470
197static int acpi_fujitsu_add(struct acpi_device *device) 471static int acpi_fujitsu_add(struct acpi_device *device)
198{ 472{
473 acpi_status status;
474 acpi_handle handle;
199 int result = 0; 475 int result = 0;
200 int state = 0; 476 int state = 0;
201 477 struct input_dev *input;
202 ACPI_FUNCTION_TRACE("acpi_fujitsu_add"); 478 int error;
203 479
204 if (!device) 480 if (!device)
205 return -EINVAL; 481 return -EINVAL;
@@ -209,10 +485,42 @@ static int acpi_fujitsu_add(struct acpi_device *device)
209 sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); 485 sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
210 acpi_driver_data(device) = fujitsu; 486 acpi_driver_data(device) = fujitsu;
211 487
488 status = acpi_install_notify_handler(device->handle,
489 ACPI_DEVICE_NOTIFY,
490 acpi_fujitsu_notify, fujitsu);
491
492 if (ACPI_FAILURE(status)) {
493 printk(KERN_ERR "Error installing notify handler\n");
494 error = -ENODEV;
495 goto err_stop;
496 }
497
498 fujitsu->input = input = input_allocate_device();
499 if (!input) {
500 error = -ENOMEM;
501 goto err_uninstall_notify;
502 }
503
504 snprintf(fujitsu->phys, sizeof(fujitsu->phys),
505 "%s/video/input0", acpi_device_hid(device));
506
507 input->name = acpi_device_name(device);
508 input->phys = fujitsu->phys;
509 input->id.bustype = BUS_HOST;
510 input->id.product = 0x06;
511 input->dev.parent = &device->dev;
512 input->evbit[0] = BIT(EV_KEY);
513 set_bit(KEY_BRIGHTNESSUP, input->keybit);
514 set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
515 set_bit(KEY_UNKNOWN, input->keybit);
516
517 error = input_register_device(input);
518 if (error)
519 goto err_free_input_dev;
520
212 result = acpi_bus_get_power(fujitsu->acpi_handle, &state); 521 result = acpi_bus_get_power(fujitsu->acpi_handle, &state);
213 if (result) { 522 if (result) {
214 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 523 printk(KERN_ERR "Error reading power state\n");
215 "Error reading power state\n"));
216 goto end; 524 goto end;
217 } 525 }
218 526
@@ -220,22 +528,373 @@ static int acpi_fujitsu_add(struct acpi_device *device)
220 acpi_device_name(device), acpi_device_bid(device), 528 acpi_device_name(device), acpi_device_bid(device),
221 !device->power.state ? "on" : "off"); 529 !device->power.state ? "on" : "off");
222 530
223 end: 531 fujitsu->dev = device;
532
533 if (ACPI_SUCCESS
534 (acpi_get_handle(device->handle, METHOD_NAME__INI, &handle))) {
535 vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
536 if (ACPI_FAILURE
537 (acpi_evaluate_object
538 (device->handle, METHOD_NAME__INI, NULL, NULL)))
539 printk(KERN_ERR "_INI Method failed\n");
540 }
541
542 /* do config (detect defaults) */
543 dmi_check_system(fujitsu_dmi_table);
544 use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
545 disable_brightness_keys = disable_brightness_keys == 1 ? 1 : 0;
546 disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
547 vdbg_printk(FUJLAPTOP_DBG_INFO,
548 "config: [alt interface: %d], [key disable: %d], [adjust disable: %d]\n",
549 use_alt_lcd_levels, disable_brightness_keys,
550 disable_brightness_adjust);
551
552 if (get_max_brightness() <= 0)
553 fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS;
554 if (use_alt_lcd_levels)
555 get_lcd_level_alt();
556 else
557 get_lcd_level();
558
559 return result;
560
561end:
562err_free_input_dev:
563 input_free_device(input);
564err_uninstall_notify:
565 acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
566 acpi_fujitsu_notify);
567err_stop:
224 568
225 return result; 569 return result;
226} 570}
227 571
228static int acpi_fujitsu_remove(struct acpi_device *device, int type) 572static int acpi_fujitsu_remove(struct acpi_device *device, int type)
229{ 573{
230 ACPI_FUNCTION_TRACE("acpi_fujitsu_remove"); 574 acpi_status status;
575 struct fujitsu_t *fujitsu = NULL;
231 576
232 if (!device || !acpi_driver_data(device)) 577 if (!device || !acpi_driver_data(device))
233 return -EINVAL; 578 return -EINVAL;
579
580 fujitsu = acpi_driver_data(device);
581
582 status = acpi_remove_notify_handler(fujitsu->acpi_handle,
583 ACPI_DEVICE_NOTIFY,
584 acpi_fujitsu_notify);
585
586 if (!device || !acpi_driver_data(device))
587 return -EINVAL;
588
234 fujitsu->acpi_handle = NULL; 589 fujitsu->acpi_handle = NULL;
235 590
236 return 0; 591 return 0;
237} 592}
238 593
594/* Brightness notify */
595
596static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
597{
598 struct input_dev *input;
599 int keycode;
600 int oldb, newb;
601
602 input = fujitsu->input;
603
604 switch (event) {
605 case ACPI_FUJITSU_NOTIFY_CODE1:
606 keycode = 0;
607 oldb = fujitsu->brightness_level;
608 get_lcd_level(); /* the alt version always yields changed */
609 newb = fujitsu->brightness_level;
610
611 vdbg_printk(FUJLAPTOP_DBG_TRACE,
612 "brightness button event [%i -> %i (%i)]\n",
613 oldb, newb, fujitsu->brightness_changed);
614
615 if (oldb == newb && fujitsu->brightness_changed) {
616 keycode = 0;
617 if (disable_brightness_keys != 1) {
618 if (oldb == 0) {
619 acpi_bus_generate_proc_event(fujitsu->
620 dev,
621 ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
622 0);
623 keycode = KEY_BRIGHTNESSDOWN;
624 } else if (oldb ==
625 (fujitsu->max_brightness) - 1) {
626 acpi_bus_generate_proc_event(fujitsu->
627 dev,
628 ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
629 0);
630 keycode = KEY_BRIGHTNESSUP;
631 }
632 }
633 } else if (oldb < newb) {
634 if (disable_brightness_adjust != 1) {
635 if (use_alt_lcd_levels)
636 set_lcd_level_alt(newb);
637 else
638 set_lcd_level(newb);
639 }
640 if (disable_brightness_keys != 1) {
641 acpi_bus_generate_proc_event(fujitsu->dev,
642 ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
643 0);
644 keycode = KEY_BRIGHTNESSUP;
645 }
646 } else if (oldb > newb) {
647 if (disable_brightness_adjust != 1) {
648 if (use_alt_lcd_levels)
649 set_lcd_level_alt(newb);
650 else
651 set_lcd_level(newb);
652 }
653 if (disable_brightness_keys != 1) {
654 acpi_bus_generate_proc_event(fujitsu->dev,
655 ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
656 0);
657 keycode = KEY_BRIGHTNESSDOWN;
658 }
659 } else {
660 keycode = KEY_UNKNOWN;
661 }
662 break;
663 default:
664 keycode = KEY_UNKNOWN;
665 vdbg_printk(FUJLAPTOP_DBG_WARN,
666 "unsupported event [0x%x]\n", event);
667 break;
668 }
669
670 if (keycode != 0) {
671 input_report_key(input, keycode, 1);
672 input_sync(input);
673 input_report_key(input, keycode, 0);
674 input_sync(input);
675 }
676
677 return;
678}
679
680/* ACPI device for hotkey handling */
681
682static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
683{
684 acpi_status status;
685 acpi_handle handle;
686 int result = 0;
687 int state = 0;
688 struct input_dev *input;
689 int error;
690 int i;
691
692 if (!device)
693 return -EINVAL;
694
695 fujitsu_hotkey->acpi_handle = device->handle;
696 sprintf(acpi_device_name(device), "%s",
697 ACPI_FUJITSU_HOTKEY_DEVICE_NAME);
698 sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
699 acpi_driver_data(device) = fujitsu_hotkey;
700
701 status = acpi_install_notify_handler(device->handle,
702 ACPI_DEVICE_NOTIFY,
703 acpi_fujitsu_hotkey_notify,
704 fujitsu_hotkey);
705
706 if (ACPI_FAILURE(status)) {
707 printk(KERN_ERR "Error installing notify handler\n");
708 error = -ENODEV;
709 goto err_stop;
710 }
711
712 /* kfifo */
713 spin_lock_init(&fujitsu_hotkey->fifo_lock);
714 fujitsu_hotkey->fifo =
715 kfifo_alloc(RINGBUFFERSIZE * sizeof(int), GFP_KERNEL,
716 &fujitsu_hotkey->fifo_lock);
717 if (IS_ERR(fujitsu_hotkey->fifo)) {
718 printk(KERN_ERR "kfifo_alloc failed\n");
719 error = PTR_ERR(fujitsu_hotkey->fifo);
720 goto err_stop;
721 }
722
723 fujitsu_hotkey->input = input = input_allocate_device();
724 if (!input) {
725 error = -ENOMEM;
726 goto err_uninstall_notify;
727 }
728
729 snprintf(fujitsu_hotkey->phys, sizeof(fujitsu_hotkey->phys),
730 "%s/video/input0", acpi_device_hid(device));
731
732 input->name = acpi_device_name(device);
733 input->phys = fujitsu_hotkey->phys;
734 input->id.bustype = BUS_HOST;
735 input->id.product = 0x06;
736 input->dev.parent = &device->dev;
737 input->evbit[0] = BIT(EV_KEY);
738 set_bit(KEY_SCREENLOCK, input->keybit);
739 set_bit(KEY_MEDIA, input->keybit);
740 set_bit(KEY_EMAIL, input->keybit);
741 set_bit(KEY_SUSPEND, input->keybit);
742 set_bit(KEY_UNKNOWN, input->keybit);
743
744 error = input_register_device(input);
745 if (error)
746 goto err_free_input_dev;
747
748 result = acpi_bus_get_power(fujitsu_hotkey->acpi_handle, &state);
749 if (result) {
750 printk(KERN_ERR "Error reading power state\n");
751 goto end;
752 }
753
754 printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
755 acpi_device_name(device), acpi_device_bid(device),
756 !device->power.state ? "on" : "off");
757
758 fujitsu_hotkey->dev = device;
759
760 if (ACPI_SUCCESS
761 (acpi_get_handle(device->handle, METHOD_NAME__INI, &handle))) {
762 vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
763 if (ACPI_FAILURE
764 (acpi_evaluate_object
765 (device->handle, METHOD_NAME__INI, NULL, NULL)))
766 printk(KERN_ERR "_INI Method failed\n");
767 }
768
769 i = 0; /* Discard hotkey ringbuffer */
770 while (get_irb() != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ;
771 vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i);
772
773 return result;
774
775end:
776err_free_input_dev:
777 input_free_device(input);
778err_uninstall_notify:
779 acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
780 acpi_fujitsu_hotkey_notify);
781 kfifo_free(fujitsu_hotkey->fifo);
782err_stop:
783
784 return result;
785}
786
787static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type)
788{
789 acpi_status status;
790 struct fujitsu_hotkey_t *fujitsu_hotkey = NULL;
791
792 if (!device || !acpi_driver_data(device))
793 return -EINVAL;
794
795 fujitsu_hotkey = acpi_driver_data(device);
796
797 status = acpi_remove_notify_handler(fujitsu_hotkey->acpi_handle,
798 ACPI_DEVICE_NOTIFY,
799 acpi_fujitsu_hotkey_notify);
800
801 fujitsu_hotkey->acpi_handle = NULL;
802
803 kfifo_free(fujitsu_hotkey->fifo);
804
805 return 0;
806}
807
808static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
809 void *data)
810{
811 struct input_dev *input;
812 int keycode, keycode_r;
813 unsigned int irb = 1;
814 int i, status;
815
816 input = fujitsu_hotkey->input;
817
818 vdbg_printk(FUJLAPTOP_DBG_TRACE, "Hotkey event\n");
819
820 switch (event) {
821 case ACPI_FUJITSU_NOTIFY_CODE1:
822 i = 0;
823 while ((irb = get_irb()) != 0
824 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
825 vdbg_printk(FUJLAPTOP_DBG_TRACE, "GIRB result [%x]\n",
826 irb);
827
828 switch (irb & 0x4ff) {
829 case LOCK_KEY:
830 keycode = KEY_SCREENLOCK;
831 break;
832 case DISPLAY_KEY:
833 keycode = KEY_MEDIA;
834 break;
835 case ENERGY_KEY:
836 keycode = KEY_EMAIL;
837 break;
838 case REST_KEY:
839 keycode = KEY_SUSPEND;
840 break;
841 case 0:
842 keycode = 0;
843 break;
844 default:
845 vdbg_printk(FUJLAPTOP_DBG_WARN,
846 "Unknown GIRB result [%x]\n", irb);
847 keycode = -1;
848 break;
849 }
850 if (keycode > 0) {
851 vdbg_printk(FUJLAPTOP_DBG_TRACE,
852 "Push keycode into ringbuffer [%d]\n",
853 keycode);
854 status = kfifo_put(fujitsu_hotkey->fifo,
855 (unsigned char *)&keycode,
856 sizeof(keycode));
857 if (status != sizeof(keycode)) {
858 vdbg_printk(FUJLAPTOP_DBG_WARN,
859 "Could not push keycode [0x%x]\n",
860 keycode);
861 } else {
862 input_report_key(input, keycode, 1);
863 input_sync(input);
864 }
865 } else if (keycode == 0) {
866 while ((status =
867 kfifo_get
868 (fujitsu_hotkey->fifo, (unsigned char *)
869 &keycode_r,
870 sizeof
871 (keycode_r))) == sizeof(keycode_r)) {
872 input_report_key(input, keycode_r, 0);
873 input_sync(input);
874 vdbg_printk(FUJLAPTOP_DBG_TRACE,
875 "Pop keycode from ringbuffer [%d]\n",
876 keycode_r);
877 }
878 }
879 }
880
881 break;
882 default:
883 keycode = KEY_UNKNOWN;
884 vdbg_printk(FUJLAPTOP_DBG_WARN,
885 "Unsupported event [0x%x]\n", event);
886 input_report_key(input, keycode, 1);
887 input_sync(input);
888 input_report_key(input, keycode, 0);
889 input_sync(input);
890 break;
891 }
892
893 return;
894}
895
896/* Initialization */
897
239static const struct acpi_device_id fujitsu_device_ids[] = { 898static const struct acpi_device_id fujitsu_device_ids[] = {
240 {ACPI_FUJITSU_HID, 0}, 899 {ACPI_FUJITSU_HID, 0},
241 {"", 0}, 900 {"", 0},
@@ -251,11 +910,24 @@ static struct acpi_driver acpi_fujitsu_driver = {
251 }, 910 },
252}; 911};
253 912
254/* Initialization */ 913static const struct acpi_device_id fujitsu_hotkey_device_ids[] = {
914 {ACPI_FUJITSU_HOTKEY_HID, 0},
915 {"", 0},
916};
917
918static struct acpi_driver acpi_fujitsu_hotkey_driver = {
919 .name = ACPI_FUJITSU_HOTKEY_DRIVER_NAME,
920 .class = ACPI_FUJITSU_CLASS,
921 .ids = fujitsu_hotkey_device_ids,
922 .ops = {
923 .add = acpi_fujitsu_hotkey_add,
924 .remove = acpi_fujitsu_hotkey_remove,
925 },
926};
255 927
256static int __init fujitsu_init(void) 928static int __init fujitsu_init(void)
257{ 929{
258 int ret, result; 930 int ret, result, max_brightness;
259 931
260 if (acpi_disabled) 932 if (acpi_disabled)
261 return -ENODEV; 933 return -ENODEV;
@@ -271,19 +943,6 @@ static int __init fujitsu_init(void)
271 goto fail_acpi; 943 goto fail_acpi;
272 } 944 }
273 945
274 /* Register backlight stuff */
275
276 fujitsu->bl_device =
277 backlight_device_register("fujitsu-laptop", NULL, NULL,
278 &fujitsubl_ops);
279 if (IS_ERR(fujitsu->bl_device))
280 return PTR_ERR(fujitsu->bl_device);
281
282 fujitsu->bl_device->props.max_brightness = FUJITSU_LCD_N_LEVELS - 1;
283 ret = platform_driver_register(&fujitsupf_driver);
284 if (ret)
285 goto fail_backlight;
286
287 /* Register platform stuff */ 946 /* Register platform stuff */
288 947
289 fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1); 948 fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1);
@@ -302,28 +961,68 @@ static int __init fujitsu_init(void)
302 if (ret) 961 if (ret)
303 goto fail_platform_device2; 962 goto fail_platform_device2;
304 963
964 /* Register backlight stuff */
965
966 fujitsu->bl_device =
967 backlight_device_register("fujitsu-laptop", NULL, NULL,
968 &fujitsubl_ops);
969 if (IS_ERR(fujitsu->bl_device))
970 return PTR_ERR(fujitsu->bl_device);
971
972 max_brightness = fujitsu->max_brightness;
973
974 fujitsu->bl_device->props.max_brightness = max_brightness - 1;
975 fujitsu->bl_device->props.brightness = fujitsu->brightness_level;
976
977 ret = platform_driver_register(&fujitsupf_driver);
978 if (ret)
979 goto fail_backlight;
980
981 /* Register hotkey driver */
982
983 fujitsu_hotkey = kmalloc(sizeof(struct fujitsu_hotkey_t), GFP_KERNEL);
984 if (!fujitsu_hotkey) {
985 ret = -ENOMEM;
986 goto fail_hotkey;
987 }
988 memset(fujitsu_hotkey, 0, sizeof(struct fujitsu_hotkey_t));
989
990 result = acpi_bus_register_driver(&acpi_fujitsu_hotkey_driver);
991 if (result < 0) {
992 ret = -ENODEV;
993 goto fail_hotkey1;
994 }
995
305 printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION 996 printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION
306 " successfully loaded.\n"); 997 " successfully loaded.\n");
307 998
308 return 0; 999 return 0;
309 1000
310 fail_platform_device2: 1001fail_hotkey1:
311 1002
312 platform_device_del(fujitsu->pf_device); 1003 kfree(fujitsu_hotkey);
313 1004
314 fail_platform_device1: 1005fail_hotkey:
315
316 platform_device_put(fujitsu->pf_device);
317
318 fail_platform_driver:
319 1006
320 platform_driver_unregister(&fujitsupf_driver); 1007 platform_driver_unregister(&fujitsupf_driver);
321 1008
322 fail_backlight: 1009fail_backlight:
323 1010
324 backlight_device_unregister(fujitsu->bl_device); 1011 backlight_device_unregister(fujitsu->bl_device);
325 1012
326 fail_acpi: 1013fail_platform_device2:
1014
1015 platform_device_del(fujitsu->pf_device);
1016
1017fail_platform_device1:
1018
1019 platform_device_put(fujitsu->pf_device);
1020
1021fail_platform_driver:
1022
1023 acpi_bus_unregister_driver(&acpi_fujitsu_driver);
1024
1025fail_acpi:
327 1026
328 kfree(fujitsu); 1027 kfree(fujitsu);
329 1028
@@ -342,13 +1041,43 @@ static void __exit fujitsu_cleanup(void)
342 1041
343 kfree(fujitsu); 1042 kfree(fujitsu);
344 1043
1044 acpi_bus_unregister_driver(&acpi_fujitsu_hotkey_driver);
1045
1046 kfree(fujitsu_hotkey);
1047
345 printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n"); 1048 printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n");
346} 1049}
347 1050
348module_init(fujitsu_init); 1051module_init(fujitsu_init);
349module_exit(fujitsu_cleanup); 1052module_exit(fujitsu_cleanup);
350 1053
351MODULE_AUTHOR("Jonathan Woithe"); 1054module_param(use_alt_lcd_levels, uint, 0644);
1055MODULE_PARM_DESC(use_alt_lcd_levels,
1056 "Use alternative interface for lcd_levels (needed for Lifebook s6410).");
1057module_param(disable_brightness_keys, uint, 0644);
1058MODULE_PARM_DESC(disable_brightness_keys,
1059 "Disable brightness keys (eg. if they are already handled by the generic ACPI_VIDEO device).");
1060module_param(disable_brightness_adjust, uint, 0644);
1061MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment .");
1062#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
1063module_param_named(debug, dbg_level, uint, 0644);
1064MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
1065#endif
1066
1067MODULE_AUTHOR("Jonathan Woithe, Peter Gruber");
352MODULE_DESCRIPTION("Fujitsu laptop extras support"); 1068MODULE_DESCRIPTION("Fujitsu laptop extras support");
353MODULE_VERSION(FUJITSU_DRIVER_VERSION); 1069MODULE_VERSION(FUJITSU_DRIVER_VERSION);
354MODULE_LICENSE("GPL"); 1070MODULE_LICENSE("GPL");
1071
1072MODULE_ALIAS
1073 ("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
1074MODULE_ALIAS
1075 ("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
1076
1077static struct pnp_device_id pnp_ids[] = {
1078 { .id = "FUJ02bf" },
1079 { .id = "FUJ02B1" },
1080 { .id = "FUJ02E3" },
1081 { .id = "" }
1082};
1083MODULE_DEVICE_TABLE(pnp, pnp_ids);
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index ff51ab67231c..176fe4e09d3f 100644
--- a/drivers/misc/hdpuftrs/hdpu_cpustate.c
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -17,6 +17,7 @@
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/spinlock.h> 19#include <linux/spinlock.h>
20#include <linux/smp_lock.h>
20#include <linux/miscdevice.h> 21#include <linux/miscdevice.h>
21#include <linux/proc_fs.h> 22#include <linux/proc_fs.h>
22#include <linux/hdpu_features.h> 23#include <linux/hdpu_features.h>
@@ -151,7 +152,13 @@ static ssize_t cpustate_write(struct file *file, const char *buf,
151 152
152static int cpustate_open(struct inode *inode, struct file *file) 153static int cpustate_open(struct inode *inode, struct file *file)
153{ 154{
154 return cpustate_get_ref((file->f_flags & O_EXCL)); 155 int ret;
156
157 lock_kernel();
158 ret = cpustate_get_ref((file->f_flags & O_EXCL));
159 unlock_kernel();
160
161 return ret;
155} 162}
156 163
157static int cpustate_release(struct inode *inode, struct file *file) 164static int cpustate_release(struct inode *inode, struct file *file)
diff --git a/drivers/misc/hp-wmi.c b/drivers/misc/hp-wmi.c
new file mode 100644
index 000000000000..1dbcbcb323a2
--- /dev/null
+++ b/drivers/misc/hp-wmi.c
@@ -0,0 +1,494 @@
1/*
2 * HP WMI hotkeys
3 *
4 * Copyright (C) 2008 Red Hat <mjg@redhat.com>
5 *
6 * Portions based on wistron_btns.c:
7 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
8 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
9 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/types.h>
30#include <linux/input.h>
31#include <acpi/acpi_drivers.h>
32#include <linux/platform_device.h>
33#include <linux/acpi.h>
34#include <linux/rfkill.h>
35#include <linux/string.h>
36
37MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
38MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
39MODULE_LICENSE("GPL");
40
41MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
42MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
43
44#define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
45#define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
46
47#define HPWMI_DISPLAY_QUERY 0x1
48#define HPWMI_HDDTEMP_QUERY 0x2
49#define HPWMI_ALS_QUERY 0x3
50#define HPWMI_DOCK_QUERY 0x4
51#define HPWMI_WIRELESS_QUERY 0x5
52
53static int __init hp_wmi_bios_setup(struct platform_device *device);
54static int __exit hp_wmi_bios_remove(struct platform_device *device);
55
56struct bios_args {
57 u32 signature;
58 u32 command;
59 u32 commandtype;
60 u32 datasize;
61 u32 data;
62};
63
64struct bios_return {
65 u32 sigpass;
66 u32 return_code;
67 u32 value;
68};
69
70struct key_entry {
71 char type; /* See KE_* below */
72 u8 code;
73 u16 keycode;
74};
75
76enum { KE_KEY, KE_SW, KE_END };
77
78static struct key_entry hp_wmi_keymap[] = {
79 {KE_SW, 0x01, SW_DOCK},
80 {KE_KEY, 0x02, KEY_BRIGHTNESSUP},
81 {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
82 {KE_KEY, 0x04, KEY_HELP},
83 {KE_END, 0}
84};
85
86static struct input_dev *hp_wmi_input_dev;
87static struct platform_device *hp_wmi_platform_dev;
88
89static struct rfkill *wifi_rfkill;
90static struct rfkill *bluetooth_rfkill;
91static struct rfkill *wwan_rfkill;
92
93static struct platform_driver hp_wmi_driver = {
94 .driver = {
95 .name = "hp-wmi",
96 .owner = THIS_MODULE,
97 },
98 .probe = hp_wmi_bios_setup,
99 .remove = hp_wmi_bios_remove,
100};
101
102static int hp_wmi_perform_query(int query, int write, int value)
103{
104 struct bios_return bios_return;
105 acpi_status status;
106 union acpi_object *obj;
107 struct bios_args args = {
108 .signature = 0x55434553,
109 .command = write ? 0x2 : 0x1,
110 .commandtype = query,
111 .datasize = write ? 0x4 : 0,
112 .data = value,
113 };
114 struct acpi_buffer input = { sizeof(struct bios_args), &args };
115 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
116
117 status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
118
119 obj = output.pointer;
120
121 if (!obj || obj->type != ACPI_TYPE_BUFFER)
122 return -EINVAL;
123
124 bios_return = *((struct bios_return *)obj->buffer.pointer);
125 if (bios_return.return_code > 0)
126 return bios_return.return_code * -1;
127 else
128 return bios_return.value;
129}
130
131static int hp_wmi_display_state(void)
132{
133 return hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, 0);
134}
135
136static int hp_wmi_hddtemp_state(void)
137{
138 return hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, 0);
139}
140
141static int hp_wmi_als_state(void)
142{
143 return hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, 0);
144}
145
146static int hp_wmi_dock_state(void)
147{
148 return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0);
149}
150
151static int hp_wmi_wifi_set(void *data, enum rfkill_state state)
152{
153 if (state)
154 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101);
155 else
156 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100);
157}
158
159static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state)
160{
161 if (state)
162 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202);
163 else
164 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200);
165}
166
167static int hp_wmi_wwan_set(void *data, enum rfkill_state state)
168{
169 if (state)
170 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404);
171 else
172 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400);
173}
174
175static int hp_wmi_wifi_state(void)
176{
177 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
178
179 if (wireless & 0x100)
180 return 1;
181 else
182 return 0;
183}
184
185static int hp_wmi_bluetooth_state(void)
186{
187 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
188
189 if (wireless & 0x10000)
190 return 1;
191 else
192 return 0;
193}
194
195static int hp_wmi_wwan_state(void)
196{
197 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
198
199 if (wireless & 0x1000000)
200 return 1;
201 else
202 return 0;
203}
204
205static ssize_t show_display(struct device *dev, struct device_attribute *attr,
206 char *buf)
207{
208 int value = hp_wmi_display_state();
209 if (value < 0)
210 return -EINVAL;
211 return sprintf(buf, "%d\n", value);
212}
213
214static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr,
215 char *buf)
216{
217 int value = hp_wmi_hddtemp_state();
218 if (value < 0)
219 return -EINVAL;
220 return sprintf(buf, "%d\n", value);
221}
222
223static ssize_t show_als(struct device *dev, struct device_attribute *attr,
224 char *buf)
225{
226 int value = hp_wmi_als_state();
227 if (value < 0)
228 return -EINVAL;
229 return sprintf(buf, "%d\n", value);
230}
231
232static ssize_t show_dock(struct device *dev, struct device_attribute *attr,
233 char *buf)
234{
235 int value = hp_wmi_dock_state();
236 if (value < 0)
237 return -EINVAL;
238 return sprintf(buf, "%d\n", value);
239}
240
241static ssize_t set_als(struct device *dev, struct device_attribute *attr,
242 const char *buf, size_t count)
243{
244 u32 tmp = simple_strtoul(buf, NULL, 10);
245 hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, tmp);
246 return count;
247}
248
249static DEVICE_ATTR(display, S_IRUGO, show_display, NULL);
250static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL);
251static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
252static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
253
254static struct key_entry *hp_wmi_get_entry_by_scancode(int code)
255{
256 struct key_entry *key;
257
258 for (key = hp_wmi_keymap; key->type != KE_END; key++)
259 if (code == key->code)
260 return key;
261
262 return NULL;
263}
264
265static struct key_entry *hp_wmi_get_entry_by_keycode(int keycode)
266{
267 struct key_entry *key;
268
269 for (key = hp_wmi_keymap; key->type != KE_END; key++)
270 if (key->type == KE_KEY && keycode == key->keycode)
271 return key;
272
273 return NULL;
274}
275
276static int hp_wmi_getkeycode(struct input_dev *dev, int scancode, int *keycode)
277{
278 struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
279
280 if (key && key->type == KE_KEY) {
281 *keycode = key->keycode;
282 return 0;
283 }
284
285 return -EINVAL;
286}
287
288static int hp_wmi_setkeycode(struct input_dev *dev, int scancode, int keycode)
289{
290 struct key_entry *key;
291 int old_keycode;
292
293 if (keycode < 0 || keycode > KEY_MAX)
294 return -EINVAL;
295
296 key = hp_wmi_get_entry_by_scancode(scancode);
297 if (key && key->type == KE_KEY) {
298 old_keycode = key->keycode;
299 key->keycode = keycode;
300 set_bit(keycode, dev->keybit);
301 if (!hp_wmi_get_entry_by_keycode(old_keycode))
302 clear_bit(old_keycode, dev->keybit);
303 return 0;
304 }
305
306 return -EINVAL;
307}
308
309void hp_wmi_notify(u32 value, void *context)
310{
311 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
312 static struct key_entry *key;
313 union acpi_object *obj;
314
315 wmi_get_event_data(value, &response);
316
317 obj = (union acpi_object *)response.pointer;
318
319 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == 8) {
320 int eventcode = *((u8 *) obj->buffer.pointer);
321 key = hp_wmi_get_entry_by_scancode(eventcode);
322 if (key) {
323 switch (key->type) {
324 case KE_KEY:
325 input_report_key(hp_wmi_input_dev,
326 key->keycode, 1);
327 input_sync(hp_wmi_input_dev);
328 input_report_key(hp_wmi_input_dev,
329 key->keycode, 0);
330 input_sync(hp_wmi_input_dev);
331 break;
332 case KE_SW:
333 input_report_switch(hp_wmi_input_dev,
334 key->keycode,
335 hp_wmi_dock_state());
336 input_sync(hp_wmi_input_dev);
337 break;
338 }
339 } else if (eventcode == 0x5) {
340 if (wifi_rfkill)
341 wifi_rfkill->state = hp_wmi_wifi_state();
342 if (bluetooth_rfkill)
343 bluetooth_rfkill->state =
344 hp_wmi_bluetooth_state();
345 if (wwan_rfkill)
346 wwan_rfkill->state = hp_wmi_wwan_state();
347 } else
348 printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
349 eventcode);
350 } else
351 printk(KERN_INFO "HP WMI: Unknown response received\n");
352}
353
354static int __init hp_wmi_input_setup(void)
355{
356 struct key_entry *key;
357 int err;
358
359 hp_wmi_input_dev = input_allocate_device();
360
361 hp_wmi_input_dev->name = "HP WMI hotkeys";
362 hp_wmi_input_dev->phys = "wmi/input0";
363 hp_wmi_input_dev->id.bustype = BUS_HOST;
364 hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode;
365 hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode;
366
367 for (key = hp_wmi_keymap; key->type != KE_END; key++) {
368 switch (key->type) {
369 case KE_KEY:
370 set_bit(EV_KEY, hp_wmi_input_dev->evbit);
371 set_bit(key->keycode, hp_wmi_input_dev->keybit);
372 break;
373 case KE_SW:
374 set_bit(EV_SW, hp_wmi_input_dev->evbit);
375 set_bit(key->keycode, hp_wmi_input_dev->swbit);
376 break;
377 }
378 }
379
380 err = input_register_device(hp_wmi_input_dev);
381
382 if (err) {
383 input_free_device(hp_wmi_input_dev);
384 return err;
385 }
386
387 return 0;
388}
389
390static void cleanup_sysfs(struct platform_device *device)
391{
392 device_remove_file(&device->dev, &dev_attr_display);
393 device_remove_file(&device->dev, &dev_attr_hddtemp);
394 device_remove_file(&device->dev, &dev_attr_als);
395 device_remove_file(&device->dev, &dev_attr_dock);
396}
397
398static int __init hp_wmi_bios_setup(struct platform_device *device)
399{
400 int err;
401
402 err = device_create_file(&device->dev, &dev_attr_display);
403 if (err)
404 goto add_sysfs_error;
405 err = device_create_file(&device->dev, &dev_attr_hddtemp);
406 if (err)
407 goto add_sysfs_error;
408 err = device_create_file(&device->dev, &dev_attr_als);
409 if (err)
410 goto add_sysfs_error;
411 err = device_create_file(&device->dev, &dev_attr_dock);
412 if (err)
413 goto add_sysfs_error;
414
415 wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
416 wifi_rfkill->name = "hp-wifi";
417 wifi_rfkill->state = hp_wmi_wifi_state();
418 wifi_rfkill->toggle_radio = hp_wmi_wifi_set;
419 wifi_rfkill->user_claim_unsupported = 1;
420
421 bluetooth_rfkill = rfkill_allocate(&device->dev,
422 RFKILL_TYPE_BLUETOOTH);
423 bluetooth_rfkill->name = "hp-bluetooth";
424 bluetooth_rfkill->state = hp_wmi_bluetooth_state();
425 bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set;
426 bluetooth_rfkill->user_claim_unsupported = 1;
427
428 wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX);
429 wwan_rfkill->name = "hp-wwan";
430 wwan_rfkill->state = hp_wmi_wwan_state();
431 wwan_rfkill->toggle_radio = hp_wmi_wwan_set;
432 wwan_rfkill->user_claim_unsupported = 1;
433
434 rfkill_register(wifi_rfkill);
435 rfkill_register(bluetooth_rfkill);
436 rfkill_register(wwan_rfkill);
437
438 return 0;
439add_sysfs_error:
440 cleanup_sysfs(device);
441 return err;
442}
443
444static int __exit hp_wmi_bios_remove(struct platform_device *device)
445{
446 cleanup_sysfs(device);
447
448 rfkill_unregister(wifi_rfkill);
449 rfkill_unregister(bluetooth_rfkill);
450 rfkill_unregister(wwan_rfkill);
451
452 return 0;
453}
454
455static int __init hp_wmi_init(void)
456{
457 int err;
458
459 if (wmi_has_guid(HPWMI_EVENT_GUID)) {
460 err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
461 hp_wmi_notify, NULL);
462 if (!err)
463 hp_wmi_input_setup();
464 }
465
466 if (wmi_has_guid(HPWMI_BIOS_GUID)) {
467 err = platform_driver_register(&hp_wmi_driver);
468 if (err)
469 return 0;
470 hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1);
471 if (!hp_wmi_platform_dev) {
472 platform_driver_unregister(&hp_wmi_driver);
473 return 0;
474 }
475 platform_device_add(hp_wmi_platform_dev);
476 }
477
478 return 0;
479}
480
481static void __exit hp_wmi_exit(void)
482{
483 if (wmi_has_guid(HPWMI_EVENT_GUID)) {
484 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
485 input_unregister_device(hp_wmi_input_dev);
486 }
487 if (hp_wmi_platform_dev) {
488 platform_device_del(hp_wmi_platform_dev);
489 platform_driver_unregister(&hp_wmi_driver);
490 }
491}
492
493module_init(hp_wmi_init);
494module_exit(hp_wmi_exit);
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
new file mode 100644
index 000000000000..05e298289238
--- /dev/null
+++ b/drivers/misc/hpilo.c
@@ -0,0 +1,768 @@
1/*
2 * Driver for HP iLO/iLO2 management processor.
3 *
4 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
5 * David Altobelli <david.altobelli@hp.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/kernel.h>
12#include <linux/types.h>
13#include <linux/module.h>
14#include <linux/fs.h>
15#include <linux/pci.h>
16#include <linux/ioport.h>
17#include <linux/device.h>
18#include <linux/file.h>
19#include <linux/cdev.h>
20#include <linux/spinlock.h>
21#include <linux/delay.h>
22#include <linux/uaccess.h>
23#include <linux/io.h>
24#include "hpilo.h"
25
26static struct class *ilo_class;
27static unsigned int ilo_major;
28static char ilo_hwdev[MAX_ILO_DEV];
29
30static inline int get_entry_id(int entry)
31{
32 return (entry & ENTRY_MASK_DESCRIPTOR) >> ENTRY_BITPOS_DESCRIPTOR;
33}
34
35static inline int get_entry_len(int entry)
36{
37 return ((entry & ENTRY_MASK_QWORDS) >> ENTRY_BITPOS_QWORDS) << 3;
38}
39
40static inline int mk_entry(int id, int len)
41{
42 int qlen = len & 7 ? (len >> 3) + 1 : len >> 3;
43 return id << ENTRY_BITPOS_DESCRIPTOR | qlen << ENTRY_BITPOS_QWORDS;
44}
45
46static inline int desc_mem_sz(int nr_entry)
47{
48 return nr_entry << L2_QENTRY_SZ;
49}
50
51/*
52 * FIFO queues, shared with hardware.
53 *
54 * If a queue has empty slots, an entry is added to the queue tail,
55 * and that entry is marked as occupied.
56 * Entries can be dequeued from the head of the list, when the device
57 * has marked the entry as consumed.
58 *
59 * Returns true on successful queue/dequeue, false on failure.
60 */
61static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry)
62{
63 struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
64 int ret = 0;
65
66 spin_lock(&hw->fifo_lock);
67 if (!(fifo_q->fifobar[(fifo_q->tail + 1) & fifo_q->imask]
68 & ENTRY_MASK_O)) {
69 fifo_q->fifobar[fifo_q->tail & fifo_q->imask] |=
70 (entry & ENTRY_MASK_NOSTATE) | fifo_q->merge;
71 fifo_q->tail += 1;
72 ret = 1;
73 }
74 spin_unlock(&hw->fifo_lock);
75
76 return ret;
77}
78
79static int fifo_dequeue(struct ilo_hwinfo *hw, char *fifobar, int *entry)
80{
81 struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
82 int ret = 0;
83 u64 c;
84
85 spin_lock(&hw->fifo_lock);
86 c = fifo_q->fifobar[fifo_q->head & fifo_q->imask];
87 if (c & ENTRY_MASK_C) {
88 if (entry)
89 *entry = c & ENTRY_MASK_NOSTATE;
90
91 fifo_q->fifobar[fifo_q->head & fifo_q->imask] =
92 (c | ENTRY_MASK) + 1;
93 fifo_q->head += 1;
94 ret = 1;
95 }
96 spin_unlock(&hw->fifo_lock);
97
98 return ret;
99}
100
101static int ilo_pkt_enqueue(struct ilo_hwinfo *hw, struct ccb *ccb,
102 int dir, int id, int len)
103{
104 char *fifobar;
105 int entry;
106
107 if (dir == SENDQ)
108 fifobar = ccb->ccb_u1.send_fifobar;
109 else
110 fifobar = ccb->ccb_u3.recv_fifobar;
111
112 entry = mk_entry(id, len);
113 return fifo_enqueue(hw, fifobar, entry);
114}
115
116static int ilo_pkt_dequeue(struct ilo_hwinfo *hw, struct ccb *ccb,
117 int dir, int *id, int *len, void **pkt)
118{
119 char *fifobar, *desc;
120 int entry = 0, pkt_id = 0;
121 int ret;
122
123 if (dir == SENDQ) {
124 fifobar = ccb->ccb_u1.send_fifobar;
125 desc = ccb->ccb_u2.send_desc;
126 } else {
127 fifobar = ccb->ccb_u3.recv_fifobar;
128 desc = ccb->ccb_u4.recv_desc;
129 }
130
131 ret = fifo_dequeue(hw, fifobar, &entry);
132 if (ret) {
133 pkt_id = get_entry_id(entry);
134 if (id)
135 *id = pkt_id;
136 if (len)
137 *len = get_entry_len(entry);
138 if (pkt)
139 *pkt = (void *)(desc + desc_mem_sz(pkt_id));
140 }
141
142 return ret;
143}
144
145static inline void doorbell_set(struct ccb *ccb)
146{
147 iowrite8(1, ccb->ccb_u5.db_base);
148}
149
150static inline void doorbell_clr(struct ccb *ccb)
151{
152 iowrite8(2, ccb->ccb_u5.db_base);
153}
154static inline int ctrl_set(int l2sz, int idxmask, int desclim)
155{
156 int active = 0, go = 1;
157 return l2sz << CTRL_BITPOS_L2SZ |
158 idxmask << CTRL_BITPOS_FIFOINDEXMASK |
159 desclim << CTRL_BITPOS_DESCLIMIT |
160 active << CTRL_BITPOS_A |
161 go << CTRL_BITPOS_G;
162}
163static void ctrl_setup(struct ccb *ccb, int nr_desc, int l2desc_sz)
164{
165 /* for simplicity, use the same parameters for send and recv ctrls */
166 ccb->send_ctrl = ctrl_set(l2desc_sz, nr_desc-1, nr_desc-1);
167 ccb->recv_ctrl = ctrl_set(l2desc_sz, nr_desc-1, nr_desc-1);
168}
169
170static inline int fifo_sz(int nr_entry)
171{
172 /* size of a fifo is determined by the number of entries it contains */
173 return (nr_entry * sizeof(u64)) + FIFOHANDLESIZE;
174}
175
176static void fifo_setup(void *base_addr, int nr_entry)
177{
178 struct fifo *fifo_q = base_addr;
179 int i;
180
181 /* set up an empty fifo */
182 fifo_q->head = 0;
183 fifo_q->tail = 0;
184 fifo_q->reset = 0;
185 fifo_q->nrents = nr_entry;
186 fifo_q->imask = nr_entry - 1;
187 fifo_q->merge = ENTRY_MASK_O;
188
189 for (i = 0; i < nr_entry; i++)
190 fifo_q->fifobar[i] = 0;
191}
192
193static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data)
194{
195 struct ccb *driver_ccb;
196 struct ccb __iomem *device_ccb;
197 int retries;
198
199 driver_ccb = &data->driver_ccb;
200 device_ccb = data->mapped_ccb;
201
202 /* complicated dance to tell the hw we are stopping */
203 doorbell_clr(driver_ccb);
204 iowrite32(ioread32(&device_ccb->send_ctrl) & ~(1 << CTRL_BITPOS_G),
205 &device_ccb->send_ctrl);
206 iowrite32(ioread32(&device_ccb->recv_ctrl) & ~(1 << CTRL_BITPOS_G),
207 &device_ccb->recv_ctrl);
208
209 /* give iLO some time to process stop request */
210 for (retries = 1000; retries > 0; retries--) {
211 doorbell_set(driver_ccb);
212 udelay(1);
213 if (!(ioread32(&device_ccb->send_ctrl) & (1 << CTRL_BITPOS_A))
214 &&
215 !(ioread32(&device_ccb->recv_ctrl) & (1 << CTRL_BITPOS_A)))
216 break;
217 }
218 if (retries == 0)
219 dev_err(&pdev->dev, "Closing, but controller still active\n");
220
221 /* clear the hw ccb */
222 memset_io(device_ccb, 0, sizeof(struct ccb));
223
224 /* free resources used to back send/recv queues */
225 pci_free_consistent(pdev, data->dma_size, data->dma_va, data->dma_pa);
226}
227
228static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
229{
230 char *dma_va, *dma_pa;
231 int pkt_id, pkt_sz, i, error;
232 struct ccb *driver_ccb, *ilo_ccb;
233 struct pci_dev *pdev;
234
235 driver_ccb = &data->driver_ccb;
236 ilo_ccb = &data->ilo_ccb;
237 pdev = hw->ilo_dev;
238
239 data->dma_size = 2 * fifo_sz(NR_QENTRY) +
240 2 * desc_mem_sz(NR_QENTRY) +
241 ILO_START_ALIGN + ILO_CACHE_SZ;
242
243 error = -ENOMEM;
244 data->dma_va = pci_alloc_consistent(pdev, data->dma_size,
245 &data->dma_pa);
246 if (!data->dma_va)
247 goto out;
248
249 dma_va = (char *)data->dma_va;
250 dma_pa = (char *)data->dma_pa;
251
252 memset(dma_va, 0, data->dma_size);
253
254 dma_va = (char *)roundup((unsigned long)dma_va, ILO_START_ALIGN);
255 dma_pa = (char *)roundup((unsigned long)dma_pa, ILO_START_ALIGN);
256
257 /*
258 * Create two ccb's, one with virt addrs, one with phys addrs.
259 * Copy the phys addr ccb to device shared mem.
260 */
261 ctrl_setup(driver_ccb, NR_QENTRY, L2_QENTRY_SZ);
262 ctrl_setup(ilo_ccb, NR_QENTRY, L2_QENTRY_SZ);
263
264 fifo_setup(dma_va, NR_QENTRY);
265 driver_ccb->ccb_u1.send_fifobar = dma_va + FIFOHANDLESIZE;
266 ilo_ccb->ccb_u1.send_fifobar = dma_pa + FIFOHANDLESIZE;
267 dma_va += fifo_sz(NR_QENTRY);
268 dma_pa += fifo_sz(NR_QENTRY);
269
270 dma_va = (char *)roundup((unsigned long)dma_va, ILO_CACHE_SZ);
271 dma_pa = (char *)roundup((unsigned long)dma_pa, ILO_CACHE_SZ);
272
273 fifo_setup(dma_va, NR_QENTRY);
274 driver_ccb->ccb_u3.recv_fifobar = dma_va + FIFOHANDLESIZE;
275 ilo_ccb->ccb_u3.recv_fifobar = dma_pa + FIFOHANDLESIZE;
276 dma_va += fifo_sz(NR_QENTRY);
277 dma_pa += fifo_sz(NR_QENTRY);
278
279 driver_ccb->ccb_u2.send_desc = dma_va;
280 ilo_ccb->ccb_u2.send_desc = dma_pa;
281 dma_pa += desc_mem_sz(NR_QENTRY);
282 dma_va += desc_mem_sz(NR_QENTRY);
283
284 driver_ccb->ccb_u4.recv_desc = dma_va;
285 ilo_ccb->ccb_u4.recv_desc = dma_pa;
286
287 driver_ccb->channel = slot;
288 ilo_ccb->channel = slot;
289
290 driver_ccb->ccb_u5.db_base = hw->db_vaddr + (slot << L2_DB_SIZE);
291 ilo_ccb->ccb_u5.db_base = NULL; /* hw ccb's doorbell is not used */
292
293 /* copy the ccb with physical addrs to device memory */
294 data->mapped_ccb = (struct ccb __iomem *)
295 (hw->ram_vaddr + (slot * ILOHW_CCB_SZ));
296 memcpy_toio(data->mapped_ccb, ilo_ccb, sizeof(struct ccb));
297
298 /* put packets on the send and receive queues */
299 pkt_sz = 0;
300 for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++) {
301 ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, pkt_sz);
302 doorbell_set(driver_ccb);
303 }
304
305 pkt_sz = desc_mem_sz(1);
306 for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++)
307 ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz);
308
309 doorbell_clr(driver_ccb);
310
311 /* make sure iLO is really handling requests */
312 for (i = 1000; i > 0; i--) {
313 if (ilo_pkt_dequeue(hw, driver_ccb, SENDQ, &pkt_id, NULL, NULL))
314 break;
315 udelay(1);
316 }
317
318 if (i) {
319 ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0);
320 doorbell_set(driver_ccb);
321 } else {
322 dev_err(&pdev->dev, "Open could not dequeue a packet\n");
323 error = -EBUSY;
324 goto free;
325 }
326
327 return 0;
328free:
329 pci_free_consistent(pdev, data->dma_size, data->dma_va, data->dma_pa);
330out:
331 return error;
332}
333
334static inline int is_channel_reset(struct ccb *ccb)
335{
336 /* check for this particular channel needing a reset */
337 return FIFOBARTOHANDLE(ccb->ccb_u1.send_fifobar)->reset;
338}
339
340static inline void set_channel_reset(struct ccb *ccb)
341{
342 /* set a flag indicating this channel needs a reset */
343 FIFOBARTOHANDLE(ccb->ccb_u1.send_fifobar)->reset = 1;
344}
345
346static inline int is_device_reset(struct ilo_hwinfo *hw)
347{
348 /* check for global reset condition */
349 return ioread32(&hw->mmio_vaddr[DB_OUT]) & (1 << DB_RESET);
350}
351
352static inline void clear_device(struct ilo_hwinfo *hw)
353{
354 /* clear the device (reset bits, pending channel entries) */
355 iowrite32(-1, &hw->mmio_vaddr[DB_OUT]);
356}
357
358static void ilo_locked_reset(struct ilo_hwinfo *hw)
359{
360 int slot;
361
362 /*
363 * Mapped memory is zeroed on ilo reset, so set a per ccb flag
364 * to indicate that this ccb needs to be closed and reopened.
365 */
366 for (slot = 0; slot < MAX_CCB; slot++) {
367 if (!hw->ccb_alloc[slot])
368 continue;
369 set_channel_reset(&hw->ccb_alloc[slot]->driver_ccb);
370 }
371
372 clear_device(hw);
373}
374
375static void ilo_reset(struct ilo_hwinfo *hw)
376{
377 spin_lock(&hw->alloc_lock);
378
379 /* reset might have been handled after lock was taken */
380 if (is_device_reset(hw))
381 ilo_locked_reset(hw);
382
383 spin_unlock(&hw->alloc_lock);
384}
385
386static ssize_t ilo_read(struct file *fp, char __user *buf,
387 size_t len, loff_t *off)
388{
389 int err, found, cnt, pkt_id, pkt_len;
390 struct ccb_data *data;
391 struct ccb *driver_ccb;
392 struct ilo_hwinfo *hw;
393 void *pkt;
394
395 data = fp->private_data;
396 driver_ccb = &data->driver_ccb;
397 hw = data->ilo_hw;
398
399 if (is_device_reset(hw) || is_channel_reset(driver_ccb)) {
400 /*
401 * If the device has been reset, applications
402 * need to close and reopen all ccbs.
403 */
404 ilo_reset(hw);
405 return -ENODEV;
406 }
407
408 /*
409 * This function is to be called when data is expected
410 * in the channel, and will return an error if no packet is found
411 * during the loop below. The sleep/retry logic is to allow
412 * applications to call read() immediately post write(),
413 * and give iLO some time to process the sent packet.
414 */
415 cnt = 20;
416 do {
417 /* look for a received packet */
418 found = ilo_pkt_dequeue(hw, driver_ccb, RECVQ, &pkt_id,
419 &pkt_len, &pkt);
420 if (found)
421 break;
422 cnt--;
423 msleep(100);
424 } while (!found && cnt);
425
426 if (!found)
427 return -EAGAIN;
428
429 /* only copy the length of the received packet */
430 if (pkt_len < len)
431 len = pkt_len;
432
433 err = copy_to_user(buf, pkt, len);
434
435 /* return the received packet to the queue */
436 ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, desc_mem_sz(1));
437
438 return err ? -EFAULT : len;
439}
440
441static ssize_t ilo_write(struct file *fp, const char __user *buf,
442 size_t len, loff_t *off)
443{
444 int err, pkt_id, pkt_len;
445 struct ccb_data *data;
446 struct ccb *driver_ccb;
447 struct ilo_hwinfo *hw;
448 void *pkt;
449
450 data = fp->private_data;
451 driver_ccb = &data->driver_ccb;
452 hw = data->ilo_hw;
453
454 if (is_device_reset(hw) || is_channel_reset(driver_ccb)) {
455 /*
456 * If the device has been reset, applications
457 * need to close and reopen all ccbs.
458 */
459 ilo_reset(hw);
460 return -ENODEV;
461 }
462
463 /* get a packet to send the user command */
464 if (!ilo_pkt_dequeue(hw, driver_ccb, SENDQ, &pkt_id, &pkt_len, &pkt))
465 return -EBUSY;
466
467 /* limit the length to the length of the packet */
468 if (pkt_len < len)
469 len = pkt_len;
470
471 /* on failure, set the len to 0 to return empty packet to the device */
472 err = copy_from_user(pkt, buf, len);
473 if (err)
474 len = 0;
475
476 /* send the packet */
477 ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, len);
478 doorbell_set(driver_ccb);
479
480 return err ? -EFAULT : len;
481}
482
483static int ilo_close(struct inode *ip, struct file *fp)
484{
485 int slot;
486 struct ccb_data *data;
487 struct ilo_hwinfo *hw;
488
489 slot = iminor(ip) % MAX_CCB;
490 hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
491
492 spin_lock(&hw->alloc_lock);
493
494 if (is_device_reset(hw))
495 ilo_locked_reset(hw);
496
497 if (hw->ccb_alloc[slot]->ccb_cnt == 1) {
498
499 data = fp->private_data;
500
501 ilo_ccb_close(hw->ilo_dev, data);
502
503 kfree(data);
504 hw->ccb_alloc[slot] = NULL;
505 } else
506 hw->ccb_alloc[slot]->ccb_cnt--;
507
508 spin_unlock(&hw->alloc_lock);
509
510 return 0;
511}
512
513static int ilo_open(struct inode *ip, struct file *fp)
514{
515 int slot, error;
516 struct ccb_data *data;
517 struct ilo_hwinfo *hw;
518
519 slot = iminor(ip) % MAX_CCB;
520 hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
521
522 /* new ccb allocation */
523 data = kzalloc(sizeof(*data), GFP_KERNEL);
524 if (!data)
525 return -ENOMEM;
526
527 spin_lock(&hw->alloc_lock);
528
529 if (is_device_reset(hw))
530 ilo_locked_reset(hw);
531
532 /* each fd private_data holds sw/hw view of ccb */
533 if (hw->ccb_alloc[slot] == NULL) {
534 /* create a channel control block for this minor */
535 error = ilo_ccb_open(hw, data, slot);
536 if (!error) {
537 hw->ccb_alloc[slot] = data;
538 hw->ccb_alloc[slot]->ccb_cnt = 1;
539 hw->ccb_alloc[slot]->ccb_excl = fp->f_flags & O_EXCL;
540 hw->ccb_alloc[slot]->ilo_hw = hw;
541 } else
542 kfree(data);
543 } else {
544 kfree(data);
545 if (fp->f_flags & O_EXCL || hw->ccb_alloc[slot]->ccb_excl) {
546 /*
547 * The channel exists, and either this open
548 * or a previous open of this channel wants
549 * exclusive access.
550 */
551 error = -EBUSY;
552 } else {
553 hw->ccb_alloc[slot]->ccb_cnt++;
554 error = 0;
555 }
556 }
557 spin_unlock(&hw->alloc_lock);
558
559 if (!error)
560 fp->private_data = hw->ccb_alloc[slot];
561
562 return error;
563}
564
565static const struct file_operations ilo_fops = {
566 .owner = THIS_MODULE,
567 .read = ilo_read,
568 .write = ilo_write,
569 .open = ilo_open,
570 .release = ilo_close,
571};
572
573static void ilo_unmap_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
574{
575 pci_iounmap(pdev, hw->db_vaddr);
576 pci_iounmap(pdev, hw->ram_vaddr);
577 pci_iounmap(pdev, hw->mmio_vaddr);
578}
579
580static int __devinit ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
581{
582 int error = -ENOMEM;
583
584 /* map the memory mapped i/o registers */
585 hw->mmio_vaddr = pci_iomap(pdev, 1, 0);
586 if (hw->mmio_vaddr == NULL) {
587 dev_err(&pdev->dev, "Error mapping mmio\n");
588 goto out;
589 }
590
591 /* map the adapter shared memory region */
592 hw->ram_vaddr = pci_iomap(pdev, 2, MAX_CCB * ILOHW_CCB_SZ);
593 if (hw->ram_vaddr == NULL) {
594 dev_err(&pdev->dev, "Error mapping shared mem\n");
595 goto mmio_free;
596 }
597
598 /* map the doorbell aperture */
599 hw->db_vaddr = pci_iomap(pdev, 3, MAX_CCB * ONE_DB_SIZE);
600 if (hw->db_vaddr == NULL) {
601 dev_err(&pdev->dev, "Error mapping doorbell\n");
602 goto ram_free;
603 }
604
605 return 0;
606ram_free:
607 pci_iounmap(pdev, hw->ram_vaddr);
608mmio_free:
609 pci_iounmap(pdev, hw->mmio_vaddr);
610out:
611 return error;
612}
613
614static void ilo_remove(struct pci_dev *pdev)
615{
616 int i, minor;
617 struct ilo_hwinfo *ilo_hw = pci_get_drvdata(pdev);
618
619 clear_device(ilo_hw);
620
621 minor = MINOR(ilo_hw->cdev.dev);
622 for (i = minor; i < minor + MAX_CCB; i++)
623 device_destroy(ilo_class, MKDEV(ilo_major, i));
624
625 cdev_del(&ilo_hw->cdev);
626 ilo_unmap_device(pdev, ilo_hw);
627 pci_release_regions(pdev);
628 pci_disable_device(pdev);
629 kfree(ilo_hw);
630 ilo_hwdev[(minor / MAX_CCB)] = 0;
631}
632
633static int __devinit ilo_probe(struct pci_dev *pdev,
634 const struct pci_device_id *ent)
635{
636 int devnum, minor, start, error;
637 struct ilo_hwinfo *ilo_hw;
638
639 /* find a free range for device files */
640 for (devnum = 0; devnum < MAX_ILO_DEV; devnum++) {
641 if (ilo_hwdev[devnum] == 0) {
642 ilo_hwdev[devnum] = 1;
643 break;
644 }
645 }
646
647 if (devnum == MAX_ILO_DEV) {
648 dev_err(&pdev->dev, "Error finding free device\n");
649 return -ENODEV;
650 }
651
652 /* track global allocations for this device */
653 error = -ENOMEM;
654 ilo_hw = kzalloc(sizeof(*ilo_hw), GFP_KERNEL);
655 if (!ilo_hw)
656 goto out;
657
658 ilo_hw->ilo_dev = pdev;
659 spin_lock_init(&ilo_hw->alloc_lock);
660 spin_lock_init(&ilo_hw->fifo_lock);
661
662 error = pci_enable_device(pdev);
663 if (error)
664 goto free;
665
666 pci_set_master(pdev);
667
668 error = pci_request_regions(pdev, ILO_NAME);
669 if (error)
670 goto disable;
671
672 error = ilo_map_device(pdev, ilo_hw);
673 if (error)
674 goto free_regions;
675
676 pci_set_drvdata(pdev, ilo_hw);
677 clear_device(ilo_hw);
678
679 cdev_init(&ilo_hw->cdev, &ilo_fops);
680 ilo_hw->cdev.owner = THIS_MODULE;
681 start = devnum * MAX_CCB;
682 error = cdev_add(&ilo_hw->cdev, MKDEV(ilo_major, start), MAX_CCB);
683 if (error) {
684 dev_err(&pdev->dev, "Could not add cdev\n");
685 goto unmap;
686 }
687
688 for (minor = 0 ; minor < MAX_CCB; minor++) {
689 struct device *dev;
690 dev = device_create(ilo_class, &pdev->dev,
691 MKDEV(ilo_major, minor), NULL,
692 "hpilo!d%dccb%d", devnum, minor);
693 if (IS_ERR(dev))
694 dev_err(&pdev->dev, "Could not create files\n");
695 }
696
697 return 0;
698unmap:
699 ilo_unmap_device(pdev, ilo_hw);
700free_regions:
701 pci_release_regions(pdev);
702disable:
703 pci_disable_device(pdev);
704free:
705 kfree(ilo_hw);
706out:
707 ilo_hwdev[devnum] = 0;
708 return error;
709}
710
711static struct pci_device_id ilo_devices[] = {
712 { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB204) },
713 { }
714};
715MODULE_DEVICE_TABLE(pci, ilo_devices);
716
717static struct pci_driver ilo_driver = {
718 .name = ILO_NAME,
719 .id_table = ilo_devices,
720 .probe = ilo_probe,
721 .remove = __devexit_p(ilo_remove),
722};
723
724static int __init ilo_init(void)
725{
726 int error;
727 dev_t dev;
728
729 ilo_class = class_create(THIS_MODULE, "iLO");
730 if (IS_ERR(ilo_class)) {
731 error = PTR_ERR(ilo_class);
732 goto out;
733 }
734
735 error = alloc_chrdev_region(&dev, 0, MAX_OPEN, ILO_NAME);
736 if (error)
737 goto class_destroy;
738
739 ilo_major = MAJOR(dev);
740
741 error = pci_register_driver(&ilo_driver);
742 if (error)
743 goto chr_remove;
744
745 return 0;
746chr_remove:
747 unregister_chrdev_region(dev, MAX_OPEN);
748class_destroy:
749 class_destroy(ilo_class);
750out:
751 return error;
752}
753
754static void __exit ilo_exit(void)
755{
756 pci_unregister_driver(&ilo_driver);
757 unregister_chrdev_region(MKDEV(ilo_major, 0), MAX_OPEN);
758 class_destroy(ilo_class);
759}
760
761MODULE_VERSION("0.05");
762MODULE_ALIAS(ILO_NAME);
763MODULE_DESCRIPTION(ILO_NAME);
764MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>");
765MODULE_LICENSE("GPL v2");
766
767module_init(ilo_init);
768module_exit(ilo_exit);
diff --git a/drivers/misc/hpilo.h b/drivers/misc/hpilo.h
new file mode 100644
index 000000000000..a281207696c1
--- /dev/null
+++ b/drivers/misc/hpilo.h
@@ -0,0 +1,189 @@
1/*
2 * linux/drivers/char/hpilo.h
3 *
4 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
5 * David Altobelli <david.altobelli@hp.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef __HPILO_H
12#define __HPILO_H
13
14#define ILO_NAME "hpilo"
15
16/* max number of open channel control blocks per device, hw limited to 32 */
17#define MAX_CCB 8
18/* max number of supported devices */
19#define MAX_ILO_DEV 1
20/* max number of files */
21#define MAX_OPEN (MAX_CCB * MAX_ILO_DEV)
22
23/*
24 * Per device, used to track global memory allocations.
25 */
26struct ilo_hwinfo {
27 /* mmio registers on device */
28 char __iomem *mmio_vaddr;
29
30 /* doorbell registers on device */
31 char __iomem *db_vaddr;
32
33 /* shared memory on device used for channel control blocks */
34 char __iomem *ram_vaddr;
35
36 /* files corresponding to this device */
37 struct ccb_data *ccb_alloc[MAX_CCB];
38
39 struct pci_dev *ilo_dev;
40
41 spinlock_t alloc_lock;
42 spinlock_t fifo_lock;
43
44 struct cdev cdev;
45};
46
47/* offset from mmio_vaddr */
48#define DB_OUT 0xD4
49/* DB_OUT reset bit */
50#define DB_RESET 26
51
52/*
53 * Channel control block. Used to manage hardware queues.
54 * The format must match hw's version. The hw ccb is 128 bytes,
55 * but the context area shouldn't be touched by the driver.
56 */
57#define ILOSW_CCB_SZ 64
58#define ILOHW_CCB_SZ 128
59struct ccb {
60 union {
61 char *send_fifobar;
62 u64 padding1;
63 } ccb_u1;
64 union {
65 char *send_desc;
66 u64 padding2;
67 } ccb_u2;
68 u64 send_ctrl;
69
70 union {
71 char *recv_fifobar;
72 u64 padding3;
73 } ccb_u3;
74 union {
75 char *recv_desc;
76 u64 padding4;
77 } ccb_u4;
78 u64 recv_ctrl;
79
80 union {
81 char __iomem *db_base;
82 u64 padding5;
83 } ccb_u5;
84
85 u64 channel;
86
87 /* unused context area (64 bytes) */
88};
89
90/* ccb queue parameters */
91#define SENDQ 1
92#define RECVQ 2
93#define NR_QENTRY 4
94#define L2_QENTRY_SZ 12
95
96/* ccb ctrl bitfields */
97#define CTRL_BITPOS_L2SZ 0
98#define CTRL_BITPOS_FIFOINDEXMASK 4
99#define CTRL_BITPOS_DESCLIMIT 18
100#define CTRL_BITPOS_A 30
101#define CTRL_BITPOS_G 31
102
103/* ccb doorbell macros */
104#define L2_DB_SIZE 14
105#define ONE_DB_SIZE (1 << L2_DB_SIZE)
106
107/*
108 * Per fd structure used to track the ccb allocated to that dev file.
109 */
110struct ccb_data {
111 /* software version of ccb, using virtual addrs */
112 struct ccb driver_ccb;
113
114 /* hardware version of ccb, using physical addrs */
115 struct ccb ilo_ccb;
116
117 /* hardware ccb is written to this shared mapped device memory */
118 struct ccb __iomem *mapped_ccb;
119
120 /* dma'able memory used for send/recv queues */
121 void *dma_va;
122 dma_addr_t dma_pa;
123 size_t dma_size;
124
125 /* pointer to hardware device info */
126 struct ilo_hwinfo *ilo_hw;
127
128 /* usage count, to allow for shared ccb's */
129 int ccb_cnt;
130
131 /* open wanted exclusive access to this ccb */
132 int ccb_excl;
133};
134
135/*
136 * FIFO queue structure, shared with hw.
137 */
138#define ILO_START_ALIGN 4096
139#define ILO_CACHE_SZ 128
140struct fifo {
141 u64 nrents; /* user requested number of fifo entries */
142 u64 imask; /* mask to extract valid fifo index */
143 u64 merge; /* O/C bits to merge in during enqueue operation */
144 u64 reset; /* set to non-zero when the target device resets */
145 u8 pad_0[ILO_CACHE_SZ - (sizeof(u64) * 4)];
146
147 u64 head;
148 u8 pad_1[ILO_CACHE_SZ - (sizeof(u64))];
149
150 u64 tail;
151 u8 pad_2[ILO_CACHE_SZ - (sizeof(u64))];
152
153 u64 fifobar[1];
154};
155
156/* convert between struct fifo, and the fifobar, which is saved in the ccb */
157#define FIFOHANDLESIZE (sizeof(struct fifo) - sizeof(u64))
158#define FIFOBARTOHANDLE(_fifo) \
159 ((struct fifo *)(((char *)(_fifo)) - FIFOHANDLESIZE))
160
161/* the number of qwords to consume from the entry descriptor */
162#define ENTRY_BITPOS_QWORDS 0
163/* descriptor index number (within a specified queue) */
164#define ENTRY_BITPOS_DESCRIPTOR 10
165/* state bit, fifo entry consumed by consumer */
166#define ENTRY_BITPOS_C 22
167/* state bit, fifo entry is occupied */
168#define ENTRY_BITPOS_O 23
169
170#define ENTRY_BITS_QWORDS 10
171#define ENTRY_BITS_DESCRIPTOR 12
172#define ENTRY_BITS_C 1
173#define ENTRY_BITS_O 1
174#define ENTRY_BITS_TOTAL \
175 (ENTRY_BITS_C + ENTRY_BITS_O + \
176 ENTRY_BITS_QWORDS + ENTRY_BITS_DESCRIPTOR)
177
178/* extract various entry fields */
179#define ENTRY_MASK ((1 << ENTRY_BITS_TOTAL) - 1)
180#define ENTRY_MASK_C (((1 << ENTRY_BITS_C) - 1) << ENTRY_BITPOS_C)
181#define ENTRY_MASK_O (((1 << ENTRY_BITS_O) - 1) << ENTRY_BITPOS_O)
182#define ENTRY_MASK_QWORDS \
183 (((1 << ENTRY_BITS_QWORDS) - 1) << ENTRY_BITPOS_QWORDS)
184#define ENTRY_MASK_DESCRIPTOR \
185 (((1 << ENTRY_BITS_DESCRIPTOR) - 1) << ENTRY_BITPOS_DESCRIPTOR)
186
187#define ENTRY_MASK_NOSTATE (ENTRY_MASK >> (ENTRY_BITS_C + ENTRY_BITS_O))
188
189#endif /* __HPILO_H */
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index fa394104339c..e4ff50b95a5e 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -102,7 +102,6 @@
102#include <linux/nmi.h> 102#include <linux/nmi.h>
103#include <linux/delay.h> 103#include <linux/delay.h>
104#include <linux/kthread.h> 104#include <linux/kthread.h>
105#include <linux/delay.h>
106 105
107#define v1printk(a...) do { \ 106#define v1printk(a...) do { \
108 if (verbose) \ 107 if (verbose) \
@@ -119,7 +118,6 @@
119 } while (0) 118 } while (0)
120#define MAX_CONFIG_LEN 40 119#define MAX_CONFIG_LEN 40
121 120
122static const char hexchars[] = "0123456789abcdef";
123static struct kgdb_io kgdbts_io_ops; 121static struct kgdb_io kgdbts_io_ops;
124static char get_buf[BUFMAX]; 122static char get_buf[BUFMAX];
125static int get_buf_cnt; 123static int get_buf_cnt;
@@ -131,6 +129,8 @@ static int repeat_test;
131static int test_complete; 129static int test_complete;
132static int send_ack; 130static int send_ack;
133static int final_ack; 131static int final_ack;
132static int force_hwbrks;
133static int hwbreaks_ok;
134static int hw_break_val; 134static int hw_break_val;
135static int hw_break_val2; 135static int hw_break_val2;
136#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC) 136#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC)
@@ -234,12 +234,12 @@ static void break_helper(char *bp_type, char *arg, unsigned long vaddr)
234 234
235static void sw_break(char *arg) 235static void sw_break(char *arg)
236{ 236{
237 break_helper("Z0", arg, 0); 237 break_helper(force_hwbrks ? "Z1" : "Z0", arg, 0);
238} 238}
239 239
240static void sw_rem_break(char *arg) 240static void sw_rem_break(char *arg)
241{ 241{
242 break_helper("z0", arg, 0); 242 break_helper(force_hwbrks ? "z1" : "z0", arg, 0);
243} 243}
244 244
245static void hw_break(char *arg) 245static void hw_break(char *arg)
@@ -619,8 +619,8 @@ static void fill_get_buf(char *buf)
619 count++; 619 count++;
620 } 620 }
621 strcat(get_buf, "#"); 621 strcat(get_buf, "#");
622 get_buf[count + 2] = hexchars[checksum >> 4]; 622 get_buf[count + 2] = hex_asc_hi(checksum);
623 get_buf[count + 3] = hexchars[checksum & 0xf]; 623 get_buf[count + 3] = hex_asc_lo(checksum);
624 get_buf[count + 4] = '\0'; 624 get_buf[count + 4] = '\0';
625 v2printk("get%i: %s\n", ts.idx, get_buf); 625 v2printk("get%i: %s\n", ts.idx, get_buf);
626} 626}
@@ -781,6 +781,8 @@ static void run_breakpoint_test(int is_hw_breakpoint)
781 return; 781 return;
782 782
783 eprintk("kgdbts: ERROR %s test failed\n", ts.name); 783 eprintk("kgdbts: ERROR %s test failed\n", ts.name);
784 if (is_hw_breakpoint)
785 hwbreaks_ok = 0;
784} 786}
785 787
786static void run_hw_break_test(int is_write_test) 788static void run_hw_break_test(int is_write_test)
@@ -798,9 +800,11 @@ static void run_hw_break_test(int is_write_test)
798 kgdb_breakpoint(); 800 kgdb_breakpoint();
799 hw_break_val_access(); 801 hw_break_val_access();
800 if (is_write_test) { 802 if (is_write_test) {
801 if (test_complete == 2) 803 if (test_complete == 2) {
802 eprintk("kgdbts: ERROR %s broke on access\n", 804 eprintk("kgdbts: ERROR %s broke on access\n",
803 ts.name); 805 ts.name);
806 hwbreaks_ok = 0;
807 }
804 hw_break_val_write(); 808 hw_break_val_write();
805 } 809 }
806 kgdb_breakpoint(); 810 kgdb_breakpoint();
@@ -809,6 +813,7 @@ static void run_hw_break_test(int is_write_test)
809 return; 813 return;
810 814
811 eprintk("kgdbts: ERROR %s test failed\n", ts.name); 815 eprintk("kgdbts: ERROR %s test failed\n", ts.name);
816 hwbreaks_ok = 0;
812} 817}
813 818
814static void run_nmi_sleep_test(int nmi_sleep) 819static void run_nmi_sleep_test(int nmi_sleep)
@@ -912,6 +917,7 @@ static void kgdbts_run_tests(void)
912 917
913 /* All HW break point tests */ 918 /* All HW break point tests */
914 if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) { 919 if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) {
920 hwbreaks_ok = 1;
915 v1printk("kgdbts:RUN hw breakpoint test\n"); 921 v1printk("kgdbts:RUN hw breakpoint test\n");
916 run_breakpoint_test(1); 922 run_breakpoint_test(1);
917 v1printk("kgdbts:RUN hw write breakpoint test\n"); 923 v1printk("kgdbts:RUN hw write breakpoint test\n");
@@ -925,6 +931,19 @@ static void kgdbts_run_tests(void)
925 run_nmi_sleep_test(nmi_sleep); 931 run_nmi_sleep_test(nmi_sleep);
926 } 932 }
927 933
934#ifdef CONFIG_DEBUG_RODATA
935 /* Until there is an api to write to read-only text segments, use
936 * HW breakpoints for the remainder of any tests, else print a
937 * failure message if hw breakpoints do not work.
938 */
939 if (!(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT && hwbreaks_ok)) {
940 eprintk("kgdbts: HW breakpoints do not work,"
941 "skipping remaining tests\n");
942 return;
943 }
944 force_hwbrks = 1;
945#endif /* CONFIG_DEBUG_RODATA */
946
928 /* If the do_fork test is run it will be the last test that is 947 /* If the do_fork test is run it will be the last test that is
929 * executed because a kernel thread will be spawned at the very 948 * executed because a kernel thread will be spawned at the very
930 * end to unregister the debug hooks. 949 * end to unregister the debug hooks.
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index 71d1c84e2fa8..daf585689ce3 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -22,6 +22,7 @@
22#include <linux/interrupt.h> 22#include <linux/interrupt.h>
23#include <linux/cdev.h> 23#include <linux/cdev.h>
24#include <linux/phantom.h> 24#include <linux/phantom.h>
25#include <linux/smp_lock.h>
25 26
26#include <asm/atomic.h> 27#include <asm/atomic.h>
27#include <asm/io.h> 28#include <asm/io.h>
@@ -212,13 +213,17 @@ static int phantom_open(struct inode *inode, struct file *file)
212 struct phantom_device *dev = container_of(inode->i_cdev, 213 struct phantom_device *dev = container_of(inode->i_cdev,
213 struct phantom_device, cdev); 214 struct phantom_device, cdev);
214 215
216 lock_kernel();
215 nonseekable_open(inode, file); 217 nonseekable_open(inode, file);
216 218
217 if (mutex_lock_interruptible(&dev->open_lock)) 219 if (mutex_lock_interruptible(&dev->open_lock)) {
220 unlock_kernel();
218 return -ERESTARTSYS; 221 return -ERESTARTSYS;
222 }
219 223
220 if (dev->opened) { 224 if (dev->opened) {
221 mutex_unlock(&dev->open_lock); 225 mutex_unlock(&dev->open_lock);
226 unlock_kernel();
222 return -EINVAL; 227 return -EINVAL;
223 } 228 }
224 229
@@ -229,7 +234,7 @@ static int phantom_open(struct inode *inode, struct file *file)
229 atomic_set(&dev->counter, 0); 234 atomic_set(&dev->counter, 0);
230 dev->opened++; 235 dev->opened++;
231 mutex_unlock(&dev->open_lock); 236 mutex_unlock(&dev->open_lock);
232 237 unlock_kernel();
233 return 0; 238 return 0;
234} 239}
235 240
@@ -394,8 +399,9 @@ static int __devinit phantom_probe(struct pci_dev *pdev,
394 goto err_irq; 399 goto err_irq;
395 } 400 }
396 401
397 if (IS_ERR(device_create(phantom_class, &pdev->dev, MKDEV(phantom_major, 402 if (IS_ERR(device_create_drvdata(phantom_class, &pdev->dev,
398 minor), "phantom%u", minor))) 403 MKDEV(phantom_major, minor),
404 NULL, "phantom%u", minor)))
399 dev_err(&pdev->dev, "can't create device\n"); 405 dev_err(&pdev->dev, "can't create device\n");
400 406
401 pci_set_drvdata(pdev, pht); 407 pci_set_drvdata(pdev, pht);
@@ -557,6 +563,6 @@ module_init(phantom_init);
557module_exit(phantom_exit); 563module_exit(phantom_exit);
558 564
559MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>"); 565MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>");
560MODULE_DESCRIPTION("Sensable Phantom driver"); 566MODULE_DESCRIPTION("Sensable Phantom driver (PCI devices)");
561MODULE_LICENSE("GPL"); 567MODULE_LICENSE("GPL");
562MODULE_VERSION(PHANTOM_VERSION); 568MODULE_VERSION(PHANTOM_VERSION);
diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c
index 08256ed0d9a6..579b01ff82d4 100644
--- a/drivers/misc/sgi-xp/xpc_main.c
+++ b/drivers/misc/sgi-xp/xpc_main.c
@@ -229,10 +229,11 @@ xpc_hb_checker(void *ignore)
229 int last_IRQ_count = 0; 229 int last_IRQ_count = 0;
230 int new_IRQ_count; 230 int new_IRQ_count;
231 int force_IRQ = 0; 231 int force_IRQ = 0;
232 cpumask_of_cpu_ptr(cpumask, XPC_HB_CHECK_CPU);
232 233
233 /* this thread was marked active by xpc_hb_init() */ 234 /* this thread was marked active by xpc_hb_init() */
234 235
235 set_cpus_allowed(current, cpumask_of_cpu(XPC_HB_CHECK_CPU)); 236 set_cpus_allowed_ptr(current, cpumask);
236 237
237 /* set our heartbeating to other partitions into motion */ 238 /* set our heartbeating to other partitions into motion */
238 xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ); 239 xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ);
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index 00e48e2a9c11..60775be22822 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -46,6 +46,7 @@
46#include <linux/module.h> 46#include <linux/module.h>
47#include <linux/moduleparam.h> 47#include <linux/moduleparam.h>
48#include <linux/init.h> 48#include <linux/init.h>
49#include <linux/smp_lock.h>
49#include <linux/types.h> 50#include <linux/types.h>
50#include <linux/backlight.h> 51#include <linux/backlight.h>
51#include <linux/platform_device.h> 52#include <linux/platform_device.h>
@@ -1927,8 +1928,10 @@ static int sonypi_misc_release(struct inode *inode, struct file *file)
1927static int sonypi_misc_open(struct inode *inode, struct file *file) 1928static int sonypi_misc_open(struct inode *inode, struct file *file)
1928{ 1929{
1929 /* Flush input queue on first open */ 1930 /* Flush input queue on first open */
1931 lock_kernel();
1930 if (atomic_inc_return(&sonypi_compat.open_count) == 1) 1932 if (atomic_inc_return(&sonypi_compat.open_count) == 1)
1931 kfifo_reset(sonypi_compat.fifo); 1933 kfifo_reset(sonypi_compat.fifo);
1934 unlock_kernel();
1932 return 0; 1935 return 0;
1933} 1936}
1934 1937
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index a0ce0b2fa03e..d3eb7903c346 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -21,7 +21,7 @@
21 * 02110-1301, USA. 21 * 02110-1301, USA.
22 */ 22 */
23 23
24#define TPACPI_VERSION "0.20" 24#define TPACPI_VERSION "0.21"
25#define TPACPI_SYSFS_VERSION 0x020200 25#define TPACPI_SYSFS_VERSION 0x020200
26 26
27/* 27/*
@@ -68,6 +68,7 @@
68#include <linux/hwmon-sysfs.h> 68#include <linux/hwmon-sysfs.h>
69#include <linux/input.h> 69#include <linux/input.h>
70#include <linux/leds.h> 70#include <linux/leds.h>
71#include <linux/rfkill.h>
71#include <asm/uaccess.h> 72#include <asm/uaccess.h>
72 73
73#include <linux/dmi.h> 74#include <linux/dmi.h>
@@ -144,6 +145,12 @@ enum {
144 145
145#define TPACPI_MAX_ACPI_ARGS 3 146#define TPACPI_MAX_ACPI_ARGS 3
146 147
148/* rfkill switches */
149enum {
150 TPACPI_RFK_BLUETOOTH_SW_ID = 0,
151 TPACPI_RFK_WWAN_SW_ID,
152};
153
147/* Debugging */ 154/* Debugging */
148#define TPACPI_LOG TPACPI_FILE ": " 155#define TPACPI_LOG TPACPI_FILE ": "
149#define TPACPI_ERR KERN_ERR TPACPI_LOG 156#define TPACPI_ERR KERN_ERR TPACPI_LOG
@@ -905,6 +912,43 @@ static int __init tpacpi_check_std_acpi_brightness_support(void)
905 return 0; 912 return 0;
906} 913}
907 914
915static int __init tpacpi_new_rfkill(const unsigned int id,
916 struct rfkill **rfk,
917 const enum rfkill_type rfktype,
918 const char *name,
919 int (*toggle_radio)(void *, enum rfkill_state),
920 int (*get_state)(void *, enum rfkill_state *))
921{
922 int res;
923 enum rfkill_state initial_state;
924
925 *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype);
926 if (!*rfk) {
927 printk(TPACPI_ERR
928 "failed to allocate memory for rfkill class\n");
929 return -ENOMEM;
930 }
931
932 (*rfk)->name = name;
933 (*rfk)->get_state = get_state;
934 (*rfk)->toggle_radio = toggle_radio;
935
936 if (!get_state(NULL, &initial_state))
937 (*rfk)->state = initial_state;
938
939 res = rfkill_register(*rfk);
940 if (res < 0) {
941 printk(TPACPI_ERR
942 "failed to register %s rfkill switch: %d\n",
943 name, res);
944 rfkill_free(*rfk);
945 *rfk = NULL;
946 return res;
947 }
948
949 return 0;
950}
951
908/************************************************************************* 952/*************************************************************************
909 * thinkpad-acpi driver attributes 953 * thinkpad-acpi driver attributes
910 */ 954 */
@@ -1285,21 +1329,6 @@ static int hotkey_status_set(int status)
1285 return 0; 1329 return 0;
1286} 1330}
1287 1331
1288static void tpacpi_input_send_radiosw(void)
1289{
1290 int wlsw;
1291
1292 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
1293 mutex_lock(&tpacpi_inputdev_send_mutex);
1294
1295 input_report_switch(tpacpi_inputdev,
1296 SW_RADIO, !!wlsw);
1297 input_sync(tpacpi_inputdev);
1298
1299 mutex_unlock(&tpacpi_inputdev_send_mutex);
1300 }
1301}
1302
1303static void tpacpi_input_send_tabletsw(void) 1332static void tpacpi_input_send_tabletsw(void)
1304{ 1333{
1305 int state; 1334 int state;
@@ -1921,6 +1950,53 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
1921 &dev_attr_hotkey_wakeup_hotunplug_complete.attr, 1950 &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
1922}; 1951};
1923 1952
1953static void bluetooth_update_rfk(void);
1954static void wan_update_rfk(void);
1955static void tpacpi_send_radiosw_update(void)
1956{
1957 int wlsw;
1958
1959 /* Sync these BEFORE sending any rfkill events */
1960 if (tp_features.bluetooth)
1961 bluetooth_update_rfk();
1962 if (tp_features.wan)
1963 wan_update_rfk();
1964
1965 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
1966 mutex_lock(&tpacpi_inputdev_send_mutex);
1967
1968 input_report_switch(tpacpi_inputdev,
1969 SW_RFKILL_ALL, !!wlsw);
1970 input_sync(tpacpi_inputdev);
1971
1972 mutex_unlock(&tpacpi_inputdev_send_mutex);
1973 }
1974 hotkey_radio_sw_notify_change();
1975}
1976
1977static void hotkey_exit(void)
1978{
1979#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1980 hotkey_poll_stop_sync();
1981#endif
1982
1983 if (hotkey_dev_attributes)
1984 delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
1985
1986 kfree(hotkey_keycode_map);
1987
1988 if (tp_features.hotkey) {
1989 dbg_printk(TPACPI_DBG_EXIT,
1990 "restoring original hot key mask\n");
1991 /* no short-circuit boolean operator below! */
1992 if ((hotkey_mask_set(hotkey_orig_mask) |
1993 hotkey_status_set(hotkey_orig_status)) != 0)
1994 printk(TPACPI_ERR
1995 "failed to restore hot key mask "
1996 "to BIOS defaults\n");
1997 }
1998}
1999
1924static int __init hotkey_init(struct ibm_init_struct *iibm) 2000static int __init hotkey_init(struct ibm_init_struct *iibm)
1925{ 2001{
1926 /* Requirements for changing the default keymaps: 2002 /* Requirements for changing the default keymaps:
@@ -2060,226 +2136,221 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
2060 vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n", 2136 vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",
2061 str_supported(tp_features.hotkey)); 2137 str_supported(tp_features.hotkey));
2062 2138
2063 if (tp_features.hotkey) { 2139 if (!tp_features.hotkey)
2064 hotkey_dev_attributes = create_attr_set(13, NULL); 2140 return 1;
2065 if (!hotkey_dev_attributes)
2066 return -ENOMEM;
2067 res = add_many_to_attr_set(hotkey_dev_attributes,
2068 hotkey_attributes,
2069 ARRAY_SIZE(hotkey_attributes));
2070 if (res)
2071 return res;
2072 2141
2073 /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, 2142 hotkey_dev_attributes = create_attr_set(13, NULL);
2074 A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking 2143 if (!hotkey_dev_attributes)
2075 for HKEY interface version 0x100 */ 2144 return -ENOMEM;
2076 if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { 2145 res = add_many_to_attr_set(hotkey_dev_attributes,
2077 if ((hkeyv >> 8) != 1) { 2146 hotkey_attributes,
2078 printk(TPACPI_ERR "unknown version of the " 2147 ARRAY_SIZE(hotkey_attributes));
2079 "HKEY interface: 0x%x\n", hkeyv); 2148 if (res)
2080 printk(TPACPI_ERR "please report this to %s\n", 2149 goto err_exit;
2081 TPACPI_MAIL); 2150
2082 } else { 2151 /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
2083 /* 2152 A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking
2084 * MHKV 0x100 in A31, R40, R40e, 2153 for HKEY interface version 0x100 */
2085 * T4x, X31, and later 2154 if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
2086 */ 2155 if ((hkeyv >> 8) != 1) {
2087 tp_features.hotkey_mask = 1; 2156 printk(TPACPI_ERR "unknown version of the "
2088 } 2157 "HKEY interface: 0x%x\n", hkeyv);
2158 printk(TPACPI_ERR "please report this to %s\n",
2159 TPACPI_MAIL);
2160 } else {
2161 /*
2162 * MHKV 0x100 in A31, R40, R40e,
2163 * T4x, X31, and later
2164 */
2165 tp_features.hotkey_mask = 1;
2089 } 2166 }
2167 }
2090 2168
2091 vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", 2169 vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
2092 str_supported(tp_features.hotkey_mask)); 2170 str_supported(tp_features.hotkey_mask));
2093 2171
2094 if (tp_features.hotkey_mask) { 2172 if (tp_features.hotkey_mask) {
2095 if (!acpi_evalf(hkey_handle, &hotkey_all_mask, 2173 if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
2096 "MHKA", "qd")) { 2174 "MHKA", "qd")) {
2097 printk(TPACPI_ERR 2175 printk(TPACPI_ERR
2098 "missing MHKA handler, " 2176 "missing MHKA handler, "
2099 "please report this to %s\n", 2177 "please report this to %s\n",
2100 TPACPI_MAIL); 2178 TPACPI_MAIL);
2101 /* FN+F12, FN+F4, FN+F3 */ 2179 /* FN+F12, FN+F4, FN+F3 */
2102 hotkey_all_mask = 0x080cU; 2180 hotkey_all_mask = 0x080cU;
2103 }
2104 } 2181 }
2182 }
2105 2183
2106 /* hotkey_source_mask *must* be zero for 2184 /* hotkey_source_mask *must* be zero for
2107 * the first hotkey_mask_get */ 2185 * the first hotkey_mask_get */
2108 res = hotkey_status_get(&hotkey_orig_status); 2186 res = hotkey_status_get(&hotkey_orig_status);
2109 if (!res && tp_features.hotkey_mask) { 2187 if (res)
2110 res = hotkey_mask_get(); 2188 goto err_exit;
2111 hotkey_orig_mask = hotkey_mask; 2189
2112 if (!res) { 2190 if (tp_features.hotkey_mask) {
2113 res = add_many_to_attr_set( 2191 res = hotkey_mask_get();
2114 hotkey_dev_attributes, 2192 if (res)
2115 hotkey_mask_attributes, 2193 goto err_exit;
2116 ARRAY_SIZE(hotkey_mask_attributes)); 2194
2117 } 2195 hotkey_orig_mask = hotkey_mask;
2118 } 2196 res = add_many_to_attr_set(
2197 hotkey_dev_attributes,
2198 hotkey_mask_attributes,
2199 ARRAY_SIZE(hotkey_mask_attributes));
2200 if (res)
2201 goto err_exit;
2202 }
2119 2203
2120#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL 2204#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
2121 if (tp_features.hotkey_mask) { 2205 if (tp_features.hotkey_mask) {
2122 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK 2206 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
2123 & ~hotkey_all_mask; 2207 & ~hotkey_all_mask;
2124 } else { 2208 } else {
2125 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; 2209 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK;
2126 } 2210 }
2127 2211
2128 vdbg_printk(TPACPI_DBG_INIT, 2212 vdbg_printk(TPACPI_DBG_INIT,
2129 "hotkey source mask 0x%08x, polling freq %d\n", 2213 "hotkey source mask 0x%08x, polling freq %d\n",
2130 hotkey_source_mask, hotkey_poll_freq); 2214 hotkey_source_mask, hotkey_poll_freq);
2131#endif 2215#endif
2132 2216
2133 /* Not all thinkpads have a hardware radio switch */ 2217 /* Not all thinkpads have a hardware radio switch */
2134 if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { 2218 if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
2135 tp_features.hotkey_wlsw = 1; 2219 tp_features.hotkey_wlsw = 1;
2136 printk(TPACPI_INFO 2220 printk(TPACPI_INFO
2137 "radio switch found; radios are %s\n", 2221 "radio switch found; radios are %s\n",
2138 enabled(status, 0)); 2222 enabled(status, 0));
2139 res = add_to_attr_set(hotkey_dev_attributes, 2223 }
2140 &dev_attr_hotkey_radio_sw.attr); 2224 if (tp_features.hotkey_wlsw)
2141 } 2225 res = add_to_attr_set(hotkey_dev_attributes,
2226 &dev_attr_hotkey_radio_sw.attr);
2142 2227
2143 /* For X41t, X60t, X61t Tablets... */ 2228 /* For X41t, X60t, X61t Tablets... */
2144 if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { 2229 if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
2145 tp_features.hotkey_tablet = 1; 2230 tp_features.hotkey_tablet = 1;
2146 printk(TPACPI_INFO 2231 printk(TPACPI_INFO
2147 "possible tablet mode switch found; " 2232 "possible tablet mode switch found; "
2148 "ThinkPad in %s mode\n", 2233 "ThinkPad in %s mode\n",
2149 (status & TP_HOTKEY_TABLET_MASK)? 2234 (status & TP_HOTKEY_TABLET_MASK)?
2150 "tablet" : "laptop"); 2235 "tablet" : "laptop");
2151 res = add_to_attr_set(hotkey_dev_attributes, 2236 res = add_to_attr_set(hotkey_dev_attributes,
2152 &dev_attr_hotkey_tablet_mode.attr); 2237 &dev_attr_hotkey_tablet_mode.attr);
2153 } 2238 }
2154 2239
2155 if (!res) 2240 if (!res)
2156 res = register_attr_set_with_sysfs( 2241 res = register_attr_set_with_sysfs(
2157 hotkey_dev_attributes, 2242 hotkey_dev_attributes,
2158 &tpacpi_pdev->dev.kobj); 2243 &tpacpi_pdev->dev.kobj);
2159 if (res) 2244 if (res)
2160 return res; 2245 goto err_exit;
2161 2246
2162 /* Set up key map */ 2247 /* Set up key map */
2163 2248
2164 hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, 2249 hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
2165 GFP_KERNEL); 2250 GFP_KERNEL);
2166 if (!hotkey_keycode_map) { 2251 if (!hotkey_keycode_map) {
2167 printk(TPACPI_ERR 2252 printk(TPACPI_ERR
2168 "failed to allocate memory for key map\n"); 2253 "failed to allocate memory for key map\n");
2169 return -ENOMEM; 2254 res = -ENOMEM;
2170 } 2255 goto err_exit;
2256 }
2171 2257
2172 if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { 2258 if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
2173 dbg_printk(TPACPI_DBG_INIT, 2259 dbg_printk(TPACPI_DBG_INIT,
2174 "using Lenovo default hot key map\n"); 2260 "using Lenovo default hot key map\n");
2175 memcpy(hotkey_keycode_map, &lenovo_keycode_map, 2261 memcpy(hotkey_keycode_map, &lenovo_keycode_map,
2176 TPACPI_HOTKEY_MAP_SIZE); 2262 TPACPI_HOTKEY_MAP_SIZE);
2263 } else {
2264 dbg_printk(TPACPI_DBG_INIT,
2265 "using IBM default hot key map\n");
2266 memcpy(hotkey_keycode_map, &ibm_keycode_map,
2267 TPACPI_HOTKEY_MAP_SIZE);
2268 }
2269
2270 set_bit(EV_KEY, tpacpi_inputdev->evbit);
2271 set_bit(EV_MSC, tpacpi_inputdev->evbit);
2272 set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
2273 tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
2274 tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
2275 tpacpi_inputdev->keycode = hotkey_keycode_map;
2276 for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
2277 if (hotkey_keycode_map[i] != KEY_RESERVED) {
2278 set_bit(hotkey_keycode_map[i],
2279 tpacpi_inputdev->keybit);
2177 } else { 2280 } else {
2178 dbg_printk(TPACPI_DBG_INIT, 2281 if (i < sizeof(hotkey_reserved_mask)*8)
2179 "using IBM default hot key map\n"); 2282 hotkey_reserved_mask |= 1 << i;
2180 memcpy(hotkey_keycode_map, &ibm_keycode_map,
2181 TPACPI_HOTKEY_MAP_SIZE);
2182 }
2183
2184 set_bit(EV_KEY, tpacpi_inputdev->evbit);
2185 set_bit(EV_MSC, tpacpi_inputdev->evbit);
2186 set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
2187 tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
2188 tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
2189 tpacpi_inputdev->keycode = hotkey_keycode_map;
2190 for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
2191 if (hotkey_keycode_map[i] != KEY_RESERVED) {
2192 set_bit(hotkey_keycode_map[i],
2193 tpacpi_inputdev->keybit);
2194 } else {
2195 if (i < sizeof(hotkey_reserved_mask)*8)
2196 hotkey_reserved_mask |= 1 << i;
2197 }
2198 } 2283 }
2284 }
2199 2285
2200 if (tp_features.hotkey_wlsw) { 2286 if (tp_features.hotkey_wlsw) {
2201 set_bit(EV_SW, tpacpi_inputdev->evbit); 2287 set_bit(EV_SW, tpacpi_inputdev->evbit);
2202 set_bit(SW_RADIO, tpacpi_inputdev->swbit); 2288 set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit);
2203 } 2289 }
2204 if (tp_features.hotkey_tablet) { 2290 if (tp_features.hotkey_tablet) {
2205 set_bit(EV_SW, tpacpi_inputdev->evbit); 2291 set_bit(EV_SW, tpacpi_inputdev->evbit);
2206 set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); 2292 set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
2207 } 2293 }
2208 2294
2209 /* Do not issue duplicate brightness change events to 2295 /* Do not issue duplicate brightness change events to
2210 * userspace */ 2296 * userspace */
2211 if (!tp_features.bright_acpimode) 2297 if (!tp_features.bright_acpimode)
2212 /* update bright_acpimode... */ 2298 /* update bright_acpimode... */
2213 tpacpi_check_std_acpi_brightness_support(); 2299 tpacpi_check_std_acpi_brightness_support();
2214
2215 if (tp_features.bright_acpimode) {
2216 printk(TPACPI_INFO
2217 "This ThinkPad has standard ACPI backlight "
2218 "brightness control, supported by the ACPI "
2219 "video driver\n");
2220 printk(TPACPI_NOTICE
2221 "Disabling thinkpad-acpi brightness events "
2222 "by default...\n");
2223
2224 /* The hotkey_reserved_mask change below is not
2225 * necessary while the keys are at KEY_RESERVED in the
2226 * default map, but better safe than sorry, leave it
2227 * here as a marker of what we have to do, especially
2228 * when we finally become able to set this at runtime
2229 * on response to X.org requests */
2230 hotkey_reserved_mask |=
2231 (1 << TP_ACPI_HOTKEYSCAN_FNHOME)
2232 | (1 << TP_ACPI_HOTKEYSCAN_FNEND);
2233 }
2234 2300
2235 dbg_printk(TPACPI_DBG_INIT, 2301 if (tp_features.bright_acpimode) {
2236 "enabling hot key handling\n"); 2302 printk(TPACPI_INFO
2237 res = hotkey_status_set(1); 2303 "This ThinkPad has standard ACPI backlight "
2238 if (res) 2304 "brightness control, supported by the ACPI "
2239 return res; 2305 "video driver\n");
2240 res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) 2306 printk(TPACPI_NOTICE
2241 & ~hotkey_reserved_mask) 2307 "Disabling thinkpad-acpi brightness events "
2242 | hotkey_orig_mask); 2308 "by default...\n");
2243 if (res < 0 && res != -ENXIO) 2309
2244 return res; 2310 /* The hotkey_reserved_mask change below is not
2311 * necessary while the keys are at KEY_RESERVED in the
2312 * default map, but better safe than sorry, leave it
2313 * here as a marker of what we have to do, especially
2314 * when we finally become able to set this at runtime
2315 * on response to X.org requests */
2316 hotkey_reserved_mask |=
2317 (1 << TP_ACPI_HOTKEYSCAN_FNHOME)
2318 | (1 << TP_ACPI_HOTKEYSCAN_FNEND);
2319 }
2320
2321 dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n");
2322 res = hotkey_status_set(1);
2323 if (res) {
2324 hotkey_exit();
2325 return res;
2326 }
2327 res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask)
2328 & ~hotkey_reserved_mask)
2329 | hotkey_orig_mask);
2330 if (res < 0 && res != -ENXIO) {
2331 hotkey_exit();
2332 return res;
2333 }
2245 2334
2246 dbg_printk(TPACPI_DBG_INIT, 2335 dbg_printk(TPACPI_DBG_INIT,
2247 "legacy hot key reporting over procfs %s\n", 2336 "legacy hot key reporting over procfs %s\n",
2248 (hotkey_report_mode < 2) ? 2337 (hotkey_report_mode < 2) ?
2249 "enabled" : "disabled"); 2338 "enabled" : "disabled");
2250 2339
2251 tpacpi_inputdev->open = &hotkey_inputdev_open; 2340 tpacpi_inputdev->open = &hotkey_inputdev_open;
2252 tpacpi_inputdev->close = &hotkey_inputdev_close; 2341 tpacpi_inputdev->close = &hotkey_inputdev_close;
2253 2342
2254 hotkey_poll_setup_safe(1); 2343 hotkey_poll_setup_safe(1);
2255 tpacpi_input_send_radiosw(); 2344 tpacpi_send_radiosw_update();
2256 tpacpi_input_send_tabletsw(); 2345 tpacpi_input_send_tabletsw();
2257 }
2258 2346
2259 return (tp_features.hotkey)? 0 : 1; 2347 return 0;
2260}
2261 2348
2262static void hotkey_exit(void) 2349err_exit:
2263{ 2350 delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
2264#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL 2351 hotkey_dev_attributes = NULL;
2265 hotkey_poll_stop_sync();
2266#endif
2267 2352
2268 if (tp_features.hotkey) { 2353 return (res < 0)? res : 1;
2269 dbg_printk(TPACPI_DBG_EXIT,
2270 "restoring original hot key mask\n");
2271 /* no short-circuit boolean operator below! */
2272 if ((hotkey_mask_set(hotkey_orig_mask) |
2273 hotkey_status_set(hotkey_orig_status)) != 0)
2274 printk(TPACPI_ERR
2275 "failed to restore hot key mask "
2276 "to BIOS defaults\n");
2277 }
2278
2279 if (hotkey_dev_attributes) {
2280 delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
2281 hotkey_dev_attributes = NULL;
2282 }
2283} 2354}
2284 2355
2285static void hotkey_notify(struct ibm_struct *ibm, u32 event) 2356static void hotkey_notify(struct ibm_struct *ibm, u32 event)
@@ -2402,8 +2473,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
2402 case 7: 2473 case 7:
2403 /* 0x7000-0x7FFF: misc */ 2474 /* 0x7000-0x7FFF: misc */
2404 if (tp_features.hotkey_wlsw && hkey == 0x7000) { 2475 if (tp_features.hotkey_wlsw && hkey == 0x7000) {
2405 tpacpi_input_send_radiosw(); 2476 tpacpi_send_radiosw_update();
2406 hotkey_radio_sw_notify_change();
2407 send_acpi_ev = 0; 2477 send_acpi_ev = 0;
2408 break; 2478 break;
2409 } 2479 }
@@ -2446,8 +2516,7 @@ static void hotkey_resume(void)
2446 printk(TPACPI_ERR 2516 printk(TPACPI_ERR
2447 "error while trying to read hot key mask " 2517 "error while trying to read hot key mask "
2448 "from firmware\n"); 2518 "from firmware\n");
2449 tpacpi_input_send_radiosw(); 2519 tpacpi_send_radiosw_update();
2450 hotkey_radio_sw_notify_change();
2451 hotkey_tablet_mode_notify_change(); 2520 hotkey_tablet_mode_notify_change();
2452 hotkey_wakeup_reason_notify_change(); 2521 hotkey_wakeup_reason_notify_change();
2453 hotkey_wakeup_hotunplug_complete_notify_change(); 2522 hotkey_wakeup_hotunplug_complete_notify_change();
@@ -2564,8 +2633,66 @@ enum {
2564 TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ 2633 TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
2565}; 2634};
2566 2635
2567static int bluetooth_get_radiosw(void); 2636static struct rfkill *tpacpi_bluetooth_rfkill;
2568static int bluetooth_set_radiosw(int radio_on); 2637
2638static int bluetooth_get_radiosw(void)
2639{
2640 int status;
2641
2642 if (!tp_features.bluetooth)
2643 return -ENODEV;
2644
2645 /* WLSW overrides bluetooth in firmware/hardware, reflect that */
2646 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
2647 return RFKILL_STATE_HARD_BLOCKED;
2648
2649 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
2650 return -EIO;
2651
2652 return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ?
2653 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
2654}
2655
2656static void bluetooth_update_rfk(void)
2657{
2658 int status;
2659
2660 if (!tpacpi_bluetooth_rfkill)
2661 return;
2662
2663 status = bluetooth_get_radiosw();
2664 if (status < 0)
2665 return;
2666 rfkill_force_state(tpacpi_bluetooth_rfkill, status);
2667}
2668
2669static int bluetooth_set_radiosw(int radio_on, int update_rfk)
2670{
2671 int status;
2672
2673 if (!tp_features.bluetooth)
2674 return -ENODEV;
2675
2676 /* WLSW overrides bluetooth in firmware/hardware, but there is no
2677 * reason to risk weird behaviour. */
2678 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
2679 && radio_on)
2680 return -EPERM;
2681
2682 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
2683 return -EIO;
2684 if (radio_on)
2685 status |= TP_ACPI_BLUETOOTH_RADIOSSW;
2686 else
2687 status &= ~TP_ACPI_BLUETOOTH_RADIOSSW;
2688 if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
2689 return -EIO;
2690
2691 if (update_rfk)
2692 bluetooth_update_rfk();
2693
2694 return 0;
2695}
2569 2696
2570/* sysfs bluetooth enable ---------------------------------------------- */ 2697/* sysfs bluetooth enable ---------------------------------------------- */
2571static ssize_t bluetooth_enable_show(struct device *dev, 2698static ssize_t bluetooth_enable_show(struct device *dev,
@@ -2578,7 +2705,8 @@ static ssize_t bluetooth_enable_show(struct device *dev,
2578 if (status < 0) 2705 if (status < 0)
2579 return status; 2706 return status;
2580 2707
2581 return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); 2708 return snprintf(buf, PAGE_SIZE, "%d\n",
2709 (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0);
2582} 2710}
2583 2711
2584static ssize_t bluetooth_enable_store(struct device *dev, 2712static ssize_t bluetooth_enable_store(struct device *dev,
@@ -2591,7 +2719,7 @@ static ssize_t bluetooth_enable_store(struct device *dev,
2591 if (parse_strtoul(buf, 1, &t)) 2719 if (parse_strtoul(buf, 1, &t))
2592 return -EINVAL; 2720 return -EINVAL;
2593 2721
2594 res = bluetooth_set_radiosw(t); 2722 res = bluetooth_set_radiosw(t, 1);
2595 2723
2596 return (res) ? res : count; 2724 return (res) ? res : count;
2597} 2725}
@@ -2611,6 +2739,31 @@ static const struct attribute_group bluetooth_attr_group = {
2611 .attrs = bluetooth_attributes, 2739 .attrs = bluetooth_attributes,
2612}; 2740};
2613 2741
2742static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state)
2743{
2744 int bts = bluetooth_get_radiosw();
2745
2746 if (bts < 0)
2747 return bts;
2748
2749 *state = bts;
2750 return 0;
2751}
2752
2753static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state)
2754{
2755 return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
2756}
2757
2758static void bluetooth_exit(void)
2759{
2760 if (tpacpi_bluetooth_rfkill)
2761 rfkill_unregister(tpacpi_bluetooth_rfkill);
2762
2763 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
2764 &bluetooth_attr_group);
2765}
2766
2614static int __init bluetooth_init(struct ibm_init_struct *iibm) 2767static int __init bluetooth_init(struct ibm_init_struct *iibm)
2615{ 2768{
2616 int res; 2769 int res;
@@ -2629,57 +2782,32 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
2629 str_supported(tp_features.bluetooth), 2782 str_supported(tp_features.bluetooth),
2630 status); 2783 status);
2631 2784
2632 if (tp_features.bluetooth) { 2785 if (tp_features.bluetooth &&
2633 if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { 2786 !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) {
2634 /* no bluetooth hardware present in system */ 2787 /* no bluetooth hardware present in system */
2635 tp_features.bluetooth = 0; 2788 tp_features.bluetooth = 0;
2636 dbg_printk(TPACPI_DBG_INIT, 2789 dbg_printk(TPACPI_DBG_INIT,
2637 "bluetooth hardware not installed\n"); 2790 "bluetooth hardware not installed\n");
2638 } else {
2639 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
2640 &bluetooth_attr_group);
2641 if (res)
2642 return res;
2643 }
2644 } 2791 }
2645 2792
2646 return (tp_features.bluetooth)? 0 : 1;
2647}
2648
2649static void bluetooth_exit(void)
2650{
2651 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
2652 &bluetooth_attr_group);
2653}
2654
2655static int bluetooth_get_radiosw(void)
2656{
2657 int status;
2658
2659 if (!tp_features.bluetooth) 2793 if (!tp_features.bluetooth)
2660 return -ENODEV; 2794 return 1;
2661
2662 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
2663 return -EIO;
2664
2665 return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0);
2666}
2667
2668static int bluetooth_set_radiosw(int radio_on)
2669{
2670 int status;
2671 2795
2672 if (!tp_features.bluetooth) 2796 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
2673 return -ENODEV; 2797 &bluetooth_attr_group);
2798 if (res)
2799 return res;
2674 2800
2675 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) 2801 res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID,
2676 return -EIO; 2802 &tpacpi_bluetooth_rfkill,
2677 if (radio_on) 2803 RFKILL_TYPE_BLUETOOTH,
2678 status |= TP_ACPI_BLUETOOTH_RADIOSSW; 2804 "tpacpi_bluetooth_sw",
2679 else 2805 tpacpi_bluetooth_rfk_set,
2680 status &= ~TP_ACPI_BLUETOOTH_RADIOSSW; 2806 tpacpi_bluetooth_rfk_get);
2681 if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) 2807 if (res) {
2682 return -EIO; 2808 bluetooth_exit();
2809 return res;
2810 }
2683 2811
2684 return 0; 2812 return 0;
2685} 2813}
@@ -2694,7 +2822,8 @@ static int bluetooth_read(char *p)
2694 len += sprintf(p + len, "status:\t\tnot supported\n"); 2822 len += sprintf(p + len, "status:\t\tnot supported\n");
2695 else { 2823 else {
2696 len += sprintf(p + len, "status:\t\t%s\n", 2824 len += sprintf(p + len, "status:\t\t%s\n",
2697 (status)? "enabled" : "disabled"); 2825 (status == RFKILL_STATE_UNBLOCKED) ?
2826 "enabled" : "disabled");
2698 len += sprintf(p + len, "commands:\tenable, disable\n"); 2827 len += sprintf(p + len, "commands:\tenable, disable\n");
2699 } 2828 }
2700 2829
@@ -2710,9 +2839,9 @@ static int bluetooth_write(char *buf)
2710 2839
2711 while ((cmd = next_cmd(&buf))) { 2840 while ((cmd = next_cmd(&buf))) {
2712 if (strlencmp(cmd, "enable") == 0) { 2841 if (strlencmp(cmd, "enable") == 0) {
2713 bluetooth_set_radiosw(1); 2842 bluetooth_set_radiosw(1, 1);
2714 } else if (strlencmp(cmd, "disable") == 0) { 2843 } else if (strlencmp(cmd, "disable") == 0) {
2715 bluetooth_set_radiosw(0); 2844 bluetooth_set_radiosw(0, 1);
2716 } else 2845 } else
2717 return -EINVAL; 2846 return -EINVAL;
2718 } 2847 }
@@ -2738,8 +2867,66 @@ enum {
2738 TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ 2867 TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
2739}; 2868};
2740 2869
2741static int wan_get_radiosw(void); 2870static struct rfkill *tpacpi_wan_rfkill;
2742static int wan_set_radiosw(int radio_on); 2871
2872static int wan_get_radiosw(void)
2873{
2874 int status;
2875
2876 if (!tp_features.wan)
2877 return -ENODEV;
2878
2879 /* WLSW overrides WWAN in firmware/hardware, reflect that */
2880 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
2881 return RFKILL_STATE_HARD_BLOCKED;
2882
2883 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
2884 return -EIO;
2885
2886 return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ?
2887 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
2888}
2889
2890static void wan_update_rfk(void)
2891{
2892 int status;
2893
2894 if (!tpacpi_wan_rfkill)
2895 return;
2896
2897 status = wan_get_radiosw();
2898 if (status < 0)
2899 return;
2900 rfkill_force_state(tpacpi_wan_rfkill, status);
2901}
2902
2903static int wan_set_radiosw(int radio_on, int update_rfk)
2904{
2905 int status;
2906
2907 if (!tp_features.wan)
2908 return -ENODEV;
2909
2910 /* WLSW overrides bluetooth in firmware/hardware, but there is no
2911 * reason to risk weird behaviour. */
2912 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
2913 && radio_on)
2914 return -EPERM;
2915
2916 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
2917 return -EIO;
2918 if (radio_on)
2919 status |= TP_ACPI_WANCARD_RADIOSSW;
2920 else
2921 status &= ~TP_ACPI_WANCARD_RADIOSSW;
2922 if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
2923 return -EIO;
2924
2925 if (update_rfk)
2926 wan_update_rfk();
2927
2928 return 0;
2929}
2743 2930
2744/* sysfs wan enable ---------------------------------------------------- */ 2931/* sysfs wan enable ---------------------------------------------------- */
2745static ssize_t wan_enable_show(struct device *dev, 2932static ssize_t wan_enable_show(struct device *dev,
@@ -2752,7 +2939,8 @@ static ssize_t wan_enable_show(struct device *dev,
2752 if (status < 0) 2939 if (status < 0)
2753 return status; 2940 return status;
2754 2941
2755 return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); 2942 return snprintf(buf, PAGE_SIZE, "%d\n",
2943 (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0);
2756} 2944}
2757 2945
2758static ssize_t wan_enable_store(struct device *dev, 2946static ssize_t wan_enable_store(struct device *dev,
@@ -2765,7 +2953,7 @@ static ssize_t wan_enable_store(struct device *dev,
2765 if (parse_strtoul(buf, 1, &t)) 2953 if (parse_strtoul(buf, 1, &t))
2766 return -EINVAL; 2954 return -EINVAL;
2767 2955
2768 res = wan_set_radiosw(t); 2956 res = wan_set_radiosw(t, 1);
2769 2957
2770 return (res) ? res : count; 2958 return (res) ? res : count;
2771} 2959}
@@ -2785,6 +2973,31 @@ static const struct attribute_group wan_attr_group = {
2785 .attrs = wan_attributes, 2973 .attrs = wan_attributes,
2786}; 2974};
2787 2975
2976static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state)
2977{
2978 int wans = wan_get_radiosw();
2979
2980 if (wans < 0)
2981 return wans;
2982
2983 *state = wans;
2984 return 0;
2985}
2986
2987static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state)
2988{
2989 return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
2990}
2991
2992static void wan_exit(void)
2993{
2994 if (tpacpi_wan_rfkill)
2995 rfkill_unregister(tpacpi_wan_rfkill);
2996
2997 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
2998 &wan_attr_group);
2999}
3000
2788static int __init wan_init(struct ibm_init_struct *iibm) 3001static int __init wan_init(struct ibm_init_struct *iibm)
2789{ 3002{
2790 int res; 3003 int res;
@@ -2801,57 +3014,32 @@ static int __init wan_init(struct ibm_init_struct *iibm)
2801 str_supported(tp_features.wan), 3014 str_supported(tp_features.wan),
2802 status); 3015 status);
2803 3016
2804 if (tp_features.wan) { 3017 if (tp_features.wan &&
2805 if (!(status & TP_ACPI_WANCARD_HWPRESENT)) { 3018 !(status & TP_ACPI_WANCARD_HWPRESENT)) {
2806 /* no wan hardware present in system */ 3019 /* no wan hardware present in system */
2807 tp_features.wan = 0; 3020 tp_features.wan = 0;
2808 dbg_printk(TPACPI_DBG_INIT, 3021 dbg_printk(TPACPI_DBG_INIT,
2809 "wan hardware not installed\n"); 3022 "wan hardware not installed\n");
2810 } else {
2811 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
2812 &wan_attr_group);
2813 if (res)
2814 return res;
2815 }
2816 } 3023 }
2817 3024
2818 return (tp_features.wan)? 0 : 1;
2819}
2820
2821static void wan_exit(void)
2822{
2823 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
2824 &wan_attr_group);
2825}
2826
2827static int wan_get_radiosw(void)
2828{
2829 int status;
2830
2831 if (!tp_features.wan) 3025 if (!tp_features.wan)
2832 return -ENODEV; 3026 return 1;
2833
2834 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
2835 return -EIO;
2836
2837 return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0);
2838}
2839
2840static int wan_set_radiosw(int radio_on)
2841{
2842 int status;
2843 3027
2844 if (!tp_features.wan) 3028 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
2845 return -ENODEV; 3029 &wan_attr_group);
3030 if (res)
3031 return res;
2846 3032
2847 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) 3033 res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID,
2848 return -EIO; 3034 &tpacpi_wan_rfkill,
2849 if (radio_on) 3035 RFKILL_TYPE_WWAN,
2850 status |= TP_ACPI_WANCARD_RADIOSSW; 3036 "tpacpi_wwan_sw",
2851 else 3037 tpacpi_wan_rfk_set,
2852 status &= ~TP_ACPI_WANCARD_RADIOSSW; 3038 tpacpi_wan_rfk_get);
2853 if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) 3039 if (res) {
2854 return -EIO; 3040 wan_exit();
3041 return res;
3042 }
2855 3043
2856 return 0; 3044 return 0;
2857} 3045}
@@ -2866,7 +3054,8 @@ static int wan_read(char *p)
2866 len += sprintf(p + len, "status:\t\tnot supported\n"); 3054 len += sprintf(p + len, "status:\t\tnot supported\n");
2867 else { 3055 else {
2868 len += sprintf(p + len, "status:\t\t%s\n", 3056 len += sprintf(p + len, "status:\t\t%s\n",
2869 (status)? "enabled" : "disabled"); 3057 (status == RFKILL_STATE_UNBLOCKED) ?
3058 "enabled" : "disabled");
2870 len += sprintf(p + len, "commands:\tenable, disable\n"); 3059 len += sprintf(p + len, "commands:\tenable, disable\n");
2871 } 3060 }
2872 3061
@@ -2882,9 +3071,9 @@ static int wan_write(char *buf)
2882 3071
2883 while ((cmd = next_cmd(&buf))) { 3072 while ((cmd = next_cmd(&buf))) {
2884 if (strlencmp(cmd, "enable") == 0) { 3073 if (strlencmp(cmd, "enable") == 0) {
2885 wan_set_radiosw(1); 3074 wan_set_radiosw(1, 1);
2886 } else if (strlencmp(cmd, "disable") == 0) { 3075 } else if (strlencmp(cmd, "disable") == 0) {
2887 wan_set_radiosw(0); 3076 wan_set_radiosw(0, 1);
2888 } else 3077 } else
2889 return -EINVAL; 3078 return -EINVAL;
2890 } 3079 }
@@ -3319,7 +3508,7 @@ static struct tpacpi_led_classdev tpacpi_led_thinklight = {
3319 3508
3320static int __init light_init(struct ibm_init_struct *iibm) 3509static int __init light_init(struct ibm_init_struct *iibm)
3321{ 3510{
3322 int rc = 0; 3511 int rc;
3323 3512
3324 vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); 3513 vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
3325 3514
@@ -3337,20 +3526,23 @@ static int __init light_init(struct ibm_init_struct *iibm)
3337 tp_features.light_status = 3526 tp_features.light_status =
3338 acpi_evalf(ec_handle, NULL, "KBLT", "qv"); 3527 acpi_evalf(ec_handle, NULL, "KBLT", "qv");
3339 3528
3340 vdbg_printk(TPACPI_DBG_INIT, "light is %s\n", 3529 vdbg_printk(TPACPI_DBG_INIT, "light is %s, light status is %s\n",
3341 str_supported(tp_features.light)); 3530 str_supported(tp_features.light),
3531 str_supported(tp_features.light_status));
3342 3532
3343 if (tp_features.light) { 3533 if (!tp_features.light)
3344 rc = led_classdev_register(&tpacpi_pdev->dev, 3534 return 1;
3345 &tpacpi_led_thinklight.led_classdev); 3535
3346 } 3536 rc = led_classdev_register(&tpacpi_pdev->dev,
3537 &tpacpi_led_thinklight.led_classdev);
3347 3538
3348 if (rc < 0) { 3539 if (rc < 0) {
3349 tp_features.light = 0; 3540 tp_features.light = 0;
3350 tp_features.light_status = 0; 3541 tp_features.light_status = 0;
3351 } else { 3542 } else {
3352 rc = (tp_features.light)? 0 : 1; 3543 rc = 0;
3353 } 3544 }
3545
3354 return rc; 3546 return rc;
3355} 3547}
3356 3548
@@ -3833,7 +4025,7 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
3833 "tpacpi::standby", 4025 "tpacpi::standby",
3834}; 4026};
3835 4027
3836static int led_get_status(unsigned int led) 4028static int led_get_status(const unsigned int led)
3837{ 4029{
3838 int status; 4030 int status;
3839 enum led_status_t led_s; 4031 enum led_status_t led_s;
@@ -3857,41 +4049,42 @@ static int led_get_status(unsigned int led)
3857 /* not reached */ 4049 /* not reached */
3858} 4050}
3859 4051
3860static int led_set_status(unsigned int led, enum led_status_t ledstatus) 4052static int led_set_status(const unsigned int led,
4053 const enum led_status_t ledstatus)
3861{ 4054{
3862 /* off, on, blink. Index is led_status_t */ 4055 /* off, on, blink. Index is led_status_t */
3863 static const int led_sled_arg1[] = { 0, 1, 3 }; 4056 static const unsigned int led_sled_arg1[] = { 0, 1, 3 };
3864 static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */ 4057 static const unsigned int led_led_arg1[] = { 0, 0x80, 0xc0 };
3865 static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
3866 static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
3867 4058
3868 int rc = 0; 4059 int rc = 0;
3869 4060
3870 switch (led_supported) { 4061 switch (led_supported) {
3871 case TPACPI_LED_570: 4062 case TPACPI_LED_570:
3872 /* 570 */ 4063 /* 570 */
3873 led = 1 << led; 4064 if (led > 7)
3874 if (!acpi_evalf(led_handle, NULL, NULL, "vdd", 4065 return -EINVAL;
3875 led, led_sled_arg1[ledstatus])) 4066 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
3876 rc = -EIO; 4067 (1 << led), led_sled_arg1[ledstatus]))
3877 break; 4068 rc = -EIO;
4069 break;
3878 case TPACPI_LED_OLD: 4070 case TPACPI_LED_OLD:
3879 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ 4071 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
3880 led = 1 << led; 4072 if (led > 7)
3881 rc = ec_write(TPACPI_LED_EC_HLMS, led); 4073 return -EINVAL;
3882 if (rc >= 0) 4074 rc = ec_write(TPACPI_LED_EC_HLMS, (1 << led));
3883 rc = ec_write(TPACPI_LED_EC_HLBL, 4075 if (rc >= 0)
3884 led * led_exp_hlbl[ledstatus]); 4076 rc = ec_write(TPACPI_LED_EC_HLBL,
3885 if (rc >= 0) 4077 (ledstatus == TPACPI_LED_BLINK) << led);
3886 rc = ec_write(TPACPI_LED_EC_HLCL, 4078 if (rc >= 0)
3887 led * led_exp_hlcl[ledstatus]); 4079 rc = ec_write(TPACPI_LED_EC_HLCL,
3888 break; 4080 (ledstatus != TPACPI_LED_OFF) << led);
4081 break;
3889 case TPACPI_LED_NEW: 4082 case TPACPI_LED_NEW:
3890 /* all others */ 4083 /* all others */
3891 if (!acpi_evalf(led_handle, NULL, NULL, "vdd", 4084 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
3892 led, led_led_arg1[ledstatus])) 4085 led, led_led_arg1[ledstatus]))
3893 rc = -EIO; 4086 rc = -EIO;
3894 break; 4087 break;
3895 default: 4088 default:
3896 rc = -ENXIO; 4089 rc = -ENXIO;
3897 } 4090 }
@@ -3978,7 +4171,6 @@ static void led_exit(void)
3978 } 4171 }
3979 4172
3980 kfree(tpacpi_leds); 4173 kfree(tpacpi_leds);
3981 tpacpi_leds = NULL;
3982} 4174}
3983 4175
3984static int __init led_init(struct ibm_init_struct *iibm) 4176static int __init led_init(struct ibm_init_struct *iibm)
@@ -4802,7 +4994,6 @@ static void brightness_exit(void)
4802 vdbg_printk(TPACPI_DBG_EXIT, 4994 vdbg_printk(TPACPI_DBG_EXIT,
4803 "calling backlight_device_unregister()\n"); 4995 "calling backlight_device_unregister()\n");
4804 backlight_device_unregister(ibm_backlight_device); 4996 backlight_device_unregister(ibm_backlight_device);
4805 ibm_backlight_device = NULL;
4806 } 4997 }
4807} 4998}
4808 4999
@@ -5764,11 +5955,16 @@ static int __init fan_init(struct ibm_init_struct *iibm)
5764 fan_control_access_mode != TPACPI_FAN_WR_NONE) { 5955 fan_control_access_mode != TPACPI_FAN_WR_NONE) {
5765 rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, 5956 rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
5766 &fan_attr_group); 5957 &fan_attr_group);
5767 if (!(rc < 0))
5768 rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
5769 &driver_attr_fan_watchdog);
5770 if (rc < 0) 5958 if (rc < 0)
5771 return rc; 5959 return rc;
5960
5961 rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
5962 &driver_attr_fan_watchdog);
5963 if (rc < 0) {
5964 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
5965 &fan_attr_group);
5966 return rc;
5967 }
5772 return 0; 5968 return 0;
5773 } else 5969 } else
5774 return 1; 5970 return 1;
@@ -6144,13 +6340,18 @@ err_out:
6144 6340
6145/* Probing */ 6341/* Probing */
6146 6342
6147static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) 6343/* returns 0 - probe ok, or < 0 - probe error.
6344 * Probe ok doesn't mean thinkpad found.
6345 * On error, kfree() cleanup on tp->* is not performed, caller must do it */
6346static int __must_check __init get_thinkpad_model_data(
6347 struct thinkpad_id_data *tp)
6148{ 6348{
6149 const struct dmi_device *dev = NULL; 6349 const struct dmi_device *dev = NULL;
6150 char ec_fw_string[18]; 6350 char ec_fw_string[18];
6351 char const *s;
6151 6352
6152 if (!tp) 6353 if (!tp)
6153 return; 6354 return -EINVAL;
6154 6355
6155 memset(tp, 0, sizeof(*tp)); 6356 memset(tp, 0, sizeof(*tp));
6156 6357
@@ -6159,12 +6360,14 @@ static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
6159 else if (dmi_name_in_vendors("LENOVO")) 6360 else if (dmi_name_in_vendors("LENOVO"))
6160 tp->vendor = PCI_VENDOR_ID_LENOVO; 6361 tp->vendor = PCI_VENDOR_ID_LENOVO;
6161 else 6362 else
6162 return; 6363 return 0;
6163 6364
6164 tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION), 6365 s = dmi_get_system_info(DMI_BIOS_VERSION);
6165 GFP_KERNEL); 6366 tp->bios_version_str = kstrdup(s, GFP_KERNEL);
6367 if (s && !tp->bios_version_str)
6368 return -ENOMEM;
6166 if (!tp->bios_version_str) 6369 if (!tp->bios_version_str)
6167 return; 6370 return 0;
6168 tp->bios_model = tp->bios_version_str[0] 6371 tp->bios_model = tp->bios_version_str[0]
6169 | (tp->bios_version_str[1] << 8); 6372 | (tp->bios_version_str[1] << 8);
6170 6373
@@ -6183,21 +6386,27 @@ static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
6183 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; 6386 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
6184 6387
6185 tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); 6388 tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
6389 if (!tp->ec_version_str)
6390 return -ENOMEM;
6186 tp->ec_model = ec_fw_string[0] 6391 tp->ec_model = ec_fw_string[0]
6187 | (ec_fw_string[1] << 8); 6392 | (ec_fw_string[1] << 8);
6188 break; 6393 break;
6189 } 6394 }
6190 } 6395 }
6191 6396
6192 tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION), 6397 s = dmi_get_system_info(DMI_PRODUCT_VERSION);
6193 GFP_KERNEL); 6398 if (s && !strnicmp(s, "ThinkPad", 8)) {
6194 if (tp->model_str && strnicmp(tp->model_str, "ThinkPad", 8) != 0) { 6399 tp->model_str = kstrdup(s, GFP_KERNEL);
6195 kfree(tp->model_str); 6400 if (!tp->model_str)
6196 tp->model_str = NULL; 6401 return -ENOMEM;
6197 } 6402 }
6198 6403
6199 tp->nummodel_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_NAME), 6404 s = dmi_get_system_info(DMI_PRODUCT_NAME);
6200 GFP_KERNEL); 6405 tp->nummodel_str = kstrdup(s, GFP_KERNEL);
6406 if (s && !tp->nummodel_str)
6407 return -ENOMEM;
6408
6409 return 0;
6201} 6410}
6202 6411
6203static int __init probe_for_thinkpad(void) 6412static int __init probe_for_thinkpad(void)
@@ -6460,7 +6669,13 @@ static int __init thinkpad_acpi_module_init(void)
6460 6669
6461 /* Driver-level probe */ 6670 /* Driver-level probe */
6462 6671
6463 get_thinkpad_model_data(&thinkpad_id); 6672 ret = get_thinkpad_model_data(&thinkpad_id);
6673 if (ret) {
6674 printk(TPACPI_ERR
6675 "unable to get DMI data: %d\n", ret);
6676 thinkpad_acpi_module_exit();
6677 return ret;
6678 }
6464 ret = probe_for_thinkpad(); 6679 ret = probe_for_thinkpad();
6465 if (ret) { 6680 if (ret) {
6466 thinkpad_acpi_module_exit(); 6681 thinkpad_acpi_module_exit();