Deleted Added
full compact
1/*-
2 * Copyright (c) 2004 Philip Paeps <philip@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/dev/acpi_support/acpi_asus.c 137632 2004-11-12 23:21:19Z philip $");
28__FBSDID("$FreeBSD: head/sys/dev/acpi_support/acpi_asus.c 138825 2004-12-13 23:31:46Z njl $");
29
30/*
31 * Driver for extra ACPI-controlled gadgets (hotkeys, leds, etc) found on
32 * recent Asus (and Medion) laptops. Inspired by the acpi4asus project which
33 * implements these features in the Linux kernel.
34 *
35 * <http://sourceforge.net/projects/acpi4asus/>
36 *
37 * Currently should support most features, but could use some more testing.
38 * Particularly the display-switching stuff is a bit hairy. If you have an
39 * Asus laptop which doesn't appear to be supported, or strange things happen
40 * when using this driver, please report to <acpi@FreeBSD.org>.
41 */
42
43#include "opt_acpi.h"
44#include <sys/param.h>
45#include <sys/kernel.h>
46#include <sys/module.h>
47#include <sys/bus.h>
48#include <sys/sbuf.h>
49
50#include "acpi.h"
51#include <dev/acpica/acpivar.h>
52#include <dev/led/led.h>
53
54#define _COMPONENT ACPI_ASUS
54#define _COMPONENT ACPI_OEM
55ACPI_MODULE_NAME("ASUS")
56
57struct acpi_asus_model {
58 char *name;
59
60 char *mled_set;
61 char *tled_set;
62 char *wled_set;
63
64 char *brn_get;
65 char *brn_set;
66 char *brn_up;
67 char *brn_dn;
68
69 char *lcd_get;
70 char *lcd_set;
71
72 char *disp_get;
73 char *disp_set;
74};
75
76struct acpi_asus_led {
77 struct cdev *cdev;
78 device_t dev;
79 enum {
80 ACPI_ASUS_LED_MLED,
81 ACPI_ASUS_LED_TLED,
82 ACPI_ASUS_LED_WLED,
83 } type;
84};
85
86struct acpi_asus_softc {
87 device_t dev;
88 ACPI_HANDLE handle;
89
90 struct acpi_asus_model *model;
91 struct sysctl_ctx_list sysctl_ctx;
92 struct sysctl_oid *sysctl_tree;
93
94 struct acpi_asus_led s_mled;
95 struct acpi_asus_led s_tled;
96 struct acpi_asus_led s_wled;
97
98 int s_brn;
99 int s_disp;
100 int s_lcd;
101};
102
103/*
104 * We can identify Asus laptops from the string they return
105 * as a result of calling the ATK0100 'INIT' method.
106 */
107static struct acpi_asus_model acpi_asus_models[] = {
108 {
109 .name = "L2D",
110 .mled_set = "MLED",
111 .wled_set = "WLED",
112 .brn_up = "\\Q0E",
113 .brn_dn = "\\Q0F",
114 .lcd_get = "\\SGP0",
115 .lcd_set = "\\Q10"
116 },
117 {
118 .name = "L3C",
119 .mled_set = "MLED",
120 .wled_set = "WLED",
121 .brn_get = "GPLV",
122 .brn_set = "SPLV",
123 .lcd_get = "\\GL32",
124 .lcd_set = "\\_SB.PCI0.PX40.ECD0._Q10"
125 },
126 {
127 .name = "L3D",
128 .mled_set = "MLED",
129 .wled_set = "WLED",
130 .brn_get = "GPLV",
131 .brn_set = "SPLV",
132 .lcd_get = "\\BKLG",
133 .lcd_set = "\\Q10"
134 },
135 {
136 .name = "L3H",
137 .mled_set = "MLED",
138 .wled_set = "WLED",
139 .brn_get = "GPLV",
140 .brn_set = "SPLV",
141 .lcd_get = "\\_SB.PCI0.PM.PBC",
142 .lcd_set = "EHK",
143 .disp_get = "\\_SB.INFB",
144 .disp_set = "SDSP"
145 },
146 {
147 .name = "L4R",
148 .mled_set = "MLED",
149 .wled_set = "WLED",
150 .brn_get = "GPLV",
151 .brn_set = "SPLV",
152 .lcd_get = "\\_SB.PCI0.SBSM.SEO4",
153 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
154 .disp_get = "\\_SB.PCI0.P0P1.VGA.GETD",
155 .disp_set = "SDSP"
156 },
157 {
158 .name = "L8L"
159 /* Only has hotkeys, apparantly */
160 },
161 {
162 .name = "M1A",
163 .mled_set = "MLED",
164 .brn_up = "\\_SB.PCI0.PX40.EC0.Q0E",
165 .brn_dn = "\\_SB.PCI0.PX40.EC0.Q0F",
166 .lcd_get = "\\PNOF",
167 .lcd_set = "\\_SB.PCI0.PX40.EC0.Q10"
168 },
169 {
170 .name = "M2E",
171 .mled_set = "MLED",
172 .wled_set = "WLED",
173 .brn_get = "GPLV",
174 .brn_set = "SPLV",
175 .lcd_get = "\\GP06",
176 .lcd_set = "\\Q10"
177 },
178 {
179 .name = "M6N",
180 .mled_set = "MLED",
181 .wled_set = "WLED",
182 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
183 .lcd_get = "\\_SB.BKLT",
184 .brn_set = "SPLV",
185 .brn_get = "GPLV",
186 .disp_set = "SDSP",
187 .disp_get = "\\SSTE"
188 },
189 {
190 .name = "M6R",
191 .mled_set = "MLED",
192 .wled_set = "WLED",
193 .brn_get = "GPLV",
194 .brn_set = "SPLV",
195 .lcd_get = "\\_SB.PCI0.SBSM.SEO4",
196 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
197 .disp_get = "\\SSTE",
198 .disp_set = "SDSP"
199 },
200
201 { .name = NULL }
202};
203
204/*
205 * Samsung P30/P35 laptops have an Asus ATK0100 gadget interface,
206 * but they can't be probed quite the same way as Asus laptops.
207 */
208static struct acpi_asus_model acpi_samsung_models[] = {
209 {
210 .name = "P30",
211 .wled_set = "WLED",
212 .brn_up = "\\_SB.PCI0.LPCB.EC0._Q68",
213 .brn_dn = "\\_SB.PCI0.LPCB.EC0._Q69",
214 .lcd_get = "\\BKLT",
215 .lcd_set = "\\_SB.PCI0.LPCB.EC0._Q0E"
216 },
217
218 { .name = NULL }
219};
220
221ACPI_SERIAL_DECL(asus, "ACPI ASUS extras");
222
223/* Function prototypes */
224static int acpi_asus_probe(device_t dev);
225static int acpi_asus_attach(device_t dev);
226static int acpi_asus_detach(device_t dev);
227
228static void acpi_asus_led(struct acpi_asus_led *led, int state);
229
230static int acpi_asus_sysctl_brn(SYSCTL_HANDLER_ARGS);
231static int acpi_asus_sysctl_lcd(SYSCTL_HANDLER_ARGS);
232static int acpi_asus_sysctl_disp(SYSCTL_HANDLER_ARGS);
233
234static void acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context);
235
236static device_method_t acpi_asus_methods[] = {
237 DEVMETHOD(device_probe, acpi_asus_probe),
238 DEVMETHOD(device_attach, acpi_asus_attach),
239 DEVMETHOD(device_detach, acpi_asus_detach),
240
241 { 0, 0 }
242};
243
244static driver_t acpi_asus_driver = {
245 "acpi_asus",
246 acpi_asus_methods,
247 sizeof(struct acpi_asus_softc)
248};
249
250static devclass_t acpi_asus_devclass;
251
252DRIVER_MODULE(acpi_asus, acpi, acpi_asus_driver, acpi_asus_devclass, 0, 0);
253MODULE_DEPEND(acpi_asus, acpi, 1, 1, 1);
254
255static int
256acpi_asus_probe(device_t dev)
257{
258 struct acpi_asus_model *model;
259 struct acpi_asus_softc *sc;
260 struct sbuf *sb;
261 ACPI_BUFFER Buf;
262 ACPI_OBJECT Arg, *Obj;
263 ACPI_OBJECT_LIST Args;
264 static char *asus_ids[] = { "ATK0100", NULL };
265
266 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
267
268 if (acpi_disabled("asus") ||
269 ACPI_ID_PROBE(device_get_parent(dev), dev, asus_ids) == NULL)
270 return (ENXIO);
271
272 sc = device_get_softc(dev);
273 sc->dev = dev;
274 sc->handle = acpi_get_handle(dev);
275
276 Arg.Type = ACPI_TYPE_INTEGER;
277 Arg.Integer.Value = 0;
278
279 Args.Count = 1;
280 Args.Pointer = &Arg;
281
282 Buf.Pointer = NULL;
283 Buf.Length = ACPI_ALLOCATE_BUFFER;
284
285 AcpiEvaluateObject(sc->handle, "INIT", &Args, &Buf);
286 Obj = Buf.Pointer;
287
288 /*
289 * The Samsung P30 returns a null-pointer from INIT, we
290 * can identify it from the 'ODEM' string in the DSDT.
291 */
292 if (Obj->String.Pointer == NULL) {
293 ACPI_STATUS status;
294 ACPI_TABLE_HEADER th;
295
296 status = AcpiGetTableHeader(ACPI_TABLE_DSDT, 1, &th);
297 if (ACPI_FAILURE(status)) {
298 device_printf(dev, "Unsupported (Samsung?) laptop\n");
299 AcpiOsFree(Buf.Pointer);
300 return (ENXIO);
301 }
302
303 if (strncmp("ODEM", th.OemTableId, 4) == 0) {
304 sc->model = &acpi_samsung_models[0];
305 device_set_desc(dev, "Samsung P30 Laptop Extras");
306 AcpiOsFree(Buf.Pointer);
307 return (0);
308 }
309 }
310
311 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
312 if (sb == NULL)
313 return (ENOMEM);
314
315 /*
316 * Asus laptops are simply identified by name, easy!
317 */
318 for (model = acpi_asus_models; model->name != NULL; model++)
319 if (strncmp(Obj->String.Pointer, model->name, 3) == 0) {
320 sbuf_printf(sb, "Asus %s Laptop Extras", model->name);
321 sbuf_finish(sb);
322
323 sc->model = model;
324 device_set_desc(dev, sbuf_data(sb));
325
326 sbuf_delete(sb);
327 AcpiOsFree(Buf.Pointer);
328 return (0);
329 }
330
331 sbuf_printf(sb, "Unsupported Asus laptop: %s\n", Obj->String.Pointer);
332 sbuf_finish(sb);
333
334 device_printf(dev, sbuf_data(sb));
335
336 sbuf_delete(sb);
337 AcpiOsFree(Buf.Pointer);
338
339 return (ENXIO);
340}
341
342static int
343acpi_asus_attach(device_t dev)
344{
345 struct acpi_asus_softc *sc;
346 struct acpi_softc *acpi_sc;
347
348 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
349
350 sc = device_get_softc(dev);
351 acpi_sc = acpi_device_get_parent_softc(dev);
352
353 /* Build sysctl tree */
354 sysctl_ctx_init(&sc->sysctl_ctx);
355 sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
356 SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
357 OID_AUTO, "asus", CTLFLAG_RD, 0, "");
358
359 /* Attach leds */
360 if (sc->model->mled_set) {
361 sc->s_mled.dev = dev;
362 sc->s_mled.type = ACPI_ASUS_LED_MLED;
363 sc->s_mled.cdev =
364 led_create((led_t *)acpi_asus_led, &sc->s_mled, "mled");
365 }
366
367 if (sc->model->tled_set) {
368 sc->s_tled.dev = dev;
369 sc->s_tled.type = ACPI_ASUS_LED_TLED;
370 sc->s_tled.cdev =
371 led_create((led_t *)acpi_asus_led, &sc->s_tled, "tled");
372 }
373
374 if (sc->model->wled_set) {
375 sc->s_wled.dev = dev;
376 sc->s_wled.type = ACPI_ASUS_LED_WLED;
377 sc->s_wled.cdev =
378 led_create((led_t *)acpi_asus_led, &sc->s_wled, "wled");
379 }
380
381 /* Attach brightness for GPLV/SPLV models */
382 if (sc->model->brn_get && ACPI_SUCCESS(acpi_GetInteger(sc->handle,
383 sc->model->brn_get, &sc->s_brn)))
384 SYSCTL_ADD_PROC(&sc->sysctl_ctx,
385 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
386 "lcd_brightness", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
387 acpi_asus_sysctl_brn, "I", "brightness of the lcd panel");
388
389 /* Attach brightness for other models */
390 if (sc->model->brn_up &&
391 ACPI_SUCCESS(AcpiEvaluateObject(sc->handle, sc->model->brn_up,
392 NULL, NULL)) &&
393 ACPI_SUCCESS(AcpiEvaluateObject(sc->handle, sc->model->brn_dn,
394 NULL, NULL)))
395 SYSCTL_ADD_PROC(&sc->sysctl_ctx,
396 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
397 "lcd_brightness", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
398 acpi_asus_sysctl_brn, "I", "brightness of the lcd panel");
399
400 /* Attach display switching */
401 if (sc->model->disp_get && ACPI_SUCCESS(acpi_GetInteger(sc->handle,
402 sc->model->disp_get, &sc->s_disp)))
403 SYSCTL_ADD_PROC(&sc->sysctl_ctx,
404 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
405 "video_output", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
406 acpi_asus_sysctl_disp, "I", "display output state");
407
408 /* Attach LCD state, easy for most models... */
409 if (sc->model->lcd_get && strncmp(sc->model->name, "L3H", 3) != 0 &&
410 ACPI_SUCCESS(acpi_GetInteger(sc->handle, sc->model->lcd_get,
411 &sc->s_lcd))) {
412 SYSCTL_ADD_PROC(&sc->sysctl_ctx,
413 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
414 "lcd_backlight", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
415 acpi_asus_sysctl_lcd, "I", "state of the lcd backlight");
416 } else if (sc->model->lcd_get) {
417 ACPI_BUFFER Buf;
418 ACPI_OBJECT Arg[2], Obj;
419 ACPI_OBJECT_LIST Args;
420
421 /* ...a nightmare for the L3H */
422 Arg[0].Type = ACPI_TYPE_INTEGER;
423 Arg[0].Integer.Value = 0x02;
424 Arg[1].Type = ACPI_TYPE_INTEGER;
425 Arg[1].Integer.Value = 0x03;
426
427 Args.Count = 2;
428 Args.Pointer = Arg;
429
430 Buf.Length = sizeof(Obj);
431 Buf.Pointer = &Obj;
432
433 if (ACPI_SUCCESS(AcpiEvaluateObject(sc->handle,
434 sc->model->lcd_get, &Args, &Buf)) &&
435 Obj.Type == ACPI_TYPE_INTEGER) {
436 sc->s_lcd = Obj.Integer.Value >> 8;
437
438 SYSCTL_ADD_PROC(&sc->sysctl_ctx,
439 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
440 "lcd_backlight", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
441 acpi_asus_sysctl_lcd, "I",
442 "state of the lcd backlight");
443 }
444 }
445
446 /* Activate hotkeys */
447 AcpiEvaluateObject(sc->handle, "BSTS", NULL, NULL);
448
449 /* Handle notifies */
450 AcpiInstallNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
451 acpi_asus_notify, dev);
452
453 return (0);
454}
455
456static int
457acpi_asus_detach(device_t dev)
458{
459 struct acpi_asus_softc *sc;
460
461 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
462
463 sc = device_get_softc(dev);
464
465 /* Turn the lights off */
466 if (sc->model->mled_set)
467 led_destroy(sc->s_mled.cdev);
468
469 if (sc->model->tled_set)
470 led_destroy(sc->s_tled.cdev);
471
472 if (sc->model->wled_set)
473 led_destroy(sc->s_wled.cdev);
474
475 /* Remove notify handler */
476 AcpiRemoveNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
477 acpi_asus_notify);
478
479 /* Free sysctl tree */
480 sysctl_ctx_free(&sc->sysctl_ctx);
481
482 return (0);
483}
484
485static void
486acpi_asus_led(struct acpi_asus_led *led, int state)
487{
488 struct acpi_asus_softc *sc;
489 char *method;
490
491 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
492
493 sc = device_get_softc(led->dev);
494
495 switch (led->type) {
496 case ACPI_ASUS_LED_MLED:
497 method = sc->model->mled_set;
498
499 /* Note: inverted */
500 state = !state;
501 break;
502 case ACPI_ASUS_LED_TLED:
503 method = sc->model->tled_set;
504 break;
505 case ACPI_ASUS_LED_WLED:
506 method = sc->model->wled_set;
507 break;
508 default:
509 printf("acpi_asus_led: invalid LED type %d\n",
510 (int)led->type);
511 return;
512 }
513
514 acpi_SetInteger(sc->handle, method, state);
515}
516
517static int
518acpi_asus_sysctl_brn(SYSCTL_HANDLER_ARGS)
519{
520 struct acpi_asus_softc *sc;
521 int brn, err;
522
523 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
524
525 sc = (struct acpi_asus_softc *)oidp->oid_arg1;
526 ACPI_SERIAL_BEGIN(asus);
527
528 /* Sanity check */
529 brn = sc->s_brn;
530 err = sysctl_handle_int(oidp, &brn, 0, req);
531
532 if (err != 0 || req->newptr == NULL)
533 goto out;
534
535 if (brn < 0 || brn > 15) {
536 err = EINVAL;
537 goto out;
538 }
539
540 /* Keep track and update */
541 sc->s_brn = brn;
542
543 if (sc->model->brn_set)
544 acpi_SetInteger(sc->handle, sc->model->brn_set, brn);
545 else {
546 brn -= sc->s_brn;
547
548 while (brn != 0) {
549 AcpiEvaluateObject(sc->handle, (brn > 0) ?
550 sc->model->brn_up : sc->model->brn_dn,
551 NULL, NULL);
552 (brn > 0) ? brn-- : brn++;
553 }
554 }
555
556out:
557 ACPI_SERIAL_END(asus);
558 return (err);
559}
560
561static int
562acpi_asus_sysctl_lcd(SYSCTL_HANDLER_ARGS)
563{
564 struct acpi_asus_softc *sc;
565 int lcd, err;
566
567 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
568
569 sc = (struct acpi_asus_softc *)oidp->oid_arg1;
570 ACPI_SERIAL_BEGIN(asus);
571
572 /* Sanity check */
573 lcd = sc->s_lcd;
574 err = sysctl_handle_int(oidp, &lcd, 0, req);
575
576 if (err != 0 || req->newptr == NULL)
577 goto out;
578
579 if (lcd < 0 || lcd > 1) {
580 err = EINVAL;
581 goto out;
582 }
583
584 /* Keep track and update */
585 sc->s_lcd = lcd;
586
587 /* Most models just need a lcd_set evaluated, the L3H is trickier */
588 if (strncmp(sc->model->name, "L3H", 3) != 0)
589 AcpiEvaluateObject(sc->handle, sc->model->lcd_set, NULL, NULL);
590 else
591 acpi_SetInteger(sc->handle, sc->model->lcd_set, 0x7);
592
593out:
594 ACPI_SERIAL_END(asus);
595 return (err);
596}
597
598static int
599acpi_asus_sysctl_disp(SYSCTL_HANDLER_ARGS)
600{
601 struct acpi_asus_softc *sc;
602 int disp, err;
603
604 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
605
606 sc = (struct acpi_asus_softc *)oidp->oid_arg1;
607
608 /* Sanity check */
609 ACPI_SERIAL_BEGIN(asus);
610 disp = sc->s_disp;
611 err = sysctl_handle_int(oidp, &disp, 0, req);
612
613 if (err != 0 || req->newptr == NULL)
614 goto out;
615
616 if (disp < 0 || disp > 7) {
617 err = EINVAL;
618 goto out;
619 }
620
621 /* Keep track and update */
622 sc->s_disp = disp;
623 acpi_SetInteger(sc->handle, sc->model->disp_set, disp);
624
625out:
626 ACPI_SERIAL_END(asus);
627 return (err);
628}
629
630static void
631acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context)
632{
633 struct acpi_asus_softc *sc;
634 struct acpi_softc *acpi_sc;
635
636 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
637
638 sc = device_get_softc((device_t)context);
639 acpi_sc = acpi_device_get_parent_softc(sc->dev);
640
641 ACPI_SERIAL_BEGIN(asus);
642 if ((notify & ~0x10) <= 15) {
643 sc->s_brn = notify & ~0x10;
644 ACPI_VPRINT(sc->dev, acpi_sc, "Brightness increased\n");
645 } else if ((notify & ~0x20) <= 15) {
646 sc->s_brn = notify & ~0x20;
647 ACPI_VPRINT(sc->dev, acpi_sc, "Brightness decreased\n");
648 } else if (notify == 0x33) {
649 sc->s_lcd = 1;
650 ACPI_VPRINT(sc->dev, acpi_sc, "LCD turned on\n");
651 } else if (notify == 0x34) {
652 sc->s_lcd = 0;
653 ACPI_VPRINT(sc->dev, acpi_sc, "LCD turned off\n");
654 } else {
655 /* Notify devd(8) */
656 acpi_UserNotify("ASUS", h, notify);
657 }
658 ACPI_SERIAL_END(asus);
659}