~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to drivers/platform/x86/eeepc-wmi.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno, Martin Michlmayr
  • Date: 2011-04-06 13:53:30 UTC
  • mfrom: (43.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110406135330-wjufxhd0tvn3zx4z
Tags: 2.6.38-3
[ Ben Hutchings ]
* [ppc64] Add to linux-tools package architectures (Closes: #620124)
* [amd64] Save cr4 to mmu_cr4_features at boot time (Closes: #620284)
* appletalk: Fix bugs introduced when removing use of BKL
* ALSA: Fix yet another race in disconnection
* cciss: Fix lost command issue
* ath9k: Fix kernel panic in AR2427
* ses: Avoid kernel panic when lun 0 is not mapped
* PCI/ACPI: Report ASPM support to BIOS if not disabled from command line

[ Aurelien Jarno ]
* rtlwifi: fix build when PCI is not enabled.

[ Martin Michlmayr ]
* rtlwifi: Eliminate udelay calls with too large values (Closes: #620204)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Eee PC WMI hotkey driver
 
3
 *
 
4
 * Copyright(C) 2010 Intel Corporation.
 
5
 * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com>
 
6
 *
 
7
 * Portions based on wistron_btns.c:
 
8
 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
 
9
 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
 
10
 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
 
11
 *
 
12
 *  This program is free software; you can redistribute it and/or modify
 
13
 *  it under the terms of the GNU General Public License as published by
 
14
 *  the Free Software Foundation; either version 2 of the License, or
 
15
 *  (at your option) any later version.
 
16
 *
 
17
 *  This program is distributed in the hope that it will be useful,
 
18
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
20
 *  GNU General Public License for more details.
 
21
 *
 
22
 *  You should have received a copy of the GNU General Public License
 
23
 *  along with this program; if not, write to the Free Software
 
24
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
25
 */
 
26
 
 
27
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
28
 
 
29
#include <linux/kernel.h>
 
30
#include <linux/module.h>
 
31
#include <linux/init.h>
 
32
#include <linux/types.h>
 
33
#include <linux/slab.h>
 
34
#include <linux/input.h>
 
35
#include <linux/input/sparse-keymap.h>
 
36
#include <linux/fb.h>
 
37
#include <linux/backlight.h>
 
38
#include <linux/leds.h>
 
39
#include <linux/rfkill.h>
 
40
#include <linux/debugfs.h>
 
41
#include <linux/seq_file.h>
 
42
#include <linux/platform_device.h>
 
43
#include <acpi/acpi_bus.h>
 
44
#include <acpi/acpi_drivers.h>
 
45
 
 
46
#define EEEPC_WMI_FILE  "eeepc-wmi"
 
47
 
 
48
MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>");
 
49
MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver");
 
50
MODULE_LICENSE("GPL");
 
51
 
 
52
#define EEEPC_ACPI_HID          "ASUS010" /* old _HID used in eeepc-laptop */
 
53
 
 
54
#define EEEPC_WMI_EVENT_GUID    "ABBC0F72-8EA1-11D1-00A0-C90629100000"
 
55
#define EEEPC_WMI_MGMT_GUID     "97845ED0-4E6D-11DE-8A39-0800200C9A66"
 
56
 
 
57
MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID);
 
58
MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);
 
59
 
 
60
#define NOTIFY_BRNUP_MIN        0x11
 
61
#define NOTIFY_BRNUP_MAX        0x1f
 
62
#define NOTIFY_BRNDOWN_MIN      0x20
 
63
#define NOTIFY_BRNDOWN_MAX      0x2e
 
64
 
 
65
#define EEEPC_WMI_METHODID_DEVS 0x53564544
 
66
#define EEEPC_WMI_METHODID_DSTS 0x53544344
 
67
#define EEEPC_WMI_METHODID_CFVS 0x53564643
 
68
 
 
69
#define EEEPC_WMI_DEVID_BACKLIGHT       0x00050012
 
70
#define EEEPC_WMI_DEVID_TPDLED          0x00100011
 
71
#define EEEPC_WMI_DEVID_WLAN            0x00010011
 
72
#define EEEPC_WMI_DEVID_BLUETOOTH       0x00010013
 
73
#define EEEPC_WMI_DEVID_WWAN3G          0x00010019
 
74
 
 
75
static const struct key_entry eeepc_wmi_keymap[] = {
 
76
        /* Sleep already handled via generic ACPI code */
 
77
        { KE_KEY, 0x5d, { KEY_WLAN } },
 
78
        { KE_KEY, 0x32, { KEY_MUTE } },
 
79
        { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
 
80
        { KE_KEY, 0x30, { KEY_VOLUMEUP } },
 
81
        { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } },
 
82
        { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } },
 
83
        { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
 
84
        { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */
 
85
        { KE_KEY, 0xe1, { KEY_F14 } },
 
86
        { KE_KEY, 0xe9, { KEY_DISPLAY_OFF } },
 
87
        { KE_KEY, 0xe0, { KEY_PROG1 } },
 
88
        { KE_KEY, 0x5c, { KEY_F15 } },
 
89
        { KE_END, 0},
 
90
};
 
91
 
 
92
struct bios_args {
 
93
        u32     dev_id;
 
94
        u32     ctrl_param;
 
95
};
 
96
 
 
97
/*
 
98
 * eeepc-wmi/    - debugfs root directory
 
99
 *   dev_id      - current dev_id
 
100
 *   ctrl_param  - current ctrl_param
 
101
 *   devs        - call DEVS(dev_id, ctrl_param) and print result
 
102
 *   dsts        - call DSTS(dev_id)  and print result
 
103
 */
 
104
struct eeepc_wmi_debug {
 
105
        struct dentry *root;
 
106
        u32 dev_id;
 
107
        u32 ctrl_param;
 
108
};
 
109
 
 
110
struct eeepc_wmi {
 
111
        struct input_dev *inputdev;
 
112
        struct backlight_device *backlight_device;
 
113
        struct platform_device *platform_device;
 
114
 
 
115
        struct led_classdev tpd_led;
 
116
        int tpd_led_wk;
 
117
        struct workqueue_struct *led_workqueue;
 
118
        struct work_struct tpd_led_work;
 
119
 
 
120
        struct rfkill *wlan_rfkill;
 
121
        struct rfkill *bluetooth_rfkill;
 
122
        struct rfkill *wwan3g_rfkill;
 
123
 
 
124
        struct eeepc_wmi_debug debug;
 
125
};
 
126
 
 
127
/* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */
 
128
static struct platform_device *platform_device;
 
129
 
 
130
static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc)
 
131
{
 
132
        int err;
 
133
 
 
134
        eeepc->inputdev = input_allocate_device();
 
135
        if (!eeepc->inputdev)
 
136
                return -ENOMEM;
 
137
 
 
138
        eeepc->inputdev->name = "Eee PC WMI hotkeys";
 
139
        eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0";
 
140
        eeepc->inputdev->id.bustype = BUS_HOST;
 
141
        eeepc->inputdev->dev.parent = &eeepc->platform_device->dev;
 
142
 
 
143
        err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL);
 
144
        if (err)
 
145
                goto err_free_dev;
 
146
 
 
147
        err = input_register_device(eeepc->inputdev);
 
148
        if (err)
 
149
                goto err_free_keymap;
 
150
 
 
151
        return 0;
 
152
 
 
153
err_free_keymap:
 
154
        sparse_keymap_free(eeepc->inputdev);
 
155
err_free_dev:
 
156
        input_free_device(eeepc->inputdev);
 
157
        return err;
 
158
}
 
159
 
 
160
static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc)
 
161
{
 
162
        if (eeepc->inputdev) {
 
163
                sparse_keymap_free(eeepc->inputdev);
 
164
                input_unregister_device(eeepc->inputdev);
 
165
        }
 
166
 
 
167
        eeepc->inputdev = NULL;
 
168
}
 
169
 
 
170
static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval)
 
171
{
 
172
        struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id };
 
173
        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 
174
        union acpi_object *obj;
 
175
        acpi_status status;
 
176
        u32 tmp;
 
177
 
 
178
        status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
 
179
                        1, EEEPC_WMI_METHODID_DSTS, &input, &output);
 
180
 
 
181
        if (ACPI_FAILURE(status))
 
182
                return status;
 
183
 
 
184
        obj = (union acpi_object *)output.pointer;
 
185
        if (obj && obj->type == ACPI_TYPE_INTEGER)
 
186
                tmp = (u32)obj->integer.value;
 
187
        else
 
188
                tmp = 0;
 
189
 
 
190
        if (retval)
 
191
                *retval = tmp;
 
192
 
 
193
        kfree(obj);
 
194
 
 
195
        return status;
 
196
 
 
197
}
 
198
 
 
199
static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
 
200
                                          u32 *retval)
 
201
{
 
202
        struct bios_args args = {
 
203
                .dev_id = dev_id,
 
204
                .ctrl_param = ctrl_param,
 
205
        };
 
206
        struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
 
207
        acpi_status status;
 
208
 
 
209
        if (!retval) {
 
210
                status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1,
 
211
                                             EEEPC_WMI_METHODID_DEVS,
 
212
                                             &input, NULL);
 
213
        } else {
 
214
                struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 
215
                union acpi_object *obj;
 
216
                u32 tmp;
 
217
 
 
218
                status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1,
 
219
                                             EEEPC_WMI_METHODID_DEVS,
 
220
                                             &input, &output);
 
221
 
 
222
                if (ACPI_FAILURE(status))
 
223
                        return status;
 
224
 
 
225
                obj = (union acpi_object *)output.pointer;
 
226
                if (obj && obj->type == ACPI_TYPE_INTEGER)
 
227
                        tmp = (u32)obj->integer.value;
 
228
                else
 
229
                        tmp = 0;
 
230
 
 
231
                *retval = tmp;
 
232
 
 
233
                kfree(obj);
 
234
        }
 
235
 
 
236
        return status;
 
237
}
 
238
 
 
239
/*
 
240
 * LEDs
 
241
 */
 
242
/*
 
243
 * These functions actually update the LED's, and are called from a
 
244
 * workqueue. By doing this as separate work rather than when the LED
 
245
 * subsystem asks, we avoid messing with the Eeepc ACPI stuff during a
 
246
 * potentially bad time, such as a timer interrupt.
 
247
 */
 
248
static void tpd_led_update(struct work_struct *work)
 
249
{
 
250
        int ctrl_param;
 
251
        struct eeepc_wmi *eeepc;
 
252
 
 
253
        eeepc = container_of(work, struct eeepc_wmi, tpd_led_work);
 
254
 
 
255
        ctrl_param = eeepc->tpd_led_wk;
 
256
        eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param, NULL);
 
257
}
 
258
 
 
259
static void tpd_led_set(struct led_classdev *led_cdev,
 
260
                        enum led_brightness value)
 
261
{
 
262
        struct eeepc_wmi *eeepc;
 
263
 
 
264
        eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led);
 
265
 
 
266
        eeepc->tpd_led_wk = !!value;
 
267
        queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);
 
268
}
 
269
 
 
270
static int read_tpd_state(struct eeepc_wmi *eeepc)
 
271
{
 
272
        u32 retval;
 
273
        acpi_status status;
 
274
 
 
275
        status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &retval);
 
276
 
 
277
        if (ACPI_FAILURE(status))
 
278
                return -1;
 
279
        else if (!retval || retval == 0x00060000)
 
280
                /*
 
281
                 * if touchpad led is present, DSTS will set some bits,
 
282
                 * usually 0x00020000.
 
283
                 * 0x00060000 means that the device is not supported
 
284
                 */
 
285
                return -ENODEV;
 
286
        else
 
287
                /* Status is stored in the first bit */
 
288
                return retval & 0x1;
 
289
}
 
290
 
 
291
static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
 
292
{
 
293
        struct eeepc_wmi *eeepc;
 
294
 
 
295
        eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led);
 
296
 
 
297
        return read_tpd_state(eeepc);
 
298
}
 
299
 
 
300
static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc)
 
301
{
 
302
        int rv;
 
303
 
 
304
        if (read_tpd_state(eeepc) < 0)
 
305
                return 0;
 
306
 
 
307
        eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue");
 
308
        if (!eeepc->led_workqueue)
 
309
                return -ENOMEM;
 
310
        INIT_WORK(&eeepc->tpd_led_work, tpd_led_update);
 
311
 
 
312
        eeepc->tpd_led.name = "eeepc::touchpad";
 
313
        eeepc->tpd_led.brightness_set = tpd_led_set;
 
314
        eeepc->tpd_led.brightness_get = tpd_led_get;
 
315
        eeepc->tpd_led.max_brightness = 1;
 
316
 
 
317
        rv = led_classdev_register(&eeepc->platform_device->dev,
 
318
                                   &eeepc->tpd_led);
 
319
        if (rv) {
 
320
                destroy_workqueue(eeepc->led_workqueue);
 
321
                return rv;
 
322
        }
 
323
 
 
324
        return 0;
 
325
}
 
326
 
 
327
static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc)
 
328
{
 
329
        if (eeepc->tpd_led.dev)
 
330
                led_classdev_unregister(&eeepc->tpd_led);
 
331
        if (eeepc->led_workqueue)
 
332
                destroy_workqueue(eeepc->led_workqueue);
 
333
}
 
334
 
 
335
/*
 
336
 * Rfkill devices
 
337
 */
 
338
static int eeepc_rfkill_set(void *data, bool blocked)
 
339
{
 
340
        int dev_id = (unsigned long)data;
 
341
        u32 ctrl_param = !blocked;
 
342
 
 
343
        return eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL);
 
344
}
 
345
 
 
346
static void eeepc_rfkill_query(struct rfkill *rfkill, void *data)
 
347
{
 
348
        int dev_id = (unsigned long)data;
 
349
        u32 retval;
 
350
        acpi_status status;
 
351
 
 
352
        status = eeepc_wmi_get_devstate(dev_id, &retval);
 
353
 
 
354
        if (ACPI_FAILURE(status))
 
355
                return ;
 
356
 
 
357
        rfkill_set_sw_state(rfkill, !(retval & 0x1));
 
358
}
 
359
 
 
360
static const struct rfkill_ops eeepc_rfkill_ops = {
 
361
        .set_block = eeepc_rfkill_set,
 
362
        .query = eeepc_rfkill_query,
 
363
};
 
364
 
 
365
static int eeepc_new_rfkill(struct eeepc_wmi *eeepc,
 
366
                            struct rfkill **rfkill,
 
367
                            const char *name,
 
368
                            enum rfkill_type type, int dev_id)
 
369
{
 
370
        int result;
 
371
        u32 retval;
 
372
        acpi_status status;
 
373
 
 
374
        status = eeepc_wmi_get_devstate(dev_id, &retval);
 
375
 
 
376
        if (ACPI_FAILURE(status))
 
377
                return -1;
 
378
 
 
379
        /* If the device is present, DSTS will always set some bits
 
380
         * 0x00070000 - 1110000000000000000 - device supported
 
381
         * 0x00060000 - 1100000000000000000 - not supported
 
382
         * 0x00020000 - 0100000000000000000 - device supported
 
383
         * 0x00010000 - 0010000000000000000 - not supported / special mode ?
 
384
         */
 
385
        if (!retval || retval == 0x00060000)
 
386
                return -ENODEV;
 
387
 
 
388
        *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
 
389
                               &eeepc_rfkill_ops, (void *)(long)dev_id);
 
390
 
 
391
        if (!*rfkill)
 
392
                return -EINVAL;
 
393
 
 
394
        rfkill_init_sw_state(*rfkill, !(retval & 0x1));
 
395
        result = rfkill_register(*rfkill);
 
396
        if (result) {
 
397
                rfkill_destroy(*rfkill);
 
398
                *rfkill = NULL;
 
399
                return result;
 
400
        }
 
401
        return 0;
 
402
}
 
403
 
 
404
static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc)
 
405
{
 
406
        if (eeepc->wlan_rfkill) {
 
407
                rfkill_unregister(eeepc->wlan_rfkill);
 
408
                rfkill_destroy(eeepc->wlan_rfkill);
 
409
                eeepc->wlan_rfkill = NULL;
 
410
        }
 
411
        if (eeepc->bluetooth_rfkill) {
 
412
                rfkill_unregister(eeepc->bluetooth_rfkill);
 
413
                rfkill_destroy(eeepc->bluetooth_rfkill);
 
414
                eeepc->bluetooth_rfkill = NULL;
 
415
        }
 
416
        if (eeepc->wwan3g_rfkill) {
 
417
                rfkill_unregister(eeepc->wwan3g_rfkill);
 
418
                rfkill_destroy(eeepc->wwan3g_rfkill);
 
419
                eeepc->wwan3g_rfkill = NULL;
 
420
        }
 
421
}
 
422
 
 
423
static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc)
 
424
{
 
425
        int result = 0;
 
426
 
 
427
        result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,
 
428
                                  "eeepc-wlan", RFKILL_TYPE_WLAN,
 
429
                                  EEEPC_WMI_DEVID_WLAN);
 
430
 
 
431
        if (result && result != -ENODEV)
 
432
                goto exit;
 
433
 
 
434
        result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill,
 
435
                                  "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH,
 
436
                                  EEEPC_WMI_DEVID_BLUETOOTH);
 
437
 
 
438
        if (result && result != -ENODEV)
 
439
                goto exit;
 
440
 
 
441
        result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill,
 
442
                                  "eeepc-wwan3g", RFKILL_TYPE_WWAN,
 
443
                                  EEEPC_WMI_DEVID_WWAN3G);
 
444
 
 
445
        if (result && result != -ENODEV)
 
446
                goto exit;
 
447
 
 
448
exit:
 
449
        if (result && result != -ENODEV)
 
450
                eeepc_wmi_rfkill_exit(eeepc);
 
451
 
 
452
        if (result == -ENODEV)
 
453
                result = 0;
 
454
 
 
455
        return result;
 
456
}
 
457
 
 
458
/*
 
459
 * Backlight
 
460
 */
 
461
static int read_brightness(struct backlight_device *bd)
 
462
{
 
463
        u32 retval;
 
464
        acpi_status status;
 
465
 
 
466
        status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &retval);
 
467
 
 
468
        if (ACPI_FAILURE(status))
 
469
                return -1;
 
470
        else
 
471
                return retval & 0xFF;
 
472
}
 
473
 
 
474
static int update_bl_status(struct backlight_device *bd)
 
475
{
 
476
 
 
477
        u32 ctrl_param;
 
478
        acpi_status status;
 
479
 
 
480
        ctrl_param = bd->props.brightness;
 
481
 
 
482
        status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT,
 
483
                                        ctrl_param, NULL);
 
484
 
 
485
        if (ACPI_FAILURE(status))
 
486
                return -1;
 
487
        else
 
488
                return 0;
 
489
}
 
490
 
 
491
static const struct backlight_ops eeepc_wmi_bl_ops = {
 
492
        .get_brightness = read_brightness,
 
493
        .update_status = update_bl_status,
 
494
};
 
495
 
 
496
static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code)
 
497
{
 
498
        struct backlight_device *bd = eeepc->backlight_device;
 
499
        int old = bd->props.brightness;
 
500
        int new = old;
 
501
 
 
502
        if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
 
503
                new = code - NOTIFY_BRNUP_MIN + 1;
 
504
        else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
 
505
                new = code - NOTIFY_BRNDOWN_MIN;
 
506
 
 
507
        bd->props.brightness = new;
 
508
        backlight_update_status(bd);
 
509
        backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
 
510
 
 
511
        return old;
 
512
}
 
513
 
 
514
static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc)
 
515
{
 
516
        struct backlight_device *bd;
 
517
        struct backlight_properties props;
 
518
 
 
519
        memset(&props, 0, sizeof(struct backlight_properties));
 
520
        props.max_brightness = 15;
 
521
        bd = backlight_device_register(EEEPC_WMI_FILE,
 
522
                                       &eeepc->platform_device->dev, eeepc,
 
523
                                       &eeepc_wmi_bl_ops, &props);
 
524
        if (IS_ERR(bd)) {
 
525
                pr_err("Could not register backlight device\n");
 
526
                return PTR_ERR(bd);
 
527
        }
 
528
 
 
529
        eeepc->backlight_device = bd;
 
530
 
 
531
        bd->props.brightness = read_brightness(bd);
 
532
        bd->props.power = FB_BLANK_UNBLANK;
 
533
        backlight_update_status(bd);
 
534
 
 
535
        return 0;
 
536
}
 
537
 
 
538
static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc)
 
539
{
 
540
        if (eeepc->backlight_device)
 
541
                backlight_device_unregister(eeepc->backlight_device);
 
542
 
 
543
        eeepc->backlight_device = NULL;
 
544
}
 
545
 
 
546
static void eeepc_wmi_notify(u32 value, void *context)
 
547
{
 
548
        struct eeepc_wmi *eeepc = context;
 
549
        struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
 
550
        union acpi_object *obj;
 
551
        acpi_status status;
 
552
        int code;
 
553
        int orig_code;
 
554
 
 
555
        status = wmi_get_event_data(value, &response);
 
556
        if (status != AE_OK) {
 
557
                pr_err("bad event status 0x%x\n", status);
 
558
                return;
 
559
        }
 
560
 
 
561
        obj = (union acpi_object *)response.pointer;
 
562
 
 
563
        if (obj && obj->type == ACPI_TYPE_INTEGER) {
 
564
                code = obj->integer.value;
 
565
                orig_code = code;
 
566
 
 
567
                if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
 
568
                        code = NOTIFY_BRNUP_MIN;
 
569
                else if (code >= NOTIFY_BRNDOWN_MIN &&
 
570
                         code <= NOTIFY_BRNDOWN_MAX)
 
571
                        code = NOTIFY_BRNDOWN_MIN;
 
572
 
 
573
                if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {
 
574
                        if (!acpi_video_backlight_support())
 
575
                                eeepc_wmi_backlight_notify(eeepc, orig_code);
 
576
                }
 
577
 
 
578
                if (!sparse_keymap_report_event(eeepc->inputdev,
 
579
                                                code, 1, true))
 
580
                        pr_info("Unknown key %x pressed\n", code);
 
581
        }
 
582
 
 
583
        kfree(obj);
 
584
}
 
585
 
 
586
static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
 
587
                           const char *buf, size_t count)
 
588
{
 
589
        int value;
 
590
        struct acpi_buffer input = { (acpi_size)sizeof(value), &value };
 
591
        acpi_status status;
 
592
 
 
593
        if (!count || sscanf(buf, "%i", &value) != 1)
 
594
                return -EINVAL;
 
595
        if (value < 0 || value > 2)
 
596
                return -EINVAL;
 
597
 
 
598
        status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
 
599
                                     1, EEEPC_WMI_METHODID_CFVS, &input, NULL);
 
600
 
 
601
        if (ACPI_FAILURE(status))
 
602
                return -EIO;
 
603
        else
 
604
                return count;
 
605
}
 
606
 
 
607
static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
 
608
 
 
609
static struct attribute *platform_attributes[] = {
 
610
        &dev_attr_cpufv.attr,
 
611
        NULL
 
612
};
 
613
 
 
614
static struct attribute_group platform_attribute_group = {
 
615
        .attrs = platform_attributes
 
616
};
 
617
 
 
618
static void eeepc_wmi_sysfs_exit(struct platform_device *device)
 
619
{
 
620
        sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
 
621
}
 
622
 
 
623
static int eeepc_wmi_sysfs_init(struct platform_device *device)
 
624
{
 
625
        return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
 
626
}
 
627
 
 
628
/*
 
629
 * Platform device
 
630
 */
 
631
static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc)
 
632
{
 
633
        int err;
 
634
 
 
635
        eeepc->platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1);
 
636
        if (!eeepc->platform_device)
 
637
                return -ENOMEM;
 
638
        platform_set_drvdata(eeepc->platform_device, eeepc);
 
639
 
 
640
        err = platform_device_add(eeepc->platform_device);
 
641
        if (err)
 
642
                goto fail_platform_device;
 
643
 
 
644
        err = eeepc_wmi_sysfs_init(eeepc->platform_device);
 
645
        if (err)
 
646
                goto fail_sysfs;
 
647
        return 0;
 
648
 
 
649
fail_sysfs:
 
650
        platform_device_del(eeepc->platform_device);
 
651
fail_platform_device:
 
652
        platform_device_put(eeepc->platform_device);
 
653
        return err;
 
654
}
 
655
 
 
656
static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc)
 
657
{
 
658
        eeepc_wmi_sysfs_exit(eeepc->platform_device);
 
659
        platform_device_unregister(eeepc->platform_device);
 
660
}
 
661
 
 
662
/*
 
663
 * debugfs
 
664
 */
 
665
struct eeepc_wmi_debugfs_node {
 
666
        struct eeepc_wmi *eeepc;
 
667
        char *name;
 
668
        int (*show)(struct seq_file *m, void *data);
 
669
};
 
670
 
 
671
static int show_dsts(struct seq_file *m, void *data)
 
672
{
 
673
        struct eeepc_wmi *eeepc = m->private;
 
674
        acpi_status status;
 
675
        u32 retval = -1;
 
676
 
 
677
        status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval);
 
678
 
 
679
        if (ACPI_FAILURE(status))
 
680
                return -EIO;
 
681
 
 
682
        seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval);
 
683
 
 
684
        return 0;
 
685
}
 
686
 
 
687
static int show_devs(struct seq_file *m, void *data)
 
688
{
 
689
        struct eeepc_wmi *eeepc = m->private;
 
690
        acpi_status status;
 
691
        u32 retval = -1;
 
692
 
 
693
        status = eeepc_wmi_set_devstate(eeepc->debug.dev_id,
 
694
                                        eeepc->debug.ctrl_param, &retval);
 
695
        if (ACPI_FAILURE(status))
 
696
                return -EIO;
 
697
 
 
698
        seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id,
 
699
                   eeepc->debug.ctrl_param, retval);
 
700
 
 
701
        return 0;
 
702
}
 
703
 
 
704
static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = {
 
705
        { NULL, "devs", show_devs },
 
706
        { NULL, "dsts", show_dsts },
 
707
};
 
708
 
 
709
static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file)
 
710
{
 
711
        struct eeepc_wmi_debugfs_node *node = inode->i_private;
 
712
 
 
713
        return single_open(file, node->show, node->eeepc);
 
714
}
 
715
 
 
716
static const struct file_operations eeepc_wmi_debugfs_io_ops = {
 
717
        .owner = THIS_MODULE,
 
718
        .open  = eeepc_wmi_debugfs_open,
 
719
        .read = seq_read,
 
720
        .llseek = seq_lseek,
 
721
        .release = single_release,
 
722
};
 
723
 
 
724
static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc)
 
725
{
 
726
        debugfs_remove_recursive(eeepc->debug.root);
 
727
}
 
728
 
 
729
static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc)
 
730
{
 
731
        struct dentry *dent;
 
732
        int i;
 
733
 
 
734
        eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL);
 
735
        if (!eeepc->debug.root) {
 
736
                pr_err("failed to create debugfs directory");
 
737
                goto error_debugfs;
 
738
        }
 
739
 
 
740
        dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR,
 
741
                                  eeepc->debug.root, &eeepc->debug.dev_id);
 
742
        if (!dent)
 
743
                goto error_debugfs;
 
744
 
 
745
        dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR,
 
746
                                  eeepc->debug.root, &eeepc->debug.ctrl_param);
 
747
        if (!dent)
 
748
                goto error_debugfs;
 
749
 
 
750
        for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) {
 
751
                struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i];
 
752
 
 
753
                node->eeepc = eeepc;
 
754
                dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO,
 
755
                                           eeepc->debug.root, node,
 
756
                                           &eeepc_wmi_debugfs_io_ops);
 
757
                if (!dent) {
 
758
                        pr_err("failed to create debug file: %s\n", node->name);
 
759
                        goto error_debugfs;
 
760
                }
 
761
        }
 
762
 
 
763
        return 0;
 
764
 
 
765
error_debugfs:
 
766
        eeepc_wmi_debugfs_exit(eeepc);
 
767
        return -ENOMEM;
 
768
}
 
769
 
 
770
/*
 
771
 * WMI Driver
 
772
 */
 
773
static struct platform_device * __init eeepc_wmi_add(void)
 
774
{
 
775
        struct eeepc_wmi *eeepc;
 
776
        acpi_status status;
 
777
        int err;
 
778
 
 
779
        eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL);
 
780
        if (!eeepc)
 
781
                return ERR_PTR(-ENOMEM);
 
782
 
 
783
        /*
 
784
         * Register the platform device first.  It is used as a parent for the
 
785
         * sub-devices below.
 
786
         */
 
787
        err = eeepc_wmi_platform_init(eeepc);
 
788
        if (err)
 
789
                goto fail_platform;
 
790
 
 
791
        err = eeepc_wmi_input_init(eeepc);
 
792
        if (err)
 
793
                goto fail_input;
 
794
 
 
795
        err = eeepc_wmi_led_init(eeepc);
 
796
        if (err)
 
797
                goto fail_leds;
 
798
 
 
799
        err = eeepc_wmi_rfkill_init(eeepc);
 
800
        if (err)
 
801
                goto fail_rfkill;
 
802
 
 
803
        if (!acpi_video_backlight_support()) {
 
804
                err = eeepc_wmi_backlight_init(eeepc);
 
805
                if (err)
 
806
                        goto fail_backlight;
 
807
        } else
 
808
                pr_info("Backlight controlled by ACPI video driver\n");
 
809
 
 
810
        status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID,
 
811
                                            eeepc_wmi_notify, eeepc);
 
812
        if (ACPI_FAILURE(status)) {
 
813
                pr_err("Unable to register notify handler - %d\n",
 
814
                        status);
 
815
                err = -ENODEV;
 
816
                goto fail_wmi_handler;
 
817
        }
 
818
 
 
819
        err = eeepc_wmi_debugfs_init(eeepc);
 
820
        if (err)
 
821
                goto fail_debugfs;
 
822
 
 
823
        return eeepc->platform_device;
 
824
 
 
825
fail_debugfs:
 
826
        wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
 
827
fail_wmi_handler:
 
828
        eeepc_wmi_backlight_exit(eeepc);
 
829
fail_backlight:
 
830
        eeepc_wmi_rfkill_exit(eeepc);
 
831
fail_rfkill:
 
832
        eeepc_wmi_led_exit(eeepc);
 
833
fail_leds:
 
834
        eeepc_wmi_input_exit(eeepc);
 
835
fail_input:
 
836
        eeepc_wmi_platform_exit(eeepc);
 
837
fail_platform:
 
838
        kfree(eeepc);
 
839
        return ERR_PTR(err);
 
840
}
 
841
 
 
842
static int eeepc_wmi_remove(struct platform_device *device)
 
843
{
 
844
        struct eeepc_wmi *eeepc;
 
845
 
 
846
        eeepc = platform_get_drvdata(device);
 
847
        wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
 
848
        eeepc_wmi_backlight_exit(eeepc);
 
849
        eeepc_wmi_input_exit(eeepc);
 
850
        eeepc_wmi_led_exit(eeepc);
 
851
        eeepc_wmi_rfkill_exit(eeepc);
 
852
        eeepc_wmi_debugfs_exit(eeepc);
 
853
        eeepc_wmi_platform_exit(eeepc);
 
854
 
 
855
        kfree(eeepc);
 
856
        return 0;
 
857
}
 
858
 
 
859
static struct platform_driver platform_driver = {
 
860
        .driver = {
 
861
                .name = EEEPC_WMI_FILE,
 
862
                .owner = THIS_MODULE,
 
863
        },
 
864
};
 
865
 
 
866
static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level,
 
867
                                                 void *context, void **retval)
 
868
{
 
869
        pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID);
 
870
        *(bool *)context = true;
 
871
        return AE_CTRL_TERMINATE;
 
872
}
 
873
 
 
874
static int __init eeepc_wmi_check_atkd(void)
 
875
{
 
876
        acpi_status status;
 
877
        bool found = false;
 
878
 
 
879
        status = acpi_get_devices(EEEPC_ACPI_HID, eeepc_wmi_parse_device,
 
880
                                  &found, NULL);
 
881
 
 
882
        if (ACPI_FAILURE(status) || !found)
 
883
                return 0;
 
884
        return -1;
 
885
}
 
886
 
 
887
static int __init eeepc_wmi_init(void)
 
888
{
 
889
        int err;
 
890
 
 
891
        if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) ||
 
892
            !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) {
 
893
                pr_warning("No known WMI GUID found\n");
 
894
                return -ENODEV;
 
895
        }
 
896
 
 
897
        if (eeepc_wmi_check_atkd()) {
 
898
                pr_warning("WMI device present, but legacy ATKD device is also "
 
899
                           "present and enabled.");
 
900
                pr_warning("You probably booted with acpi_osi=\"Linux\" or "
 
901
                           "acpi_osi=\"!Windows 2009\"");
 
902
                pr_warning("Can't load eeepc-wmi, use default acpi_osi "
 
903
                           "(preferred) or eeepc-laptop");
 
904
                return -ENODEV;
 
905
        }
 
906
 
 
907
        platform_device = eeepc_wmi_add();
 
908
        if (IS_ERR(platform_device)) {
 
909
                err = PTR_ERR(platform_device);
 
910
                goto fail_eeepc_wmi;
 
911
        }
 
912
 
 
913
        err = platform_driver_register(&platform_driver);
 
914
        if (err) {
 
915
                pr_warning("Unable to register platform driver\n");
 
916
                goto fail_platform_driver;
 
917
        }
 
918
 
 
919
        return 0;
 
920
 
 
921
fail_platform_driver:
 
922
        eeepc_wmi_remove(platform_device);
 
923
fail_eeepc_wmi:
 
924
        return err;
 
925
}
 
926
 
 
927
static void __exit eeepc_wmi_exit(void)
 
928
{
 
929
        eeepc_wmi_remove(platform_device);
 
930
        platform_driver_unregister(&platform_driver);
 
931
}
 
932
 
 
933
module_init(eeepc_wmi_init);
 
934
module_exit(eeepc_wmi_exit);