source: src/linux/universal/linux-3.18/drivers/platform/x86/acer-wmi.c @ 31885

Last change on this file since 31885 was 31885, checked in by brainslayer, 5 weeks ago

update

File size: 54.3 KB
Line 
1/*
2 *  Acer WMI Laptop Extras
3 *
4 *  Copyright (C) 2007-2009     Carlos Corbacho <carlos@strangeworlds.co.uk>
5 *
6 *  Based on acer_acpi:
7 *    Copyright (C) 2005-2007   E.M. Smith
8 *    Copyright (C) 2007-2008   Carlos Corbacho <cathectic@gmail.com>
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,
16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *  GNU 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/init.h>
30#include <linux/types.h>
31#include <linux/dmi.h>
32#include <linux/fb.h>
33#include <linux/backlight.h>
34#include <linux/leds.h>
35#include <linux/platform_device.h>
36#include <linux/acpi.h>
37#include <linux/i8042.h>
38#include <linux/rfkill.h>
39#include <linux/workqueue.h>
40#include <linux/debugfs.h>
41#include <linux/slab.h>
42#include <linux/input.h>
43#include <linux/input/sparse-keymap.h>
44#include <acpi/video.h>
45
46MODULE_AUTHOR("Carlos Corbacho");
47MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
48MODULE_LICENSE("GPL");
49
50/*
51 * Magic Number
52 * Meaning is unknown - this number is required for writing to ACPI for AMW0
53 * (it's also used in acerhk when directly accessing the BIOS)
54 */
55#define ACER_AMW0_WRITE 0x9610
56
57/*
58 * Bit masks for the AMW0 interface
59 */
60#define ACER_AMW0_WIRELESS_MASK  0x35
61#define ACER_AMW0_BLUETOOTH_MASK 0x34
62#define ACER_AMW0_MAILLED_MASK   0x31
63
64/*
65 * Method IDs for WMID interface
66 */
67#define ACER_WMID_GET_WIRELESS_METHODID         1
68#define ACER_WMID_GET_BLUETOOTH_METHODID        2
69#define ACER_WMID_GET_BRIGHTNESS_METHODID       3
70#define ACER_WMID_SET_WIRELESS_METHODID         4
71#define ACER_WMID_SET_BLUETOOTH_METHODID        5
72#define ACER_WMID_SET_BRIGHTNESS_METHODID       6
73#define ACER_WMID_GET_THREEG_METHODID           10
74#define ACER_WMID_SET_THREEG_METHODID           11
75
76/*
77 * Acer ACPI method GUIDs
78 */
79#define AMW0_GUID1              "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
80#define AMW0_GUID2              "431F16ED-0C2B-444C-B267-27DEB140CF9C"
81#define WMID_GUID1              "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
82#define WMID_GUID2              "95764E09-FB56-4E83-B31A-37761F60994A"
83#define WMID_GUID3              "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
84
85/*
86 * Acer ACPI event GUIDs
87 */
88#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
89
90MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
91MODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3");
92MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
93
94enum acer_wmi_event_ids {
95        WMID_HOTKEY_EVENT = 0x1,
96        WMID_ACCEL_EVENT = 0x5,
97};
98
99static const struct key_entry acer_wmi_keymap[] __initconst = {
100        {KE_KEY, 0x01, {KEY_WLAN} },     /* WiFi */
101        {KE_KEY, 0x03, {KEY_WLAN} },     /* WiFi */
102        {KE_KEY, 0x04, {KEY_WLAN} },     /* WiFi */
103        {KE_KEY, 0x12, {KEY_BLUETOOTH} },       /* BT */
104        {KE_KEY, 0x21, {KEY_PROG1} },    /* Backup */
105        {KE_KEY, 0x22, {KEY_PROG2} },    /* Arcade */
106        {KE_KEY, 0x23, {KEY_PROG3} },    /* P_Key */
107        {KE_KEY, 0x24, {KEY_PROG4} },    /* Social networking_Key */
108        {KE_KEY, 0x29, {KEY_PROG3} },    /* P_Key for TM8372 */
109        {KE_IGNORE, 0x41, {KEY_MUTE} },
110        {KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
111        {KE_IGNORE, 0x4d, {KEY_PREVIOUSSONG} },
112        {KE_IGNORE, 0x43, {KEY_NEXTSONG} },
113        {KE_IGNORE, 0x4e, {KEY_NEXTSONG} },
114        {KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
115        {KE_IGNORE, 0x4f, {KEY_PLAYPAUSE} },
116        {KE_IGNORE, 0x45, {KEY_STOP} },
117        {KE_IGNORE, 0x50, {KEY_STOP} },
118        {KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
119        {KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
120        {KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} },
121        {KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} },
122        {KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
123        {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
124        {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
125        {KE_IGNORE, 0x81, {KEY_SLEEP} },
126        {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad Toggle */
127        {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} },
128        {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },
129        {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} },
130        {KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} },
131        {KE_END, 0}
132};
133
134static struct input_dev *acer_wmi_input_dev;
135static struct input_dev *acer_wmi_accel_dev;
136
137struct event_return_value {
138        u8 function;
139        u8 key_num;
140        u16 device_state;
141        u32 reserved;
142} __attribute__((packed));
143
144/*
145 * GUID3 Get Device Status device flags
146 */
147#define ACER_WMID3_GDS_WIRELESS         (1<<0)  /* WiFi */
148#define ACER_WMID3_GDS_THREEG           (1<<6)  /* 3G */
149#define ACER_WMID3_GDS_WIMAX            (1<<7)  /* WiMAX */
150#define ACER_WMID3_GDS_BLUETOOTH        (1<<11) /* BT */
151#define ACER_WMID3_GDS_TOUCHPAD         (1<<1)  /* Touchpad */
152
153struct lm_input_params {
154        u8 function_num;        /* Function Number */
155        u16 commun_devices;     /* Communication type devices default status */
156        u16 devices;            /* Other type devices default status */
157        u8 lm_status;           /* Launch Manager Status */
158        u16 reserved;
159} __attribute__((packed));
160
161struct lm_return_value {
162        u8 error_code;          /* Error Code */
163        u8 ec_return_value;     /* EC Return Value */
164        u16 reserved;
165} __attribute__((packed));
166
167struct wmid3_gds_set_input_param {     /* Set Device Status input parameter */
168        u8 function_num;        /* Function Number */
169        u8 hotkey_number;       /* Hotkey Number */
170        u16 devices;            /* Set Device */
171        u8 volume_value;        /* Volume Value */
172} __attribute__((packed));
173
174struct wmid3_gds_get_input_param {     /* Get Device Status input parameter */
175        u8 function_num;        /* Function Number */
176        u8 hotkey_number;       /* Hotkey Number */
177        u16 devices;            /* Get Device */
178} __attribute__((packed));
179
180struct wmid3_gds_return_value { /* Get Device Status return value*/
181        u8 error_code;          /* Error Code */
182        u8 ec_return_value;     /* EC Return Value */
183        u16 devices;            /* Current Device Status */
184        u32 reserved;
185} __attribute__((packed));
186
187struct hotkey_function_type_aa {
188        u8 type;
189        u8 length;
190        u16 handle;
191        u16 commun_func_bitmap;
192        u16 application_func_bitmap;
193        u16 media_func_bitmap;
194        u16 display_func_bitmap;
195        u16 others_func_bitmap;
196        u8 commun_fn_key_number;
197} __attribute__((packed));
198
199/*
200 * Interface capability flags
201 */
202#define ACER_CAP_MAILLED                (1<<0)
203#define ACER_CAP_WIRELESS               (1<<1)
204#define ACER_CAP_BLUETOOTH              (1<<2)
205#define ACER_CAP_BRIGHTNESS             (1<<3)
206#define ACER_CAP_THREEG                 (1<<4)
207#define ACER_CAP_ACCEL                  (1<<5)
208#define ACER_CAP_ANY                    (0xFFFFFFFF)
209
210/*
211 * Interface type flags
212 */
213enum interface_flags {
214        ACER_AMW0,
215        ACER_AMW0_V2,
216        ACER_WMID,
217        ACER_WMID_v2,
218};
219
220#define ACER_DEFAULT_WIRELESS  0
221#define ACER_DEFAULT_BLUETOOTH 0
222#define ACER_DEFAULT_MAILLED   0
223#define ACER_DEFAULT_THREEG    0
224
225static int max_brightness = 0xF;
226
227static int mailled = -1;
228static int brightness = -1;
229static int threeg = -1;
230static int force_series;
231static bool ec_raw_mode;
232static bool has_type_aa;
233static u16 commun_func_bitmap;
234static u8 commun_fn_key_number;
235
236module_param(mailled, int, 0444);
237module_param(brightness, int, 0444);
238module_param(threeg, int, 0444);
239module_param(force_series, int, 0444);
240module_param(ec_raw_mode, bool, 0444);
241MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
242MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
243MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
244MODULE_PARM_DESC(force_series, "Force a different laptop series");
245MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
246
247struct acer_data {
248        int mailled;
249        int threeg;
250        int brightness;
251};
252
253struct acer_debug {
254        struct dentry *root;
255        struct dentry *devices;
256        u32 wmid_devices;
257};
258
259static struct rfkill *wireless_rfkill;
260static struct rfkill *bluetooth_rfkill;
261static struct rfkill *threeg_rfkill;
262static bool rfkill_inited;
263
264/* Each low-level interface must define at least some of the following */
265struct wmi_interface {
266        /* The WMI device type */
267        u32 type;
268
269        /* The capabilities this interface provides */
270        u32 capability;
271
272        /* Private data for the current interface */
273        struct acer_data data;
274
275        /* debugfs entries associated with this interface */
276        struct acer_debug debug;
277};
278
279/* The static interface pointer, points to the currently detected interface */
280static struct wmi_interface *interface;
281
282/*
283 * Embedded Controller quirks
284 * Some laptops require us to directly access the EC to either enable or query
285 * features that are not available through WMI.
286 */
287
288struct quirk_entry {
289        u8 wireless;
290        u8 mailled;
291        s8 brightness;
292        u8 bluetooth;
293};
294
295static struct quirk_entry *quirks;
296
297static void __init set_quirks(void)
298{
299        if (!interface)
300                return;
301
302        if (quirks->mailled)
303                interface->capability |= ACER_CAP_MAILLED;
304
305        if (quirks->brightness)
306                interface->capability |= ACER_CAP_BRIGHTNESS;
307}
308
309static int __init dmi_matched(const struct dmi_system_id *dmi)
310{
311        quirks = dmi->driver_data;
312        return 1;
313}
314
315static struct quirk_entry quirk_unknown = {
316};
317
318static struct quirk_entry quirk_acer_aspire_1520 = {
319        .brightness = -1,
320};
321
322static struct quirk_entry quirk_acer_travelmate_2490 = {
323        .mailled = 1,
324};
325
326/* This AMW0 laptop has no bluetooth */
327static struct quirk_entry quirk_medion_md_98300 = {
328        .wireless = 1,
329};
330
331static struct quirk_entry quirk_fujitsu_amilo_li_1718 = {
332        .wireless = 2,
333};
334
335static struct quirk_entry quirk_lenovo_ideapad_s205 = {
336        .wireless = 3,
337};
338
339/* The Aspire One has a dummy ACPI-WMI interface - disable it */
340static const struct dmi_system_id acer_blacklist[] __initconst = {
341        {
342                .ident = "Acer Aspire One (SSD)",
343                .matches = {
344                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
345                        DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
346                },
347        },
348        {
349                .ident = "Acer Aspire One (HDD)",
350                .matches = {
351                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
352                        DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"),
353                },
354        },
355        {}
356};
357
358static const struct dmi_system_id acer_quirks[] __initconst = {
359        {
360                .callback = dmi_matched,
361                .ident = "Acer Aspire 1360",
362                .matches = {
363                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
364                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
365                },
366                .driver_data = &quirk_acer_aspire_1520,
367        },
368        {
369                .callback = dmi_matched,
370                .ident = "Acer Aspire 1520",
371                .matches = {
372                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
373                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"),
374                },
375                .driver_data = &quirk_acer_aspire_1520,
376        },
377        {
378                .callback = dmi_matched,
379                .ident = "Acer Aspire 3100",
380                .matches = {
381                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
382                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
383                },
384                .driver_data = &quirk_acer_travelmate_2490,
385        },
386        {
387                .callback = dmi_matched,
388                .ident = "Acer Aspire 3610",
389                .matches = {
390                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
391                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"),
392                },
393                .driver_data = &quirk_acer_travelmate_2490,
394        },
395        {
396                .callback = dmi_matched,
397                .ident = "Acer Aspire 5100",
398                .matches = {
399                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
400                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
401                },
402                .driver_data = &quirk_acer_travelmate_2490,
403        },
404        {
405                .callback = dmi_matched,
406                .ident = "Acer Aspire 5610",
407                .matches = {
408                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
409                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
410                },
411                .driver_data = &quirk_acer_travelmate_2490,
412        },
413        {
414                .callback = dmi_matched,
415                .ident = "Acer Aspire 5630",
416                .matches = {
417                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
418                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
419                },
420                .driver_data = &quirk_acer_travelmate_2490,
421        },
422        {
423                .callback = dmi_matched,
424                .ident = "Acer Aspire 5650",
425                .matches = {
426                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
427                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
428                },
429                .driver_data = &quirk_acer_travelmate_2490,
430        },
431        {
432                .callback = dmi_matched,
433                .ident = "Acer Aspire 5680",
434                .matches = {
435                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
436                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
437                },
438                .driver_data = &quirk_acer_travelmate_2490,
439        },
440        {
441                .callback = dmi_matched,
442                .ident = "Acer Aspire 9110",
443                .matches = {
444                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
445                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
446                },
447                .driver_data = &quirk_acer_travelmate_2490,
448        },
449        {
450                .callback = dmi_matched,
451                .ident = "Acer TravelMate 2490",
452                .matches = {
453                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
454                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
455                },
456                .driver_data = &quirk_acer_travelmate_2490,
457        },
458        {
459                .callback = dmi_matched,
460                .ident = "Acer TravelMate 4200",
461                .matches = {
462                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
463                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"),
464                },
465                .driver_data = &quirk_acer_travelmate_2490,
466        },
467        {
468                .callback = dmi_matched,
469                .ident = "Fujitsu Siemens Amilo Li 1718",
470                .matches = {
471                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
472                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"),
473                },
474                .driver_data = &quirk_fujitsu_amilo_li_1718,
475        },
476        {
477                .callback = dmi_matched,
478                .ident = "Medion MD 98300",
479                .matches = {
480                        DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
481                        DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"),
482                },
483                .driver_data = &quirk_medion_md_98300,
484        },
485        {
486                .callback = dmi_matched,
487                .ident = "Lenovo Ideapad S205",
488                .matches = {
489                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
490                        DMI_MATCH(DMI_PRODUCT_NAME, "10382LG"),
491                },
492                .driver_data = &quirk_lenovo_ideapad_s205,
493        },
494        {
495                .callback = dmi_matched,
496                .ident = "Lenovo Ideapad S205 (Brazos)",
497                .matches = {
498                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
499                        DMI_MATCH(DMI_PRODUCT_NAME, "Brazos"),
500                },
501                .driver_data = &quirk_lenovo_ideapad_s205,
502        },
503        {
504                .callback = dmi_matched,
505                .ident = "Lenovo 3000 N200",
506                .matches = {
507                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
508                        DMI_MATCH(DMI_PRODUCT_NAME, "0687A31"),
509                },
510                .driver_data = &quirk_fujitsu_amilo_li_1718,
511        },
512        {
513                .callback = dmi_matched,
514                .ident = "Lenovo Ideapad S205-10382JG",
515                .matches = {
516                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
517                        DMI_MATCH(DMI_PRODUCT_NAME, "10382JG"),
518                },
519                .driver_data = &quirk_lenovo_ideapad_s205,
520        },
521        {
522                .callback = dmi_matched,
523                .ident = "Lenovo Ideapad S205-1038DPG",
524                .matches = {
525                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
526                        DMI_MATCH(DMI_PRODUCT_NAME, "1038DPG"),
527                },
528                .driver_data = &quirk_lenovo_ideapad_s205,
529        },
530        {}
531};
532
533static int __init
534video_set_backlight_video_vendor(const struct dmi_system_id *d)
535{
536        interface->capability &= ~ACER_CAP_BRIGHTNESS;
537        pr_info("Brightness must be controlled by generic video driver\n");
538        return 0;
539}
540
541static const struct dmi_system_id video_vendor_dmi_table[] __initconst = {
542        {
543                .callback = video_set_backlight_video_vendor,
544                .ident = "Acer TravelMate 4750",
545                .matches = {
546                        DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
547                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
548                },
549        },
550        {
551                .callback = video_set_backlight_video_vendor,
552                .ident = "Acer Extensa 5235",
553                .matches = {
554                        DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
555                        DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"),
556                },
557        },
558        {
559                .callback = video_set_backlight_video_vendor,
560                .ident = "Acer TravelMate 5760",
561                .matches = {
562                        DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
563                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"),
564                },
565        },
566        {
567                .callback = video_set_backlight_video_vendor,
568                .ident = "Acer Aspire 5750",
569                .matches = {
570                        DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
571                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"),
572                },
573        },
574        {
575                .callback = video_set_backlight_video_vendor,
576                .ident = "Acer Aspire 5741",
577                .matches = {
578                        DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
579                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"),
580                },
581        },
582        {
583                /*
584                 * Note no video_set_backlight_video_vendor, we must use the
585                 * acer interface, as there is no native backlight interface.
586                 */
587                .ident = "Acer KAV80",
588                .matches = {
589                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
590                        DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"),
591                },
592        },
593        {}
594};
595
596/* Find which quirks are needed for a particular vendor/ model pair */
597static void __init find_quirks(void)
598{
599        if (!force_series) {
600                dmi_check_system(acer_quirks);
601        } else if (force_series == 2490) {
602                quirks = &quirk_acer_travelmate_2490;
603        }
604
605        if (quirks == NULL)
606                quirks = &quirk_unknown;
607
608        set_quirks();
609}
610
611/*
612 * General interface convenience methods
613 */
614
615static bool has_cap(u32 cap)
616{
617        if ((interface->capability & cap) != 0)
618                return 1;
619
620        return 0;
621}
622
623/*
624 * AMW0 (V1) interface
625 */
626struct wmab_args {
627        u32 eax;
628        u32 ebx;
629        u32 ecx;
630        u32 edx;
631};
632
633struct wmab_ret {
634        u32 eax;
635        u32 ebx;
636        u32 ecx;
637        u32 edx;
638        u32 eex;
639};
640
641static acpi_status wmab_execute(struct wmab_args *regbuf,
642struct acpi_buffer *result)
643{
644        struct acpi_buffer input;
645        acpi_status status;
646        input.length = sizeof(struct wmab_args);
647        input.pointer = (u8 *)regbuf;
648
649        status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
650
651        return status;
652}
653
654static acpi_status AMW0_get_u32(u32 *value, u32 cap)
655{
656        int err;
657        u8 result;
658
659        switch (cap) {
660        case ACER_CAP_MAILLED:
661                switch (quirks->mailled) {
662                default:
663                        err = ec_read(0xA, &result);
664                        if (err)
665                                return AE_ERROR;
666                        *value = (result >> 7) & 0x1;
667                        return AE_OK;
668                }
669                break;
670        case ACER_CAP_WIRELESS:
671                switch (quirks->wireless) {
672                case 1:
673                        err = ec_read(0x7B, &result);
674                        if (err)
675                                return AE_ERROR;
676                        *value = result & 0x1;
677                        return AE_OK;
678                case 2:
679                        err = ec_read(0x71, &result);
680                        if (err)
681                                return AE_ERROR;
682                        *value = result & 0x1;
683                        return AE_OK;
684                case 3:
685                        err = ec_read(0x78, &result);
686                        if (err)
687                                return AE_ERROR;
688                        *value = result & 0x1;
689                        return AE_OK;
690                default:
691                        err = ec_read(0xA, &result);
692                        if (err)
693                                return AE_ERROR;
694                        *value = (result >> 2) & 0x1;
695                        return AE_OK;
696                }
697                break;
698        case ACER_CAP_BLUETOOTH:
699                switch (quirks->bluetooth) {
700                default:
701                        err = ec_read(0xA, &result);
702                        if (err)
703                                return AE_ERROR;
704                        *value = (result >> 4) & 0x1;
705                        return AE_OK;
706                }
707                break;
708        case ACER_CAP_BRIGHTNESS:
709                switch (quirks->brightness) {
710                default:
711                        err = ec_read(0x83, &result);
712                        if (err)
713                                return AE_ERROR;
714                        *value = result;
715                        return AE_OK;
716                }
717                break;
718        default:
719                return AE_ERROR;
720        }
721        return AE_OK;
722}
723
724static acpi_status AMW0_set_u32(u32 value, u32 cap)
725{
726        struct wmab_args args;
727
728        args.eax = ACER_AMW0_WRITE;
729        args.ebx = value ? (1<<8) : 0;
730        args.ecx = args.edx = 0;
731
732        switch (cap) {
733        case ACER_CAP_MAILLED:
734                if (value > 1)
735                        return AE_BAD_PARAMETER;
736                args.ebx |= ACER_AMW0_MAILLED_MASK;
737                break;
738        case ACER_CAP_WIRELESS:
739                if (value > 1)
740                        return AE_BAD_PARAMETER;
741                args.ebx |= ACER_AMW0_WIRELESS_MASK;
742                break;
743        case ACER_CAP_BLUETOOTH:
744                if (value > 1)
745                        return AE_BAD_PARAMETER;
746                args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
747                break;
748        case ACER_CAP_BRIGHTNESS:
749                if (value > max_brightness)
750                        return AE_BAD_PARAMETER;
751                switch (quirks->brightness) {
752                default:
753                        return ec_write(0x83, value);
754                        break;
755                }
756        default:
757                return AE_ERROR;
758        }
759
760        /* Actually do the set */
761        return wmab_execute(&args, NULL);
762}
763
764static acpi_status __init AMW0_find_mailled(void)
765{
766        struct wmab_args args;
767        struct wmab_ret ret;
768        acpi_status status = AE_OK;
769        struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
770        union acpi_object *obj;
771
772        args.eax = 0x86;
773        args.ebx = args.ecx = args.edx = 0;
774
775        status = wmab_execute(&args, &out);
776        if (ACPI_FAILURE(status))
777                return status;
778
779        obj = (union acpi_object *) out.pointer;
780        if (obj && obj->type == ACPI_TYPE_BUFFER &&
781        obj->buffer.length == sizeof(struct wmab_ret)) {
782                ret = *((struct wmab_ret *) obj->buffer.pointer);
783        } else {
784                kfree(out.pointer);
785                return AE_ERROR;
786        }
787
788        if (ret.eex & 0x1)
789                interface->capability |= ACER_CAP_MAILLED;
790
791        kfree(out.pointer);
792
793        return AE_OK;
794}
795
796static int AMW0_set_cap_acpi_check_device_found __initdata;
797
798static acpi_status __init AMW0_set_cap_acpi_check_device_cb(acpi_handle handle,
799        u32 level, void *context, void **retval)
800{
801        AMW0_set_cap_acpi_check_device_found = 1;
802        return AE_OK;
803}
804
805static const struct acpi_device_id norfkill_ids[] __initconst = {
806        { "VPC2004", 0},
807        { "IBM0068", 0},
808        { "LEN0068", 0},
809        { "SNY5001", 0},        /* sony-laptop in charge */
810        { "", 0},
811};
812
813static int __init AMW0_set_cap_acpi_check_device(void)
814{
815        const struct acpi_device_id *id;
816
817        for (id = norfkill_ids; id->id[0]; id++)
818                acpi_get_devices(id->id, AMW0_set_cap_acpi_check_device_cb,
819                                NULL, NULL);
820        return AMW0_set_cap_acpi_check_device_found;
821}
822
823static acpi_status __init AMW0_set_capabilities(void)
824{
825        struct wmab_args args;
826        struct wmab_ret ret;
827        acpi_status status;
828        struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
829        union acpi_object *obj;
830
831        /*
832         * On laptops with this strange GUID (non Acer), normal probing doesn't
833         * work.
834         */
835        if (wmi_has_guid(AMW0_GUID2)) {
836                if ((quirks != &quirk_unknown) ||
837                    !AMW0_set_cap_acpi_check_device())
838                        interface->capability |= ACER_CAP_WIRELESS;
839                return AE_OK;
840        }
841
842        args.eax = ACER_AMW0_WRITE;
843        args.ecx = args.edx = 0;
844
845        args.ebx = 0xa2 << 8;
846        args.ebx |= ACER_AMW0_WIRELESS_MASK;
847
848        status = wmab_execute(&args, &out);
849        if (ACPI_FAILURE(status))
850                return status;
851
852        obj = out.pointer;
853        if (obj && obj->type == ACPI_TYPE_BUFFER &&
854        obj->buffer.length == sizeof(struct wmab_ret)) {
855                ret = *((struct wmab_ret *) obj->buffer.pointer);
856        } else {
857                status = AE_ERROR;
858                goto out;
859        }
860
861        if (ret.eax & 0x1)
862                interface->capability |= ACER_CAP_WIRELESS;
863
864        args.ebx = 2 << 8;
865        args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
866
867        /*
868         * It's ok to use existing buffer for next wmab_execute call.
869         * But we need to kfree(out.pointer) if next wmab_execute fail.
870         */
871        status = wmab_execute(&args, &out);
872        if (ACPI_FAILURE(status))
873                goto out;
874
875        obj = (union acpi_object *) out.pointer;
876        if (obj && obj->type == ACPI_TYPE_BUFFER
877        && obj->buffer.length == sizeof(struct wmab_ret)) {
878                ret = *((struct wmab_ret *) obj->buffer.pointer);
879        } else {
880                status = AE_ERROR;
881                goto out;
882        }
883
884        if (ret.eax & 0x1)
885                interface->capability |= ACER_CAP_BLUETOOTH;
886
887        /*
888         * This appears to be safe to enable, since all Wistron based laptops
889         * appear to use the same EC register for brightness, even if they
890         * differ for wireless, etc
891         */
892        if (quirks->brightness >= 0)
893                interface->capability |= ACER_CAP_BRIGHTNESS;
894
895        status = AE_OK;
896out:
897        kfree(out.pointer);
898        return status;
899}
900
901static struct wmi_interface AMW0_interface = {
902        .type = ACER_AMW0,
903};
904
905static struct wmi_interface AMW0_V2_interface = {
906        .type = ACER_AMW0_V2,
907};
908
909/*
910 * New interface (The WMID interface)
911 */
912static acpi_status
913WMI_execute_u32(u32 method_id, u32 in, u32 *out)
914{
915        struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
916        struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
917        union acpi_object *obj;
918        u32 tmp = 0;
919        acpi_status status;
920
921        status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
922
923        if (ACPI_FAILURE(status))
924                return status;
925
926        obj = (union acpi_object *) result.pointer;
927        if (obj) {
928                if (obj->type == ACPI_TYPE_BUFFER &&
929                        (obj->buffer.length == sizeof(u32) ||
930                        obj->buffer.length == sizeof(u64))) {
931                        tmp = *((u32 *) obj->buffer.pointer);
932                } else if (obj->type == ACPI_TYPE_INTEGER) {
933                        tmp = (u32) obj->integer.value;
934                }
935        }
936
937        if (out)
938                *out = tmp;
939
940        kfree(result.pointer);
941
942        return status;
943}
944
945static acpi_status WMID_get_u32(u32 *value, u32 cap)
946{
947        acpi_status status;
948        u8 tmp;
949        u32 result, method_id = 0;
950
951        switch (cap) {
952        case ACER_CAP_WIRELESS:
953                method_id = ACER_WMID_GET_WIRELESS_METHODID;
954                break;
955        case ACER_CAP_BLUETOOTH:
956                method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
957                break;
958        case ACER_CAP_BRIGHTNESS:
959                method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
960                break;
961        case ACER_CAP_THREEG:
962                method_id = ACER_WMID_GET_THREEG_METHODID;
963                break;
964        case ACER_CAP_MAILLED:
965                if (quirks->mailled == 1) {
966                        ec_read(0x9f, &tmp);
967                        *value = tmp & 0x1;
968                        return 0;
969                }
970        default:
971                return AE_ERROR;
972        }
973        status = WMI_execute_u32(method_id, 0, &result);
974
975        if (ACPI_SUCCESS(status))
976                *value = (u8)result;
977
978        return status;
979}
980
981static acpi_status WMID_set_u32(u32 value, u32 cap)
982{
983        u32 method_id = 0;
984        char param;
985
986        switch (cap) {
987        case ACER_CAP_BRIGHTNESS:
988                if (value > max_brightness)
989                        return AE_BAD_PARAMETER;
990                method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
991                break;
992        case ACER_CAP_WIRELESS:
993                if (value > 1)
994                        return AE_BAD_PARAMETER;
995                method_id = ACER_WMID_SET_WIRELESS_METHODID;
996                break;
997        case ACER_CAP_BLUETOOTH:
998                if (value > 1)
999                        return AE_BAD_PARAMETER;
1000                method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
1001                break;
1002        case ACER_CAP_THREEG:
1003                if (value > 1)
1004                        return AE_BAD_PARAMETER;
1005                method_id = ACER_WMID_SET_THREEG_METHODID;
1006                break;
1007        case ACER_CAP_MAILLED:
1008                if (value > 1)
1009                        return AE_BAD_PARAMETER;
1010                if (quirks->mailled == 1) {
1011                        param = value ? 0x92 : 0x93;
1012                        i8042_lock_chip();
1013                        i8042_command(&param, 0x1059);
1014                        i8042_unlock_chip();
1015                        return 0;
1016                }
1017                break;
1018        default:
1019                return AE_ERROR;
1020        }
1021        return WMI_execute_u32(method_id, (u32)value, NULL);
1022}
1023
1024static acpi_status wmid3_get_device_status(u32 *value, u16 device)
1025{
1026        struct wmid3_gds_return_value return_value;
1027        acpi_status status;
1028        union acpi_object *obj;
1029        struct wmid3_gds_get_input_param params = {
1030                .function_num = 0x1,
1031                .hotkey_number = commun_fn_key_number,
1032                .devices = device,
1033        };
1034        struct acpi_buffer input = {
1035                sizeof(struct wmid3_gds_get_input_param),
1036                &params
1037        };
1038        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1039
1040        status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
1041        if (ACPI_FAILURE(status))
1042                return status;
1043
1044        obj = output.pointer;
1045
1046        if (!obj)
1047                return AE_ERROR;
1048        else if (obj->type != ACPI_TYPE_BUFFER) {
1049                kfree(obj);
1050                return AE_ERROR;
1051        }
1052        if (obj->buffer.length != 8) {
1053                pr_warn("Unknown buffer length %d\n", obj->buffer.length);
1054                kfree(obj);
1055                return AE_ERROR;
1056        }
1057
1058        return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1059        kfree(obj);
1060
1061        if (return_value.error_code || return_value.ec_return_value)
1062                pr_warn("Get 0x%x Device Status failed: 0x%x - 0x%x\n",
1063                        device,
1064                        return_value.error_code,
1065                        return_value.ec_return_value);
1066        else
1067                *value = !!(return_value.devices & device);
1068
1069        return status;
1070}
1071
1072static acpi_status wmid_v2_get_u32(u32 *value, u32 cap)
1073{
1074        u16 device;
1075
1076        switch (cap) {
1077        case ACER_CAP_WIRELESS:
1078                device = ACER_WMID3_GDS_WIRELESS;
1079                break;
1080        case ACER_CAP_BLUETOOTH:
1081                device = ACER_WMID3_GDS_BLUETOOTH;
1082                break;
1083        case ACER_CAP_THREEG:
1084                device = ACER_WMID3_GDS_THREEG;
1085                break;
1086        default:
1087                return AE_ERROR;
1088        }
1089        return wmid3_get_device_status(value, device);
1090}
1091
1092static acpi_status wmid3_set_device_status(u32 value, u16 device)
1093{
1094        struct wmid3_gds_return_value return_value;
1095        acpi_status status;
1096        union acpi_object *obj;
1097        u16 devices;
1098        struct wmid3_gds_get_input_param get_params = {
1099                .function_num = 0x1,
1100                .hotkey_number = commun_fn_key_number,
1101                .devices = commun_func_bitmap,
1102        };
1103        struct acpi_buffer get_input = {
1104                sizeof(struct wmid3_gds_get_input_param),
1105                &get_params
1106        };
1107        struct wmid3_gds_set_input_param set_params = {
1108                .function_num = 0x2,
1109                .hotkey_number = commun_fn_key_number,
1110                .devices = commun_func_bitmap,
1111        };
1112        struct acpi_buffer set_input = {
1113                sizeof(struct wmid3_gds_set_input_param),
1114                &set_params
1115        };
1116        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1117        struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
1118
1119        status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &get_input, &output);
1120        if (ACPI_FAILURE(status))
1121                return status;
1122
1123        obj = output.pointer;
1124
1125        if (!obj)
1126                return AE_ERROR;
1127        else if (obj->type != ACPI_TYPE_BUFFER) {
1128                kfree(obj);
1129                return AE_ERROR;
1130        }
1131        if (obj->buffer.length != 8) {
1132                pr_warn("Unknown buffer length %d\n", obj->buffer.length);
1133                kfree(obj);
1134                return AE_ERROR;
1135        }
1136
1137        return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1138        kfree(obj);
1139
1140        if (return_value.error_code || return_value.ec_return_value) {
1141                pr_warn("Get Current Device Status failed: 0x%x - 0x%x\n",
1142                        return_value.error_code,
1143                        return_value.ec_return_value);
1144                return status;
1145        }
1146
1147        devices = return_value.devices;
1148        set_params.devices = (value) ? (devices | device) : (devices & ~device);
1149
1150        status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &set_input, &output2);
1151        if (ACPI_FAILURE(status))
1152                return status;
1153
1154        obj = output2.pointer;
1155
1156        if (!obj)
1157                return AE_ERROR;
1158        else if (obj->type != ACPI_TYPE_BUFFER) {
1159                kfree(obj);
1160                return AE_ERROR;
1161        }
1162        if (obj->buffer.length != 4) {
1163                pr_warn("Unknown buffer length %d\n", obj->buffer.length);
1164                kfree(obj);
1165                return AE_ERROR;
1166        }
1167
1168        return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1169        kfree(obj);
1170
1171        if (return_value.error_code || return_value.ec_return_value)
1172                pr_warn("Set Device Status failed: 0x%x - 0x%x\n",
1173                        return_value.error_code,
1174                        return_value.ec_return_value);
1175
1176        return status;
1177}
1178
1179static acpi_status wmid_v2_set_u32(u32 value, u32 cap)
1180{
1181        u16 device;
1182
1183        switch (cap) {
1184        case ACER_CAP_WIRELESS:
1185                device = ACER_WMID3_GDS_WIRELESS;
1186                break;
1187        case ACER_CAP_BLUETOOTH:
1188                device = ACER_WMID3_GDS_BLUETOOTH;
1189                break;
1190        case ACER_CAP_THREEG:
1191                device = ACER_WMID3_GDS_THREEG;
1192                break;
1193        default:
1194                return AE_ERROR;
1195        }
1196        return wmid3_set_device_status(value, device);
1197}
1198
1199static void __init type_aa_dmi_decode(const struct dmi_header *header, void *d)
1200{
1201        struct hotkey_function_type_aa *type_aa;
1202
1203        /* We are looking for OEM-specific Type AAh */
1204        if (header->type != 0xAA)
1205                return;
1206
1207        has_type_aa = true;
1208        type_aa = (struct hotkey_function_type_aa *) header;
1209
1210        pr_info("Function bitmap for Communication Button: 0x%x\n",
1211                type_aa->commun_func_bitmap);
1212        commun_func_bitmap = type_aa->commun_func_bitmap;
1213
1214        if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
1215                interface->capability |= ACER_CAP_WIRELESS;
1216        if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_THREEG)
1217                interface->capability |= ACER_CAP_THREEG;
1218        if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
1219                interface->capability |= ACER_CAP_BLUETOOTH;
1220
1221        commun_fn_key_number = type_aa->commun_fn_key_number;
1222}
1223
1224static acpi_status __init WMID_set_capabilities(void)
1225{
1226        struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
1227        union acpi_object *obj;
1228        acpi_status status;
1229        u32 devices;
1230
1231        status = wmi_query_block(WMID_GUID2, 1, &out);
1232        if (ACPI_FAILURE(status))
1233                return status;
1234
1235        obj = (union acpi_object *) out.pointer;
1236        if (obj) {
1237                if (obj->type == ACPI_TYPE_BUFFER &&
1238                        (obj->buffer.length == sizeof(u32) ||
1239                        obj->buffer.length == sizeof(u64))) {
1240                        devices = *((u32 *) obj->buffer.pointer);
1241                } else if (obj->type == ACPI_TYPE_INTEGER) {
1242                        devices = (u32) obj->integer.value;
1243                } else {
1244                        kfree(out.pointer);
1245                        return AE_ERROR;
1246                }
1247        } else {
1248                kfree(out.pointer);
1249                return AE_ERROR;
1250        }
1251
1252        pr_info("Function bitmap for Communication Device: 0x%x\n", devices);
1253        if (devices & 0x07)
1254                interface->capability |= ACER_CAP_WIRELESS;
1255        if (devices & 0x40)
1256                interface->capability |= ACER_CAP_THREEG;
1257        if (devices & 0x10)
1258                interface->capability |= ACER_CAP_BLUETOOTH;
1259
1260        if (!(devices & 0x20))
1261                max_brightness = 0x9;
1262
1263        kfree(out.pointer);
1264        return status;
1265}
1266
1267static struct wmi_interface wmid_interface = {
1268        .type = ACER_WMID,
1269};
1270
1271static struct wmi_interface wmid_v2_interface = {
1272        .type = ACER_WMID_v2,
1273};
1274
1275/*
1276 * Generic Device (interface-independent)
1277 */
1278
1279static acpi_status get_u32(u32 *value, u32 cap)
1280{
1281        acpi_status status = AE_ERROR;
1282
1283        switch (interface->type) {
1284        case ACER_AMW0:
1285                status = AMW0_get_u32(value, cap);
1286                break;
1287        case ACER_AMW0_V2:
1288                if (cap == ACER_CAP_MAILLED) {
1289                        status = AMW0_get_u32(value, cap);
1290                        break;
1291                }
1292        case ACER_WMID:
1293                status = WMID_get_u32(value, cap);
1294                break;
1295        case ACER_WMID_v2:
1296                if (cap & (ACER_CAP_WIRELESS |
1297                           ACER_CAP_BLUETOOTH |
1298                           ACER_CAP_THREEG))
1299                        status = wmid_v2_get_u32(value, cap);
1300                else if (wmi_has_guid(WMID_GUID2))
1301                        status = WMID_get_u32(value, cap);
1302                break;
1303        }
1304
1305        return status;
1306}
1307
1308static acpi_status set_u32(u32 value, u32 cap)
1309{
1310        acpi_status status;
1311
1312        if (interface->capability & cap) {
1313                switch (interface->type) {
1314                case ACER_AMW0:
1315                        return AMW0_set_u32(value, cap);
1316                case ACER_AMW0_V2:
1317                        if (cap == ACER_CAP_MAILLED)
1318                                return AMW0_set_u32(value, cap);
1319
1320                        /*
1321                         * On some models, some WMID methods don't toggle
1322                         * properly. For those cases, we want to run the AMW0
1323                         * method afterwards to be certain we've really toggled
1324                         * the device state.
1325                         */
1326                        if (cap == ACER_CAP_WIRELESS ||
1327                                cap == ACER_CAP_BLUETOOTH) {
1328                                status = WMID_set_u32(value, cap);
1329                                if (ACPI_FAILURE(status))
1330                                        return status;
1331
1332                                return AMW0_set_u32(value, cap);
1333                        }
1334                case ACER_WMID:
1335                        return WMID_set_u32(value, cap);
1336                case ACER_WMID_v2:
1337                        if (cap & (ACER_CAP_WIRELESS |
1338                                   ACER_CAP_BLUETOOTH |
1339                                   ACER_CAP_THREEG))
1340                                return wmid_v2_set_u32(value, cap);
1341                        else if (wmi_has_guid(WMID_GUID2))
1342                                return WMID_set_u32(value, cap);
1343                default:
1344                        return AE_BAD_PARAMETER;
1345                }
1346        }
1347        return AE_BAD_PARAMETER;
1348}
1349
1350static void __init acer_commandline_init(void)
1351{
1352        /*
1353         * These will all fail silently if the value given is invalid, or the
1354         * capability isn't available on the given interface
1355         */
1356        if (mailled >= 0)
1357                set_u32(mailled, ACER_CAP_MAILLED);
1358        if (!has_type_aa && threeg >= 0)
1359                set_u32(threeg, ACER_CAP_THREEG);
1360        if (brightness >= 0)
1361                set_u32(brightness, ACER_CAP_BRIGHTNESS);
1362}
1363
1364/*
1365 * LED device (Mail LED only, no other LEDs known yet)
1366 */
1367static void mail_led_set(struct led_classdev *led_cdev,
1368enum led_brightness value)
1369{
1370        set_u32(value, ACER_CAP_MAILLED);
1371}
1372
1373static struct led_classdev mail_led = {
1374        .name = "acer-wmi::mail",
1375        .brightness_set = mail_led_set,
1376};
1377
1378static int acer_led_init(struct device *dev)
1379{
1380        return led_classdev_register(dev, &mail_led);
1381}
1382
1383static void acer_led_exit(void)
1384{
1385        set_u32(LED_OFF, ACER_CAP_MAILLED);
1386        led_classdev_unregister(&mail_led);
1387}
1388
1389/*
1390 * Backlight device
1391 */
1392static struct backlight_device *acer_backlight_device;
1393
1394static int read_brightness(struct backlight_device *bd)
1395{
1396        u32 value;
1397        get_u32(&value, ACER_CAP_BRIGHTNESS);
1398        return value;
1399}
1400
1401static int update_bl_status(struct backlight_device *bd)
1402{
1403        int intensity = bd->props.brightness;
1404
1405        if (bd->props.power != FB_BLANK_UNBLANK)
1406                intensity = 0;
1407        if (bd->props.fb_blank != FB_BLANK_UNBLANK)
1408                intensity = 0;
1409
1410        set_u32(intensity, ACER_CAP_BRIGHTNESS);
1411
1412        return 0;
1413}
1414
1415static const struct backlight_ops acer_bl_ops = {
1416        .get_brightness = read_brightness,
1417        .update_status = update_bl_status,
1418};
1419
1420static int acer_backlight_init(struct device *dev)
1421{
1422        struct backlight_properties props;
1423        struct backlight_device *bd;
1424
1425        memset(&props, 0, sizeof(struct backlight_properties));
1426        props.type = BACKLIGHT_PLATFORM;
1427        props.max_brightness = max_brightness;
1428        bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
1429                                       &props);
1430        if (IS_ERR(bd)) {
1431                pr_err("Could not register Acer backlight device\n");
1432                acer_backlight_device = NULL;
1433                return PTR_ERR(bd);
1434        }
1435
1436        acer_backlight_device = bd;
1437
1438        bd->props.power = FB_BLANK_UNBLANK;
1439        bd->props.brightness = read_brightness(bd);
1440        backlight_update_status(bd);
1441        return 0;
1442}
1443
1444static void acer_backlight_exit(void)
1445{
1446        backlight_device_unregister(acer_backlight_device);
1447}
1448
1449/*
1450 * Accelerometer device
1451 */
1452static acpi_handle gsensor_handle;
1453
1454static int acer_gsensor_init(void)
1455{
1456        acpi_status status;
1457        struct acpi_buffer output;
1458        union acpi_object out_obj;
1459
1460        output.length = sizeof(out_obj);
1461        output.pointer = &out_obj;
1462        status = acpi_evaluate_object(gsensor_handle, "_INI", NULL, &output);
1463        if (ACPI_FAILURE(status))
1464                return -1;
1465
1466        return 0;
1467}
1468
1469static int acer_gsensor_open(struct input_dev *input)
1470{
1471        return acer_gsensor_init();
1472}
1473
1474static int acer_gsensor_event(void)
1475{
1476        acpi_status status;
1477        struct acpi_buffer output;
1478        union acpi_object out_obj[5];
1479
1480        if (!has_cap(ACER_CAP_ACCEL))
1481                return -1;
1482
1483        output.length = sizeof(out_obj);
1484        output.pointer = out_obj;
1485
1486        status = acpi_evaluate_object(gsensor_handle, "RDVL", NULL, &output);
1487        if (ACPI_FAILURE(status))
1488                return -1;
1489
1490        if (out_obj->package.count != 4)
1491                return -1;
1492
1493        input_report_abs(acer_wmi_accel_dev, ABS_X,
1494                (s16)out_obj->package.elements[0].integer.value);
1495        input_report_abs(acer_wmi_accel_dev, ABS_Y,
1496                (s16)out_obj->package.elements[1].integer.value);
1497        input_report_abs(acer_wmi_accel_dev, ABS_Z,
1498                (s16)out_obj->package.elements[2].integer.value);
1499        input_sync(acer_wmi_accel_dev);
1500        return 0;
1501}
1502
1503/*
1504 * Rfkill devices
1505 */
1506static void acer_rfkill_update(struct work_struct *ignored);
1507static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
1508static void acer_rfkill_update(struct work_struct *ignored)
1509{
1510        u32 state;
1511        acpi_status status;
1512
1513        if (has_cap(ACER_CAP_WIRELESS)) {
1514                status = get_u32(&state, ACER_CAP_WIRELESS);
1515                if (ACPI_SUCCESS(status)) {
1516                        if (quirks->wireless == 3)
1517                                rfkill_set_hw_state(wireless_rfkill, !state);
1518                        else
1519                                rfkill_set_sw_state(wireless_rfkill, !state);
1520                }
1521        }
1522
1523        if (has_cap(ACER_CAP_BLUETOOTH)) {
1524                status = get_u32(&state, ACER_CAP_BLUETOOTH);
1525                if (ACPI_SUCCESS(status))
1526                        rfkill_set_sw_state(bluetooth_rfkill, !state);
1527        }
1528
1529        if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
1530                status = get_u32(&state, ACER_WMID3_GDS_THREEG);
1531                if (ACPI_SUCCESS(status))
1532                        rfkill_set_sw_state(threeg_rfkill, !state);
1533        }
1534
1535        schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
1536}
1537
1538static int acer_rfkill_set(void *data, bool blocked)
1539{
1540        acpi_status status;
1541        u32 cap = (unsigned long)data;
1542
1543        if (rfkill_inited) {
1544                status = set_u32(!blocked, cap);
1545                if (ACPI_FAILURE(status))
1546                        return -ENODEV;
1547        }
1548
1549        return 0;
1550}
1551
1552static const struct rfkill_ops acer_rfkill_ops = {
1553        .set_block = acer_rfkill_set,
1554};
1555
1556static struct rfkill *acer_rfkill_register(struct device *dev,
1557                                           enum rfkill_type type,
1558                                           char *name, u32 cap)
1559{
1560        int err;
1561        struct rfkill *rfkill_dev;
1562        u32 state;
1563        acpi_status status;
1564
1565        rfkill_dev = rfkill_alloc(name, dev, type,
1566                                  &acer_rfkill_ops,
1567                                  (void *)(unsigned long)cap);
1568        if (!rfkill_dev)
1569                return ERR_PTR(-ENOMEM);
1570
1571        status = get_u32(&state, cap);
1572
1573        err = rfkill_register(rfkill_dev);
1574        if (err) {
1575                rfkill_destroy(rfkill_dev);
1576                return ERR_PTR(err);
1577        }
1578
1579        if (ACPI_SUCCESS(status))
1580                rfkill_set_sw_state(rfkill_dev, !state);
1581
1582        return rfkill_dev;
1583}
1584
1585static int acer_rfkill_init(struct device *dev)
1586{
1587        int err;
1588
1589        if (has_cap(ACER_CAP_WIRELESS)) {
1590                wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
1591                        "acer-wireless", ACER_CAP_WIRELESS);
1592                if (IS_ERR(wireless_rfkill)) {
1593                        err = PTR_ERR(wireless_rfkill);
1594                        goto error_wireless;
1595                }
1596        }
1597
1598        if (has_cap(ACER_CAP_BLUETOOTH)) {
1599                bluetooth_rfkill = acer_rfkill_register(dev,
1600                        RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
1601                        ACER_CAP_BLUETOOTH);
1602                if (IS_ERR(bluetooth_rfkill)) {
1603                        err = PTR_ERR(bluetooth_rfkill);
1604                        goto error_bluetooth;
1605                }
1606        }
1607
1608        if (has_cap(ACER_CAP_THREEG)) {
1609                threeg_rfkill = acer_rfkill_register(dev,
1610                        RFKILL_TYPE_WWAN, "acer-threeg",
1611                        ACER_CAP_THREEG);
1612                if (IS_ERR(threeg_rfkill)) {
1613                        err = PTR_ERR(threeg_rfkill);
1614                        goto error_threeg;
1615                }
1616        }
1617
1618        rfkill_inited = true;
1619
1620        if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
1621            has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
1622                schedule_delayed_work(&acer_rfkill_work,
1623                        round_jiffies_relative(HZ));
1624
1625        return 0;
1626
1627error_threeg:
1628        if (has_cap(ACER_CAP_BLUETOOTH)) {
1629                rfkill_unregister(bluetooth_rfkill);
1630                rfkill_destroy(bluetooth_rfkill);
1631        }
1632error_bluetooth:
1633        if (has_cap(ACER_CAP_WIRELESS)) {
1634                rfkill_unregister(wireless_rfkill);
1635                rfkill_destroy(wireless_rfkill);
1636        }
1637error_wireless:
1638        return err;
1639}
1640
1641static void acer_rfkill_exit(void)
1642{
1643        if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
1644            has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
1645                cancel_delayed_work_sync(&acer_rfkill_work);
1646
1647        if (has_cap(ACER_CAP_WIRELESS)) {
1648                rfkill_unregister(wireless_rfkill);
1649                rfkill_destroy(wireless_rfkill);
1650        }
1651
1652        if (has_cap(ACER_CAP_BLUETOOTH)) {
1653                rfkill_unregister(bluetooth_rfkill);
1654                rfkill_destroy(bluetooth_rfkill);
1655        }
1656
1657        if (has_cap(ACER_CAP_THREEG)) {
1658                rfkill_unregister(threeg_rfkill);
1659                rfkill_destroy(threeg_rfkill);
1660        }
1661        return;
1662}
1663
1664/*
1665 * sysfs interface
1666 */
1667static ssize_t show_bool_threeg(struct device *dev,
1668        struct device_attribute *attr, char *buf)
1669{
1670        u32 result; \
1671        acpi_status status;
1672
1673        pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n",
1674                current->comm);
1675        status = get_u32(&result, ACER_CAP_THREEG);
1676        if (ACPI_SUCCESS(status))
1677                return sprintf(buf, "%u\n", result);
1678        return sprintf(buf, "Read error\n");
1679}
1680
1681static ssize_t set_bool_threeg(struct device *dev,
1682        struct device_attribute *attr, const char *buf, size_t count)
1683{
1684        u32 tmp = simple_strtoul(buf, NULL, 10);
1685        acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
1686        pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n",
1687                current->comm);
1688        if (ACPI_FAILURE(status))
1689                return -EINVAL;
1690        return count;
1691}
1692static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
1693        set_bool_threeg);
1694
1695static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1696        char *buf)
1697{
1698        pr_info("This interface sysfs will be removed in 2014 - used by: %s\n",
1699                current->comm);
1700        switch (interface->type) {
1701        case ACER_AMW0:
1702                return sprintf(buf, "AMW0\n");
1703        case ACER_AMW0_V2:
1704                return sprintf(buf, "AMW0 v2\n");
1705        case ACER_WMID:
1706                return sprintf(buf, "WMID\n");
1707        case ACER_WMID_v2:
1708                return sprintf(buf, "WMID v2\n");
1709        default:
1710                return sprintf(buf, "Error!\n");
1711        }
1712}
1713
1714static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
1715
1716static void acer_wmi_notify(u32 value, void *context)
1717{
1718        struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
1719        union acpi_object *obj;
1720        struct event_return_value return_value;
1721        acpi_status status;
1722        u16 device_state;
1723        const struct key_entry *key;
1724        u32 scancode;
1725
1726        status = wmi_get_event_data(value, &response);
1727        if (status != AE_OK) {
1728                pr_warn("bad event status 0x%x\n", status);
1729                return;
1730        }
1731
1732        obj = (union acpi_object *)response.pointer;
1733
1734        if (!obj)
1735                return;
1736        if (obj->type != ACPI_TYPE_BUFFER) {
1737                pr_warn("Unknown response received %d\n", obj->type);
1738                kfree(obj);
1739                return;
1740        }
1741        if (obj->buffer.length != 8) {
1742                pr_warn("Unknown buffer length %d\n", obj->buffer.length);
1743                kfree(obj);
1744                return;
1745        }
1746
1747        return_value = *((struct event_return_value *)obj->buffer.pointer);
1748        kfree(obj);
1749
1750        switch (return_value.function) {
1751        case WMID_HOTKEY_EVENT:
1752                device_state = return_value.device_state;
1753                pr_debug("device state: 0x%x\n", device_state);
1754
1755                key = sparse_keymap_entry_from_scancode(acer_wmi_input_dev,
1756                                                        return_value.key_num);
1757                if (!key) {
1758                        pr_warn("Unknown key number - 0x%x\n",
1759                                return_value.key_num);
1760                } else {
1761                        scancode = return_value.key_num;
1762                        switch (key->keycode) {
1763                        case KEY_WLAN:
1764                        case KEY_BLUETOOTH:
1765                                if (has_cap(ACER_CAP_WIRELESS))
1766                                        rfkill_set_sw_state(wireless_rfkill,
1767                                                !(device_state & ACER_WMID3_GDS_WIRELESS));
1768                                if (has_cap(ACER_CAP_THREEG))
1769                                        rfkill_set_sw_state(threeg_rfkill,
1770                                                !(device_state & ACER_WMID3_GDS_THREEG));
1771                                if (has_cap(ACER_CAP_BLUETOOTH))
1772                                        rfkill_set_sw_state(bluetooth_rfkill,
1773                                                !(device_state & ACER_WMID3_GDS_BLUETOOTH));
1774                                break;
1775                        case KEY_TOUCHPAD_TOGGLE:
1776                                scancode = (device_state & ACER_WMID3_GDS_TOUCHPAD) ?
1777                                                KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF;
1778                        }
1779                        sparse_keymap_report_event(acer_wmi_input_dev, scancode, 1, true);
1780                }
1781                break;
1782        case WMID_ACCEL_EVENT:
1783                acer_gsensor_event();
1784                break;
1785        default:
1786                pr_warn("Unknown function number - %d - %d\n",
1787                        return_value.function, return_value.key_num);
1788                break;
1789        }
1790}
1791
1792static acpi_status __init
1793wmid3_set_lm_mode(struct lm_input_params *params,
1794                  struct lm_return_value *return_value)
1795{
1796        acpi_status status;
1797        union acpi_object *obj;
1798
1799        struct acpi_buffer input = { sizeof(struct lm_input_params), params };
1800        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1801
1802        status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
1803        if (ACPI_FAILURE(status))
1804                return status;
1805
1806        obj = output.pointer;
1807
1808        if (!obj)
1809                return AE_ERROR;
1810        else if (obj->type != ACPI_TYPE_BUFFER) {
1811                kfree(obj);
1812                return AE_ERROR;
1813        }
1814        if (obj->buffer.length != 4) {
1815                pr_warn("Unknown buffer length %d\n", obj->buffer.length);
1816                kfree(obj);
1817                return AE_ERROR;
1818        }
1819
1820        *return_value = *((struct lm_return_value *)obj->buffer.pointer);
1821        kfree(obj);
1822
1823        return status;
1824}
1825
1826static int __init acer_wmi_enable_ec_raw(void)
1827{
1828        struct lm_return_value return_value;
1829        acpi_status status;
1830        struct lm_input_params params = {
1831                .function_num = 0x1,
1832                .commun_devices = 0xFFFF,
1833                .devices = 0xFFFF,
1834                .lm_status = 0x00,            /* Launch Manager Deactive */
1835        };
1836
1837        status = wmid3_set_lm_mode(&params, &return_value);
1838
1839        if (return_value.error_code || return_value.ec_return_value)
1840                pr_warn("Enabling EC raw mode failed: 0x%x - 0x%x\n",
1841                        return_value.error_code,
1842                        return_value.ec_return_value);
1843        else
1844                pr_info("Enabled EC raw mode\n");
1845
1846        return status;
1847}
1848
1849static int __init acer_wmi_enable_lm(void)
1850{
1851        struct lm_return_value return_value;
1852        acpi_status status;
1853        struct lm_input_params params = {
1854                .function_num = 0x1,
1855                .commun_devices = 0xFFFF,
1856                .devices = 0xFFFF,
1857                .lm_status = 0x01,            /* Launch Manager Active */
1858        };
1859
1860        status = wmid3_set_lm_mode(&params, &return_value);
1861
1862        if (return_value.error_code || return_value.ec_return_value)
1863                pr_warn("Enabling Launch Manager failed: 0x%x - 0x%x\n",
1864                        return_value.error_code,
1865                        return_value.ec_return_value);
1866
1867        return status;
1868}
1869
1870#define ACER_WMID_ACCEL_HID     "BST0001"
1871
1872static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level,
1873                                                void *ctx, void **retval)
1874{
1875        struct acpi_device *dev;
1876
1877        if (!strcmp(ctx, "SENR")) {
1878                if (acpi_bus_get_device(ah, &dev))
1879                        return AE_OK;
1880                if (!strcmp(ACER_WMID_ACCEL_HID, acpi_device_hid(dev)))
1881                        return AE_OK;
1882        } else
1883                return AE_OK;
1884
1885        *(acpi_handle *)retval = ah;
1886
1887        return AE_CTRL_TERMINATE;
1888}
1889
1890static int __init acer_wmi_get_handle(const char *name, const char *prop,
1891                                        acpi_handle *ah)
1892{
1893        acpi_status status;
1894        acpi_handle handle;
1895
1896        BUG_ON(!name || !ah);
1897
1898        handle = NULL;
1899        status = acpi_get_devices(prop, acer_wmi_get_handle_cb,
1900                                        (void *)name, &handle);
1901
1902        if (ACPI_SUCCESS(status)) {
1903                *ah = handle;
1904                return 0;
1905        } else {
1906                return -ENODEV;
1907        }
1908}
1909
1910static int __init acer_wmi_accel_setup(void)
1911{
1912        int err;
1913
1914        err = acer_wmi_get_handle("SENR", ACER_WMID_ACCEL_HID, &gsensor_handle);
1915        if (err)
1916                return err;
1917
1918        interface->capability |= ACER_CAP_ACCEL;
1919
1920        acer_wmi_accel_dev = input_allocate_device();
1921        if (!acer_wmi_accel_dev)
1922                return -ENOMEM;
1923
1924        acer_wmi_accel_dev->open = acer_gsensor_open;
1925
1926        acer_wmi_accel_dev->name = "Acer BMA150 accelerometer";
1927        acer_wmi_accel_dev->phys = "wmi/input1";
1928        acer_wmi_accel_dev->id.bustype = BUS_HOST;
1929        acer_wmi_accel_dev->evbit[0] = BIT_MASK(EV_ABS);
1930        input_set_abs_params(acer_wmi_accel_dev, ABS_X, -16384, 16384, 0, 0);
1931        input_set_abs_params(acer_wmi_accel_dev, ABS_Y, -16384, 16384, 0, 0);
1932        input_set_abs_params(acer_wmi_accel_dev, ABS_Z, -16384, 16384, 0, 0);
1933
1934        err = input_register_device(acer_wmi_accel_dev);
1935        if (err)
1936                goto err_free_dev;
1937
1938        return 0;
1939
1940err_free_dev:
1941        input_free_device(acer_wmi_accel_dev);
1942        return err;
1943}
1944
1945static void acer_wmi_accel_destroy(void)
1946{
1947        input_unregister_device(acer_wmi_accel_dev);
1948}
1949
1950static int __init acer_wmi_input_setup(void)
1951{
1952        acpi_status status;
1953        int err;
1954
1955        acer_wmi_input_dev = input_allocate_device();
1956        if (!acer_wmi_input_dev)
1957                return -ENOMEM;
1958
1959        acer_wmi_input_dev->name = "Acer WMI hotkeys";
1960        acer_wmi_input_dev->phys = "wmi/input0";
1961        acer_wmi_input_dev->id.bustype = BUS_HOST;
1962
1963        err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
1964        if (err)
1965                goto err_free_dev;
1966
1967        status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
1968                                                acer_wmi_notify, NULL);
1969        if (ACPI_FAILURE(status)) {
1970                err = -EIO;
1971                goto err_free_keymap;
1972        }
1973
1974        err = input_register_device(acer_wmi_input_dev);
1975        if (err)
1976                goto err_uninstall_notifier;
1977
1978        return 0;
1979
1980err_uninstall_notifier:
1981        wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
1982err_free_keymap:
1983        sparse_keymap_free(acer_wmi_input_dev);
1984err_free_dev:
1985        input_free_device(acer_wmi_input_dev);
1986        return err;
1987}
1988
1989static void acer_wmi_input_destroy(void)
1990{
1991        wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
1992        sparse_keymap_free(acer_wmi_input_dev);
1993        input_unregister_device(acer_wmi_input_dev);
1994}
1995
1996/*
1997 * debugfs functions
1998 */
1999static u32 get_wmid_devices(void)
2000{
2001        struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
2002        union acpi_object *obj;
2003        acpi_status status;
2004        u32 devices = 0;
2005
2006        status = wmi_query_block(WMID_GUID2, 1, &out);
2007        if (ACPI_FAILURE(status))
2008                return 0;
2009
2010        obj = (union acpi_object *) out.pointer;
2011        if (obj) {
2012                if (obj->type == ACPI_TYPE_BUFFER &&
2013                        (obj->buffer.length == sizeof(u32) ||
2014                        obj->buffer.length == sizeof(u64))) {
2015                        devices = *((u32 *) obj->buffer.pointer);
2016                } else if (obj->type == ACPI_TYPE_INTEGER) {
2017                        devices = (u32) obj->integer.value;
2018                }
2019        }
2020
2021        kfree(out.pointer);
2022        return devices;
2023}
2024
2025/*
2026 * Platform device
2027 */
2028static int acer_platform_probe(struct platform_device *device)
2029{
2030        int err;
2031
2032        if (has_cap(ACER_CAP_MAILLED)) {
2033                err = acer_led_init(&device->dev);
2034                if (err)
2035                        goto error_mailled;
2036        }
2037
2038        if (has_cap(ACER_CAP_BRIGHTNESS)) {
2039                err = acer_backlight_init(&device->dev);
2040                if (err)
2041                        goto error_brightness;
2042        }
2043
2044        err = acer_rfkill_init(&device->dev);
2045        if (err)
2046                goto error_rfkill;
2047
2048        return err;
2049
2050error_rfkill:
2051        if (has_cap(ACER_CAP_BRIGHTNESS))
2052                acer_backlight_exit();
2053error_brightness:
2054        if (has_cap(ACER_CAP_MAILLED))
2055                acer_led_exit();
2056error_mailled:
2057        return err;
2058}
2059
2060static int acer_platform_remove(struct platform_device *device)
2061{
2062        if (has_cap(ACER_CAP_MAILLED))
2063                acer_led_exit();
2064        if (has_cap(ACER_CAP_BRIGHTNESS))
2065                acer_backlight_exit();
2066
2067        acer_rfkill_exit();
2068        return 0;
2069}
2070
2071#ifdef CONFIG_PM_SLEEP
2072static int acer_suspend(struct device *dev)
2073{
2074        u32 value;
2075        struct acer_data *data = &interface->data;
2076
2077        if (!data)
2078                return -ENOMEM;
2079
2080        if (has_cap(ACER_CAP_MAILLED)) {
2081                get_u32(&value, ACER_CAP_MAILLED);
2082                set_u32(LED_OFF, ACER_CAP_MAILLED);
2083                data->mailled = value;
2084        }
2085
2086        if (has_cap(ACER_CAP_BRIGHTNESS)) {
2087                get_u32(&value, ACER_CAP_BRIGHTNESS);
2088                data->brightness = value;
2089        }
2090
2091        return 0;
2092}
2093
2094static int acer_resume(struct device *dev)
2095{
2096        struct acer_data *data = &interface->data;
2097
2098        if (!data)
2099                return -ENOMEM;
2100
2101        if (has_cap(ACER_CAP_MAILLED))
2102                set_u32(data->mailled, ACER_CAP_MAILLED);
2103
2104        if (has_cap(ACER_CAP_BRIGHTNESS))
2105                set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
2106
2107        if (has_cap(ACER_CAP_ACCEL))
2108                acer_gsensor_init();
2109
2110        return 0;
2111}
2112#else
2113#define acer_suspend    NULL
2114#define acer_resume     NULL
2115#endif
2116
2117static SIMPLE_DEV_PM_OPS(acer_pm, acer_suspend, acer_resume);
2118
2119static void acer_platform_shutdown(struct platform_device *device)
2120{
2121        struct acer_data *data = &interface->data;
2122
2123        if (!data)
2124                return;
2125
2126        if (has_cap(ACER_CAP_MAILLED))
2127                set_u32(LED_OFF, ACER_CAP_MAILLED);
2128}
2129
2130static struct platform_driver acer_platform_driver = {
2131        .driver = {
2132                .name = "acer-wmi",
2133                .owner = THIS_MODULE,
2134                .pm = &acer_pm,
2135        },
2136        .probe = acer_platform_probe,
2137        .remove = acer_platform_remove,
2138        .shutdown = acer_platform_shutdown,
2139};
2140
2141static struct platform_device *acer_platform_device;
2142
2143static int remove_sysfs(struct platform_device *device)
2144{
2145        if (has_cap(ACER_CAP_THREEG))
2146                device_remove_file(&device->dev, &dev_attr_threeg);
2147
2148        device_remove_file(&device->dev, &dev_attr_interface);
2149
2150        return 0;
2151}
2152
2153static int __init create_sysfs(void)
2154{
2155        int retval = -ENOMEM;
2156
2157        if (has_cap(ACER_CAP_THREEG)) {
2158                retval = device_create_file(&acer_platform_device->dev,
2159                        &dev_attr_threeg);
2160                if (retval)
2161                        goto error_sysfs;
2162        }
2163
2164        retval = device_create_file(&acer_platform_device->dev,
2165                &dev_attr_interface);
2166        if (retval)
2167                goto error_sysfs;
2168
2169        return 0;
2170
2171error_sysfs:
2172                remove_sysfs(acer_platform_device);
2173        return retval;
2174}
2175
2176static void remove_debugfs(void)
2177{
2178        debugfs_remove(interface->debug.devices);
2179        debugfs_remove(interface->debug.root);
2180}
2181
2182static int __init create_debugfs(void)
2183{
2184        interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
2185        if (!interface->debug.root) {
2186                pr_err("Failed to create debugfs directory");
2187                return -ENOMEM;
2188        }
2189
2190        interface->debug.devices = debugfs_create_u32("devices", S_IRUGO,
2191                                        interface->debug.root,
2192                                        &interface->debug.wmid_devices);
2193        if (!interface->debug.devices)
2194                goto error_debugfs;
2195
2196        return 0;
2197
2198error_debugfs:
2199        remove_debugfs();
2200        return -ENOMEM;
2201}
2202
2203static int __init acer_wmi_init(void)
2204{
2205        int err;
2206
2207        pr_info("Acer Laptop ACPI-WMI Extras\n");
2208
2209        if (dmi_check_system(acer_blacklist)) {
2210                pr_info("Blacklisted hardware detected - not loading\n");
2211                return -ENODEV;
2212        }
2213
2214        find_quirks();
2215
2216        /*
2217         * Detect which ACPI-WMI interface we're using.
2218         */
2219        if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
2220                interface = &AMW0_V2_interface;
2221
2222        if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
2223                interface = &wmid_interface;
2224
2225        if (wmi_has_guid(WMID_GUID3))
2226                interface = &wmid_v2_interface;
2227
2228        if (interface)
2229                dmi_walk(type_aa_dmi_decode, NULL);
2230
2231        if (wmi_has_guid(WMID_GUID2) && interface) {
2232                if (!has_type_aa && ACPI_FAILURE(WMID_set_capabilities())) {
2233                        pr_err("Unable to detect available WMID devices\n");
2234                        return -ENODEV;
2235                }
2236                /* WMID always provides brightness methods */
2237                interface->capability |= ACER_CAP_BRIGHTNESS;
2238        } else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa) {
2239                pr_err("No WMID device detection method found\n");
2240                return -ENODEV;
2241        }
2242
2243        if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) {
2244                interface = &AMW0_interface;
2245
2246                if (ACPI_FAILURE(AMW0_set_capabilities())) {
2247                        pr_err("Unable to detect available AMW0 devices\n");
2248                        return -ENODEV;
2249                }
2250        }
2251
2252        if (wmi_has_guid(AMW0_GUID1))
2253                AMW0_find_mailled();
2254
2255        if (!interface) {
2256                pr_err("No or unsupported WMI interface, unable to load\n");
2257                return -ENODEV;
2258        }
2259
2260        set_quirks();
2261
2262        if (dmi_check_system(video_vendor_dmi_table))
2263                acpi_video_dmi_promote_vendor();
2264        if (acpi_video_backlight_support()) {
2265                interface->capability &= ~ACER_CAP_BRIGHTNESS;
2266                pr_info("Brightness must be controlled by acpi video driver\n");
2267        } else {
2268                pr_info("Disabling ACPI video driver\n");
2269                acpi_video_unregister_backlight();
2270        }
2271
2272        if (wmi_has_guid(WMID_GUID3)) {
2273                if (ec_raw_mode) {
2274                        if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
2275                                pr_err("Cannot enable EC raw mode\n");
2276                                return -ENODEV;
2277                        }
2278                } else if (ACPI_FAILURE(acer_wmi_enable_lm())) {
2279                        pr_err("Cannot enable Launch Manager mode\n");
2280                        return -ENODEV;
2281                }
2282        } else if (ec_raw_mode) {
2283                pr_info("No WMID EC raw mode enable method\n");
2284        }
2285
2286        if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
2287                err = acer_wmi_input_setup();
2288                if (err)
2289                        return err;
2290                err = acer_wmi_accel_setup();
2291                if (err)
2292                        return err;
2293        }
2294
2295        err = platform_driver_register(&acer_platform_driver);
2296        if (err) {
2297                pr_err("Unable to register platform driver\n");
2298                goto error_platform_register;
2299        }
2300
2301        acer_platform_device = platform_device_alloc("acer-wmi", -1);
2302        if (!acer_platform_device) {
2303                err = -ENOMEM;
2304                goto error_device_alloc;
2305        }
2306
2307        err = platform_device_add(acer_platform_device);
2308        if (err)
2309                goto error_device_add;
2310
2311        err = create_sysfs();
2312        if (err)
2313                goto error_create_sys;
2314
2315        if (wmi_has_guid(WMID_GUID2)) {
2316                interface->debug.wmid_devices = get_wmid_devices();
2317                err = create_debugfs();
2318                if (err)
2319                        goto error_create_debugfs;
2320        }
2321
2322        /* Override any initial settings with values from the commandline */
2323        acer_commandline_init();
2324
2325        return 0;
2326
2327error_create_debugfs:
2328        remove_sysfs(acer_platform_device);
2329error_create_sys:
2330        platform_device_del(acer_platform_device);
2331error_device_add:
2332        platform_device_put(acer_platform_device);
2333error_device_alloc:
2334        platform_driver_unregister(&acer_platform_driver);
2335error_platform_register:
2336        if (wmi_has_guid(ACERWMID_EVENT_GUID))
2337                acer_wmi_input_destroy();
2338        if (has_cap(ACER_CAP_ACCEL))
2339                acer_wmi_accel_destroy();
2340
2341        return err;
2342}
2343
2344static void __exit acer_wmi_exit(void)
2345{
2346        if (wmi_has_guid(ACERWMID_EVENT_GUID))
2347                acer_wmi_input_destroy();
2348
2349        if (has_cap(ACER_CAP_ACCEL))
2350                acer_wmi_accel_destroy();
2351
2352        remove_sysfs(acer_platform_device);
2353        remove_debugfs();
2354        platform_device_unregister(acer_platform_device);
2355        platform_driver_unregister(&acer_platform_driver);
2356
2357        pr_info("Acer Laptop WMI Extras unloaded\n");
2358        return;
2359}
2360
2361module_init(acer_wmi_init);
2362module_exit(acer_wmi_exit);
Note: See TracBrowser for help on using the repository browser.