ideapad: change parameter of ideapad_sync_rfk_state
[deliverable/linux.git] / drivers / platform / x86 / ideapad-laptop.c
CommitLineData
58ac7aa0 1/*
a4b5a279 2 * ideapad-laptop.c - Lenovo IdeaPad ACPI Extras
58ac7aa0
DW
3 *
4 * Copyright © 2010 Intel Corporation
5 * Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 */
22
9ab23989
JP
23#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24
58ac7aa0
DW
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/init.h>
28#include <linux/types.h>
29#include <acpi/acpi_bus.h>
30#include <acpi/acpi_drivers.h>
31#include <linux/rfkill.h>
98ee6919 32#include <linux/platform_device.h>
f63409ae
IP
33#include <linux/input.h>
34#include <linux/input/sparse-keymap.h>
a4ecbb8a
IP
35#include <linux/backlight.h>
36#include <linux/fb.h>
58ac7aa0 37
c1f73658 38#define IDEAPAD_RFKILL_DEV_NUM (3)
58ac7aa0 39
3371f481
IP
40#define CFG_BT_BIT (16)
41#define CFG_3G_BIT (17)
42#define CFG_WIFI_BIT (18)
a84511f7 43#define CFG_CAMERA_BIT (19)
3371f481 44
2be1dc21
IP
45enum {
46 VPCCMD_R_VPC1 = 0x10,
47 VPCCMD_R_BL_MAX,
48 VPCCMD_R_BL,
49 VPCCMD_W_BL,
50 VPCCMD_R_WIFI,
51 VPCCMD_W_WIFI,
52 VPCCMD_R_BT,
53 VPCCMD_W_BT,
54 VPCCMD_R_BL_POWER,
55 VPCCMD_R_NOVO,
56 VPCCMD_R_VPC2,
57 VPCCMD_R_TOUCHPAD,
58 VPCCMD_W_TOUCHPAD,
59 VPCCMD_R_CAMERA,
60 VPCCMD_W_CAMERA,
61 VPCCMD_R_3G,
62 VPCCMD_W_3G,
63 VPCCMD_R_ODD, /* 0x21 */
64 VPCCMD_R_RF = 0x23,
65 VPCCMD_W_RF,
66 VPCCMD_W_BL_POWER = 0x33,
67};
68
ce326329 69struct ideapad_private {
c1f73658 70 struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
98ee6919 71 struct platform_device *platform_device;
f63409ae 72 struct input_dev *inputdev;
a4ecbb8a 73 struct backlight_device *blightdev;
3371f481 74 unsigned long cfg;
58ac7aa0
DW
75};
76
c1f73658 77static acpi_handle ideapad_handle;
bfa97b7d
IP
78static bool no_bt_rfkill;
79module_param(no_bt_rfkill, bool, 0444);
80MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
81
6a09f21d
IP
82/*
83 * ACPI Helpers
84 */
85#define IDEAPAD_EC_TIMEOUT (100) /* in ms */
86
87static int read_method_int(acpi_handle handle, const char *method, int *val)
88{
89 acpi_status status;
90 unsigned long long result;
91
92 status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
93 if (ACPI_FAILURE(status)) {
94 *val = -1;
95 return -1;
96 } else {
97 *val = result;
98 return 0;
99 }
100}
101
102static int method_vpcr(acpi_handle handle, int cmd, int *ret)
103{
104 acpi_status status;
105 unsigned long long result;
106 struct acpi_object_list params;
107 union acpi_object in_obj;
108
109 params.count = 1;
110 params.pointer = &in_obj;
111 in_obj.type = ACPI_TYPE_INTEGER;
112 in_obj.integer.value = cmd;
113
114 status = acpi_evaluate_integer(handle, "VPCR", &params, &result);
115
116 if (ACPI_FAILURE(status)) {
117 *ret = -1;
118 return -1;
119 } else {
120 *ret = result;
121 return 0;
122 }
123}
124
125static int method_vpcw(acpi_handle handle, int cmd, int data)
126{
127 struct acpi_object_list params;
128 union acpi_object in_obj[2];
129 acpi_status status;
130
131 params.count = 2;
132 params.pointer = in_obj;
133 in_obj[0].type = ACPI_TYPE_INTEGER;
134 in_obj[0].integer.value = cmd;
135 in_obj[1].type = ACPI_TYPE_INTEGER;
136 in_obj[1].integer.value = data;
137
138 status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
139 if (status != AE_OK)
140 return -1;
141 return 0;
142}
143
144static int read_ec_data(acpi_handle handle, int cmd, unsigned long *data)
145{
146 int val;
147 unsigned long int end_jiffies;
148
149 if (method_vpcw(handle, 1, cmd))
150 return -1;
151
152 for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
153 time_before(jiffies, end_jiffies);) {
154 schedule();
155 if (method_vpcr(handle, 1, &val))
156 return -1;
157 if (val == 0) {
158 if (method_vpcr(handle, 0, &val))
159 return -1;
160 *data = val;
161 return 0;
162 }
163 }
164 pr_err("timeout in read_ec_cmd\n");
165 return -1;
166}
167
168static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
169{
170 int val;
171 unsigned long int end_jiffies;
172
173 if (method_vpcw(handle, 0, data))
174 return -1;
175 if (method_vpcw(handle, 1, cmd))
176 return -1;
177
178 for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
179 time_before(jiffies, end_jiffies);) {
180 schedule();
181 if (method_vpcr(handle, 1, &val))
182 return -1;
183 if (val == 0)
184 return 0;
185 }
186 pr_err("timeout in write_ec_cmd\n");
187 return -1;
188}
6a09f21d 189
a4b5a279 190/*
3371f481 191 * sysfs
a4b5a279 192 */
58ac7aa0
DW
193static ssize_t show_ideapad_cam(struct device *dev,
194 struct device_attribute *attr,
195 char *buf)
196{
26c81d5c 197 unsigned long result;
58ac7aa0 198
2be1dc21 199 if (read_ec_data(ideapad_handle, VPCCMD_R_CAMERA, &result))
26c81d5c
IP
200 return sprintf(buf, "-1\n");
201 return sprintf(buf, "%lu\n", result);
58ac7aa0
DW
202}
203
204static ssize_t store_ideapad_cam(struct device *dev,
205 struct device_attribute *attr,
206 const char *buf, size_t count)
207{
208 int ret, state;
209
210 if (!count)
211 return 0;
212 if (sscanf(buf, "%i", &state) != 1)
213 return -EINVAL;
2be1dc21 214 ret = write_ec_cmd(ideapad_handle, VPCCMD_W_CAMERA, state);
58ac7aa0
DW
215 if (ret < 0)
216 return ret;
217 return count;
218}
219
220static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
221
3371f481
IP
222static ssize_t show_ideapad_cfg(struct device *dev,
223 struct device_attribute *attr,
224 char *buf)
225{
226 struct ideapad_private *priv = dev_get_drvdata(dev);
227
228 return sprintf(buf, "0x%.8lX\n", priv->cfg);
229}
230
231static DEVICE_ATTR(cfg, 0444, show_ideapad_cfg, NULL);
232
233static struct attribute *ideapad_attributes[] = {
234 &dev_attr_camera_power.attr,
235 &dev_attr_cfg.attr,
236 NULL
237};
238
a84511f7
IP
239static mode_t ideapad_is_visible(struct kobject *kobj,
240 struct attribute *attr,
241 int idx)
242{
243 struct device *dev = container_of(kobj, struct device, kobj);
244 struct ideapad_private *priv = dev_get_drvdata(dev);
245 bool supported;
246
247 if (attr == &dev_attr_camera_power.attr)
248 supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg));
249 else
250 supported = true;
251
252 return supported ? attr->mode : 0;
253}
254
3371f481 255static struct attribute_group ideapad_attribute_group = {
a84511f7 256 .is_visible = ideapad_is_visible,
3371f481
IP
257 .attrs = ideapad_attributes
258};
259
a4b5a279
IP
260/*
261 * Rfkill
262 */
c1f73658
IP
263struct ideapad_rfk_data {
264 char *name;
265 int cfgbit;
266 int opcode;
267 int type;
268};
269
270const struct ideapad_rfk_data ideapad_rfk_data[] = {
2be1dc21
IP
271 { "ideapad_wlan", CFG_WIFI_BIT, VPCCMD_W_WIFI, RFKILL_TYPE_WLAN },
272 { "ideapad_bluetooth", CFG_BT_BIT, VPCCMD_W_BT, RFKILL_TYPE_BLUETOOTH },
273 { "ideapad_3g", CFG_3G_BIT, VPCCMD_W_3G, RFKILL_TYPE_WWAN },
c1f73658
IP
274};
275
58ac7aa0
DW
276static int ideapad_rfk_set(void *data, bool blocked)
277{
c1f73658 278 unsigned long opcode = (unsigned long)data;
fa08359e 279
c1f73658 280 return write_ec_cmd(ideapad_handle, opcode, !blocked);
58ac7aa0
DW
281}
282
283static struct rfkill_ops ideapad_rfk_ops = {
284 .set_block = ideapad_rfk_set,
285};
286
923de84a 287static void ideapad_sync_rfk_state(struct ideapad_private *priv)
58ac7aa0 288{
2b7266bd 289 unsigned long hw_blocked;
58ac7aa0
DW
290 int i;
291
2be1dc21 292 if (read_ec_data(ideapad_handle, VPCCMD_R_RF, &hw_blocked))
58ac7aa0 293 return;
2b7266bd 294 hw_blocked = !hw_blocked;
58ac7aa0 295
c1f73658 296 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
ce326329 297 if (priv->rfk[i])
2b7266bd 298 rfkill_set_hw_state(priv->rfk[i], hw_blocked);
58ac7aa0
DW
299}
300
a4b5a279
IP
301static int __devinit ideapad_register_rfkill(struct acpi_device *adevice,
302 int dev)
58ac7aa0 303{
ce326329 304 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
58ac7aa0 305 int ret;
2b7266bd 306 unsigned long sw_blocked;
58ac7aa0 307
bfa97b7d
IP
308 if (no_bt_rfkill &&
309 (ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) {
310 /* Force to enable bluetooth when no_bt_rfkill=1 */
c1f73658 311 write_ec_cmd(ideapad_handle,
bfa97b7d
IP
312 ideapad_rfk_data[dev].opcode, 1);
313 return 0;
314 }
315
2b7266bd
IP
316 priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name, &adevice->dev,
317 ideapad_rfk_data[dev].type, &ideapad_rfk_ops,
ce326329
DW
318 (void *)(long)dev);
319 if (!priv->rfk[dev])
58ac7aa0
DW
320 return -ENOMEM;
321
c1f73658 322 if (read_ec_data(ideapad_handle, ideapad_rfk_data[dev].opcode-1,
2b7266bd
IP
323 &sw_blocked)) {
324 rfkill_init_sw_state(priv->rfk[dev], 0);
325 } else {
326 sw_blocked = !sw_blocked;
327 rfkill_init_sw_state(priv->rfk[dev], sw_blocked);
328 }
329
ce326329 330 ret = rfkill_register(priv->rfk[dev]);
58ac7aa0 331 if (ret) {
ce326329 332 rfkill_destroy(priv->rfk[dev]);
58ac7aa0
DW
333 return ret;
334 }
335 return 0;
336}
337
a4ecbb8a 338static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev)
58ac7aa0 339{
ce326329
DW
340 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
341
342 if (!priv->rfk[dev])
58ac7aa0
DW
343 return;
344
ce326329
DW
345 rfkill_unregister(priv->rfk[dev]);
346 rfkill_destroy(priv->rfk[dev]);
58ac7aa0
DW
347}
348
98ee6919
IP
349/*
350 * Platform device
351 */
8693ae84 352static int __devinit ideapad_platform_init(struct ideapad_private *priv)
98ee6919
IP
353{
354 int result;
355
8693ae84
IP
356 priv->platform_device = platform_device_alloc("ideapad", -1);
357 if (!priv->platform_device)
98ee6919 358 return -ENOMEM;
8693ae84 359 platform_set_drvdata(priv->platform_device, priv);
98ee6919 360
8693ae84 361 result = platform_device_add(priv->platform_device);
98ee6919
IP
362 if (result)
363 goto fail_platform_device;
364
8693ae84 365 result = sysfs_create_group(&priv->platform_device->dev.kobj,
c9f718d0
IP
366 &ideapad_attribute_group);
367 if (result)
368 goto fail_sysfs;
98ee6919
IP
369 return 0;
370
c9f718d0 371fail_sysfs:
8693ae84 372 platform_device_del(priv->platform_device);
98ee6919 373fail_platform_device:
8693ae84 374 platform_device_put(priv->platform_device);
98ee6919
IP
375 return result;
376}
377
8693ae84 378static void ideapad_platform_exit(struct ideapad_private *priv)
98ee6919 379{
8693ae84 380 sysfs_remove_group(&priv->platform_device->dev.kobj,
c9f718d0 381 &ideapad_attribute_group);
8693ae84 382 platform_device_unregister(priv->platform_device);
98ee6919 383}
98ee6919 384
f63409ae
IP
385/*
386 * input device
387 */
388static const struct key_entry ideapad_keymap[] = {
389 { KE_KEY, 0x06, { KEY_SWITCHVIDEOMODE } },
390 { KE_KEY, 0x0D, { KEY_WLAN } },
391 { KE_END, 0 },
392};
393
8693ae84 394static int __devinit ideapad_input_init(struct ideapad_private *priv)
f63409ae
IP
395{
396 struct input_dev *inputdev;
397 int error;
398
399 inputdev = input_allocate_device();
400 if (!inputdev) {
401 pr_info("Unable to allocate input device\n");
402 return -ENOMEM;
403 }
404
405 inputdev->name = "Ideapad extra buttons";
406 inputdev->phys = "ideapad/input0";
407 inputdev->id.bustype = BUS_HOST;
8693ae84 408 inputdev->dev.parent = &priv->platform_device->dev;
f63409ae
IP
409
410 error = sparse_keymap_setup(inputdev, ideapad_keymap, NULL);
411 if (error) {
412 pr_err("Unable to setup input device keymap\n");
413 goto err_free_dev;
414 }
415
416 error = input_register_device(inputdev);
417 if (error) {
418 pr_err("Unable to register input device\n");
419 goto err_free_keymap;
420 }
421
8693ae84 422 priv->inputdev = inputdev;
f63409ae
IP
423 return 0;
424
425err_free_keymap:
426 sparse_keymap_free(inputdev);
427err_free_dev:
428 input_free_device(inputdev);
429 return error;
430}
431
7451a55a 432static void ideapad_input_exit(struct ideapad_private *priv)
f63409ae 433{
8693ae84
IP
434 sparse_keymap_free(priv->inputdev);
435 input_unregister_device(priv->inputdev);
436 priv->inputdev = NULL;
f63409ae
IP
437}
438
8693ae84
IP
439static void ideapad_input_report(struct ideapad_private *priv,
440 unsigned long scancode)
f63409ae 441{
8693ae84 442 sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
f63409ae 443}
f63409ae 444
a4ecbb8a
IP
445/*
446 * backlight
447 */
448static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
449{
450 unsigned long now;
451
2be1dc21 452 if (read_ec_data(ideapad_handle, VPCCMD_R_BL, &now))
a4ecbb8a
IP
453 return -EIO;
454 return now;
455}
456
457static int ideapad_backlight_update_status(struct backlight_device *blightdev)
458{
2be1dc21
IP
459 if (write_ec_cmd(ideapad_handle, VPCCMD_W_BL,
460 blightdev->props.brightness))
a4ecbb8a 461 return -EIO;
2be1dc21 462 if (write_ec_cmd(ideapad_handle, VPCCMD_W_BL_POWER,
a4ecbb8a
IP
463 blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1))
464 return -EIO;
465
466 return 0;
467}
468
469static const struct backlight_ops ideapad_backlight_ops = {
470 .get_brightness = ideapad_backlight_get_brightness,
471 .update_status = ideapad_backlight_update_status,
472};
473
474static int ideapad_backlight_init(struct ideapad_private *priv)
475{
476 struct backlight_device *blightdev;
477 struct backlight_properties props;
478 unsigned long max, now, power;
479
2be1dc21 480 if (read_ec_data(ideapad_handle, VPCCMD_R_BL_MAX, &max))
a4ecbb8a 481 return -EIO;
2be1dc21 482 if (read_ec_data(ideapad_handle, VPCCMD_R_BL, &now))
a4ecbb8a 483 return -EIO;
2be1dc21 484 if (read_ec_data(ideapad_handle, VPCCMD_R_BL_POWER, &power))
a4ecbb8a
IP
485 return -EIO;
486
487 memset(&props, 0, sizeof(struct backlight_properties));
488 props.max_brightness = max;
489 props.type = BACKLIGHT_PLATFORM;
490 blightdev = backlight_device_register("ideapad",
491 &priv->platform_device->dev,
492 priv,
493 &ideapad_backlight_ops,
494 &props);
495 if (IS_ERR(blightdev)) {
496 pr_err("Could not register backlight device\n");
497 return PTR_ERR(blightdev);
498 }
499
500 priv->blightdev = blightdev;
501 blightdev->props.brightness = now;
502 blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
503 backlight_update_status(blightdev);
504
505 return 0;
506}
507
508static void ideapad_backlight_exit(struct ideapad_private *priv)
509{
510 if (priv->blightdev)
511 backlight_device_unregister(priv->blightdev);
512 priv->blightdev = NULL;
513}
514
515static void ideapad_backlight_notify_power(struct ideapad_private *priv)
516{
517 unsigned long power;
518 struct backlight_device *blightdev = priv->blightdev;
519
d4afc775
RB
520 if (!blightdev)
521 return;
2be1dc21 522 if (read_ec_data(ideapad_handle, VPCCMD_R_BL_POWER, &power))
a4ecbb8a
IP
523 return;
524 blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
525}
526
527static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
528{
529 unsigned long now;
530
531 /* if we control brightness via acpi video driver */
532 if (priv->blightdev == NULL) {
2be1dc21 533 read_ec_data(ideapad_handle, VPCCMD_R_BL, &now);
a4ecbb8a
IP
534 return;
535 }
536
537 backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
538}
539
a4b5a279
IP
540/*
541 * module init/exit
542 */
58ac7aa0
DW
543static const struct acpi_device_id ideapad_device_ids[] = {
544 { "VPC2004", 0},
545 { "", 0},
546};
547MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
548
a4b5a279 549static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
58ac7aa0 550{
3371f481
IP
551 int ret, i;
552 unsigned long cfg;
ce326329 553 struct ideapad_private *priv;
58ac7aa0 554
3371f481 555 if (read_method_int(adevice->handle, "_CFG", (int *)&cfg))
6f8371c0
IP
556 return -ENODEV;
557
ce326329
DW
558 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
559 if (!priv)
560 return -ENOMEM;
c9f718d0 561 dev_set_drvdata(&adevice->dev, priv);
c1f73658 562 ideapad_handle = adevice->handle;
3371f481 563 priv->cfg = cfg;
98ee6919 564
8693ae84 565 ret = ideapad_platform_init(priv);
98ee6919
IP
566 if (ret)
567 goto platform_failed;
ce326329 568
8693ae84 569 ret = ideapad_input_init(priv);
f63409ae
IP
570 if (ret)
571 goto input_failed;
572
c1f73658 573 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) {
3371f481 574 if (test_bit(ideapad_rfk_data[i].cfgbit, &cfg))
c9f718d0 575 ideapad_register_rfkill(adevice, i);
c1f73658
IP
576 else
577 priv->rfk[i] = NULL;
58ac7aa0 578 }
923de84a 579 ideapad_sync_rfk_state(priv);
c9f718d0 580
a4ecbb8a
IP
581 if (!acpi_video_backlight_support()) {
582 ret = ideapad_backlight_init(priv);
583 if (ret && ret != -ENODEV)
584 goto backlight_failed;
585 }
586
58ac7aa0 587 return 0;
98ee6919 588
a4ecbb8a
IP
589backlight_failed:
590 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
591 ideapad_unregister_rfkill(adevice, i);
7451a55a 592 ideapad_input_exit(priv);
f63409ae 593input_failed:
8693ae84 594 ideapad_platform_exit(priv);
98ee6919
IP
595platform_failed:
596 kfree(priv);
597 return ret;
58ac7aa0
DW
598}
599
a4b5a279 600static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type)
58ac7aa0 601{
ce326329 602 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
58ac7aa0 603 int i;
ce326329 604
a4ecbb8a 605 ideapad_backlight_exit(priv);
c1f73658 606 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
ce326329 607 ideapad_unregister_rfkill(adevice, i);
8693ae84
IP
608 ideapad_input_exit(priv);
609 ideapad_platform_exit(priv);
ce326329
DW
610 dev_set_drvdata(&adevice->dev, NULL);
611 kfree(priv);
c9f718d0 612
58ac7aa0
DW
613 return 0;
614}
615
ce326329 616static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
58ac7aa0 617{
8693ae84 618 struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
8e7d3543
IP
619 acpi_handle handle = adevice->handle;
620 unsigned long vpc1, vpc2, vpc_bit;
621
2be1dc21 622 if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
8e7d3543 623 return;
2be1dc21 624 if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
8e7d3543
IP
625 return;
626
627 vpc1 = (vpc2 << 8) | vpc1;
628 for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {
629 if (test_bit(vpc_bit, &vpc1)) {
a4ecbb8a
IP
630 switch (vpc_bit) {
631 case 9:
923de84a 632 ideapad_sync_rfk_state(priv);
a4ecbb8a
IP
633 break;
634 case 4:
635 ideapad_backlight_notify_brightness(priv);
636 break;
637 case 2:
638 ideapad_backlight_notify_power(priv);
639 break;
640 default:
8693ae84 641 ideapad_input_report(priv, vpc_bit);
a4ecbb8a 642 }
8e7d3543
IP
643 }
644 }
58ac7aa0
DW
645}
646
647static struct acpi_driver ideapad_acpi_driver = {
648 .name = "ideapad_acpi",
649 .class = "IdeaPad",
650 .ids = ideapad_device_ids,
651 .ops.add = ideapad_acpi_add,
652 .ops.remove = ideapad_acpi_remove,
653 .ops.notify = ideapad_acpi_notify,
654 .owner = THIS_MODULE,
655};
656
58ac7aa0
DW
657static int __init ideapad_acpi_module_init(void)
658{
a4b5a279 659 return acpi_bus_register_driver(&ideapad_acpi_driver);
58ac7aa0
DW
660}
661
58ac7aa0
DW
662static void __exit ideapad_acpi_module_exit(void)
663{
664 acpi_bus_unregister_driver(&ideapad_acpi_driver);
58ac7aa0
DW
665}
666
667MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
668MODULE_DESCRIPTION("IdeaPad ACPI Extras");
669MODULE_LICENSE("GPL");
670
671module_init(ideapad_acpi_module_init);
672module_exit(ideapad_acpi_module_exit);
This page took 0.400413 seconds and 5 git commands to generate.