The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/acpica/acpi_asus.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: src/sys/i386/acpica/acpi_asus.c,v 1.11.2.3 2005/05/12 12:37:19 philip Exp $");
   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    *bled_set;
   66         char    *mled_set;
   67         char    *tled_set;
   68         char    *wled_set;
   69 
   70         char    *brn_get;
   71         char    *brn_set;
   72         char    *brn_up;
   73         char    *brn_dn;
   74 
   75         char    *lcd_get;
   76         char    *lcd_set;
   77 
   78         char    *disp_get;
   79         char    *disp_set;
   80 };
   81 
   82 struct acpi_asus_led {
   83         struct acpi_asus_softc *sc;
   84         struct cdev     *cdev;
   85         int             busy;
   86         int             state;
   87         enum {
   88                 ACPI_ASUS_LED_BLED,
   89                 ACPI_ASUS_LED_MLED,
   90                 ACPI_ASUS_LED_TLED,
   91                 ACPI_ASUS_LED_WLED,
   92         } type;
   93 };
   94 
   95 struct acpi_asus_softc {
   96         device_t                dev;
   97         ACPI_HANDLE             handle;
   98 
   99         struct acpi_asus_model  *model;
  100         struct sysctl_ctx_list  sysctl_ctx;
  101         struct sysctl_oid       *sysctl_tree;
  102 
  103         struct acpi_asus_led    s_bled;
  104         struct acpi_asus_led    s_mled;
  105         struct acpi_asus_led    s_tled;
  106         struct acpi_asus_led    s_wled;
  107 
  108         int                     s_brn;
  109         int                     s_disp;
  110         int                     s_lcd;
  111 };
  112 
  113 /*
  114  * We can identify Asus laptops from the string they return
  115  * as a result of calling the ATK0100 'INIT' method.
  116  */
  117 static struct acpi_asus_model acpi_asus_models[] = {
  118         {
  119                 .name           = "xxN",
  120                 .mled_set       = "MLED",
  121                 .wled_set       = "WLED",
  122                 .lcd_get        = "\\BKLT",
  123                 .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
  124                 .brn_get        = "GPLV",
  125                 .brn_set        = "SPLV",
  126                 .disp_get       = "\\ADVG",
  127                 .disp_set       = "SDSP"
  128         },
  129         {
  130                 .name           = "A1x",
  131                 .mled_set       = "MLED",
  132                 .lcd_get        = "\\BKLI",
  133                 .lcd_set        = "\\_SB.PCI0.ISA.EC0._Q10",
  134                 .brn_up         = "\\_SB.PCI0.ISA.EC0._Q0E",
  135                 .brn_dn         = "\\_SB.PCI0.ISA.EC0._Q0F"
  136         },
  137         {
  138                 .name           = "A2x",
  139                 .mled_set       = "MLED",
  140                 .wled_set       = "WLED",
  141                 .lcd_get        = "\\BAOF",
  142                 .lcd_set        = "\\Q10",
  143                 .brn_get        = "GPLV",
  144                 .brn_set        = "SPLV",
  145                 .disp_get       = "\\INFB",
  146                 .disp_set       = "SDSP"
  147         },
  148         {
  149                 .name           = "D1x",
  150                 .mled_set       = "MLED",
  151                 .lcd_get        = "\\GP11",
  152                 .lcd_set        = "\\Q0D",
  153                 .brn_up         = "\\Q0C",
  154                 .brn_dn         = "\\Q0B",
  155                 .disp_get       = "\\INFB",
  156                 .disp_set       = "SDSP"
  157         },
  158         {
  159                 .name           = "L2D",
  160                 .mled_set       = "MLED",
  161                 .wled_set       = "WLED",
  162                 .brn_up         = "\\Q0E",
  163                 .brn_dn         = "\\Q0F",
  164                 .lcd_get        = "\\SGP0",
  165                 .lcd_set        = "\\Q10"
  166         },
  167         {
  168                 .name           = "L3C",
  169                 .mled_set       = "MLED",
  170                 .wled_set       = "WLED",
  171                 .brn_get        = "GPLV",
  172                 .brn_set        = "SPLV",
  173                 .lcd_get        = "\\GL32",
  174                 .lcd_set        = "\\_SB.PCI0.PX40.ECD0._Q10"
  175         },
  176         {
  177                 .name           = "L3D",
  178                 .mled_set       = "MLED",
  179                 .wled_set       = "WLED",
  180                 .brn_get        = "GPLV",
  181                 .brn_set        = "SPLV",
  182                 .lcd_get        = "\\BKLG",
  183                 .lcd_set        = "\\Q10"
  184         },
  185         {
  186                 .name           = "L3H",
  187                 .mled_set       = "MLED",
  188                 .wled_set       = "WLED",
  189                 .brn_get        = "GPLV",
  190                 .brn_set        = "SPLV",
  191                 .lcd_get        = "\\_SB.PCI0.PM.PBC",
  192                 .lcd_set        = "EHK",
  193                 .disp_get       = "\\_SB.INFB",
  194                 .disp_set       = "SDSP"
  195         },
  196         {
  197                 .name           = "L4R",
  198                 .mled_set       = "MLED",
  199                 .wled_set       = "WLED",
  200                 .brn_get        = "GPLV",
  201                 .brn_set        = "SPLV",
  202                 .lcd_get        = "\\_SB.PCI0.SBSM.SEO4",
  203                 .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
  204                 .disp_get       = "\\_SB.PCI0.P0P1.VGA.GETD",
  205                 .disp_set       = "SDSP"
  206         },
  207         {
  208                 .name           = "L5x",
  209                 .mled_set       = "MLED",
  210                 .tled_set       = "TLED",
  211                 .lcd_get        = "\\BAOF",
  212                 .lcd_set        = "\\Q0D",
  213                 .brn_get        = "GPLV",
  214                 .brn_set        = "SPLV",
  215                 .disp_get       = "\\INFB",
  216                 .disp_set       = "SDSP"
  217         },
  218         {
  219                 .name           = "L8L"
  220                 /* Only has hotkeys, apparantly */
  221         },
  222         {
  223                 .name           = "M1A",
  224                 .mled_set       = "MLED",
  225                 .brn_up         = "\\_SB.PCI0.PX40.EC0.Q0E",
  226                 .brn_dn         = "\\_SB.PCI0.PX40.EC0.Q0F",
  227                 .lcd_get        = "\\PNOF",
  228                 .lcd_set        = "\\_SB.PCI0.PX40.EC0.Q10"
  229         },
  230         {
  231                 .name           = "M2E",
  232                 .mled_set       = "MLED",
  233                 .wled_set       = "WLED",
  234                 .brn_get        = "GPLV",
  235                 .brn_set        = "SPLV",
  236                 .lcd_get        = "\\GP06",
  237                 .lcd_set        = "\\Q10"
  238         },
  239         {
  240                 .name           = "M6N",
  241                 .mled_set       = "MLED",
  242                 .wled_set       = "WLED",
  243                 .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
  244                 .lcd_get        = "\\_SB.BKLT",
  245                 .brn_set        = "SPLV",
  246                 .brn_get        = "GPLV",
  247                 .disp_set       = "SDSP",
  248                 .disp_get       = "\\SSTE"
  249         },
  250         {
  251                 .name           = "M6R",
  252                 .mled_set       = "MLED",
  253                 .wled_set       = "WLED",
  254                 .brn_get        = "GPLV",
  255                 .brn_set        = "SPLV",
  256                 .lcd_get        = "\\_SB.PCI0.SBSM.SEO4",
  257                 .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
  258                 .disp_get       = "\\SSTE",
  259                 .disp_set       = "SDSP"
  260         },
  261         {
  262                 .name           = "S1x",
  263                 .mled_set       = "MLED",
  264                 .wled_set       = "WLED",
  265                 .lcd_get        = "\\PNOF",
  266                 .lcd_set        = "\\_SB.PCI0.PX40.Q10",
  267                 .brn_get        = "GPLV",
  268                 .brn_set        = "SPLV"
  269         },
  270         {
  271                 .name           = "S2x",
  272                 .mled_set       = "MLED",
  273                 .lcd_get        = "\\BKLI",
  274                 .lcd_set        = "\\_SB.PCI0.ISA.EC0._Q10",
  275                 .brn_up         = "\\_SB.PCI0.ISA.EC0._Q0B",
  276                 .brn_dn         = "\\_SB.PCI0.ISA.EC0._Q0A"
  277         },
  278         {
  279                 .name           = "V6V",
  280                 .bled_set       = "BLED",
  281                 .tled_set       = "TLED",
  282                 .wled_set       = "WLED",
  283                 .lcd_get        = "\\BKLT",
  284                 .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
  285                 .brn_get        = "GPLV",
  286                 .brn_set        = "SPLV",
  287                 .disp_get       = "\\_SB.PCI0.P0P1.VGA.GETD",
  288                 .disp_set       = "SDSP"
  289         },
  290 
  291         { .name = NULL }
  292 };
  293 
  294 /*
  295  * Samsung P30/P35 laptops have an Asus ATK0100 gadget interface,
  296  * but they can't be probed quite the same way as Asus laptops.
  297  */
  298 static struct acpi_asus_model acpi_samsung_models[] = {
  299         {
  300                 .name           = "P30",
  301                 .wled_set       = "WLED",
  302                 .brn_up         = "\\_SB.PCI0.LPCB.EC0._Q68",
  303                 .brn_dn         = "\\_SB.PCI0.LPCB.EC0._Q69",
  304                 .lcd_get        = "\\BKLT",
  305                 .lcd_set        = "\\_SB.PCI0.LPCB.EC0._Q0E"
  306         },
  307 
  308         { .name = NULL }
  309 };
  310 
  311 static struct {
  312         char    *name;
  313         char    *description;
  314         int     method;
  315 } acpi_asus_sysctls[] = {
  316         {
  317                 .name           = "lcd_backlight",
  318                 .method         = ACPI_ASUS_METHOD_LCD,
  319                 .description    = "state of the lcd backlight"
  320         },
  321         {
  322                 .name           = "lcd_brightness",
  323                 .method         = ACPI_ASUS_METHOD_BRN,
  324                 .description    = "brightness of the lcd panel"
  325         },
  326         {
  327                 .name           = "video_output",
  328                 .method         = ACPI_ASUS_METHOD_DISP,
  329                 .description    = "display output state"
  330         },
  331 
  332         { .name = NULL }
  333 };
  334 
  335 ACPI_SERIAL_DECL(asus, "ACPI ASUS extras");
  336 
  337 /* Function prototypes */
  338 static int      acpi_asus_probe(device_t dev);
  339 static int      acpi_asus_attach(device_t dev);
  340 static int      acpi_asus_detach(device_t dev);
  341 
  342 static void     acpi_asus_led(struct acpi_asus_led *led, int state);
  343 static void     acpi_asus_led_task(struct acpi_asus_led *led, int pending __unused);
  344 
  345 static int      acpi_asus_sysctl(SYSCTL_HANDLER_ARGS);
  346 static int      acpi_asus_sysctl_init(struct acpi_asus_softc *sc, int method);
  347 static int      acpi_asus_sysctl_get(struct acpi_asus_softc *sc, int method);
  348 static int      acpi_asus_sysctl_set(struct acpi_asus_softc *sc, int method, int val);
  349 
  350 static void     acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context);
  351 
  352 static device_method_t acpi_asus_methods[] = {
  353         DEVMETHOD(device_probe,  acpi_asus_probe),
  354         DEVMETHOD(device_attach, acpi_asus_attach),
  355         DEVMETHOD(device_detach, acpi_asus_detach),
  356 
  357         { 0, 0 }
  358 };
  359 
  360 static driver_t acpi_asus_driver = {
  361         "acpi_asus",
  362         acpi_asus_methods,
  363         sizeof(struct acpi_asus_softc)
  364 };
  365 
  366 static devclass_t acpi_asus_devclass;
  367 
  368 DRIVER_MODULE(acpi_asus, acpi, acpi_asus_driver, acpi_asus_devclass, 0, 0);
  369 MODULE_DEPEND(acpi_asus, acpi, 1, 1, 1);
  370 
  371 static int
  372 acpi_asus_probe(device_t dev)
  373 {
  374         struct acpi_asus_model  *model;
  375         struct acpi_asus_softc  *sc;
  376         struct sbuf             *sb;
  377         ACPI_BUFFER             Buf;
  378         ACPI_OBJECT             Arg, *Obj;
  379         ACPI_OBJECT_LIST        Args;
  380         static char             *asus_ids[] = { "ATK0100", NULL };
  381 
  382         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  383 
  384         if (acpi_disabled("asus") ||
  385             ACPI_ID_PROBE(device_get_parent(dev), dev, asus_ids) == NULL)
  386                 return (ENXIO);
  387 
  388         sc = device_get_softc(dev);
  389         sc->dev = dev;
  390         sc->handle = acpi_get_handle(dev);
  391 
  392         Arg.Type = ACPI_TYPE_INTEGER;
  393         Arg.Integer.Value = 0;
  394 
  395         Args.Count = 1;
  396         Args.Pointer = &Arg;
  397 
  398         Buf.Pointer = NULL;
  399         Buf.Length = ACPI_ALLOCATE_BUFFER;
  400 
  401         AcpiEvaluateObject(sc->handle, "INIT", &Args, &Buf);
  402         Obj = Buf.Pointer;
  403 
  404         /*
  405          * The Samsung P30 returns a null-pointer from INIT, we
  406          * can identify it from the 'ODEM' string in the DSDT.
  407          */
  408         if (Obj->String.Pointer == NULL) {
  409                 ACPI_STATUS             status;
  410                 ACPI_TABLE_HEADER       th;
  411 
  412                 status = AcpiGetTableHeader(ACPI_TABLE_DSDT, 1, &th);
  413                 if (ACPI_FAILURE(status)) {
  414                         device_printf(dev, "Unsupported (Samsung?) laptop\n");
  415                         AcpiOsFree(Buf.Pointer);
  416                         return (ENXIO);
  417                 }
  418 
  419                 if (strncmp("ODEM", th.OemTableId, 4) == 0) {
  420                         sc->model = &acpi_samsung_models[0];
  421                         device_set_desc(dev, "Samsung P30 Laptop Extras");
  422                         AcpiOsFree(Buf.Pointer);
  423                         return (0);
  424                 }
  425         }
  426 
  427         sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
  428         if (sb == NULL)
  429                 return (ENOMEM);
  430 
  431         /*
  432          * Asus laptops are simply identified by name, easy!
  433          */
  434         for (model = acpi_asus_models; model->name != NULL; model++) {
  435                 if (strncmp(Obj->String.Pointer, model->name, 3) == 0) {
  436 
  437 good:
  438                         sbuf_printf(sb, "Asus %s Laptop Extras",
  439                             Obj->String.Pointer);
  440                         sbuf_finish(sb);
  441 
  442                         sc->model = model;
  443                         device_set_desc_copy(dev, sbuf_data(sb));
  444 
  445                         sbuf_delete(sb);
  446                         AcpiOsFree(Buf.Pointer);
  447                         return (0);
  448                 }
  449                 
  450                 /*
  451                  * Some models look exactly the same as other models, but have
  452                  * their own ids.  If we spot these, set them up with the same
  453                  * details as the models they're like, possibly dealing with
  454                  * small differences.
  455                  *
  456                  * XXX: there must be a prettier way to do this!
  457                  */
  458                 else if (strncmp(model->name, "xxN", 3) == 0 &&
  459                     (strncmp(Obj->String.Pointer, "M3N", 3) == 0 ||
  460                      strncmp(Obj->String.Pointer, "S1N", 3) == 0))
  461                         goto good;
  462                 else if (strncmp(model->name, "A1x", 3) == 0 &&
  463                     strncmp(Obj->String.Pointer, "A1", 2) == 0)
  464                         goto good;
  465                 else if (strncmp(model->name, "A2x", 3) == 0 &&
  466                     strncmp(Obj->String.Pointer, "A2", 2) == 0)
  467                         goto good;
  468                 else if (strncmp(model->name, "D1x", 3) == 0 &&
  469                     strncmp(Obj->String.Pointer, "D1", 2) == 0)
  470                         goto good;
  471                 else if (strncmp(model->name, "L3H", 3) == 0 &&
  472                     strncmp(Obj->String.Pointer, "L2E", 3) == 0)
  473                         goto good;
  474                 else if (strncmp(model->name, "L5x", 3) == 0 &&
  475                     strncmp(Obj->String.Pointer, "L5", 2) == 0)
  476                         goto good;
  477                 else if (strncmp(model->name, "M2E", 3) == 0 &&
  478                     (strncmp(Obj->String.Pointer, "M2", 2) == 0 ||
  479                      strncmp(Obj->String.Pointer, "L4E", 3) == 0))
  480                         goto good;
  481                 else if (strncmp(model->name, "S1x", 3) == 0 &&
  482                     (strncmp(Obj->String.Pointer, "L8", 2) == 0 ||
  483                      strncmp(Obj->String.Pointer, "S1", 2) == 0))
  484                         goto good;
  485                 else if (strncmp(model->name, "S2x", 3) == 0 &&
  486                     (strncmp(Obj->String.Pointer, "J1", 2) == 0 ||
  487                      strncmp(Obj->String.Pointer, "S2", 2) == 0))
  488                         goto good;
  489 
  490                 /* L2B is like L3C but has no lcd_get method */
  491                 else if (strncmp(model->name, "L3C", 3) == 0 &&
  492                     strncmp(Obj->String.Pointer, "L2B", 3) == 0) {
  493                         model->lcd_get = NULL;
  494                         goto good;
  495                 }
  496 
  497                 /* A3G is like M6R but with a different lcd_get method */
  498                 else if (strncmp(model->name, "M6R", 3) == 0 &&
  499                     strncmp(Obj->String.Pointer, "A3G", 3) == 0) {
  500                         model->lcd_get = "\\BLFG";
  501                         goto good;
  502                 }
  503 
  504                 /* M2N and W1N are like xxN with added WLED */
  505                 else if (strncmp(model->name, "xxN", 3) == 0 &&
  506                     (strncmp(Obj->String.Pointer, "M2N", 3) == 0 ||
  507                      strncmp(Obj->String.Pointer, "W1N", 3) == 0)) {
  508                         model->wled_set = "WLED";
  509                         goto good;
  510                 }
  511 
  512                 /* M5N and S5N are like xxN without MLED */
  513                 else if (strncmp(model->name, "xxN", 3) == 0 &&
  514                     (strncmp(Obj->String.Pointer, "M5N", 3) == 0 ||
  515                      strncmp(Obj->String.Pointer, "S5N", 3) == 0)) {
  516                         model->mled_set = NULL;
  517                         goto good;
  518                 }
  519         }
  520 
  521         sbuf_printf(sb, "Unsupported Asus laptop: %s\n", Obj->String.Pointer);
  522         sbuf_finish(sb);
  523 
  524         device_printf(dev, sbuf_data(sb));
  525 
  526         sbuf_delete(sb);
  527         AcpiOsFree(Buf.Pointer);
  528 
  529         return (ENXIO);
  530 }
  531 
  532 static int
  533 acpi_asus_attach(device_t dev)
  534 {
  535         struct acpi_asus_softc  *sc;
  536         struct acpi_softc       *acpi_sc;
  537 
  538         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  539 
  540         sc = device_get_softc(dev);
  541         acpi_sc = acpi_device_get_parent_softc(dev);
  542 
  543         /* Build sysctl tree */
  544         sysctl_ctx_init(&sc->sysctl_ctx);
  545         sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
  546             SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
  547             OID_AUTO, "asus", CTLFLAG_RD, 0, "");
  548 
  549         /* Hook up nodes */
  550         for (int i = 0; acpi_asus_sysctls[i].name != NULL; i++) {
  551                 if (!acpi_asus_sysctl_init(sc, acpi_asus_sysctls[i].method))
  552                         continue;
  553 
  554                 SYSCTL_ADD_PROC(&sc->sysctl_ctx,
  555                     SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
  556                     acpi_asus_sysctls[i].name,
  557                     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY,
  558                     sc, i, acpi_asus_sysctl, "I",
  559                     acpi_asus_sysctls[i].description);
  560         }
  561 
  562         /* Attach leds */
  563         if (sc->model->bled_set) {
  564                 sc->s_bled.busy = 0;
  565                 sc->s_bled.sc = sc;
  566                 sc->s_bled.type = ACPI_ASUS_LED_BLED;
  567                 sc->s_bled.cdev =
  568                     led_create((led_t *)acpi_asus_led, &sc->s_bled, "bled");
  569         }
  570 
  571         if (sc->model->mled_set) {
  572                 sc->s_mled.busy = 0;
  573                 sc->s_mled.sc = sc;
  574                 sc->s_mled.type = ACPI_ASUS_LED_MLED;
  575                 sc->s_mled.cdev =
  576                     led_create((led_t *)acpi_asus_led, &sc->s_mled, "mled");
  577         }
  578 
  579         if (sc->model->tled_set) {
  580                 sc->s_tled.busy = 0;
  581                 sc->s_tled.sc = sc;
  582                 sc->s_tled.type = ACPI_ASUS_LED_TLED;
  583                 sc->s_tled.cdev =
  584                     led_create((led_t *)acpi_asus_led, &sc->s_tled, "tled");
  585         }
  586 
  587         if (sc->model->wled_set) {
  588                 sc->s_wled.busy = 0;
  589                 sc->s_wled.sc = sc;
  590                 sc->s_wled.type = ACPI_ASUS_LED_WLED;
  591                 sc->s_wled.cdev =
  592                     led_create((led_t *)acpi_asus_led, &sc->s_wled, "wled");
  593         }
  594 
  595         /* Activate hotkeys */
  596         AcpiEvaluateObject(sc->handle, "BSTS", NULL, NULL);
  597 
  598         /* Handle notifies */
  599         AcpiInstallNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
  600             acpi_asus_notify, dev);
  601 
  602         return (0);
  603 }
  604 
  605 static int
  606 acpi_asus_detach(device_t dev)
  607 {
  608         struct acpi_asus_softc  *sc;
  609 
  610         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  611 
  612         sc = device_get_softc(dev);
  613 
  614         /* Turn the lights off */
  615         if (sc->model->bled_set)
  616                 led_destroy(sc->s_bled.cdev);
  617 
  618         if (sc->model->mled_set)
  619                 led_destroy(sc->s_mled.cdev);
  620 
  621         if (sc->model->tled_set)
  622                 led_destroy(sc->s_tled.cdev);
  623 
  624         if (sc->model->wled_set)
  625                 led_destroy(sc->s_wled.cdev);
  626 
  627         /* Remove notify handler */
  628         AcpiRemoveNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
  629             acpi_asus_notify);
  630 
  631         /* Free sysctl tree */
  632         sysctl_ctx_free(&sc->sysctl_ctx);
  633 
  634         return (0);
  635 }
  636 
  637 static void
  638 acpi_asus_led_task(struct acpi_asus_led *led, int pending __unused)
  639 {
  640         struct acpi_asus_softc  *sc;
  641         char                    *method;
  642         int                     state;
  643         
  644         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  645 
  646         sc = led->sc;
  647 
  648         switch (led->type) {
  649         case ACPI_ASUS_LED_BLED:
  650                 method = sc->model->bled_set;
  651                 state = led->state;
  652                 break;
  653         case ACPI_ASUS_LED_MLED:
  654                 method = sc->model->mled_set;
  655 
  656                 /* Note: inverted */
  657                 state = !led->state;
  658                 break;
  659         case ACPI_ASUS_LED_TLED:
  660                 method = sc->model->tled_set;
  661                 state = led->state;
  662                 break;
  663         case ACPI_ASUS_LED_WLED:
  664                 method = sc->model->wled_set;
  665                 state = led->state;
  666                 break;
  667         default:
  668                 printf("acpi_asus_led: invalid LED type %d\n",
  669                     (int)led->type);
  670                 return;
  671         }
  672 
  673         acpi_SetInteger(sc->handle, method, state);
  674         led->busy = 0;
  675 }
  676 
  677 static void
  678 acpi_asus_led(struct acpi_asus_led *led, int state)
  679 {
  680 
  681         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  682 
  683         if (led->busy)
  684                 return;
  685 
  686         led->busy = 1;
  687         led->state = state;
  688 
  689         AcpiOsQueueForExecution(OSD_PRIORITY_LO,
  690             (void *)acpi_asus_led_task, led);
  691 }
  692 
  693 static int
  694 acpi_asus_sysctl(SYSCTL_HANDLER_ARGS)
  695 {
  696         struct acpi_asus_softc  *sc;
  697         int                     arg;
  698         int                     error = 0;
  699         int                     function;
  700         int                     method;
  701         
  702         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  703 
  704         sc = (struct acpi_asus_softc *)oidp->oid_arg1;
  705         function = oidp->oid_arg2;
  706         method = acpi_asus_sysctls[function].method;
  707 
  708         ACPI_SERIAL_BEGIN(asus);
  709         arg = acpi_asus_sysctl_get(sc, method);
  710         error = sysctl_handle_int(oidp, &arg, 0, req);
  711 
  712         /* Sanity check */
  713         if (error != 0 || req->newptr == NULL)
  714                 goto out;
  715 
  716         /* Update */
  717         error = acpi_asus_sysctl_set(sc, method, arg);
  718 
  719 out:
  720         ACPI_SERIAL_END(asus);
  721         return (error);
  722 }
  723 
  724 static int
  725 acpi_asus_sysctl_get(struct acpi_asus_softc *sc, int method)
  726 {
  727         int val = 0;
  728 
  729         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  730         ACPI_SERIAL_ASSERT(asus);
  731 
  732         switch (method) {
  733         case ACPI_ASUS_METHOD_BRN:
  734                 val = sc->s_brn;
  735                 break;
  736         case ACPI_ASUS_METHOD_DISP:
  737                 val = sc->s_disp;
  738                 break;
  739         case ACPI_ASUS_METHOD_LCD:
  740                 val = sc->s_lcd;
  741                 break;
  742         }
  743 
  744         return (val);
  745 }
  746 
  747 static int
  748 acpi_asus_sysctl_set(struct acpi_asus_softc *sc, int method, int arg)
  749 {
  750         ACPI_STATUS     status = AE_OK;
  751 
  752         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  753         ACPI_SERIAL_ASSERT(asus);
  754 
  755         switch (method) {
  756         case ACPI_ASUS_METHOD_BRN:
  757                 if (arg < 0 || arg > 15)
  758                         return (EINVAL);
  759 
  760                 if (sc->model->brn_set)
  761                         status = acpi_SetInteger(sc->handle,
  762                             sc->model->brn_set, arg);
  763                 else {
  764                         while (arg != 0) {
  765                                 status = AcpiEvaluateObject(sc->handle,
  766                                     (arg > 0) ?  sc->model->brn_up :
  767                                     sc->model->brn_dn, NULL, NULL);
  768                                 (arg > 0) ? arg-- : arg++;
  769                         }
  770                 }
  771 
  772                 if (ACPI_SUCCESS(status))
  773                         sc->s_brn = arg;
  774 
  775                 break;
  776         case ACPI_ASUS_METHOD_DISP:
  777                 if (arg < 0 || arg > 7)
  778                         return (EINVAL);
  779 
  780                 status = acpi_SetInteger(sc->handle,
  781                     sc->model->disp_set, arg);
  782 
  783                 if (ACPI_SUCCESS(status))
  784                         sc->s_disp = arg;
  785 
  786                 break;
  787         case ACPI_ASUS_METHOD_LCD:
  788                 if (arg < 0 || arg > 1)
  789                         return (EINVAL);
  790 
  791                 if (strncmp(sc->model->name, "L3H", 3) != 0)
  792                         status = AcpiEvaluateObject(sc->handle,
  793                             sc->model->lcd_set, NULL, NULL);
  794                 else
  795                         status = acpi_SetInteger(sc->handle,
  796                             sc->model->lcd_set, 0x7);
  797 
  798                 if (ACPI_SUCCESS(status))
  799                         sc->s_lcd = arg;
  800 
  801                 break;
  802         }
  803 
  804         return (0);
  805 }
  806 
  807 static int
  808 acpi_asus_sysctl_init(struct acpi_asus_softc *sc, int method)
  809 {
  810         ACPI_STATUS     status;
  811 
  812         switch (method) {
  813         case ACPI_ASUS_METHOD_BRN:
  814                 if (sc->model->brn_get) {
  815                         /* GPLV/SPLV models */
  816                         status = acpi_GetInteger(sc->handle,
  817                             sc->model->brn_get, &sc->s_brn);
  818                         if (ACPI_SUCCESS(status))
  819                                 return (TRUE);
  820                 } else if (sc->model->brn_up) {
  821                         /* Relative models */
  822                         status = AcpiEvaluateObject(sc->handle,
  823                             sc->model->brn_up, NULL, NULL);
  824                         if (ACPI_FAILURE(status))
  825                                 return (FALSE);
  826 
  827                         status = AcpiEvaluateObject(sc->handle,
  828                             sc->model->brn_dn, NULL, NULL);
  829                         if (ACPI_FAILURE(status))
  830                                 return (FALSE);
  831 
  832                         return (TRUE);
  833                 }
  834                 return (FALSE);
  835         case ACPI_ASUS_METHOD_DISP:
  836                 if (sc->model->disp_get) {
  837                         status = acpi_GetInteger(sc->handle,
  838                             sc->model->disp_get, &sc->s_disp);
  839                         if (ACPI_SUCCESS(status))
  840                                 return (TRUE);
  841                 }
  842                 return (FALSE);
  843         case ACPI_ASUS_METHOD_LCD:
  844                 if (sc->model->lcd_get &&
  845                     strncmp(sc->model->name, "L3H", 3) != 0) {
  846                         status = acpi_GetInteger(sc->handle,
  847                             sc->model->lcd_get, &sc->s_lcd);
  848                         if (ACPI_SUCCESS(status))
  849                                 return (TRUE);
  850                 }
  851                 else if (sc->model->lcd_get) {
  852                         ACPI_BUFFER             Buf;
  853                         ACPI_OBJECT             Arg[2], Obj;
  854                         ACPI_OBJECT_LIST        Args;
  855 
  856                         /* L3H is a bit special */
  857                         Arg[0].Type = ACPI_TYPE_INTEGER;
  858                         Arg[0].Integer.Value = 0x02;
  859                         Arg[1].Type = ACPI_TYPE_INTEGER;
  860                         Arg[1].Integer.Value = 0x03;
  861 
  862                         Args.Count = 2;
  863                         Args.Pointer = Arg;
  864 
  865                         Buf.Length = sizeof(Obj);
  866                         Buf.Pointer = &Obj;
  867 
  868                         status = AcpiEvaluateObject(sc->handle,
  869                             sc->model->lcd_get, &Args, &Buf);
  870                         if (ACPI_SUCCESS(status) &&
  871                             Obj.Type == ACPI_TYPE_INTEGER) {
  872                                 sc->s_lcd = Obj.Integer.Value >> 8;
  873                                 return (TRUE);
  874                         }
  875                 }
  876                 return (FALSE);
  877         }
  878         return (FALSE);
  879 }
  880 
  881 static void
  882 acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context)
  883 {
  884         struct acpi_asus_softc  *sc;
  885         struct acpi_softc       *acpi_sc;
  886 
  887         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  888 
  889         sc = device_get_softc((device_t)context);
  890         acpi_sc = acpi_device_get_parent_softc(sc->dev);
  891 
  892         ACPI_SERIAL_BEGIN(asus);
  893         if ((notify & ~0x10) <= 15) {
  894                 sc->s_brn = notify & ~0x10;
  895                 ACPI_VPRINT(sc->dev, acpi_sc, "Brightness increased\n");
  896         } else if ((notify & ~0x20) <= 15) {
  897                 sc->s_brn = notify & ~0x20;
  898                 ACPI_VPRINT(sc->dev, acpi_sc, "Brightness decreased\n");
  899         } else if (notify == 0x33) {
  900                 sc->s_lcd = 1;
  901                 ACPI_VPRINT(sc->dev, acpi_sc, "LCD turned on\n");
  902         } else if (notify == 0x34) {
  903                 sc->s_lcd = 0;
  904                 ACPI_VPRINT(sc->dev, acpi_sc, "LCD turned off\n");
  905         } else {
  906                 /* Notify devd(8) */
  907                 acpi_UserNotify("ASUS", h, notify);
  908         }
  909         ACPI_SERIAL_END(asus);
  910 }

Cache object: 8249c322268e2a8dbbf4ffb80e9a55ca


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.