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

Cache object: f02a3f54fc43b2ffe3636e31c6d3c919


[ 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.