]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/acpi_support/acpi_asus.c
Make sure status variable is always initialized. Why didn't this show up in
[FreeBSD/FreeBSD.git] / sys / dev / acpi_support / acpi_asus.c
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$");
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 /* Methods */
55 #define ACPI_ASUS_METHOD_BRN    1
56 #define ACPI_ASUS_METHOD_DISP   2
57 #define ACPI_ASUS_METHOD_LCD    3
58
59 #define _COMPONENT      ACPI_OEM
60 ACPI_MODULE_NAME("ASUS")
61
62 struct acpi_asus_model {
63         char    *name;
64
65         char    *mled_set;
66         char    *tled_set;
67         char    *wled_set;
68
69         char    *brn_get;
70         char    *brn_set;
71         char    *brn_up;
72         char    *brn_dn;
73
74         char    *lcd_get;
75         char    *lcd_set;
76
77         char    *disp_get;
78         char    *disp_set;
79 };
80
81 struct acpi_asus_led {
82         struct cdev     *cdev;
83         device_t        dev;
84         enum {
85                 ACPI_ASUS_LED_MLED,
86                 ACPI_ASUS_LED_TLED,
87                 ACPI_ASUS_LED_WLED,
88         } type;
89 };
90
91 struct acpi_asus_softc {
92         device_t                dev;
93         ACPI_HANDLE             handle;
94
95         struct acpi_asus_model  *model;
96         struct sysctl_ctx_list  sysctl_ctx;
97         struct sysctl_oid       *sysctl_tree;
98
99         struct acpi_asus_led    s_mled;
100         struct acpi_asus_led    s_tled;
101         struct acpi_asus_led    s_wled;
102
103         int                     s_brn;
104         int                     s_disp;
105         int                     s_lcd;
106 };
107
108 /*
109  * We can identify Asus laptops from the string they return
110  * as a result of calling the ATK0100 'INIT' method.
111  */
112 static struct acpi_asus_model acpi_asus_models[] = {
113         {
114                 .name           = "L2D",
115                 .mled_set       = "MLED",
116                 .wled_set       = "WLED",
117                 .brn_up         = "\\Q0E",
118                 .brn_dn         = "\\Q0F",
119                 .lcd_get        = "\\SGP0",
120                 .lcd_set        = "\\Q10"
121         },
122         {
123                 .name           = "L3C",
124                 .mled_set       = "MLED",
125                 .wled_set       = "WLED",
126                 .brn_get        = "GPLV",
127                 .brn_set        = "SPLV",
128                 .lcd_get        = "\\GL32",
129                 .lcd_set        = "\\_SB.PCI0.PX40.ECD0._Q10"
130         },
131         {
132                 .name           = "L3D",
133                 .mled_set       = "MLED",
134                 .wled_set       = "WLED",
135                 .brn_get        = "GPLV",
136                 .brn_set        = "SPLV",
137                 .lcd_get        = "\\BKLG",
138                 .lcd_set        = "\\Q10"
139         },
140         {
141                 .name           = "L3H",
142                 .mled_set       = "MLED",
143                 .wled_set       = "WLED",
144                 .brn_get        = "GPLV",
145                 .brn_set        = "SPLV",
146                 .lcd_get        = "\\_SB.PCI0.PM.PBC",
147                 .lcd_set        = "EHK",
148                 .disp_get       = "\\_SB.INFB",
149                 .disp_set       = "SDSP"
150         },
151         {
152                 .name           = "L4R",
153                 .mled_set       = "MLED",
154                 .wled_set       = "WLED",
155                 .brn_get        = "GPLV",
156                 .brn_set        = "SPLV",
157                 .lcd_get        = "\\_SB.PCI0.SBSM.SEO4",
158                 .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
159                 .disp_get       = "\\_SB.PCI0.P0P1.VGA.GETD",
160                 .disp_set       = "SDSP"
161         },
162         {
163                 .name           = "L8L"
164                 /* Only has hotkeys, apparantly */
165         },
166         {
167                 .name           = "M1A",
168                 .mled_set       = "MLED",
169                 .brn_up         = "\\_SB.PCI0.PX40.EC0.Q0E",
170                 .brn_dn         = "\\_SB.PCI0.PX40.EC0.Q0F",
171                 .lcd_get        = "\\PNOF",
172                 .lcd_set        = "\\_SB.PCI0.PX40.EC0.Q10"
173         },
174         {
175                 .name           = "M2E",
176                 .mled_set       = "MLED",
177                 .wled_set       = "WLED",
178                 .brn_get        = "GPLV",
179                 .brn_set        = "SPLV",
180                 .lcd_get        = "\\GP06",
181                 .lcd_set        = "\\Q10"
182         },
183         {
184                 .name           = "M6N",
185                 .mled_set       = "MLED",
186                 .wled_set       = "WLED",
187                 .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
188                 .lcd_get        = "\\_SB.BKLT",
189                 .brn_set        = "SPLV",
190                 .brn_get        = "GPLV",
191                 .disp_set       = "SDSP",
192                 .disp_get       = "\\SSTE"
193         },
194         {
195                 .name           = "M6R",
196                 .mled_set       = "MLED",
197                 .wled_set       = "WLED",
198                 .brn_get        = "GPLV",
199                 .brn_set        = "SPLV",
200                 .lcd_get        = "\\_SB.PCI0.SBSM.SEO4",
201                 .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
202                 .disp_get       = "\\SSTE",
203                 .disp_set       = "SDSP"
204         },
205
206         { .name = NULL }
207 };
208
209 /*
210  * Samsung P30/P35 laptops have an Asus ATK0100 gadget interface,
211  * but they can't be probed quite the same way as Asus laptops.
212  */
213 static struct acpi_asus_model acpi_samsung_models[] = {
214         {
215                 .name           = "P30",
216                 .wled_set       = "WLED",
217                 .brn_up         = "\\_SB.PCI0.LPCB.EC0._Q68",
218                 .brn_dn         = "\\_SB.PCI0.LPCB.EC0._Q69",
219                 .lcd_get        = "\\BKLT",
220                 .lcd_set        = "\\_SB.PCI0.LPCB.EC0._Q0E"
221         },
222
223         { .name = NULL }
224 };
225
226 static struct {
227         char    *name;
228         char    *description;
229         int     method;
230 } acpi_asus_sysctls[] = {
231         {
232                 .name           = "lcd_backlight",
233                 .method         = ACPI_ASUS_METHOD_LCD,
234                 .description    = "state of the lcd backlight"
235         },
236         {
237                 .name           = "lcd_brightness",
238                 .method         = ACPI_ASUS_METHOD_BRN,
239                 .description    = "brightness of the lcd panel"
240         },
241         {
242                 .name           = "video_output",
243                 .method         = ACPI_ASUS_METHOD_DISP,
244                 .description    = "display output state"
245         },
246
247         { .name = NULL }
248 };
249
250 ACPI_SERIAL_DECL(asus, "ACPI ASUS extras");
251
252 /* Function prototypes */
253 static int      acpi_asus_probe(device_t dev);
254 static int      acpi_asus_attach(device_t dev);
255 static int      acpi_asus_detach(device_t dev);
256
257 static void     acpi_asus_led(struct acpi_asus_led *led, int state);
258
259 static int      acpi_asus_sysctl(SYSCTL_HANDLER_ARGS);
260 static int      acpi_asus_sysctl_init(struct acpi_asus_softc *sc, int method);
261 static int      acpi_asus_sysctl_get(struct acpi_asus_softc *sc, int method);
262 static int      acpi_asus_sysctl_set(struct acpi_asus_softc *sc, int method, int val);
263
264 static void     acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context);
265
266 static device_method_t acpi_asus_methods[] = {
267         DEVMETHOD(device_probe,  acpi_asus_probe),
268         DEVMETHOD(device_attach, acpi_asus_attach),
269         DEVMETHOD(device_detach, acpi_asus_detach),
270
271         { 0, 0 }
272 };
273
274 static driver_t acpi_asus_driver = {
275         "acpi_asus",
276         acpi_asus_methods,
277         sizeof(struct acpi_asus_softc)
278 };
279
280 static devclass_t acpi_asus_devclass;
281
282 DRIVER_MODULE(acpi_asus, acpi, acpi_asus_driver, acpi_asus_devclass, 0, 0);
283 MODULE_DEPEND(acpi_asus, acpi, 1, 1, 1);
284
285 static int
286 acpi_asus_probe(device_t dev)
287 {
288         struct acpi_asus_model  *model;
289         struct acpi_asus_softc  *sc;
290         struct sbuf             *sb;
291         ACPI_BUFFER             Buf;
292         ACPI_OBJECT             Arg, *Obj;
293         ACPI_OBJECT_LIST        Args;
294         static char             *asus_ids[] = { "ATK0100", NULL };
295
296         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
297
298         if (acpi_disabled("asus") ||
299             ACPI_ID_PROBE(device_get_parent(dev), dev, asus_ids) == NULL)
300                 return (ENXIO);
301
302         sc = device_get_softc(dev);
303         sc->dev = dev;
304         sc->handle = acpi_get_handle(dev);
305
306         Arg.Type = ACPI_TYPE_INTEGER;
307         Arg.Integer.Value = 0;
308
309         Args.Count = 1;
310         Args.Pointer = &Arg;
311
312         Buf.Pointer = NULL;
313         Buf.Length = ACPI_ALLOCATE_BUFFER;
314
315         AcpiEvaluateObject(sc->handle, "INIT", &Args, &Buf);
316         Obj = Buf.Pointer;
317
318         /*
319          * The Samsung P30 returns a null-pointer from INIT, we
320          * can identify it from the 'ODEM' string in the DSDT.
321          */
322         if (Obj->String.Pointer == NULL) {
323                 ACPI_STATUS             status;
324                 ACPI_TABLE_HEADER       th;
325
326                 status = AcpiGetTableHeader(ACPI_TABLE_DSDT, 1, &th);
327                 if (ACPI_FAILURE(status)) {
328                         device_printf(dev, "Unsupported (Samsung?) laptop\n");
329                         AcpiOsFree(Buf.Pointer);
330                         return (ENXIO);
331                 }
332
333                 if (strncmp("ODEM", th.OemTableId, 4) == 0) {
334                         sc->model = &acpi_samsung_models[0];
335                         device_set_desc(dev, "Samsung P30 Laptop Extras");
336                         AcpiOsFree(Buf.Pointer);
337                         return (0);
338                 }
339         }
340
341         sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
342         if (sb == NULL)
343                 return (ENOMEM);
344
345         /*
346          * Asus laptops are simply identified by name, easy!
347          */
348         for (model = acpi_asus_models; model->name != NULL; model++)
349                 if (strncmp(Obj->String.Pointer, model->name, 3) == 0) {
350                         sbuf_printf(sb, "Asus %s Laptop Extras", model->name);
351                         sbuf_finish(sb);
352
353                         sc->model = model;
354                         device_set_desc(dev, sbuf_data(sb));
355
356                         sbuf_delete(sb);
357                         AcpiOsFree(Buf.Pointer);
358                         return (0);
359                 }
360
361         sbuf_printf(sb, "Unsupported Asus laptop: %s\n", Obj->String.Pointer);
362         sbuf_finish(sb);
363
364         device_printf(dev, sbuf_data(sb));
365
366         sbuf_delete(sb);
367         AcpiOsFree(Buf.Pointer);
368
369         return (ENXIO);
370 }
371
372 static int
373 acpi_asus_attach(device_t dev)
374 {
375         struct acpi_asus_softc  *sc;
376         struct acpi_softc       *acpi_sc;
377
378         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
379
380         sc = device_get_softc(dev);
381         acpi_sc = acpi_device_get_parent_softc(dev);
382
383         /* Build sysctl tree */
384         sysctl_ctx_init(&sc->sysctl_ctx);
385         sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
386             SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
387             OID_AUTO, "asus", CTLFLAG_RD, 0, "");
388
389         /* Hook up nodes */
390         for (int i = 0; acpi_asus_sysctls[i].name != NULL; i++) {
391                 if (!acpi_asus_sysctl_init(sc, acpi_asus_sysctls[i].method))
392                         continue;
393
394                 SYSCTL_ADD_PROC(&sc->sysctl_ctx,
395                     SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
396                     acpi_asus_sysctls[i].name,
397                     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY,
398                     sc, i, acpi_asus_sysctl, "I",
399                     acpi_asus_sysctls[i].description);
400         }
401
402         /* Attach leds */
403         if (sc->model->mled_set) {
404                 sc->s_mled.dev = dev;
405                 sc->s_mled.type = ACPI_ASUS_LED_MLED;
406                 sc->s_mled.cdev =
407                     led_create((led_t *)acpi_asus_led, &sc->s_mled, "mled");
408         }
409
410         if (sc->model->tled_set) {
411                 sc->s_tled.dev = dev;
412                 sc->s_tled.type = ACPI_ASUS_LED_TLED;
413                 sc->s_tled.cdev =
414                     led_create((led_t *)acpi_asus_led, &sc->s_tled, "tled");
415         }
416
417         if (sc->model->wled_set) {
418                 sc->s_wled.dev = dev;
419                 sc->s_wled.type = ACPI_ASUS_LED_WLED;
420                 sc->s_wled.cdev =
421                     led_create((led_t *)acpi_asus_led, &sc->s_wled, "wled");
422         }
423
424         /* Activate hotkeys */
425         AcpiEvaluateObject(sc->handle, "BSTS", NULL, NULL);
426
427         /* Handle notifies */
428         AcpiInstallNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
429             acpi_asus_notify, dev);
430
431         return (0);
432 }
433
434 static int
435 acpi_asus_detach(device_t dev)
436 {
437         struct acpi_asus_softc  *sc;
438
439         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
440
441         sc = device_get_softc(dev);
442
443         /* Turn the lights off */
444         if (sc->model->mled_set)
445                 led_destroy(sc->s_mled.cdev);
446
447         if (sc->model->tled_set)
448                 led_destroy(sc->s_tled.cdev);
449
450         if (sc->model->wled_set)
451                 led_destroy(sc->s_wled.cdev);
452
453         /* Remove notify handler */
454         AcpiRemoveNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
455             acpi_asus_notify);
456
457         /* Free sysctl tree */
458         sysctl_ctx_free(&sc->sysctl_ctx);
459
460         return (0);
461 }
462
463 static void
464 acpi_asus_led(struct acpi_asus_led *led, int state)
465 {
466         struct acpi_asus_softc  *sc;
467         char                    *method;
468
469         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
470
471         sc = device_get_softc(led->dev);
472
473         switch (led->type) {
474         case ACPI_ASUS_LED_MLED:
475                 method = sc->model->mled_set;
476
477                 /* Note: inverted */
478                 state = !state;
479                 break;
480         case ACPI_ASUS_LED_TLED:
481                 method = sc->model->tled_set;
482                 break;
483         case ACPI_ASUS_LED_WLED:
484                 method = sc->model->wled_set;
485                 break;
486         default:
487                 printf("acpi_asus_led: invalid LED type %d\n",
488                     (int)led->type);
489                 return;
490         }
491
492         acpi_SetInteger(sc->handle, method, state);
493 }
494
495 static int
496 acpi_asus_sysctl(SYSCTL_HANDLER_ARGS)
497 {
498         struct acpi_asus_softc  *sc;
499         int                     arg;
500         int                     error = 0;
501         int                     function;
502         int                     method;
503         
504         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
505
506         sc = (struct acpi_asus_softc *)oidp->oid_arg1;
507         function = oidp->oid_arg2;
508         method = acpi_asus_sysctls[function].method;
509
510         ACPI_SERIAL_BEGIN(asus);
511         arg = acpi_asus_sysctl_get(sc, method);
512         error = sysctl_handle_int(oidp, &arg, 0, req);
513
514         /* Sanity check */
515         if (error != 0 || req->newptr == NULL)
516                 goto out;
517
518         /* Update */
519         error = acpi_asus_sysctl_set(sc, method, arg);
520
521 out:
522         ACPI_SERIAL_END(asus);
523         return (error);
524 }
525
526 static int
527 acpi_asus_sysctl_get(struct acpi_asus_softc *sc, int method)
528 {
529         int val = 0;
530
531         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
532         ACPI_SERIAL_ASSERT(asus);
533
534         switch (method) {
535         case ACPI_ASUS_METHOD_BRN:
536                 val = sc->s_brn;
537                 break;
538         case ACPI_ASUS_METHOD_DISP:
539                 val = sc->s_disp;
540                 break;
541         case ACPI_ASUS_METHOD_LCD:
542                 val = sc->s_lcd;
543                 break;
544         }
545
546         return (val);
547 }
548
549 static int
550 acpi_asus_sysctl_set(struct acpi_asus_softc *sc, int method, int arg)
551 {
552         ACPI_STATUS     status = AE_OK;
553
554         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
555         ACPI_SERIAL_ASSERT(asus);
556
557         switch (method) {
558         case ACPI_ASUS_METHOD_BRN:
559                 if (arg < 0 || arg > 15)
560                         return (EINVAL);
561
562                 if (sc->model->brn_set)
563                         status = acpi_SetInteger(sc->handle,
564                             sc->model->brn_set, arg);
565                 else {
566                         while (arg != 0) {
567                                 status = AcpiEvaluateObject(sc->handle,
568                                     (arg > 0) ?  sc->model->brn_up :
569                                     sc->model->brn_dn, NULL, NULL);
570                                 (arg > 0) ? arg-- : arg++;
571                         }
572                 }
573
574                 if (ACPI_SUCCESS(status))
575                         sc->s_brn = arg;
576
577                 break;
578         case ACPI_ASUS_METHOD_DISP:
579                 if (arg < 0 || arg > 7)
580                         return (EINVAL);
581
582                 status = acpi_SetInteger(sc->handle,
583                     sc->model->disp_set, arg);
584
585                 if (ACPI_SUCCESS(status))
586                         sc->s_disp = arg;
587
588                 break;
589         case ACPI_ASUS_METHOD_LCD:
590                 if (arg < 0 || arg > 1)
591                         return (EINVAL);
592
593                 if (strncmp(sc->model->name, "L3H", 3) != 0)
594                         status = AcpiEvaluateObject(sc->handle,
595                             sc->model->lcd_set, NULL, NULL);
596                 else
597                         status = acpi_SetInteger(sc->handle,
598                             sc->model->lcd_set, 0x7);
599
600                 if (ACPI_SUCCESS(status))
601                         sc->s_lcd = arg;
602
603                 break;
604         }
605
606         return (0);
607 }
608
609 static int
610 acpi_asus_sysctl_init(struct acpi_asus_softc *sc, int method)
611 {
612         ACPI_STATUS     status;
613
614         switch (method) {
615         case ACPI_ASUS_METHOD_BRN:
616                 if (sc->model->brn_get) {
617                         /* GPLV/SPLV models */
618                         status = acpi_GetInteger(sc->handle,
619                             sc->model->brn_get, &sc->s_brn);
620                         if (ACPI_SUCCESS(status))
621                                 return (TRUE);
622                 } else if (sc->model->brn_up) {
623                         /* Relative models */
624                         status = AcpiEvaluateObject(sc->handle,
625                             sc->model->brn_up, NULL, NULL);
626                         if (ACPI_FAILURE(status))
627                                 return (FALSE);
628
629                         status = AcpiEvaluateObject(sc->handle,
630                             sc->model->brn_dn, NULL, NULL);
631                         if (ACPI_FAILURE(status))
632                                 return (FALSE);
633
634                         return (TRUE);
635                 }
636                 return (FALSE);
637         case ACPI_ASUS_METHOD_DISP:
638                 if (sc->model->disp_get) {
639                         status = acpi_GetInteger(sc->handle,
640                             sc->model->disp_get, &sc->s_disp);
641                         if (ACPI_SUCCESS(status))
642                                 return (TRUE);
643                 }
644                 return (FALSE);
645         case ACPI_ASUS_METHOD_LCD:
646                 if (sc->model->lcd_get &&
647                     strncmp(sc->model->name, "L3H", 3) != 0) {
648                         status = acpi_GetInteger(sc->handle,
649                             sc->model->lcd_get, &sc->s_lcd);
650                         if (ACPI_SUCCESS(status))
651                                 return (TRUE);
652                 }
653                 else if (sc->model->lcd_get) {
654                         ACPI_BUFFER             Buf;
655                         ACPI_OBJECT             Arg[2], Obj;
656                         ACPI_OBJECT_LIST        Args;
657
658                         /* L3H is a bit special */
659                         Arg[0].Type = ACPI_TYPE_INTEGER;
660                         Arg[0].Integer.Value = 0x02;
661                         Arg[1].Type = ACPI_TYPE_INTEGER;
662                         Arg[1].Integer.Value = 0x03;
663
664                         Args.Count = 2;
665                         Args.Pointer = Arg;
666
667                         Buf.Length = sizeof(Obj);
668                         Buf.Pointer = &Obj;
669
670                         status = AcpiEvaluateObject(sc->handle,
671                             sc->model->lcd_get, &Args, &Buf);
672                         if (ACPI_SUCCESS(status) &&
673                             Obj.Type == ACPI_TYPE_INTEGER) {
674                                 sc->s_lcd = Obj.Integer.Value >> 8;
675                                 return (TRUE);
676                         }
677                 }
678                 return (FALSE);
679         }
680         return (FALSE);
681 }
682
683 static void
684 acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context)
685 {
686         struct acpi_asus_softc  *sc;
687         struct acpi_softc       *acpi_sc;
688
689         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
690
691         sc = device_get_softc((device_t)context);
692         acpi_sc = acpi_device_get_parent_softc(sc->dev);
693
694         ACPI_SERIAL_BEGIN(asus);
695         if ((notify & ~0x10) <= 15) {
696                 sc->s_brn = notify & ~0x10;
697                 ACPI_VPRINT(sc->dev, acpi_sc, "Brightness increased\n");
698         } else if ((notify & ~0x20) <= 15) {
699                 sc->s_brn = notify & ~0x20;
700                 ACPI_VPRINT(sc->dev, acpi_sc, "Brightness decreased\n");
701         } else if (notify == 0x33) {
702                 sc->s_lcd = 1;
703                 ACPI_VPRINT(sc->dev, acpi_sc, "LCD turned on\n");
704         } else if (notify == 0x34) {
705                 sc->s_lcd = 0;
706                 ACPI_VPRINT(sc->dev, acpi_sc, "LCD turned off\n");
707         } else {
708                 /* Notify devd(8) */
709                 acpi_UserNotify("ASUS", h, notify);
710         }
711         ACPI_SERIAL_END(asus);
712 }