2 * Copyright (c) 2004, 2005 Philip Paeps <philip@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: src/sys/dev/acpi_support/acpi_asus.c,v 1.44 2010/06/11 20:08:20 jkim Exp $
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.
34 * <http://sourceforge.net/projects/acpi4asus/>
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>.
43 #include <sys/param.h>
44 #include <sys/kernel.h>
45 #include <sys/module.h>
53 #include <dev/misc/led/led.h>
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
63 #define _COMPONENT ACPI_OEM
64 ACPI_MODULE_NAME("ASUS")
66 struct acpi_asus_model {
95 void (*n_func)(ACPI_HANDLE, UINT32, void *);
98 void (*lcdd_n_func)(ACPI_HANDLE, UINT32, void *);
101 struct acpi_asus_led {
102 struct acpi_asus_softc *sc;
116 struct acpi_asus_softc {
119 ACPI_HANDLE lcdd_handle;
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;
139 static void acpi_asus_lcdd_notify(ACPI_HANDLE h, UINT32 notify,
143 * We can identify Asus laptops from the string they return
144 * as a result of calling the ATK0100 'INIT' method.
146 static struct acpi_asus_model acpi_asus_models[] = {
152 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
155 .disp_get = "\\ADVG",
162 .lcd_set = "\\_SB.PCI0.ISA.EC0._Q10",
163 .brn_up = "\\_SB.PCI0.ISA.EC0._Q0E",
164 .brn_dn = "\\_SB.PCI0.ISA.EC0._Q0F"
174 .disp_get = "\\INFB",
181 .lcd_get = "\\_SB.PCI0.SBRG.EC0.RPIN(0x67)",
182 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
185 .disp_get = "\\_SB.PCI0.P0P2.VGA.GETD",
193 .lcd_get = "\\_SB.PCI0.SBRG.EC0.RPIN(0x11)",
194 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
197 .disp_get = "\\SSTE",
206 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
209 .disp_get = "\\_SB.PCI0.P0P3.VGA.GETD",
215 .brn_up = "\\_SB_.PCI0.SBRG.EC0._Q0E",
216 .brn_dn = "\\_SB_.PCI0.SBRG.EC0._Q0F",
220 .disp_get = "\\_SB_.PCI0.SBRG.EC0._Q10",
221 .disp_set = "\\_SB_.PCI0.SBRG.EC0._Q11"
230 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
233 .disp_get = "\\_SB.PCI0.P0P3.VGA.GETD",
242 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
245 .disp_get = "\\_SB.PCI0.P0P1.VGA.GETD",
247 .lcdd = "\\_SB.PCI0.P0P1.VGA.LCDD",
248 .lcdd_n_func = acpi_asus_lcdd_notify
257 .disp_get = "\\INFB",
272 .disp_get = "\\_SB.PCI0.PCE2.VGA.GETD",
291 .lcd_set = "\\_SB.PCI0.PX40.ECD0._Q10"
308 .lcd_get = "\\_SB.PCI0.PM.PBC",
310 .disp_get = "\\_SB.INFB",
319 .lcd_get = "\\_SB.PCI0.SBSM.SEO4",
320 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
321 .disp_get = "\\_SB.PCI0.P0P1.VGA.GETD",
332 .disp_get = "\\INFB",
337 /* Only has hotkeys, apparently */
342 .brn_up = "\\_SB.PCI0.PX40.EC0.Q0E",
343 .brn_dn = "\\_SB.PCI0.PX40.EC0.Q0F",
345 .lcd_set = "\\_SB.PCI0.PX40.EC0.Q10"
360 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
361 .lcd_get = "\\_SB.BKLT",
373 .lcd_get = "\\_SB.PCI0.SBSM.SEO4",
374 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
375 .disp_get = "\\SSTE",
383 .lcd_set = "\\_SB.PCI0.PX40.Q10",
391 .lcd_set = "\\_SB.PCI0.ISA.EC0._Q10",
392 .brn_up = "\\_SB.PCI0.ISA.EC0._Q0B",
393 .brn_dn = "\\_SB.PCI0.ISA.EC0._Q0A"
401 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
404 .disp_get = "\\_SB.PCI0.P0P1.VGA.GETD",
411 .lcd_set = "\\_SB.PCI0.SBRG.EC0._Q10",
414 .disp_get = "\\_SB.PCI0.P0P2.VGA.GETD",
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.
425 static struct acpi_asus_model acpi_samsung_models[] = {
429 .brn_up = "\\_SB.PCI0.LPCB.EC0._Q68",
430 .brn_dn = "\\_SB.PCI0.LPCB.EC0._Q69",
432 .lcd_set = "\\_SB.PCI0.LPCB.EC0._Q0E"
438 static void acpi_asus_eeepc_notify(ACPI_HANDLE h, UINT32 notify, void *context);
441 * EeePC have an Asus ASUS010 gadget interface,
442 * but they can't be probed quite the same way as Asus laptops.
444 static struct acpi_asus_model acpi_eeepc_models[] = {
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
466 } acpi_asus_sysctls[] = {
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
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
480 .name = "video_output",
481 .method = ACPI_ASUS_METHOD_DISP,
482 .description = "display output state",
483 .flags = CTLTYPE_INT | CTLFLAG_RW
487 .method = ACPI_ASUS_METHOD_CAMERA,
488 .description = "internal camera state",
489 .flags = CTLTYPE_INT | CTLFLAG_RW
492 .name = "cardreader",
493 .method = ACPI_ASUS_METHOD_CARDRD,
494 .description = "internal card reader state",
495 .flags = CTLTYPE_INT | CTLFLAG_RW
499 .method = ACPI_ASUS_METHOD_WLAN,
500 .description = "wireless lan state",
501 .flags = CTLTYPE_INT | CTLFLAG_RW
507 ACPI_SERIAL_DECL(asus, "ACPI ASUS extras");
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);
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);
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);
522 static void acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context);
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),
532 static driver_t acpi_asus_driver = {
535 sizeof(struct acpi_asus_softc)
538 static devclass_t acpi_asus_devclass;
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);
545 acpi_asus_probe(device_t dev)
547 struct acpi_asus_model *model;
548 struct acpi_asus_softc *sc;
551 ACPI_OBJECT Arg, *Obj;
552 ACPI_OBJECT_LIST Args;
553 static char *asus_ids[] = { "ATK0100", "ASUS010", NULL };
556 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
558 if (acpi_disabled("asus"))
560 ACPI_SERIAL_INIT(asus);
561 rstr = ACPI_ID_PROBE(device_get_parent(dev), dev, asus_ids);
566 sc = device_get_softc(dev);
568 sc->handle = acpi_get_handle(dev);
570 Arg.Type = ACPI_TYPE_INTEGER;
571 Arg.Integer.Value = 0;
577 Buf.Length = ACPI_ALLOCATE_BUFFER;
579 AcpiEvaluateObject(sc->handle, "INIT", &Args, &Buf);
583 * The Samsung P30 returns a null-pointer from INIT, we
584 * can identify it from the 'ODEM' string in the DSDT.
586 if (Obj->String.Pointer == NULL) {
588 ACPI_TABLE_HEADER th;
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);
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);
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);
613 sb = sbuf_new_auto();
618 * Asus laptops are simply identified by name, easy!
620 for (model = acpi_asus_models; model->name != NULL; model++) {
621 if (strncmp(Obj->String.Pointer, model->name, 3) == 0) {
624 sbuf_printf(sb, "Asus %s Laptop Extras",
625 Obj->String.Pointer);
629 device_set_desc_copy(dev, sbuf_data(sb));
632 AcpiOsFree(Buf.Pointer);
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
642 * XXX: there must be a prettier way to do this!
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))
648 else if (strncmp(model->name, "A1x", 3) == 0 &&
649 strncmp(Obj->String.Pointer, "A1", 2) == 0)
651 else if (strncmp(model->name, "A2x", 3) == 0 &&
652 strncmp(Obj->String.Pointer, "A2", 2) == 0)
654 else if (strncmp(model->name, "A3F", 3) == 0 &&
655 strncmp(Obj->String.Pointer, "A6F", 3) == 0)
657 else if (strncmp(model->name, "D1x", 3) == 0 &&
658 strncmp(Obj->String.Pointer, "D1", 2) == 0)
660 else if (strncmp(model->name, "L3H", 3) == 0 &&
661 strncmp(Obj->String.Pointer, "L2E", 3) == 0)
663 else if (strncmp(model->name, "L5x", 3) == 0 &&
664 strncmp(Obj->String.Pointer, "L5", 2) == 0)
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))
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))
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))
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;
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";
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";
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;
710 sbuf_printf(sb, "Unsupported Asus laptop: %s\n", Obj->String.Pointer);
713 device_printf(dev, "%s", sbuf_data(sb));
716 AcpiOsFree(Buf.Pointer);
722 acpi_asus_attach(device_t dev)
724 struct acpi_asus_softc *sc;
725 struct acpi_softc *acpi_sc;
727 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
729 sc = device_get_softc(dev);
730 acpi_sc = acpi_device_get_parent_softc(dev);
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, "");
739 for (int i = 0; acpi_asus_sysctls[i].name != NULL; i++) {
740 if (!acpi_asus_sysctl_init(sc, acpi_asus_sysctls[i].method))
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);
752 if (sc->model->bled_set) {
755 sc->s_bled.type = ACPI_ASUS_LED_BLED;
757 led_create_state((led_t *)acpi_asus_led, &sc->s_bled,
761 if (sc->model->dled_set) {
764 sc->s_dled.type = ACPI_ASUS_LED_DLED;
766 led_create((led_t *)acpi_asus_led, &sc->s_dled, "dled");
769 if (sc->model->gled_set) {
772 sc->s_gled.type = ACPI_ASUS_LED_GLED;
774 led_create((led_t *)acpi_asus_led, &sc->s_gled, "gled");
777 if (sc->model->mled_set) {
780 sc->s_mled.type = ACPI_ASUS_LED_MLED;
782 led_create((led_t *)acpi_asus_led, &sc->s_mled, "mled");
785 if (sc->model->tled_set) {
788 sc->s_tled.type = ACPI_ASUS_LED_TLED;
790 led_create_state((led_t *)acpi_asus_led, &sc->s_tled,
794 if (sc->model->wled_set) {
797 sc->s_wled.type = ACPI_ASUS_LED_WLED;
799 led_create_state((led_t *)acpi_asus_led, &sc->s_wled,
803 /* Activate hotkeys */
804 AcpiEvaluateObject(sc->handle, "BSTS", NULL, NULL);
806 /* Handle notifies */
807 if (sc->model->n_func == NULL)
808 sc->model->n_func = acpi_asus_notify;
810 AcpiInstallNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
811 sc->model->n_func, dev);
813 /* Find and hook the 'LCDD' object */
814 if (sc->model->lcdd != NULL && sc->model->lcdd_n_func != NULL) {
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);
824 kprintf("%s: unable to find LCD device '%s'\n",
825 __func__, sc->model->lcdd);
833 acpi_asus_detach(device_t dev)
835 struct acpi_asus_softc *sc;
837 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
839 sc = device_get_softc(dev);
840 /* Turn the lights off */
841 if (sc->model->bled_set)
842 led_destroy(sc->s_bled.cdev);
844 if (sc->model->dled_set)
845 led_destroy(sc->s_dled.cdev);
847 if (sc->model->gled_set)
848 led_destroy(sc->s_gled.cdev);
850 if (sc->model->mled_set)
851 led_destroy(sc->s_mled.cdev);
853 if (sc->model->tled_set)
854 led_destroy(sc->s_tled.cdev);
856 if (sc->model->wled_set)
857 led_destroy(sc->s_wled.cdev);
859 /* Remove notify handler */
860 AcpiRemoveNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
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);
870 /* Free sysctl tree */
871 sysctl_ctx_free(&sc->sysctl_ctx);
877 acpi_asus_led_task(struct acpi_asus_led *led, int pending __unused)
879 struct acpi_asus_softc *sc;
883 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
888 case ACPI_ASUS_LED_BLED:
889 method = sc->model->bled_set;
892 case ACPI_ASUS_LED_DLED:
893 method = sc->model->dled_set;
896 case ACPI_ASUS_LED_GLED:
897 method = sc->model->gled_set;
898 state = led->state + 1; /* 1: off, 2: on */
900 case ACPI_ASUS_LED_MLED:
901 method = sc->model->mled_set;
902 state = !led->state; /* inverted */
904 case ACPI_ASUS_LED_TLED:
905 method = sc->model->tled_set;
908 case ACPI_ASUS_LED_WLED:
909 method = sc->model->wled_set;
913 kprintf("acpi_asus_led: invalid LED type %d\n",
918 acpi_SetInteger(sc->handle, method, state);
923 acpi_asus_led(struct acpi_asus_led *led, int state)
926 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
934 AcpiOsExecute(OSL_NOTIFY_HANDLER, (void *)acpi_asus_led_task, led);
938 acpi_asus_sysctl(SYSCTL_HANDLER_ARGS)
940 struct acpi_asus_softc *sc;
946 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
948 sc = (struct acpi_asus_softc *)oidp->oid_arg1;
949 function = oidp->oid_arg2;
950 method = acpi_asus_sysctls[function].method;
952 ACPI_SERIAL_BEGIN(asus);
953 arg = acpi_asus_sysctl_get(sc, method);
954 error = sysctl_handle_int(oidp, &arg, 0, req);
957 if (error != 0 || req->newptr == NULL)
961 error = acpi_asus_sysctl_set(sc, method, arg);
964 ACPI_SERIAL_END(asus);
969 acpi_asus_sysctl_get(struct acpi_asus_softc *sc, int method)
973 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
974 ACPI_SERIAL_ASSERT(asus);
977 case ACPI_ASUS_METHOD_BRN:
980 case ACPI_ASUS_METHOD_DISP:
983 case ACPI_ASUS_METHOD_LCD:
986 case ACPI_ASUS_METHOD_CAMERA:
989 case ACPI_ASUS_METHOD_CARDRD:
992 case ACPI_ASUS_METHOD_WLAN:
1001 acpi_asus_sysctl_set(struct acpi_asus_softc *sc, int method, int arg)
1003 ACPI_STATUS status = AE_OK;
1004 ACPI_OBJECT_LIST acpiargs;
1005 ACPI_OBJECT acpiarg[1];
1007 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1008 ACPI_SERIAL_ASSERT(asus);
1011 acpiargs.Pointer = acpiarg;
1012 acpiarg[0].Type = ACPI_TYPE_INTEGER;
1013 acpiarg[0].Integer.Value = arg;
1016 case ACPI_ASUS_METHOD_BRN:
1017 if (arg < 0 || arg > 15)
1020 if (sc->model->brn_set)
1021 status = acpi_SetInteger(sc->handle,
1022 sc->model->brn_set, arg);
1025 status = AcpiEvaluateObject(sc->handle,
1026 (arg > 0) ? sc->model->brn_up :
1027 sc->model->brn_dn, NULL, NULL);
1028 (arg > 0) ? arg-- : arg++;
1032 if (ACPI_SUCCESS(status))
1036 case ACPI_ASUS_METHOD_DISP:
1037 if (arg < 0 || arg > 7)
1040 status = acpi_SetInteger(sc->handle,
1041 sc->model->disp_set, arg);
1043 if (ACPI_SUCCESS(status))
1047 case ACPI_ASUS_METHOD_LCD:
1048 if (arg < 0 || arg > 1)
1051 if (strncmp(sc->model->name, "L3H", 3) != 0)
1052 status = AcpiEvaluateObject(sc->handle,
1053 sc->model->lcd_set, NULL, NULL);
1055 status = acpi_SetInteger(sc->handle,
1056 sc->model->lcd_set, 0x7);
1058 if (ACPI_SUCCESS(status))
1062 case ACPI_ASUS_METHOD_CAMERA:
1063 if (arg < 0 || arg > 1)
1066 status = AcpiEvaluateObject(sc->handle,
1067 sc->model->cam_set, &acpiargs, NULL);
1069 if (ACPI_SUCCESS(status))
1072 case ACPI_ASUS_METHOD_CARDRD:
1073 if (arg < 0 || arg > 1)
1076 status = AcpiEvaluateObject(sc->handle,
1077 sc->model->crd_set, &acpiargs, NULL);
1079 if (ACPI_SUCCESS(status))
1082 case ACPI_ASUS_METHOD_WLAN:
1083 if (arg < 0 || arg > 1)
1086 status = AcpiEvaluateObject(sc->handle,
1087 sc->model->wlan_set, &acpiargs, NULL);
1089 if (ACPI_SUCCESS(status))
1098 acpi_asus_sysctl_init(struct acpi_asus_softc *sc, int 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))
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))
1117 status = AcpiEvaluateObject(sc->handle,
1118 sc->model->brn_dn, NULL, NULL);
1119 if (ACPI_FAILURE(status))
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))
1133 case ACPI_ASUS_METHOD_LCD:
1134 if (sc->model->lcd_get) {
1135 if (strncmp(sc->model->name, "L3H", 3) == 0) {
1137 ACPI_OBJECT Arg[2], Obj;
1138 ACPI_OBJECT_LIST Args;
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;
1149 Buf.Length = sizeof(Obj);
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;
1160 status = acpi_GetInteger(sc->handle,
1161 sc->model->lcd_get, &sc->s_lcd);
1162 if (ACPI_SUCCESS(status))
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))
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))
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))
1196 acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context)
1198 struct acpi_asus_softc *sc;
1199 struct acpi_softc *acpi_sc;
1201 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1203 sc = device_get_softc((device_t)context);
1204 acpi_sc = acpi_device_get_parent_softc(sc->dev);
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) {
1215 ACPI_VPRINT(sc->dev, acpi_sc, "LCD turned on\n");
1216 } else if (notify == 0x34) {
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");
1226 /* Notify devd(8) */
1227 acpi_UserNotify("ASUS", h, notify);
1229 ACPI_SERIAL_END(asus);
1233 acpi_asus_lcdd_notify(ACPI_HANDLE h, UINT32 notify, void *context)
1235 struct acpi_asus_softc *sc;
1236 struct acpi_softc *acpi_sc;
1238 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1240 sc = device_get_softc((device_t)context);
1241 acpi_sc = acpi_device_get_parent_softc(sc->dev);
1243 ACPI_SERIAL_BEGIN(asus);
1246 acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_BRN, sc->s_brn-1);
1247 ACPI_VPRINT(sc->dev, acpi_sc, "Brightness decreased\n");
1250 acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_BRN, sc->s_brn+1);
1251 ACPI_VPRINT(sc->dev, acpi_sc, "Brightness increased\n");
1254 device_printf(sc->dev, "unknown notify: %#x\n", notify);
1257 ACPI_SERIAL_END(asus);
1261 acpi_asus_eeepc_notify(ACPI_HANDLE h, UINT32 notify, void *context)
1263 struct acpi_asus_softc *sc;
1264 struct acpi_softc *acpi_sc;
1266 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1268 sc = device_get_softc((device_t)context);
1269 acpi_sc = acpi_device_get_parent_softc(sc->dev);
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");
1277 /* Notify devd(8) */
1278 acpi_UserNotify("ASUS-Eee", h, notify);
1280 ACPI_SERIAL_END(asus);