diff options
-rw-r--r-- | MAINTAINERS | 5 | ||||
-rw-r--r-- | drivers/misc/Kconfig | 17 | ||||
-rw-r--r-- | drivers/misc/Makefile | 5 | ||||
-rw-r--r-- | drivers/misc/compal-laptop.c | 437 |
4 files changed, 462 insertions, 2 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index ee1c56a20750..2bfde0326300 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1160,6 +1160,11 @@ M: scott@spiteful.org | |||
1160 | L: pcihpd-discuss@lists.sourceforge.net | 1160 | L: pcihpd-discuss@lists.sourceforge.net |
1161 | S: Supported | 1161 | S: Supported |
1162 | 1162 | ||
1163 | COMPAL LAPTOP SUPPORT | ||
1164 | P: Cezary Jackiewicz | ||
1165 | M: cezary.jackiewicz@gmail.com | ||
1166 | S: Maintained | ||
1167 | |||
1163 | COMPUTONE INTELLIPORT MULTIPORT CARD | 1168 | COMPUTONE INTELLIPORT MULTIPORT CARD |
1164 | P: Michael H. Warfield | 1169 | P: Michael H. Warfield |
1165 | M: mhw@wittsend.com | 1170 | M: mhw@wittsend.com |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 636af2862308..7fce0da86548 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -219,6 +219,23 @@ config MSI_LAPTOP | |||
219 | 219 | ||
220 | If you have an MSI S270 laptop, say Y or M here. | 220 | If you have an MSI S270 laptop, say Y or M here. |
221 | 221 | ||
222 | config COMPAL_LAPTOP | ||
223 | tristate "Compal Laptop Extras" | ||
224 | depends on X86 | ||
225 | depends on ACPI_EC | ||
226 | depends on BACKLIGHT_CLASS_DEVICE | ||
227 | ---help--- | ||
228 | This is a driver for laptops built by Compal: | ||
229 | |||
230 | Compal FL90/IFL90 | ||
231 | Compal FL91/IFL91 | ||
232 | Compal FL92/JFL92 | ||
233 | Compal FT00/IFT00 | ||
234 | |||
235 | It adds support for Bluetooth, WLAN and LCD brightness control. | ||
236 | |||
237 | If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here. | ||
238 | |||
222 | config SONY_LAPTOP | 239 | config SONY_LAPTOP |
223 | tristate "Sony Laptop Extras" | 240 | tristate "Sony Laptop Extras" |
224 | depends on X86 && ACPI | 241 | depends on X86 && ACPI |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 1952875a272e..a6dac6a2e7e5 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -5,10 +5,11 @@ obj- := misc.o # Dummy rule to force built-in.o to be made | |||
5 | 5 | ||
6 | obj-$(CONFIG_IBM_ASM) += ibmasm/ | 6 | obj-$(CONFIG_IBM_ASM) += ibmasm/ |
7 | obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ | 7 | obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ |
8 | obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o | ||
9 | obj-$(CONFIG_ACER_WMI) += acer-wmi.o | ||
10 | obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o | 8 | obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o |
11 | obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o | 9 | obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o |
10 | obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o | ||
11 | obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o | ||
12 | obj-$(CONFIG_ACER_WMI) += acer-wmi.o | ||
12 | obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o | 13 | obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o |
13 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o | 14 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o |
14 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o | 15 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o |
diff --git a/drivers/misc/compal-laptop.c b/drivers/misc/compal-laptop.c new file mode 100644 index 000000000000..0c1f5875fbb9 --- /dev/null +++ b/drivers/misc/compal-laptop.c | |||
@@ -0,0 +1,437 @@ | |||
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 | * lcd_level - Screen brightness: contains a single integer in the | ||
32 | * range 0..7. (rw) | ||
33 | * | ||
34 | * wlan - wlan subsystem state: contains 0 or 1 (rw) | ||
35 | * | ||
36 | * bluetooth - Bluetooth subsystem state: contains 0 or 1 (rw) | ||
37 | * | ||
38 | * raw - raw value taken from embedded controller register (ro) | ||
39 | * | ||
40 | * In addition to these platform device attributes the driver | ||
41 | * registers itself in the Linux backlight control subsystem and is | ||
42 | * available to userspace under /sys/class/backlight/compal-laptop/. | ||
43 | * | ||
44 | * This driver might work on other laptops produced by Compal. If you | ||
45 | * want to try it you can pass force=1 as argument to the module which | ||
46 | * will force it to load even when the DMI data doesn't identify the | ||
47 | * laptop as IFL90. | ||
48 | */ | ||
49 | |||
50 | #include <linux/module.h> | ||
51 | #include <linux/kernel.h> | ||
52 | #include <linux/init.h> | ||
53 | #include <linux/acpi.h> | ||
54 | #include <linux/dmi.h> | ||
55 | #include <linux/backlight.h> | ||
56 | #include <linux/platform_device.h> | ||
57 | #include <linux/autoconf.h> | ||
58 | |||
59 | #define COMPAL_DRIVER_VERSION "0.2.5" | ||
60 | |||
61 | #define COMPAL_LCD_LEVEL_MAX 8 | ||
62 | |||
63 | #define COMPAL_EC_COMMAND_WIRELESS 0xBB | ||
64 | #define COMPAL_EC_COMMAND_LCD_LEVEL 0xB9 | ||
65 | |||
66 | #define KILLSWITCH_MASK 0x10 | ||
67 | #define WLAN_MASK 0x01 | ||
68 | #define BT_MASK 0x02 | ||
69 | |||
70 | static int force; | ||
71 | module_param(force, bool, 0); | ||
72 | MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); | ||
73 | |||
74 | /* Hardware access */ | ||
75 | |||
76 | static int set_lcd_level(int level) | ||
77 | { | ||
78 | if (level < 0 || level >= COMPAL_LCD_LEVEL_MAX) | ||
79 | return -EINVAL; | ||
80 | |||
81 | ec_write(COMPAL_EC_COMMAND_LCD_LEVEL, level); | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int get_lcd_level(void) | ||
87 | { | ||
88 | u8 result; | ||
89 | |||
90 | ec_read(COMPAL_EC_COMMAND_LCD_LEVEL, &result); | ||
91 | |||
92 | return (int) result; | ||
93 | } | ||
94 | |||
95 | static int set_wlan_state(int state) | ||
96 | { | ||
97 | u8 result, value; | ||
98 | |||
99 | ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); | ||
100 | |||
101 | if ((result & KILLSWITCH_MASK) == 0) | ||
102 | return -EINVAL; | ||
103 | else { | ||
104 | if (state) | ||
105 | value = (u8) (result | WLAN_MASK); | ||
106 | else | ||
107 | value = (u8) (result & ~WLAN_MASK); | ||
108 | ec_write(COMPAL_EC_COMMAND_WIRELESS, value); | ||
109 | } | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int set_bluetooth_state(int state) | ||
115 | { | ||
116 | u8 result, value; | ||
117 | |||
118 | ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); | ||
119 | |||
120 | if ((result & KILLSWITCH_MASK) == 0) | ||
121 | return -EINVAL; | ||
122 | else { | ||
123 | if (state) | ||
124 | value = (u8) (result | BT_MASK); | ||
125 | else | ||
126 | value = (u8) (result & ~BT_MASK); | ||
127 | ec_write(COMPAL_EC_COMMAND_WIRELESS, value); | ||
128 | } | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int get_wireless_state(int *wlan, int *bluetooth) | ||
134 | { | ||
135 | u8 result; | ||
136 | |||
137 | ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); | ||
138 | |||
139 | if (wlan) { | ||
140 | if ((result & KILLSWITCH_MASK) == 0) | ||
141 | *wlan = 0; | ||
142 | else | ||
143 | *wlan = result & WLAN_MASK; | ||
144 | } | ||
145 | |||
146 | if (bluetooth) { | ||
147 | if ((result & KILLSWITCH_MASK) == 0) | ||
148 | *bluetooth = 0; | ||
149 | else | ||
150 | *bluetooth = (result & BT_MASK) >> 1; | ||
151 | } | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | /* Backlight device stuff */ | ||
157 | |||
158 | static int bl_get_brightness(struct backlight_device *b) | ||
159 | { | ||
160 | return get_lcd_level(); | ||
161 | } | ||
162 | |||
163 | |||
164 | static int bl_update_status(struct backlight_device *b) | ||
165 | { | ||
166 | return set_lcd_level(b->props.brightness); | ||
167 | } | ||
168 | |||
169 | static struct backlight_ops compalbl_ops = { | ||
170 | .get_brightness = bl_get_brightness, | ||
171 | .update_status = bl_update_status, | ||
172 | }; | ||
173 | |||
174 | static struct backlight_device *compalbl_device; | ||
175 | |||
176 | /* Platform device */ | ||
177 | |||
178 | static ssize_t show_wlan(struct device *dev, | ||
179 | struct device_attribute *attr, char *buf) | ||
180 | { | ||
181 | int ret, enabled; | ||
182 | |||
183 | ret = get_wireless_state(&enabled, NULL); | ||
184 | if (ret < 0) | ||
185 | return ret; | ||
186 | |||
187 | return sprintf(buf, "%i\n", enabled); | ||
188 | } | ||
189 | |||
190 | static ssize_t show_raw(struct device *dev, | ||
191 | struct device_attribute *attr, char *buf) | ||
192 | { | ||
193 | u8 result; | ||
194 | |||
195 | ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); | ||
196 | |||
197 | return sprintf(buf, "%i\n", result); | ||
198 | } | ||
199 | |||
200 | static ssize_t show_bluetooth(struct device *dev, | ||
201 | struct device_attribute *attr, char *buf) | ||
202 | { | ||
203 | int ret, enabled; | ||
204 | |||
205 | ret = get_wireless_state(NULL, &enabled); | ||
206 | if (ret < 0) | ||
207 | return ret; | ||
208 | |||
209 | return sprintf(buf, "%i\n", enabled); | ||
210 | } | ||
211 | |||
212 | static ssize_t show_lcd_level(struct device *dev, | ||
213 | struct device_attribute *attr, char *buf) | ||
214 | { | ||
215 | int ret; | ||
216 | |||
217 | ret = get_lcd_level(); | ||
218 | if (ret < 0) | ||
219 | return ret; | ||
220 | |||
221 | return sprintf(buf, "%i\n", ret); | ||
222 | } | ||
223 | |||
224 | static ssize_t store_lcd_level(struct device *dev, | ||
225 | struct device_attribute *attr, const char *buf, size_t count) | ||
226 | { | ||
227 | int level, ret; | ||
228 | |||
229 | if (sscanf(buf, "%i", &level) != 1 || | ||
230 | (level < 0 || level >= COMPAL_LCD_LEVEL_MAX)) | ||
231 | return -EINVAL; | ||
232 | |||
233 | ret = set_lcd_level(level); | ||
234 | if (ret < 0) | ||
235 | return ret; | ||
236 | |||
237 | return count; | ||
238 | } | ||
239 | |||
240 | static ssize_t store_wlan_state(struct device *dev, | ||
241 | struct device_attribute *attr, const char *buf, size_t count) | ||
242 | { | ||
243 | int state, ret; | ||
244 | |||
245 | if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1)) | ||
246 | return -EINVAL; | ||
247 | |||
248 | ret = set_wlan_state(state); | ||
249 | if (ret < 0) | ||
250 | return ret; | ||
251 | |||
252 | return count; | ||
253 | } | ||
254 | |||
255 | static ssize_t store_bluetooth_state(struct device *dev, | ||
256 | struct device_attribute *attr, const char *buf, size_t count) | ||
257 | { | ||
258 | int state, ret; | ||
259 | |||
260 | if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1)) | ||
261 | return -EINVAL; | ||
262 | |||
263 | ret = set_bluetooth_state(state); | ||
264 | if (ret < 0) | ||
265 | return ret; | ||
266 | |||
267 | return count; | ||
268 | } | ||
269 | |||
270 | static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); | ||
271 | static DEVICE_ATTR(bluetooth, 0644, show_bluetooth, store_bluetooth_state); | ||
272 | static DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan_state); | ||
273 | static DEVICE_ATTR(raw, 0444, show_raw, NULL); | ||
274 | |||
275 | static struct attribute *compal_attributes[] = { | ||
276 | &dev_attr_lcd_level.attr, | ||
277 | &dev_attr_bluetooth.attr, | ||
278 | &dev_attr_wlan.attr, | ||
279 | &dev_attr_raw.attr, | ||
280 | NULL | ||
281 | }; | ||
282 | |||
283 | static struct attribute_group compal_attribute_group = { | ||
284 | .attrs = compal_attributes | ||
285 | }; | ||
286 | |||
287 | static struct platform_driver compal_driver = { | ||
288 | .driver = { | ||
289 | .name = "compal-laptop", | ||
290 | .owner = THIS_MODULE, | ||
291 | } | ||
292 | }; | ||
293 | |||
294 | static struct platform_device *compal_device; | ||
295 | |||
296 | /* Initialization */ | ||
297 | |||
298 | static int dmi_check_cb(const struct dmi_system_id *id) | ||
299 | { | ||
300 | printk(KERN_INFO "compal-laptop: Identified laptop model '%s'.\n", | ||
301 | id->ident); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static struct dmi_system_id __initdata compal_dmi_table[] = { | ||
307 | { | ||
308 | .ident = "FL90/IFL90", | ||
309 | .matches = { | ||
310 | DMI_MATCH(DMI_BOARD_NAME, "IFL90"), | ||
311 | DMI_MATCH(DMI_BOARD_VERSION, "IFT00"), | ||
312 | }, | ||
313 | .callback = dmi_check_cb | ||
314 | }, | ||
315 | { | ||
316 | .ident = "FL90/IFL90", | ||
317 | .matches = { | ||
318 | DMI_MATCH(DMI_BOARD_NAME, "IFL90"), | ||
319 | DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"), | ||
320 | }, | ||
321 | .callback = dmi_check_cb | ||
322 | }, | ||
323 | { | ||
324 | .ident = "FL91/IFL91", | ||
325 | .matches = { | ||
326 | DMI_MATCH(DMI_BOARD_NAME, "IFL91"), | ||
327 | DMI_MATCH(DMI_BOARD_VERSION, "IFT00"), | ||
328 | }, | ||
329 | .callback = dmi_check_cb | ||
330 | }, | ||
331 | { | ||
332 | .ident = "FL92/JFL92", | ||
333 | .matches = { | ||
334 | DMI_MATCH(DMI_BOARD_NAME, "JFL92"), | ||
335 | DMI_MATCH(DMI_BOARD_VERSION, "IFT00"), | ||
336 | }, | ||
337 | .callback = dmi_check_cb | ||
338 | }, | ||
339 | { | ||
340 | .ident = "FT00/IFT00", | ||
341 | .matches = { | ||
342 | DMI_MATCH(DMI_BOARD_NAME, "IFT00"), | ||
343 | DMI_MATCH(DMI_BOARD_VERSION, "IFT00"), | ||
344 | }, | ||
345 | .callback = dmi_check_cb | ||
346 | }, | ||
347 | { } | ||
348 | }; | ||
349 | |||
350 | static int __init compal_init(void) | ||
351 | { | ||
352 | int ret; | ||
353 | |||
354 | if (acpi_disabled) | ||
355 | return -ENODEV; | ||
356 | |||
357 | if (!force && !dmi_check_system(compal_dmi_table)) | ||
358 | return -ENODEV; | ||
359 | |||
360 | /* Register backlight stuff */ | ||
361 | |||
362 | compalbl_device = backlight_device_register("compal-laptop", NULL, NULL, | ||
363 | &compalbl_ops); | ||
364 | if (IS_ERR(compalbl_device)) | ||
365 | return PTR_ERR(compalbl_device); | ||
366 | |||
367 | compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1; | ||
368 | |||
369 | ret = platform_driver_register(&compal_driver); | ||
370 | if (ret) | ||
371 | goto fail_backlight; | ||
372 | |||
373 | /* Register platform stuff */ | ||
374 | |||
375 | compal_device = platform_device_alloc("compal-laptop", -1); | ||
376 | if (!compal_device) { | ||
377 | ret = -ENOMEM; | ||
378 | goto fail_platform_driver; | ||
379 | } | ||
380 | |||
381 | ret = platform_device_add(compal_device); | ||
382 | if (ret) | ||
383 | goto fail_platform_device1; | ||
384 | |||
385 | ret = sysfs_create_group(&compal_device->dev.kobj, | ||
386 | &compal_attribute_group); | ||
387 | if (ret) | ||
388 | goto fail_platform_device2; | ||
389 | |||
390 | printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION | ||
391 | " successfully loaded.\n"); | ||
392 | |||
393 | return 0; | ||
394 | |||
395 | fail_platform_device2: | ||
396 | |||
397 | platform_device_del(compal_device); | ||
398 | |||
399 | fail_platform_device1: | ||
400 | |||
401 | platform_device_put(compal_device); | ||
402 | |||
403 | fail_platform_driver: | ||
404 | |||
405 | platform_driver_unregister(&compal_driver); | ||
406 | |||
407 | fail_backlight: | ||
408 | |||
409 | backlight_device_unregister(compalbl_device); | ||
410 | |||
411 | return ret; | ||
412 | } | ||
413 | |||
414 | static void __exit compal_cleanup(void) | ||
415 | { | ||
416 | |||
417 | sysfs_remove_group(&compal_device->dev.kobj, &compal_attribute_group); | ||
418 | platform_device_unregister(compal_device); | ||
419 | platform_driver_unregister(&compal_driver); | ||
420 | backlight_device_unregister(compalbl_device); | ||
421 | |||
422 | printk(KERN_INFO "compal-laptop: driver unloaded.\n"); | ||
423 | } | ||
424 | |||
425 | module_init(compal_init); | ||
426 | module_exit(compal_cleanup); | ||
427 | |||
428 | MODULE_AUTHOR("Cezary Jackiewicz"); | ||
429 | MODULE_DESCRIPTION("Compal Laptop Support"); | ||
430 | MODULE_VERSION(COMPAL_DRIVER_VERSION); | ||
431 | MODULE_LICENSE("GPL"); | ||
432 | |||
433 | MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*"); | ||
434 | MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*"); | ||
435 | MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*"); | ||
436 | MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*"); | ||
437 | MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*"); | ||