xref: /dragonfly/sys/dev/acpica/acpi_asus/acpi_asus.c (revision f2c400e8d295d33c95df1bc50e36c0585233955e)
1 /*-
2  * Copyright (c) 2004, 2005 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  * $FreeBSD: src/sys/dev/acpi_support/acpi_asus.c,v 1.44 2010/06/11 20:08:20 jkim Exp $
27  */
28 
29 /*
30  * Driver for extra ACPI-controlled gadgets (hotkeys, leds, etc) found on
31  * recent Asus (and Medion) laptops.  Inspired by the acpi4asus project which
32  * implements these features in the Linux kernel.
33  *
34  *   <http://sourceforge.net/projects/acpi4asus/>
35  *
36  * Currently should support most features, but could use some more testing.
37  * Particularly the display-switching stuff is a bit hairy.  If you have an
38  * Asus laptop which doesn't appear to be supported, or strange things happen
39  * when using this driver, please report to <acpi@FreeBSD.org>.
40  */
41 
42 #include "opt_acpi.h"
43 #include <sys/param.h>
44 #include <sys/kernel.h>
45 #include <sys/module.h>
46 #include <sys/bus.h>
47 #include <sys/sbuf.h>
48 
49 #include "acpi.h"
50 #include "accommon.h"
51 #include "acpivar.h"
52 
53 #include <dev/misc/led/led.h>
54 
55 /* Methods */
56 #define ACPI_ASUS_METHOD_BRN  1
57 #define ACPI_ASUS_METHOD_DISP 2
58 #define ACPI_ASUS_METHOD_LCD  3
59 #define ACPI_ASUS_METHOD_CAMERA         4
60 #define ACPI_ASUS_METHOD_CARDRD         5
61 #define ACPI_ASUS_METHOD_WLAN 6
62 
63 #define _COMPONENT  ACPI_OEM
64 ACPI_MODULE_NAME("ASUS")
65 
66 struct acpi_asus_model {
67           char      *name;
68           char      *bled_set;
69           char      *dled_set;
70           char      *gled_set;
71           char      *mled_set;
72           char      *tled_set;
73           char      *wled_set;
74 
75           char      *brn_get;
76           char      *brn_set;
77           char      *brn_up;
78           char      *brn_dn;
79 
80           char      *lcd_get;
81           char      *lcd_set;
82 
83           char      *disp_get;
84           char      *disp_set;
85 
86           char      *cam_get;
87           char      *cam_set;
88 
89           char      *crd_get;
90           char      *crd_set;
91 
92           char      *wlan_get;
93           char      *wlan_set;
94 
95           void      (*n_func)(ACPI_HANDLE, UINT32, void *);
96 
97           char      *lcdd;
98           void      (*lcdd_n_func)(ACPI_HANDLE, UINT32, void *);
99 };
100 
101 struct acpi_asus_led {
102           struct acpi_asus_softc *sc;
103           struct cdev         *cdev;
104           int                 busy;
105           int                 state;
106           enum {
107                     ACPI_ASUS_LED_BLED,
108                     ACPI_ASUS_LED_DLED,
109                     ACPI_ASUS_LED_GLED,
110                     ACPI_ASUS_LED_MLED,
111                     ACPI_ASUS_LED_TLED,
112                     ACPI_ASUS_LED_WLED,
113           } type;
114 };
115 
116 struct acpi_asus_softc {
117           device_t            dev;
118           ACPI_HANDLE                   handle;
119           ACPI_HANDLE                   lcdd_handle;
120 
121           struct acpi_asus_model        *model;
122           struct sysctl_ctx_list        sysctl_ctx;
123           struct sysctl_oid   *sysctl_tree;
124           struct acpi_asus_led          s_bled;
125           struct acpi_asus_led          s_dled;
126           struct acpi_asus_led          s_gled;
127           struct acpi_asus_led          s_mled;
128           struct acpi_asus_led          s_tled;
129           struct acpi_asus_led          s_wled;
130 
131           int                           s_brn;
132           int                           s_disp;
133           int                           s_lcd;
134           int                           s_cam;
135           int                           s_crd;
136           int                           s_wlan;
137 };
138 
139 static void         acpi_asus_lcdd_notify(ACPI_HANDLE h, UINT32 notify,
140     void *context);
141 
142 /*
143  * We can identify Asus laptops from the string they return
144  * as a result of calling the ATK0100 'INIT' method.
145  */
146 static struct acpi_asus_model acpi_asus_models[] = {
147           {
148                     .name               = "xxN",
149                     .mled_set = "MLED",
150                     .wled_set = "WLED",
151                     .lcd_get  = "\\BKLT",
152                     .lcd_set  = "\\_SB.PCI0.SBRG.EC0._Q10",
153                     .brn_get  = "GPLV",
154                     .brn_set  = "SPLV",
155                     .disp_get = "\\ADVG",
156                     .disp_set = "SDSP"
157           },
158           {
159                     .name               = "A1x",
160                     .mled_set = "MLED",
161                     .lcd_get  = "\\BKLI",
162                     .lcd_set  = "\\_SB.PCI0.ISA.EC0._Q10",
163                     .brn_up             = "\\_SB.PCI0.ISA.EC0._Q0E",
164                     .brn_dn             = "\\_SB.PCI0.ISA.EC0._Q0F"
165           },
166           {
167                     .name               = "A2x",
168                     .mled_set = "MLED",
169                     .wled_set = "WLED",
170                     .lcd_get  = "\\BAOF",
171                     .lcd_set  = "\\Q10",
172                     .brn_get  = "GPLV",
173                     .brn_set  = "SPLV",
174                     .disp_get = "\\INFB",
175                     .disp_set = "SDSP"
176           },
177           {
178                     .name           = "A3E",
179                     .mled_set       = "MLED",
180                     .wled_set       = "WLED",
181                     .lcd_get        = "\\_SB.PCI0.SBRG.EC0.RPIN(0x67)",
182                     .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
183                     .brn_get        = "GPLV",
184                     .brn_set        = "SPLV",
185                     .disp_get       = "\\_SB.PCI0.P0P2.VGA.GETD",
186                     .disp_set       = "SDSP"
187           },
188           {
189                     .name           = "A3F",
190                     .mled_set       = "MLED",
191                     .wled_set       = "WLED",
192                     .bled_set       = "BLED",
193                     .lcd_get        = "\\_SB.PCI0.SBRG.EC0.RPIN(0x11)",
194                     .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
195                     .brn_get        = "GPLV",
196                     .brn_set        = "SPLV",
197                     .disp_get       = "\\SSTE",
198                     .disp_set       = "SDSP"
199           },
200           {
201                     .name           = "A3N",
202                     .mled_set       = "MLED",
203                     .bled_set       = "BLED",
204                     .wled_set       = "WLED",
205                     .lcd_get        = "\\BKLT",
206                     .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
207                     .brn_get        = "GPLV",
208                     .brn_set        = "SPLV",
209                     .disp_get       = "\\_SB.PCI0.P0P3.VGA.GETD",
210                     .disp_set       = "SDSP"
211           },
212           {
213                     .name               = "A4D",
214                     .mled_set = "MLED",
215                     .brn_up             = "\\_SB_.PCI0.SBRG.EC0._Q0E",
216                     .brn_dn             = "\\_SB_.PCI0.SBRG.EC0._Q0F",
217                     .brn_get  = "GPLV",
218                     .brn_set  = "SPLV",
219 #ifdef notyet
220                     .disp_get = "\\_SB_.PCI0.SBRG.EC0._Q10",
221                     .disp_set = "\\_SB_.PCI0.SBRG.EC0._Q11"
222 #endif
223           },
224           {
225                     .name               = "A6V",
226                     .bled_set = "BLED",
227                     .mled_set = "MLED",
228                     .wled_set = "WLED",
229                     .lcd_get  = NULL,
230                     .lcd_set  = "\\_SB.PCI0.SBRG.EC0._Q10",
231                     .brn_get  = "GPLV",
232                     .brn_set  = "SPLV",
233                     .disp_get = "\\_SB.PCI0.P0P3.VGA.GETD",
234                     .disp_set = "SDSP"
235           },
236           {
237                     .name               = "A8SR",
238                     .bled_set = "BLED",
239                     .mled_set = "MLED",
240                     .wled_set = "WLED",
241                     .lcd_get  = NULL,
242                     .lcd_set  = "\\_SB.PCI0.SBRG.EC0._Q10",
243                     .brn_get  = "GPLV",
244                     .brn_set  = "SPLV",
245                     .disp_get = "\\_SB.PCI0.P0P1.VGA.GETD",
246                     .disp_set = "SDSP",
247                     .lcdd               = "\\_SB.PCI0.P0P1.VGA.LCDD",
248                     .lcdd_n_func        = acpi_asus_lcdd_notify
249           },
250           {
251                     .name               = "D1x",
252                     .mled_set = "MLED",
253                     .lcd_get  = "\\GP11",
254                     .lcd_set  = "\\Q0D",
255                     .brn_up             = "\\Q0C",
256                     .brn_dn             = "\\Q0B",
257                     .disp_get = "\\INFB",
258                     .disp_set = "SDSP"
259           },
260           {
261                     .name               = "G2K",
262                     .bled_set = "BLED",
263                     .dled_set = "DLED",
264                     .gled_set = "GLED",
265                     .mled_set = "MLED",
266                     .tled_set = "TLED",
267                     .wled_set = "WLED",
268                     .brn_get  = "GPLV",
269                     .brn_set  = "SPLV",
270                     .lcd_get  = "GBTL",
271                     .lcd_set  = "SBTL",
272                     .disp_get = "\\_SB.PCI0.PCE2.VGA.GETD",
273                     .disp_set = "SDSP",
274           },
275           {
276                     .name               = "L2D",
277                     .mled_set = "MLED",
278                     .wled_set = "WLED",
279                     .brn_up             = "\\Q0E",
280                     .brn_dn             = "\\Q0F",
281                     .lcd_get  = "\\SGP0",
282                     .lcd_set  = "\\Q10"
283           },
284           {
285                     .name               = "L3C",
286                     .mled_set = "MLED",
287                     .wled_set = "WLED",
288                     .brn_get  = "GPLV",
289                     .brn_set  = "SPLV",
290                     .lcd_get  = "\\GL32",
291                     .lcd_set  = "\\_SB.PCI0.PX40.ECD0._Q10"
292           },
293           {
294                     .name               = "L3D",
295                     .mled_set = "MLED",
296                     .wled_set = "WLED",
297                     .brn_get  = "GPLV",
298                     .brn_set  = "SPLV",
299                     .lcd_get  = "\\BKLG",
300                     .lcd_set  = "\\Q10"
301           },
302           {
303                     .name               = "L3H",
304                     .mled_set = "MLED",
305                     .wled_set = "WLED",
306                     .brn_get  = "GPLV",
307                     .brn_set  = "SPLV",
308                     .lcd_get  = "\\_SB.PCI0.PM.PBC",
309                     .lcd_set  = "EHK",
310                     .disp_get = "\\_SB.INFB",
311                     .disp_set = "SDSP"
312           },
313           {
314                     .name               = "L4R",
315                     .mled_set = "MLED",
316                     .wled_set = "WLED",
317                     .brn_get  = "GPLV",
318                     .brn_set  = "SPLV",
319                     .lcd_get  = "\\_SB.PCI0.SBSM.SEO4",
320                     .lcd_set  = "\\_SB.PCI0.SBRG.EC0._Q10",
321                     .disp_get = "\\_SB.PCI0.P0P1.VGA.GETD",
322                     .disp_set = "SDSP"
323           },
324           {
325                     .name               = "L5x",
326                     .mled_set = "MLED",
327                     .tled_set = "TLED",
328                     .lcd_get  = "\\BAOF",
329                     .lcd_set  = "\\Q0D",
330                     .brn_get  = "GPLV",
331                     .brn_set  = "SPLV",
332                     .disp_get = "\\INFB",
333                     .disp_set = "SDSP"
334           },
335           {
336                     .name               = "L8L"
337                     /* Only has hotkeys, apparently */
338           },
339           {
340                     .name               = "M1A",
341                     .mled_set = "MLED",
342                     .brn_up             = "\\_SB.PCI0.PX40.EC0.Q0E",
343                     .brn_dn             = "\\_SB.PCI0.PX40.EC0.Q0F",
344                     .lcd_get  = "\\PNOF",
345                     .lcd_set  = "\\_SB.PCI0.PX40.EC0.Q10"
346           },
347           {
348                     .name               = "M2E",
349                     .mled_set = "MLED",
350                     .wled_set = "WLED",
351                     .brn_get  = "GPLV",
352                     .brn_set  = "SPLV",
353                     .lcd_get  = "\\GP06",
354                     .lcd_set  = "\\Q10"
355           },
356           {
357                     .name               = "M6N",
358                     .mled_set = "MLED",
359                     .wled_set = "WLED",
360                     .lcd_set  = "\\_SB.PCI0.SBRG.EC0._Q10",
361                     .lcd_get  = "\\_SB.BKLT",
362                     .brn_set  = "SPLV",
363                     .brn_get  = "GPLV",
364                     .disp_set = "SDSP",
365                     .disp_get = "\\SSTE"
366           },
367           {
368                     .name               = "M6R",
369                     .mled_set = "MLED",
370                     .wled_set = "WLED",
371                     .brn_get  = "GPLV",
372                     .brn_set  = "SPLV",
373                     .lcd_get  = "\\_SB.PCI0.SBSM.SEO4",
374                     .lcd_set  = "\\_SB.PCI0.SBRG.EC0._Q10",
375                     .disp_get = "\\SSTE",
376                     .disp_set = "SDSP"
377           },
378           {
379                     .name               = "S1x",
380                     .mled_set = "MLED",
381                     .wled_set = "WLED",
382                     .lcd_get  = "\\PNOF",
383                     .lcd_set  = "\\_SB.PCI0.PX40.Q10",
384                     .brn_get  = "GPLV",
385                     .brn_set  = "SPLV"
386           },
387           {
388                     .name               = "S2x",
389                     .mled_set = "MLED",
390                     .lcd_get  = "\\BKLI",
391                     .lcd_set  = "\\_SB.PCI0.ISA.EC0._Q10",
392                     .brn_up             = "\\_SB.PCI0.ISA.EC0._Q0B",
393                     .brn_dn             = "\\_SB.PCI0.ISA.EC0._Q0A"
394           },
395           {
396                     .name               = "V6V",
397                     .bled_set = "BLED",
398                     .tled_set = "TLED",
399                     .wled_set = "WLED",
400                     .lcd_get  = "\\BKLT",
401                     .lcd_set  = "\\_SB.PCI0.SBRG.EC0._Q10",
402                     .brn_get  = "GPLV",
403                     .brn_set  = "SPLV",
404                     .disp_get = "\\_SB.PCI0.P0P1.VGA.GETD",
405                     .disp_set = "SDSP"
406           },
407           {
408                     .name               = "W5A",
409                     .bled_set = "BLED",
410                     .lcd_get  = "\\BKLT",
411                     .lcd_set  = "\\_SB.PCI0.SBRG.EC0._Q10",
412                     .brn_get  = "GPLV",
413                     .brn_set  = "SPLV",
414                     .disp_get = "\\_SB.PCI0.P0P2.VGA.GETD",
415                     .disp_set = "SDSP"
416           },
417 
418           { .name = NULL }
419 };
420 
421 /*
422  * Samsung P30/P35 laptops have an Asus ATK0100 gadget interface,
423  * but they can't be probed quite the same way as Asus laptops.
424  */
425 static struct acpi_asus_model acpi_samsung_models[] = {
426           {
427                     .name               = "P30",
428                     .wled_set = "WLED",
429                     .brn_up             = "\\_SB.PCI0.LPCB.EC0._Q68",
430                     .brn_dn             = "\\_SB.PCI0.LPCB.EC0._Q69",
431                     .lcd_get  = "\\BKLT",
432                     .lcd_set  = "\\_SB.PCI0.LPCB.EC0._Q0E"
433           },
434 
435           { .name = NULL }
436 };
437 
438 static void         acpi_asus_eeepc_notify(ACPI_HANDLE h, UINT32 notify, void *context);
439 
440 /*
441  * EeePC have an Asus ASUS010 gadget interface,
442  * but they can't be probed quite the same way as Asus laptops.
443  */
444 static struct acpi_asus_model acpi_eeepc_models[] = {
445           {
446                     .name               = "EEE",
447                     .brn_get  = "\\_SB.ATKD.PBLG",
448                     .brn_set  = "\\_SB.ATKD.PBLS",
449                     .cam_get  = "\\_SB.ATKD.CAMG",
450                     .cam_set  = "\\_SB.ATKD.CAMS",
451                     .crd_set  = "\\_SB.ATKD.CRDS",
452                     .crd_get  = "\\_SB.ATKD.CRDG",
453                     .wlan_get = "\\_SB.ATKD.WLDG",
454                     .wlan_set = "\\_SB.ATKD.WLDS",
455                     .n_func             = acpi_asus_eeepc_notify
456           },
457 
458           { .name = NULL }
459 };
460 
461 static struct {
462           char      *name;
463           char      *description;
464           int       method;
465           int       flags;
466 } acpi_asus_sysctls[] = {
467           {
468                     .name               = "lcd_backlight",
469                     .method             = ACPI_ASUS_METHOD_LCD,
470                     .description        = "state of the lcd backlight",
471                     .flags              = CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY
472           },
473           {
474                     .name               = "lcd_brightness",
475                     .method             = ACPI_ASUS_METHOD_BRN,
476                     .description        = "brightness of the lcd panel",
477                     .flags              = CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY
478           },
479           {
480                     .name               = "video_output",
481                     .method             = ACPI_ASUS_METHOD_DISP,
482                     .description        = "display output state",
483                     .flags              = CTLTYPE_INT | CTLFLAG_RW
484           },
485           {
486                     .name               = "camera",
487                     .method             = ACPI_ASUS_METHOD_CAMERA,
488                     .description        = "internal camera state",
489                     .flags              = CTLTYPE_INT | CTLFLAG_RW
490           },
491           {
492                     .name               = "cardreader",
493                     .method             = ACPI_ASUS_METHOD_CARDRD,
494                     .description        = "internal card reader state",
495                     .flags              = CTLTYPE_INT | CTLFLAG_RW
496           },
497           {
498                     .name               = "wlan",
499                     .method             = ACPI_ASUS_METHOD_WLAN,
500                     .description        = "wireless lan state",
501                     .flags              = CTLTYPE_INT | CTLFLAG_RW
502           },
503 
504           { .name = NULL }
505 };
506 
507 ACPI_SERIAL_DECL(asus, "ACPI ASUS extras");
508 
509 /* Function prototypes */
510 static int          acpi_asus_probe(device_t dev);
511 static int          acpi_asus_attach(device_t dev);
512 static int          acpi_asus_detach(device_t dev);
513 
514 static void         acpi_asus_led(struct acpi_asus_led *led, int state);
515 static void         acpi_asus_led_task(struct acpi_asus_led *led, int pending __unused);
516 
517 static int          acpi_asus_sysctl(SYSCTL_HANDLER_ARGS);
518 static int          acpi_asus_sysctl_init(struct acpi_asus_softc *sc, int method);
519 static int          acpi_asus_sysctl_get(struct acpi_asus_softc *sc, int method);
520 static int          acpi_asus_sysctl_set(struct acpi_asus_softc *sc, int method, int val);
521 
522 static void         acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context);
523 
524 static device_method_t acpi_asus_methods[] = {
525           DEVMETHOD(device_probe,  acpi_asus_probe),
526           DEVMETHOD(device_attach, acpi_asus_attach),
527           DEVMETHOD(device_detach, acpi_asus_detach),
528 
529           DEVMETHOD_END
530 };
531 
532 static driver_t acpi_asus_driver = {
533           "acpi_asus",
534           acpi_asus_methods,
535           sizeof(struct acpi_asus_softc)
536 };
537 
538 static devclass_t acpi_asus_devclass;
539 
540 DRIVER_MODULE(acpi_asus, acpi, acpi_asus_driver, acpi_asus_devclass, NULL, NULL);
541 MODULE_DEPEND(acpi_asus, acpi, 1, 1, 1);
542 MODULE_DEPEND(acpi_asus, led, 1, 1, 1);
543 
544 static int
acpi_asus_probe(device_t dev)545 acpi_asus_probe(device_t dev)
546 {
547           struct acpi_asus_model        *model;
548           struct acpi_asus_softc        *sc;
549           struct sbuf                   *sb;
550           ACPI_BUFFER                   Buf;
551           ACPI_OBJECT                   Arg, *Obj;
552           ACPI_OBJECT_LIST    Args;
553           static char                   *asus_ids[] = { "ATK0100", "ASUS010", NULL };
554           char *rstr;
555 
556           ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
557 
558           if (acpi_disabled("asus"))
559                     return (ENXIO);
560           ACPI_SERIAL_INIT(asus);
561           rstr = ACPI_ID_PROBE(device_get_parent(dev), dev, asus_ids);
562           if (rstr == NULL) {
563                     return (ENXIO);
564           }
565 
566           sc = device_get_softc(dev);
567           sc->dev = dev;
568           sc->handle = acpi_get_handle(dev);
569 
570           Arg.Type = ACPI_TYPE_INTEGER;
571           Arg.Integer.Value = 0;
572 
573           Args.Count = 1;
574           Args.Pointer = &Arg;
575 
576           Buf.Pointer = NULL;
577           Buf.Length = ACPI_ALLOCATE_BUFFER;
578 
579           AcpiEvaluateObject(sc->handle, "INIT", &Args, &Buf);
580           Obj = Buf.Pointer;
581 
582           /*
583            * The Samsung P30 returns a null-pointer from INIT, we
584            * can identify it from the 'ODEM' string in the DSDT.
585            */
586           if (Obj->String.Pointer == NULL) {
587                     ACPI_STATUS                   status;
588                     ACPI_TABLE_HEADER   th;
589 
590                     status = AcpiGetTableHeader(ACPI_SIG_DSDT, 0, &th);
591                     if (ACPI_FAILURE(status)) {
592                               device_printf(dev, "Unsupported (Samsung?) laptop\n");
593                               AcpiOsFree(Buf.Pointer);
594                               return (ENXIO);
595                     }
596 
597                     if (strncmp("ODEM", th.OemTableId, 4) == 0) {
598                               sc->model = &acpi_samsung_models[0];
599                               device_set_desc(dev, "Samsung P30 Laptop Extras");
600                               AcpiOsFree(Buf.Pointer);
601                               return (0);
602                     }
603 
604                     /* EeePC */
605                     if (strncmp("ASUS010", rstr, 7) == 0) {
606                               sc->model = &acpi_eeepc_models[0];
607                               device_set_desc(dev, "ASUS EeePC");
608                               AcpiOsFree(Buf.Pointer);
609                               return (0);
610                     }
611           }
612 
613           sb = sbuf_new_auto();
614           if (sb == NULL)
615                     return (ENOMEM);
616 
617           /*
618            * Asus laptops are simply identified by name, easy!
619            */
620           for (model = acpi_asus_models; model->name != NULL; model++) {
621                     if (strncmp(Obj->String.Pointer, model->name, 3) == 0) {
622 
623 good:
624                               sbuf_printf(sb, "Asus %s Laptop Extras",
625                                   Obj->String.Pointer);
626                               sbuf_finish(sb);
627 
628                               sc->model = model;
629                               device_set_desc_copy(dev, sbuf_data(sb));
630 
631                               sbuf_delete(sb);
632                               AcpiOsFree(Buf.Pointer);
633                               return (0);
634                     }
635 
636                     /*
637                      * Some models look exactly the same as other models, but have
638                      * their own ids.  If we spot these, set them up with the same
639                      * details as the models they're like, possibly dealing with
640                      * small differences.
641                      *
642                      * XXX: there must be a prettier way to do this!
643                      */
644                     else if (strncmp(model->name, "xxN", 3) == 0 &&
645                         (strncmp(Obj->String.Pointer, "M3N", 3) == 0 ||
646                          strncmp(Obj->String.Pointer, "S1N", 3) == 0))
647                               goto good;
648                     else if (strncmp(model->name, "A1x", 3) == 0 &&
649                         strncmp(Obj->String.Pointer, "A1", 2) == 0)
650                               goto good;
651                     else if (strncmp(model->name, "A2x", 3) == 0 &&
652                         strncmp(Obj->String.Pointer, "A2", 2) == 0)
653                               goto good;
654                     else if (strncmp(model->name, "A3F", 3) == 0 &&
655                         strncmp(Obj->String.Pointer, "A6F", 3) == 0)
656                               goto good;
657                     else if (strncmp(model->name, "D1x", 3) == 0 &&
658                         strncmp(Obj->String.Pointer, "D1", 2) == 0)
659                               goto good;
660                     else if (strncmp(model->name, "L3H", 3) == 0 &&
661                         strncmp(Obj->String.Pointer, "L2E", 3) == 0)
662                               goto good;
663                     else if (strncmp(model->name, "L5x", 3) == 0 &&
664                         strncmp(Obj->String.Pointer, "L5", 2) == 0)
665                               goto good;
666                     else if (strncmp(model->name, "M2E", 3) == 0 &&
667                         (strncmp(Obj->String.Pointer, "M2", 2) == 0 ||
668                          strncmp(Obj->String.Pointer, "L4E", 3) == 0))
669                               goto good;
670                     else if (strncmp(model->name, "S1x", 3) == 0 &&
671                         (strncmp(Obj->String.Pointer, "L8", 2) == 0 ||
672                          strncmp(Obj->String.Pointer, "S1", 2) == 0))
673                               goto good;
674                     else if (strncmp(model->name, "S2x", 3) == 0 &&
675                         (strncmp(Obj->String.Pointer, "J1", 2) == 0 ||
676                          strncmp(Obj->String.Pointer, "S2", 2) == 0))
677                               goto good;
678 
679                     /* L2B is like L3C but has no lcd_get method */
680                     else if (strncmp(model->name, "L3C", 3) == 0 &&
681                         strncmp(Obj->String.Pointer, "L2B", 3) == 0) {
682                               model->lcd_get = NULL;
683                               goto good;
684                     }
685 
686                     /* A3G is like M6R but with a different lcd_get method */
687                     else if (strncmp(model->name, "M6R", 3) == 0 &&
688                         strncmp(Obj->String.Pointer, "A3G", 3) == 0) {
689                               model->lcd_get = "\\BLFG";
690                               goto good;
691                     }
692 
693                     /* M2N and W1N are like xxN with added WLED */
694                     else if (strncmp(model->name, "xxN", 3) == 0 &&
695                         (strncmp(Obj->String.Pointer, "M2N", 3) == 0 ||
696                          strncmp(Obj->String.Pointer, "W1N", 3) == 0)) {
697                               model->wled_set = "WLED";
698                               goto good;
699                     }
700 
701                     /* M5N and S5N are like xxN without MLED */
702                     else if (strncmp(model->name, "xxN", 3) == 0 &&
703                         (strncmp(Obj->String.Pointer, "M5N", 3) == 0 ||
704                          strncmp(Obj->String.Pointer, "S5N", 3) == 0)) {
705                               model->mled_set = NULL;
706                               goto good;
707                     }
708           }
709 
710           sbuf_printf(sb, "Unsupported Asus laptop: %s\n", Obj->String.Pointer);
711           sbuf_finish(sb);
712 
713           device_printf(dev, "%s", sbuf_data(sb));
714 
715           sbuf_delete(sb);
716           AcpiOsFree(Buf.Pointer);
717 
718           return (ENXIO);
719 }
720 
721 static int
acpi_asus_attach(device_t dev)722 acpi_asus_attach(device_t dev)
723 {
724           struct acpi_asus_softc        *sc;
725           struct acpi_softc   *acpi_sc;
726 
727           ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
728 
729           sc = device_get_softc(dev);
730           acpi_sc = acpi_device_get_parent_softc(dev);
731 
732           /* Build sysctl tree */
733           sysctl_ctx_init(&sc->sysctl_ctx);
734           sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
735               SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
736               OID_AUTO, "asus", CTLFLAG_RD, 0, "");
737 
738           /* Hook up nodes */
739           for (int i = 0; acpi_asus_sysctls[i].name != NULL; i++) {
740                     if (!acpi_asus_sysctl_init(sc, acpi_asus_sysctls[i].method))
741                               continue;
742 
743                     SYSCTL_ADD_PROC(&sc->sysctl_ctx,
744                         SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
745                         acpi_asus_sysctls[i].name,
746                         acpi_asus_sysctls[i].flags,
747                         sc, i, acpi_asus_sysctl, "I",
748                         acpi_asus_sysctls[i].description);
749           }
750 
751           /* Attach leds */
752           if (sc->model->bled_set) {
753                     sc->s_bled.busy = 0;
754                     sc->s_bled.sc = sc;
755                     sc->s_bled.type = ACPI_ASUS_LED_BLED;
756                     sc->s_bled.cdev =
757                         led_create_state((led_t *)acpi_asus_led, &sc->s_bled,
758                               "bled", 1);
759           }
760 
761           if (sc->model->dled_set) {
762                     sc->s_dled.busy = 0;
763                     sc->s_dled.sc = sc;
764                     sc->s_dled.type = ACPI_ASUS_LED_DLED;
765                     sc->s_dled.cdev =
766                         led_create((led_t *)acpi_asus_led, &sc->s_dled, "dled");
767           }
768 
769           if (sc->model->gled_set) {
770                     sc->s_gled.busy = 0;
771                     sc->s_gled.sc = sc;
772                     sc->s_gled.type = ACPI_ASUS_LED_GLED;
773                     sc->s_gled.cdev =
774                         led_create((led_t *)acpi_asus_led, &sc->s_gled, "gled");
775           }
776 
777           if (sc->model->mled_set) {
778                     sc->s_mled.busy = 0;
779                     sc->s_mled.sc = sc;
780                     sc->s_mled.type = ACPI_ASUS_LED_MLED;
781                     sc->s_mled.cdev =
782                         led_create((led_t *)acpi_asus_led, &sc->s_mled, "mled");
783           }
784 
785           if (sc->model->tled_set) {
786                     sc->s_tled.busy = 0;
787                     sc->s_tled.sc = sc;
788                     sc->s_tled.type = ACPI_ASUS_LED_TLED;
789                     sc->s_tled.cdev =
790                         led_create_state((led_t *)acpi_asus_led, &sc->s_tled,
791                               "tled", 1);
792           }
793 
794           if (sc->model->wled_set) {
795                     sc->s_wled.busy = 0;
796                     sc->s_wled.sc = sc;
797                     sc->s_wled.type = ACPI_ASUS_LED_WLED;
798                     sc->s_wled.cdev =
799                         led_create_state((led_t *)acpi_asus_led, &sc->s_wled,
800                               "wled", 1);
801           }
802 
803           /* Activate hotkeys */
804           AcpiEvaluateObject(sc->handle, "BSTS", NULL, NULL);
805 
806           /* Handle notifies */
807           if (sc->model->n_func == NULL)
808                     sc->model->n_func = acpi_asus_notify;
809 
810           AcpiInstallNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
811               sc->model->n_func, dev);
812 
813           /* Find and hook the 'LCDD' object */
814           if (sc->model->lcdd != NULL && sc->model->lcdd_n_func != NULL) {
815                     ACPI_STATUS res;
816 
817                     sc->lcdd_handle = NULL;
818                     res = AcpiGetHandle((sc->model->lcdd[0] == '\\' ?
819                         NULL : sc->handle), sc->model->lcdd, &(sc->lcdd_handle));
820                     if (ACPI_SUCCESS(res)) {
821                               AcpiInstallNotifyHandler((sc->lcdd_handle),
822                                   ACPI_DEVICE_NOTIFY, sc->model->lcdd_n_func, dev);
823                     } else {
824                               kprintf("%s: unable to find LCD device '%s'\n",
825                                   __func__, sc->model->lcdd);
826                     }
827           }
828 
829           return (0);
830 }
831 
832 static int
acpi_asus_detach(device_t dev)833 acpi_asus_detach(device_t dev)
834 {
835           struct acpi_asus_softc        *sc;
836 
837           ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
838 
839           sc = device_get_softc(dev);
840           /* Turn the lights off */
841           if (sc->model->bled_set)
842                     led_destroy(sc->s_bled.cdev);
843 
844           if (sc->model->dled_set)
845                     led_destroy(sc->s_dled.cdev);
846 
847           if (sc->model->gled_set)
848                     led_destroy(sc->s_gled.cdev);
849 
850           if (sc->model->mled_set)
851                     led_destroy(sc->s_mled.cdev);
852 
853           if (sc->model->tled_set)
854                     led_destroy(sc->s_tled.cdev);
855 
856           if (sc->model->wled_set)
857                     led_destroy(sc->s_wled.cdev);
858 
859           /* Remove notify handler */
860           AcpiRemoveNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
861               acpi_asus_notify);
862 
863           if (sc->lcdd_handle) {
864                     KASSERT(sc->model->lcdd_n_func != NULL,
865                         ("model->lcdd_n_func is NULL, but lcdd_handle is non-zero"));
866                     AcpiRemoveNotifyHandler((sc->lcdd_handle),
867                         ACPI_DEVICE_NOTIFY, sc->model->lcdd_n_func);
868           }
869 
870           /* Free sysctl tree */
871           sysctl_ctx_free(&sc->sysctl_ctx);
872 
873           return (0);
874 }
875 
876 static void
acpi_asus_led_task(struct acpi_asus_led * led,int pending __unused)877 acpi_asus_led_task(struct acpi_asus_led *led, int pending __unused)
878 {
879           struct acpi_asus_softc        *sc;
880           char                          *method;
881           int                           state;
882 
883           ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
884 
885           sc = led->sc;
886 
887           switch (led->type) {
888           case ACPI_ASUS_LED_BLED:
889                     method = sc->model->bled_set;
890                     state = led->state;
891                     break;
892           case ACPI_ASUS_LED_DLED:
893                     method = sc->model->dled_set;
894                     state = led->state;
895                     break;
896           case ACPI_ASUS_LED_GLED:
897                     method = sc->model->gled_set;
898                     state = led->state + 1;       /* 1: off, 2: on */
899                     break;
900           case ACPI_ASUS_LED_MLED:
901                     method = sc->model->mled_set;
902                     state = !led->state;          /* inverted */
903                     break;
904           case ACPI_ASUS_LED_TLED:
905                     method = sc->model->tled_set;
906                     state = led->state;
907                     break;
908           case ACPI_ASUS_LED_WLED:
909                     method = sc->model->wled_set;
910                     state = led->state;
911                     break;
912           default:
913                     kprintf("acpi_asus_led: invalid LED type %d\n",
914                         (int)led->type);
915                     return;
916           }
917 
918           acpi_SetInteger(sc->handle, method, state);
919           led->busy = 0;
920 }
921 
922 static void
acpi_asus_led(struct acpi_asus_led * led,int state)923 acpi_asus_led(struct acpi_asus_led *led, int state)
924 {
925 
926           ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
927 
928           if (led->busy)
929                     return;
930 
931           led->busy = 1;
932           led->state = state;
933 
934           AcpiOsExecute(OSL_NOTIFY_HANDLER, (void *)acpi_asus_led_task, led);
935 }
936 
937 static int
acpi_asus_sysctl(SYSCTL_HANDLER_ARGS)938 acpi_asus_sysctl(SYSCTL_HANDLER_ARGS)
939 {
940           struct acpi_asus_softc        *sc;
941           int                           arg;
942           int                           error = 0;
943           int                           function;
944           int                           method;
945 
946           ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
947 
948           sc = (struct acpi_asus_softc *)oidp->oid_arg1;
949           function = oidp->oid_arg2;
950           method = acpi_asus_sysctls[function].method;
951 
952           ACPI_SERIAL_BEGIN(asus);
953           arg = acpi_asus_sysctl_get(sc, method);
954           error = sysctl_handle_int(oidp, &arg, 0, req);
955 
956           /* Sanity check */
957           if (error != 0 || req->newptr == NULL)
958                     goto out;
959 
960           /* Update */
961           error = acpi_asus_sysctl_set(sc, method, arg);
962 
963 out:
964           ACPI_SERIAL_END(asus);
965           return (error);
966 }
967 
968 static int
acpi_asus_sysctl_get(struct acpi_asus_softc * sc,int method)969 acpi_asus_sysctl_get(struct acpi_asus_softc *sc, int method)
970 {
971           int val = 0;
972 
973           ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
974           ACPI_SERIAL_ASSERT(asus);
975 
976           switch (method) {
977           case ACPI_ASUS_METHOD_BRN:
978                     val = sc->s_brn;
979                     break;
980           case ACPI_ASUS_METHOD_DISP:
981                     val = sc->s_disp;
982                     break;
983           case ACPI_ASUS_METHOD_LCD:
984                     val = sc->s_lcd;
985                     break;
986           case ACPI_ASUS_METHOD_CAMERA:
987                     val = sc->s_cam;
988                     break;
989           case ACPI_ASUS_METHOD_CARDRD:
990                     val = sc->s_crd;
991                     break;
992           case ACPI_ASUS_METHOD_WLAN:
993                     val = sc->s_wlan;
994                     break;
995           }
996 
997           return (val);
998 }
999 
1000 static int
acpi_asus_sysctl_set(struct acpi_asus_softc * sc,int method,int arg)1001 acpi_asus_sysctl_set(struct acpi_asus_softc *sc, int method, int arg)
1002 {
1003           ACPI_STATUS                   status = AE_OK;
1004           ACPI_OBJECT_LIST    acpiargs;
1005           ACPI_OBJECT                   acpiarg[1];
1006 
1007           ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1008           ACPI_SERIAL_ASSERT(asus);
1009 
1010           acpiargs.Count = 1;
1011           acpiargs.Pointer = acpiarg;
1012           acpiarg[0].Type = ACPI_TYPE_INTEGER;
1013           acpiarg[0].Integer.Value = arg;
1014 
1015           switch (method) {
1016           case ACPI_ASUS_METHOD_BRN:
1017                     if (arg < 0 || arg > 15)
1018                               return (EINVAL);
1019 
1020                     if (sc->model->brn_set)
1021                               status = acpi_SetInteger(sc->handle,
1022                                   sc->model->brn_set, arg);
1023                     else {
1024                               while (arg != 0) {
1025                                         status = AcpiEvaluateObject(sc->handle,
1026                                             (arg > 0) ?  sc->model->brn_up :
1027                                             sc->model->brn_dn, NULL, NULL);
1028                                         (arg > 0) ? arg-- : arg++;
1029                               }
1030                     }
1031 
1032                     if (ACPI_SUCCESS(status))
1033                               sc->s_brn = arg;
1034 
1035                     break;
1036           case ACPI_ASUS_METHOD_DISP:
1037                     if (arg < 0 || arg > 7)
1038                               return (EINVAL);
1039 
1040                     status = acpi_SetInteger(sc->handle,
1041                         sc->model->disp_set, arg);
1042 
1043                     if (ACPI_SUCCESS(status))
1044                               sc->s_disp = arg;
1045 
1046                     break;
1047           case ACPI_ASUS_METHOD_LCD:
1048                     if (arg < 0 || arg > 1)
1049                               return (EINVAL);
1050 
1051                     if (strncmp(sc->model->name, "L3H", 3) != 0)
1052                               status = AcpiEvaluateObject(sc->handle,
1053                                   sc->model->lcd_set, NULL, NULL);
1054                     else
1055                               status = acpi_SetInteger(sc->handle,
1056                                   sc->model->lcd_set, 0x7);
1057 
1058                     if (ACPI_SUCCESS(status))
1059                               sc->s_lcd = arg;
1060 
1061                     break;
1062           case ACPI_ASUS_METHOD_CAMERA:
1063                     if (arg < 0 || arg > 1)
1064                               return (EINVAL);
1065 
1066                     status = AcpiEvaluateObject(sc->handle,
1067                         sc->model->cam_set, &acpiargs, NULL);
1068 
1069                     if (ACPI_SUCCESS(status))
1070                               sc->s_cam = arg;
1071                     break;
1072           case ACPI_ASUS_METHOD_CARDRD:
1073                     if (arg < 0 || arg > 1)
1074                               return (EINVAL);
1075 
1076                     status = AcpiEvaluateObject(sc->handle,
1077                         sc->model->crd_set, &acpiargs, NULL);
1078 
1079                     if (ACPI_SUCCESS(status))
1080                               sc->s_crd = arg;
1081                     break;
1082           case ACPI_ASUS_METHOD_WLAN:
1083                     if (arg < 0 || arg > 1)
1084                               return (EINVAL);
1085 
1086                     status = AcpiEvaluateObject(sc->handle,
1087                         sc->model->wlan_set, &acpiargs, NULL);
1088 
1089                     if (ACPI_SUCCESS(status))
1090                               sc->s_wlan = arg;
1091                     break;
1092           }
1093 
1094           return (0);
1095 }
1096 
1097 static int
acpi_asus_sysctl_init(struct acpi_asus_softc * sc,int method)1098 acpi_asus_sysctl_init(struct acpi_asus_softc *sc, int method)
1099 {
1100           ACPI_STATUS         status;
1101 
1102           switch (method) {
1103           case ACPI_ASUS_METHOD_BRN:
1104                     if (sc->model->brn_get) {
1105                               /* GPLV/SPLV models */
1106                               status = acpi_GetInteger(sc->handle,
1107                                   sc->model->brn_get, &sc->s_brn);
1108                               if (ACPI_SUCCESS(status))
1109                                         return (TRUE);
1110                     } else if (sc->model->brn_up) {
1111                               /* Relative models */
1112                               status = AcpiEvaluateObject(sc->handle,
1113                                   sc->model->brn_up, NULL, NULL);
1114                               if (ACPI_FAILURE(status))
1115                                         return (FALSE);
1116 
1117                               status = AcpiEvaluateObject(sc->handle,
1118                                   sc->model->brn_dn, NULL, NULL);
1119                               if (ACPI_FAILURE(status))
1120                                         return (FALSE);
1121 
1122                               return (TRUE);
1123                     }
1124                     return (FALSE);
1125           case ACPI_ASUS_METHOD_DISP:
1126                     if (sc->model->disp_get) {
1127                               status = acpi_GetInteger(sc->handle,
1128                                   sc->model->disp_get, &sc->s_disp);
1129                               if (ACPI_SUCCESS(status))
1130                                         return (TRUE);
1131                     }
1132                     return (FALSE);
1133           case ACPI_ASUS_METHOD_LCD:
1134                     if (sc->model->lcd_get) {
1135                               if (strncmp(sc->model->name, "L3H", 3) == 0) {
1136                                         ACPI_BUFFER                   Buf;
1137                                         ACPI_OBJECT                   Arg[2], Obj;
1138                                         ACPI_OBJECT_LIST    Args;
1139 
1140                                         /* L3H is a bit special */
1141                                         Arg[0].Type = ACPI_TYPE_INTEGER;
1142                                         Arg[0].Integer.Value = 0x02;
1143                                         Arg[1].Type = ACPI_TYPE_INTEGER;
1144                                         Arg[1].Integer.Value = 0x03;
1145 
1146                                         Args.Count = 2;
1147                                         Args.Pointer = Arg;
1148 
1149                                         Buf.Length = sizeof(Obj);
1150                                         Buf.Pointer = &Obj;
1151 
1152                                         status = AcpiEvaluateObject(sc->handle,
1153                                             sc->model->lcd_get, &Args, &Buf);
1154                                         if (ACPI_SUCCESS(status) &&
1155                                             Obj.Type == ACPI_TYPE_INTEGER) {
1156                                                   sc->s_lcd = Obj.Integer.Value >> 8;
1157                                                   return (TRUE);
1158                                         }
1159                               } else {
1160                                         status = acpi_GetInteger(sc->handle,
1161                                             sc->model->lcd_get, &sc->s_lcd);
1162                                         if (ACPI_SUCCESS(status))
1163                                                   return (TRUE);
1164                               }
1165                     }
1166                     return (FALSE);
1167           case ACPI_ASUS_METHOD_CAMERA:
1168                     if (sc->model->cam_get) {
1169                               status = acpi_GetInteger(sc->handle,
1170                                   sc->model->cam_get, &sc->s_cam);
1171                               if (ACPI_SUCCESS(status))
1172                                         return (TRUE);
1173                     }
1174                     return (FALSE);
1175           case ACPI_ASUS_METHOD_CARDRD:
1176                     if (sc->model->crd_get) {
1177                               status = acpi_GetInteger(sc->handle,
1178                                   sc->model->crd_get, &sc->s_crd);
1179                               if (ACPI_SUCCESS(status))
1180                                         return (TRUE);
1181                     }
1182                     return (FALSE);
1183           case ACPI_ASUS_METHOD_WLAN:
1184                     if (sc->model->wlan_get) {
1185                               status = acpi_GetInteger(sc->handle,
1186                                   sc->model->wlan_get, &sc->s_wlan);
1187                               if (ACPI_SUCCESS(status))
1188                                         return (TRUE);
1189                     }
1190                     return (FALSE);
1191           }
1192           return (FALSE);
1193 }
1194 
1195 static void
acpi_asus_notify(ACPI_HANDLE h,UINT32 notify,void * context)1196 acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context)
1197 {
1198           struct acpi_asus_softc        *sc;
1199           struct acpi_softc   *acpi_sc;
1200 
1201           ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1202 
1203           sc = device_get_softc((device_t)context);
1204           acpi_sc = acpi_device_get_parent_softc(sc->dev);
1205 
1206           ACPI_SERIAL_BEGIN(asus);
1207           if ((notify & ~0x10) <= 15) {
1208                     sc->s_brn = notify & ~0x10;
1209                     ACPI_VPRINT(sc->dev, acpi_sc, "Brightness increased\n");
1210           } else if ((notify & ~0x20) <= 15) {
1211                     sc->s_brn = notify & ~0x20;
1212                     ACPI_VPRINT(sc->dev, acpi_sc, "Brightness decreased\n");
1213           } else if (notify == 0x33) {
1214                     sc->s_lcd = 1;
1215                     ACPI_VPRINT(sc->dev, acpi_sc, "LCD turned on\n");
1216           } else if (notify == 0x34) {
1217                     sc->s_lcd = 0;
1218                     ACPI_VPRINT(sc->dev, acpi_sc, "LCD turned off\n");
1219           } else if (notify == 0x86) {
1220                     acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_BRN, sc->s_brn-1);
1221                     ACPI_VPRINT(sc->dev, acpi_sc, "Brightness decreased\n");
1222           } else if (notify == 0x87) {
1223                     acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_BRN, sc->s_brn+1);
1224                     ACPI_VPRINT(sc->dev, acpi_sc, "Brightness increased\n");
1225           } else {
1226                     /* Notify devd(8) */
1227                     acpi_UserNotify("ASUS", h, notify);
1228           }
1229           ACPI_SERIAL_END(asus);
1230 }
1231 
1232 static void
acpi_asus_lcdd_notify(ACPI_HANDLE h,UINT32 notify,void * context)1233 acpi_asus_lcdd_notify(ACPI_HANDLE h, UINT32 notify, void *context)
1234 {
1235           struct acpi_asus_softc        *sc;
1236           struct acpi_softc   *acpi_sc;
1237 
1238           ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1239 
1240           sc = device_get_softc((device_t)context);
1241           acpi_sc = acpi_device_get_parent_softc(sc->dev);
1242 
1243           ACPI_SERIAL_BEGIN(asus);
1244           switch (notify) {
1245           case 0x87:
1246                     acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_BRN, sc->s_brn-1);
1247                     ACPI_VPRINT(sc->dev, acpi_sc, "Brightness decreased\n");
1248                     break;
1249           case 0x86:
1250                     acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_BRN, sc->s_brn+1);
1251                     ACPI_VPRINT(sc->dev, acpi_sc, "Brightness increased\n");
1252                     break;
1253           default:
1254                     device_printf(sc->dev, "unknown notify: %#x\n", notify);
1255                     break;
1256           }
1257           ACPI_SERIAL_END(asus);
1258 }
1259 
1260 static void
acpi_asus_eeepc_notify(ACPI_HANDLE h,UINT32 notify,void * context)1261 acpi_asus_eeepc_notify(ACPI_HANDLE h, UINT32 notify, void *context)
1262 {
1263           struct acpi_asus_softc        *sc;
1264           struct acpi_softc   *acpi_sc;
1265 
1266           ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1267 
1268           sc = device_get_softc((device_t)context);
1269           acpi_sc = acpi_device_get_parent_softc(sc->dev);
1270 
1271           ACPI_SERIAL_BEGIN(asus);
1272           if ((notify & ~0x20) <= 15) {
1273                     sc->s_brn = notify & ~0x20;
1274                     ACPI_VPRINT(sc->dev, acpi_sc,
1275                         "Brightness increased/decreased\n");
1276           } else {
1277                     /* Notify devd(8) */
1278                     acpi_UserNotify("ASUS-Eee", h, notify);
1279           }
1280           ACPI_SERIAL_END(asus);
1281 }
1282