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_hp.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) 2009 Michael Gmelin <freebsd@grem.de>
    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/8.4/sys/dev/acpi_support/acpi_hp.c 212810 2010-09-18 07:16:38Z avg $");
   29 
   30 /*
   31  * Driver for extra ACPI-controlled features found on HP laptops
   32  * that use a WMI enabled BIOS (e.g. HP Compaq 8510p and 6510p).
   33  * Allows to control and read status of integrated hardware and read
   34  * BIOS settings through CMI.
   35  * Inspired by the hp-wmi driver, which implements a subset of these
   36  * features (hotkeys) on Linux.
   37  *
   38  * HP CMI whitepaper:
   39  *     http://h20331.www2.hp.com/Hpsub/downloads/cmi_whitepaper.pdf
   40  * wmi-hp for Linux:
   41  *     http://www.kernel.org
   42  * WMI and ACPI:
   43  *     http://www.microsoft.com/whdc/system/pnppwr/wmi/wmi-acpi.mspx
   44  */
   45 
   46 #include "opt_acpi.h"
   47 #include <sys/param.h>
   48 #include <sys/conf.h>
   49 #include <sys/uio.h>
   50 #include <sys/proc.h>
   51 #include <sys/kernel.h>
   52 #include <sys/bus.h>
   53 #include <sys/sbuf.h>
   54 #include <sys/module.h>
   55 #include <sys/sysctl.h>
   56 
   57 #include <contrib/dev/acpica/include/acpi.h>
   58 #include <contrib/dev/acpica/include/accommon.h>                                
   59 #include <dev/acpica/acpivar.h>
   60 #include "acpi_wmi_if.h"
   61 
   62 #define _COMPONENT      ACPI_OEM
   63 ACPI_MODULE_NAME("HP")
   64 
   65 #define ACPI_HP_WMI_EVENT_GUID          "95F24279-4D7B-4334-9387-ACCDC67EF61C"
   66 #define ACPI_HP_WMI_BIOS_GUID           "5FB7F034-2C63-45E9-BE91-3D44E2C707E4"
   67 #define ACPI_HP_WMI_CMI_GUID            "2D114B49-2DFB-4130-B8FE-4A3C09E75133"
   68 
   69 #define ACPI_HP_WMI_DISPLAY_COMMAND     0x1
   70 #define ACPI_HP_WMI_HDDTEMP_COMMAND     0x2
   71 #define ACPI_HP_WMI_ALS_COMMAND         0x3
   72 #define ACPI_HP_WMI_DOCK_COMMAND        0x4
   73 #define ACPI_HP_WMI_WIRELESS_COMMAND    0x5
   74 
   75 #define ACPI_HP_METHOD_WLAN_ENABLED                     1
   76 #define ACPI_HP_METHOD_WLAN_RADIO                       2
   77 #define ACPI_HP_METHOD_WLAN_ON_AIR                      3
   78 #define ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON          4
   79 #define ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF        5
   80 #define ACPI_HP_METHOD_BLUETOOTH_ENABLED                6
   81 #define ACPI_HP_METHOD_BLUETOOTH_RADIO                  7
   82 #define ACPI_HP_METHOD_BLUETOOTH_ON_AIR                 8
   83 #define ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON     9
   84 #define ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF   10
   85 #define ACPI_HP_METHOD_WWAN_ENABLED                     11
   86 #define ACPI_HP_METHOD_WWAN_RADIO                       12
   87 #define ACPI_HP_METHOD_WWAN_ON_AIR                      13
   88 #define ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON          14
   89 #define ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF        15
   90 #define ACPI_HP_METHOD_ALS                              16
   91 #define ACPI_HP_METHOD_DISPLAY                          17
   92 #define ACPI_HP_METHOD_HDDTEMP                          18
   93 #define ACPI_HP_METHOD_DOCK                             19
   94 #define ACPI_HP_METHOD_CMI_DETAIL                       20
   95 #define ACPI_HP_METHOD_VERBOSE                          21
   96 
   97 #define HP_MASK_WWAN_ON_AIR                     0x1000000
   98 #define HP_MASK_BLUETOOTH_ON_AIR                0x10000
   99 #define HP_MASK_WLAN_ON_AIR                     0x100
  100 #define HP_MASK_WWAN_RADIO                      0x8000000
  101 #define HP_MASK_BLUETOOTH_RADIO                 0x80000
  102 #define HP_MASK_WLAN_RADIO                      0x800
  103 #define HP_MASK_WWAN_ENABLED                    0x2000000
  104 #define HP_MASK_BLUETOOTH_ENABLED               0x20000
  105 #define HP_MASK_WLAN_ENABLED                    0x200
  106 
  107 #define ACPI_HP_CMI_DETAIL_PATHS                0x01
  108 #define ACPI_HP_CMI_DETAIL_ENUMS                0x02
  109 #define ACPI_HP_CMI_DETAIL_FLAGS                0x04
  110 #define ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE    0x08
  111 
  112 struct acpi_hp_inst_seq_pair {
  113         UINT32  sequence;       /* sequence number as suggested by cmi bios */
  114         UINT8   instance;       /* object instance on guid */
  115 };
  116 
  117 struct acpi_hp_softc {
  118         device_t        dev;
  119         device_t        wmi_dev;
  120         int             has_notify;             /* notification GUID found */
  121         int             has_cmi;                /* CMI GUID found */
  122         int             cmi_detail;             /* CMI detail level
  123                                                    (set by sysctl) */
  124         int             verbose;                /* add debug output */
  125         int             wlan_enable_if_radio_on;        /* set by sysctl */
  126         int             wlan_disable_if_radio_off;      /* set by sysctl */
  127         int             bluetooth_enable_if_radio_on;   /* set by sysctl */
  128         int             bluetooth_disable_if_radio_off; /* set by sysctl */
  129         int             wwan_enable_if_radio_on;        /* set by sysctl */
  130         int             wwan_disable_if_radio_off;      /* set by sysctl */
  131         int             was_wlan_on_air;                /* last known WLAN
  132                                                            on air status */
  133         int             was_bluetooth_on_air;           /* last known BT
  134                                                            on air status */
  135         int             was_wwan_on_air;                /* last known WWAN
  136                                                            on air status */
  137         struct sysctl_ctx_list  *sysctl_ctx;
  138         struct sysctl_oid       *sysctl_tree;
  139         struct cdev     *hpcmi_dev_t;           /* hpcmi device handle */
  140         struct sbuf     hpcmi_sbuf;             /* /dev/hpcmi output sbuf */
  141         pid_t           hpcmi_open_pid;         /* pid operating on
  142                                                    /dev/hpcmi */
  143         int             hpcmi_bufptr;           /* current pointer position
  144                                                    in /dev/hpcmi output buffer
  145                                                  */
  146         int             cmi_order_size;         /* size of cmi_order list */
  147         struct acpi_hp_inst_seq_pair cmi_order[128];    /* list of CMI
  148                              instances ordered by BIOS suggested sequence */
  149 };
  150 
  151 static struct {
  152         char    *name;
  153         int     method;
  154         char    *description;
  155         int     access;
  156 } acpi_hp_sysctls[] = {
  157         {
  158                 .name           = "wlan_enabled",
  159                 .method         = ACPI_HP_METHOD_WLAN_ENABLED,
  160                 .description    = "Enable/Disable WLAN (WiFi)",
  161                 .access         = CTLTYPE_INT | CTLFLAG_RW
  162         },
  163         {
  164                 .name           = "wlan_radio",
  165                 .method         = ACPI_HP_METHOD_WLAN_RADIO,
  166                 .description    = "WLAN radio status",
  167                 .access         = CTLTYPE_INT | CTLFLAG_RD
  168         },
  169         {
  170                 .name           = "wlan_on_air",
  171                 .method         = ACPI_HP_METHOD_WLAN_ON_AIR,
  172                 .description    = "WLAN radio ready to use (enabled and radio)",
  173                 .access         = CTLTYPE_INT | CTLFLAG_RD
  174         },
  175         {
  176                 .name           = "wlan_enable_if_radio_on",
  177                 .method         = ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON,
  178                 .description    = "Enable WLAN if radio is turned on",
  179                 .access         = CTLTYPE_INT | CTLFLAG_RW
  180         },
  181         {
  182                 .name           = "wlan_disable_if_radio_off",
  183                 .method         = ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF,
  184                 .description    = "Disable WLAN if radio is turned off",
  185                 .access         = CTLTYPE_INT | CTLFLAG_RW
  186         },
  187         {
  188                 .name           = "bt_enabled",
  189                 .method         = ACPI_HP_METHOD_BLUETOOTH_ENABLED,
  190                 .description    = "Enable/Disable Bluetooth",
  191                 .access         = CTLTYPE_INT | CTLFLAG_RW
  192         },
  193         {
  194                 .name           = "bt_radio",
  195                 .method         = ACPI_HP_METHOD_BLUETOOTH_RADIO,
  196                 .description    = "Bluetooth radio status",
  197                 .access         = CTLTYPE_INT | CTLFLAG_RD
  198         },
  199         {
  200                 .name           = "bt_on_air",
  201                 .method         = ACPI_HP_METHOD_BLUETOOTH_ON_AIR,
  202                 .description    = "Bluetooth radio ready to use"
  203                                     " (enabled and radio)",
  204                 .access         = CTLTYPE_INT | CTLFLAG_RD
  205         },
  206         {
  207                 .name           = "bt_enable_if_radio_on",
  208                 .method         = ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON,
  209                 .description    = "Enable bluetooth if radio is turned on",
  210                 .access         = CTLTYPE_INT | CTLFLAG_RW
  211         },
  212         {
  213                 .name           = "bt_disable_if_radio_off",
  214                 .method         = ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF,
  215                 .description    = "Disable bluetooth if radio is turned off",
  216                 .access         = CTLTYPE_INT | CTLFLAG_RW
  217         },
  218         {
  219                 .name           = "wwan_enabled",
  220                 .method         = ACPI_HP_METHOD_WWAN_ENABLED,
  221                 .description    = "Enable/Disable WWAN (UMTS)",
  222                 .access         = CTLTYPE_INT | CTLFLAG_RW
  223         },
  224         {
  225                 .name           = "wwan_radio",
  226                 .method         = ACPI_HP_METHOD_WWAN_RADIO,
  227                 .description    = "WWAN radio status",
  228                 .access         = CTLTYPE_INT | CTLFLAG_RD
  229         },
  230         {
  231                 .name           = "wwan_on_air",
  232                 .method         = ACPI_HP_METHOD_WWAN_ON_AIR,
  233                 .description    = "WWAN radio ready to use (enabled and radio)",
  234                 .access         = CTLTYPE_INT | CTLFLAG_RD
  235         },
  236         {
  237                 .name           = "wwan_enable_if_radio_on",
  238                 .method         = ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON,
  239                 .description    = "Enable WWAN if radio is turned on",
  240                 .access         = CTLTYPE_INT | CTLFLAG_RW
  241         },
  242         {
  243                 .name           = "wwan_disable_if_radio_off",
  244                 .method         = ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF,
  245                 .description    = "Disable WWAN if radio is turned off",
  246                 .access         = CTLTYPE_INT | CTLFLAG_RW
  247         },
  248         {
  249                 .name           = "als_enabled",
  250                 .method         = ACPI_HP_METHOD_ALS,
  251                 .description    = "Enable/Disable ALS (Ambient light sensor)",
  252                 .access         = CTLTYPE_INT | CTLFLAG_RW
  253         },
  254         {
  255                 .name           = "display",
  256                 .method         = ACPI_HP_METHOD_DISPLAY,
  257                 .description    = "Display status",
  258                 .access         = CTLTYPE_INT | CTLFLAG_RD
  259         },
  260         {
  261                 .name           = "hdd_temperature",
  262                 .method         = ACPI_HP_METHOD_HDDTEMP,
  263                 .description    = "HDD temperature",
  264                 .access         = CTLTYPE_INT | CTLFLAG_RD
  265         },
  266         {
  267                 .name           = "is_docked",
  268                 .method         = ACPI_HP_METHOD_DOCK,
  269                 .description    = "Docking station status",
  270                 .access         = CTLTYPE_INT | CTLFLAG_RD
  271         },
  272         {
  273                 .name           = "cmi_detail",
  274                 .method         = ACPI_HP_METHOD_CMI_DETAIL,
  275                 .description    = "Details shown in CMI output "
  276                                     "(cat /dev/hpcmi)",
  277                 .access         = CTLTYPE_INT | CTLFLAG_RW
  278         },
  279         {
  280                 .name           = "verbose",
  281                 .method         = ACPI_HP_METHOD_VERBOSE,
  282                 .description    = "Verbosity level",
  283                 .access         = CTLTYPE_INT | CTLFLAG_RW
  284         },
  285 
  286         { NULL, 0, NULL, 0 }
  287 };
  288 
  289 ACPI_SERIAL_DECL(hp, "HP ACPI-WMI Mapping");
  290 
  291 static void     acpi_hp_identify(driver_t *driver, device_t parent);
  292 static int      acpi_hp_probe(device_t dev);
  293 static int      acpi_hp_attach(device_t dev);
  294 static int      acpi_hp_detach(device_t dev);
  295 
  296 static void     acpi_hp_evaluate_auto_on_off(struct acpi_hp_softc* sc);
  297 static int      acpi_hp_sysctl(SYSCTL_HANDLER_ARGS);
  298 static int      acpi_hp_sysctl_set(struct acpi_hp_softc *sc, int method,
  299                     int arg, int oldarg);
  300 static int      acpi_hp_sysctl_get(struct acpi_hp_softc *sc, int method);
  301 static int      acpi_hp_exec_wmi_command(device_t wmi_dev, int command,
  302                     int is_write, int val);
  303 static void     acpi_hp_notify(ACPI_HANDLE h, UINT32 notify, void *context);
  304 static int      acpi_hp_get_cmi_block(device_t wmi_dev, const char* guid,
  305                     UINT8 instance, char* outbuf, size_t outsize,
  306                     UINT32* sequence, int detail);
  307 static void     acpi_hp_hex_decode(char* buffer);
  308 
  309 static d_open_t acpi_hp_hpcmi_open;
  310 static d_close_t acpi_hp_hpcmi_close;
  311 static d_read_t acpi_hp_hpcmi_read;
  312 
  313 /* handler /dev/hpcmi device */
  314 static struct cdevsw hpcmi_cdevsw = {
  315         .d_version = D_VERSION,
  316         .d_open = acpi_hp_hpcmi_open,
  317         .d_close = acpi_hp_hpcmi_close,
  318         .d_read = acpi_hp_hpcmi_read,
  319         .d_name = "hpcmi",
  320 };
  321 
  322 static device_method_t acpi_hp_methods[] = {
  323         DEVMETHOD(device_identify, acpi_hp_identify),
  324         DEVMETHOD(device_probe, acpi_hp_probe),
  325         DEVMETHOD(device_attach, acpi_hp_attach),
  326         DEVMETHOD(device_detach, acpi_hp_detach),
  327         {0, 0}
  328 };
  329 
  330 static driver_t acpi_hp_driver = {
  331         "acpi_hp",
  332         acpi_hp_methods,
  333         sizeof(struct acpi_hp_softc),
  334 };
  335 
  336 static devclass_t acpi_hp_devclass;
  337 
  338 DRIVER_MODULE(acpi_hp, acpi_wmi, acpi_hp_driver, acpi_hp_devclass,
  339                 0, 0);
  340 MODULE_DEPEND(acpi_hp, acpi_wmi, 1, 1, 1);
  341 MODULE_DEPEND(acpi_hp, acpi, 1, 1, 1);
  342 
  343 static void     
  344 acpi_hp_evaluate_auto_on_off(struct acpi_hp_softc *sc)
  345 {
  346         int     wireless;
  347         int     new_wlan_status;
  348         int     new_bluetooth_status;
  349         int     new_wwan_status;
  350 
  351         wireless = acpi_hp_exec_wmi_command(sc->wmi_dev,
  352                     ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
  353         new_wlan_status = -1;
  354         new_bluetooth_status = -1;
  355         new_wwan_status = -1;
  356 
  357         if (sc->verbose)
  358                 device_printf(sc->wmi_dev, "Wireless status is %x\n", wireless);
  359         if (sc->wlan_disable_if_radio_off && !(wireless & HP_MASK_WLAN_RADIO)
  360             &&  (wireless & HP_MASK_WLAN_ENABLED)) {
  361                 acpi_hp_exec_wmi_command(sc->wmi_dev,
  362                     ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x100);
  363                 new_wlan_status = 0;
  364         }
  365         else if (sc->wlan_enable_if_radio_on && (wireless & HP_MASK_WLAN_RADIO)
  366                 &&  !(wireless & HP_MASK_WLAN_ENABLED)) {
  367                 acpi_hp_exec_wmi_command(sc->wmi_dev,
  368                     ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x101);
  369                 new_wlan_status = 1;
  370         }
  371         if (sc->bluetooth_disable_if_radio_off &&
  372             !(wireless & HP_MASK_BLUETOOTH_RADIO) &&
  373             (wireless & HP_MASK_BLUETOOTH_ENABLED)) {
  374                 acpi_hp_exec_wmi_command(sc->wmi_dev,
  375                     ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x200);
  376                 new_bluetooth_status = 0;
  377         }
  378         else if (sc->bluetooth_enable_if_radio_on &&
  379                 (wireless & HP_MASK_BLUETOOTH_RADIO) &&
  380                 !(wireless & HP_MASK_BLUETOOTH_ENABLED)) {
  381                 acpi_hp_exec_wmi_command(sc->wmi_dev,
  382                     ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x202);
  383                 new_bluetooth_status = 1;
  384         }
  385         if (sc->wwan_disable_if_radio_off &&
  386             !(wireless & HP_MASK_WWAN_RADIO) &&
  387             (wireless & HP_MASK_WWAN_ENABLED)) {
  388                 acpi_hp_exec_wmi_command(sc->wmi_dev,
  389                 ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x400);
  390                 new_wwan_status = 0;
  391         }
  392         else if (sc->wwan_enable_if_radio_on &&
  393                 (wireless & HP_MASK_WWAN_RADIO) &&
  394                 !(wireless & HP_MASK_WWAN_ENABLED)) {
  395                 acpi_hp_exec_wmi_command(sc->wmi_dev,
  396                     ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x404);
  397                 new_wwan_status = 1;
  398         }
  399 
  400         if (new_wlan_status == -1) {
  401                 new_wlan_status = (wireless & HP_MASK_WLAN_ON_AIR);
  402                 if ((new_wlan_status?1:0) != sc->was_wlan_on_air) {
  403                         sc->was_wlan_on_air = sc->was_wlan_on_air?0:1;
  404                         if (sc->verbose)
  405                                 device_printf(sc->wmi_dev,
  406                                     "WLAN on air changed to %i "
  407                                     "(new_wlan_status is %i)\n",
  408                                     sc->was_wlan_on_air, new_wlan_status);
  409                         acpi_UserNotify("HP", ACPI_ROOT_OBJECT,
  410                             0xc0+sc->was_wlan_on_air);
  411                 }
  412         }
  413         if (new_bluetooth_status == -1) {
  414                 new_bluetooth_status = (wireless & HP_MASK_BLUETOOTH_ON_AIR);
  415                 if ((new_bluetooth_status?1:0) != sc->was_bluetooth_on_air) {
  416                         sc->was_bluetooth_on_air = sc->was_bluetooth_on_air?
  417                             0:1;
  418                         if (sc->verbose)
  419                                 device_printf(sc->wmi_dev,
  420                                     "BLUETOOTH on air changed"
  421                                     " to %i (new_bluetooth_status is %i)\n",
  422                                     sc->was_bluetooth_on_air,
  423                                     new_bluetooth_status);
  424                         acpi_UserNotify("HP", ACPI_ROOT_OBJECT,
  425                             0xd0+sc->was_bluetooth_on_air);
  426                 }
  427         }
  428         if (new_wwan_status == -1) {
  429                 new_wwan_status = (wireless & HP_MASK_WWAN_ON_AIR);
  430                 if ((new_wwan_status?1:0) != sc->was_wwan_on_air) {
  431                         sc->was_wwan_on_air = sc->was_wwan_on_air?0:1;
  432                         if (sc->verbose)
  433                                 device_printf(sc->wmi_dev,
  434                                     "WWAN on air changed to %i"
  435                                     " (new_wwan_status is %i)\n",
  436                                     sc->was_wwan_on_air, new_wwan_status);
  437                         acpi_UserNotify("HP", ACPI_ROOT_OBJECT,
  438                             0xe0+sc->was_wwan_on_air);
  439                 }
  440         }
  441 }
  442 
  443 static void
  444 acpi_hp_identify(driver_t *driver, device_t parent)
  445 {
  446 
  447         /* Don't do anything if driver is disabled. */
  448         if (acpi_disabled("hp"))
  449                 return;
  450 
  451         /* Add only a single device instance. */
  452         if (device_find_child(parent, "acpi_hp", -1) != NULL)
  453                 return;
  454 
  455         if (BUS_ADD_CHILD(parent, 0, "acpi_hp", -1) == NULL)
  456                 device_printf(parent, "add acpi_hp child failed\n");
  457 }
  458 
  459 static int
  460 acpi_hp_probe(device_t dev)
  461 {
  462 
  463         device_set_desc(dev, "HP ACPI-WMI Mapping");
  464         return (0);
  465 }
  466 
  467 static int
  468 acpi_hp_attach(device_t dev)
  469 {
  470         struct acpi_hp_softc    *sc;
  471         int                     arg;
  472 
  473         ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
  474 
  475         sc = device_get_softc(dev);
  476         sc->dev = dev;
  477         sc->has_notify = 0;
  478         sc->has_cmi = 0;
  479         sc->bluetooth_enable_if_radio_on = 0;
  480         sc->bluetooth_disable_if_radio_off = 0;
  481         sc->wlan_enable_if_radio_on = 0;
  482         sc->wlan_disable_if_radio_off = 0;
  483         sc->wlan_enable_if_radio_on = 0;
  484         sc->wlan_disable_if_radio_off = 0;
  485         sc->was_wlan_on_air = 0;
  486         sc->was_bluetooth_on_air = 0;
  487         sc->was_wwan_on_air = 0;
  488         sc->cmi_detail = 0;
  489         sc->cmi_order_size = -1;
  490         sc->verbose = 0;
  491         memset(sc->cmi_order, 0, sizeof(sc->cmi_order));
  492 
  493         sc->wmi_dev = device_get_parent(dev);
  494         if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
  495             ACPI_HP_WMI_BIOS_GUID)) {
  496                 device_printf(dev,
  497                     "WMI device does not provide the HP BIOS GUID\n");
  498                 return (EINVAL);
  499         }
  500         if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
  501             ACPI_HP_WMI_EVENT_GUID)) {
  502                 device_printf(dev,
  503                     "HP event GUID detected, installing event handler\n");
  504                 if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev,
  505                     ACPI_HP_WMI_EVENT_GUID, acpi_hp_notify, dev)) {
  506                         device_printf(dev,
  507                             "Could not install notification handler!\n");
  508                 }
  509                 else {
  510                         sc->has_notify = 1;
  511                 }
  512         }
  513         if ((sc->has_cmi = 
  514             ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, ACPI_HP_WMI_CMI_GUID)
  515             )) {
  516                 device_printf(dev, "HP CMI GUID detected\n");
  517         }
  518 
  519         if (sc->has_cmi) {
  520                 sc->hpcmi_dev_t = make_dev(&hpcmi_cdevsw, 0, UID_ROOT,
  521                             GID_WHEEL, 0644, "hpcmi");
  522                 sc->hpcmi_dev_t->si_drv1 = sc;
  523                 sc->hpcmi_open_pid = 0;
  524                 sc->hpcmi_bufptr = -1;
  525         }
  526 
  527         ACPI_SERIAL_BEGIN(hp);
  528 
  529         sc->sysctl_ctx = device_get_sysctl_ctx(dev);
  530         sc->sysctl_tree = device_get_sysctl_tree(dev);
  531         for (int i = 0; acpi_hp_sysctls[i].name != NULL; ++i) {
  532                 arg = 0;
  533                 if ((!sc->has_notify &&
  534                     (acpi_hp_sysctls[i].method ==
  535                         ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON ||
  536                     acpi_hp_sysctls[i].method ==
  537                         ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF ||
  538                     acpi_hp_sysctls[i].method ==
  539                         ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON ||
  540                     acpi_hp_sysctls[i].method ==
  541                         ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF ||
  542                     acpi_hp_sysctls[i].method ==
  543                         ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON ||
  544                     acpi_hp_sysctls[i].method ==
  545                         ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF)) ||
  546                     (arg = acpi_hp_sysctl_get(sc,
  547                     acpi_hp_sysctls[i].method)) < 0) {
  548                         continue;
  549                 }
  550                 if (acpi_hp_sysctls[i].method == ACPI_HP_METHOD_WLAN_ON_AIR) {
  551                         sc->was_wlan_on_air = arg;
  552                 }
  553                 else if (acpi_hp_sysctls[i].method ==
  554                             ACPI_HP_METHOD_BLUETOOTH_ON_AIR) {
  555                         sc->was_bluetooth_on_air = arg;
  556                 }
  557                 else if (acpi_hp_sysctls[i].method ==
  558                             ACPI_HP_METHOD_WWAN_ON_AIR) {
  559                         sc->was_wwan_on_air = arg;
  560                 }
  561 
  562                 SYSCTL_ADD_PROC(sc->sysctl_ctx,
  563                 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
  564                         acpi_hp_sysctls[i].name, acpi_hp_sysctls[i].access,
  565                         sc, i, acpi_hp_sysctl, "I",
  566                         acpi_hp_sysctls[i].description);
  567         }
  568         ACPI_SERIAL_END(hp);
  569 
  570         return (0);
  571 }
  572 
  573 static int
  574 acpi_hp_detach(device_t dev)
  575 {
  576         int     ret;
  577         
  578         ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
  579         struct acpi_hp_softc *sc = device_get_softc(dev);
  580         if (sc->has_cmi && sc->hpcmi_open_pid != 0) {
  581                 ret = EBUSY;
  582         }
  583         else {
  584                 if (sc->has_notify) {
  585                         ACPI_WMI_REMOVE_EVENT_HANDLER(dev,
  586                             ACPI_HP_WMI_EVENT_GUID);
  587                 }
  588                 if (sc->hpcmi_bufptr != -1) {
  589                         sbuf_delete(&sc->hpcmi_sbuf);
  590                         sc->hpcmi_bufptr = -1;
  591                 }
  592                 sc->hpcmi_open_pid = 0;
  593                 destroy_dev(sc->hpcmi_dev_t);
  594                 ret = 0;
  595         }
  596 
  597         return (ret);
  598 }
  599 
  600 static int
  601 acpi_hp_sysctl(SYSCTL_HANDLER_ARGS)
  602 {
  603         struct acpi_hp_softc    *sc;
  604         int                     arg;
  605         int                     oldarg;
  606         int                     error = 0;
  607         int                     function;
  608         int                     method;
  609         
  610         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  611 
  612         sc = (struct acpi_hp_softc *)oidp->oid_arg1;
  613         function = oidp->oid_arg2;
  614         method = acpi_hp_sysctls[function].method;
  615 
  616         ACPI_SERIAL_BEGIN(hp);
  617         arg = acpi_hp_sysctl_get(sc, method);
  618         oldarg = arg;
  619         error = sysctl_handle_int(oidp, &arg, 0, req);
  620         if (!error && req->newptr != NULL) {
  621                 error = acpi_hp_sysctl_set(sc, method, arg, oldarg);
  622         }
  623         ACPI_SERIAL_END(hp);
  624 
  625         return (error);
  626 }
  627 
  628 static int
  629 acpi_hp_sysctl_get(struct acpi_hp_softc *sc, int method)
  630 {
  631         int     val = 0;
  632 
  633         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  634         ACPI_SERIAL_ASSERT(hp);
  635 
  636         switch (method) {
  637         case ACPI_HP_METHOD_WLAN_ENABLED:
  638                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  639                         ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
  640                 val = ((val & HP_MASK_WLAN_ENABLED) != 0);
  641                 break;
  642         case ACPI_HP_METHOD_WLAN_RADIO:
  643                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  644                         ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
  645                 val = ((val & HP_MASK_WLAN_RADIO) != 0);
  646                 break;
  647         case ACPI_HP_METHOD_WLAN_ON_AIR:
  648                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  649                         ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
  650                 val = ((val & HP_MASK_WLAN_ON_AIR) != 0);
  651                 break;
  652         case ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON:
  653                 val = sc->wlan_enable_if_radio_on;
  654                 break;
  655         case ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF:
  656                 val = sc->wlan_disable_if_radio_off;
  657                 break;
  658         case ACPI_HP_METHOD_BLUETOOTH_ENABLED:
  659                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  660                         ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
  661                 val = ((val & HP_MASK_BLUETOOTH_ENABLED) != 0);
  662                 break;
  663         case ACPI_HP_METHOD_BLUETOOTH_RADIO:
  664                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  665                         ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
  666                 val = ((val & HP_MASK_BLUETOOTH_RADIO) != 0);
  667                 break;
  668         case ACPI_HP_METHOD_BLUETOOTH_ON_AIR:
  669                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  670                         ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
  671                 val = ((val & HP_MASK_BLUETOOTH_ON_AIR) != 0);
  672                 break;
  673         case ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON:
  674                 val = sc->bluetooth_enable_if_radio_on;
  675                 break;
  676         case ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF:
  677                 val = sc->bluetooth_disable_if_radio_off;
  678                 break;
  679         case ACPI_HP_METHOD_WWAN_ENABLED:
  680                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  681                         ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
  682                 val = ((val & HP_MASK_WWAN_ENABLED) != 0);
  683                 break;
  684         case ACPI_HP_METHOD_WWAN_RADIO:
  685                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  686                         ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
  687                 val = ((val & HP_MASK_WWAN_RADIO) != 0);
  688                 break;
  689         case ACPI_HP_METHOD_WWAN_ON_AIR:
  690                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  691                         ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
  692                 val = ((val & HP_MASK_WWAN_ON_AIR) != 0);
  693                 break;
  694         case ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON:
  695                 val = sc->wwan_enable_if_radio_on;
  696                 break;
  697         case ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF:
  698                 val = sc->wwan_disable_if_radio_off;
  699                 break;
  700         case ACPI_HP_METHOD_ALS:
  701                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  702                         ACPI_HP_WMI_ALS_COMMAND, 0, 0);
  703                 break;
  704         case ACPI_HP_METHOD_DISPLAY:
  705                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  706                         ACPI_HP_WMI_DISPLAY_COMMAND, 0, 0);
  707                 break;
  708         case ACPI_HP_METHOD_HDDTEMP:
  709                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  710                         ACPI_HP_WMI_HDDTEMP_COMMAND, 0, 0);
  711                 break;
  712         case ACPI_HP_METHOD_DOCK:
  713                 val = acpi_hp_exec_wmi_command(sc->wmi_dev,
  714                         ACPI_HP_WMI_DOCK_COMMAND, 0, 0);
  715                 break;
  716         case ACPI_HP_METHOD_CMI_DETAIL:
  717                 val = sc->cmi_detail;
  718                 break;
  719         case ACPI_HP_METHOD_VERBOSE:
  720                 val = sc->verbose;
  721                 break;
  722         }
  723 
  724         return (val);
  725 }
  726 
  727 static int
  728 acpi_hp_sysctl_set(struct acpi_hp_softc *sc, int method, int arg, int oldarg)
  729 {
  730         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  731         ACPI_SERIAL_ASSERT(hp);
  732 
  733         if (method != ACPI_HP_METHOD_CMI_DETAIL &&
  734             method != ACPI_HP_METHOD_VERBOSE)
  735                 arg = arg?1:0;
  736 
  737         if (arg != oldarg) {
  738                 switch (method) {
  739                 case ACPI_HP_METHOD_WLAN_ENABLED:
  740                         return (acpi_hp_exec_wmi_command(sc->wmi_dev,
  741                                     ACPI_HP_WMI_WIRELESS_COMMAND, 1,
  742                                     arg?0x101:0x100));
  743                 case ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON:
  744                         sc->wlan_enable_if_radio_on = arg;
  745                         acpi_hp_evaluate_auto_on_off(sc);
  746                         break;
  747                 case ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF:
  748                         sc->wlan_disable_if_radio_off = arg;
  749                         acpi_hp_evaluate_auto_on_off(sc);
  750                         break;
  751                 case ACPI_HP_METHOD_BLUETOOTH_ENABLED:
  752                         return (acpi_hp_exec_wmi_command(sc->wmi_dev,
  753                                     ACPI_HP_WMI_WIRELESS_COMMAND, 1,
  754                                     arg?0x202:0x200));
  755                 case ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON:
  756                         sc->bluetooth_enable_if_radio_on = arg;
  757                         acpi_hp_evaluate_auto_on_off(sc);
  758                         break;
  759                 case ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF:
  760                         sc->bluetooth_disable_if_radio_off = arg?1:0;
  761                         acpi_hp_evaluate_auto_on_off(sc);
  762                         break;
  763                 case ACPI_HP_METHOD_WWAN_ENABLED:
  764                         return (acpi_hp_exec_wmi_command(sc->wmi_dev,
  765                                     ACPI_HP_WMI_WIRELESS_COMMAND, 1,
  766                                     arg?0x404:0x400));
  767                 case ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON:
  768                         sc->wwan_enable_if_radio_on = arg?1:0;
  769                         acpi_hp_evaluate_auto_on_off(sc);
  770                         break;
  771                 case ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF:
  772                         sc->wwan_disable_if_radio_off = arg?1:0;
  773                         acpi_hp_evaluate_auto_on_off(sc);
  774                         break;
  775                 case ACPI_HP_METHOD_ALS:
  776                         return (acpi_hp_exec_wmi_command(sc->wmi_dev,
  777                                     ACPI_HP_WMI_ALS_COMMAND, 1,
  778                                     arg?1:0));
  779                 case ACPI_HP_METHOD_CMI_DETAIL:
  780                         sc->cmi_detail = arg;
  781                         if ((arg & ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE) != 
  782                             (oldarg & ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE)) {
  783                             sc->cmi_order_size = -1;
  784                         }
  785                         break;
  786                 case ACPI_HP_METHOD_VERBOSE:
  787                         sc->verbose = arg;
  788                         break;
  789                 }
  790         }
  791 
  792         return (0);
  793 }
  794 
  795 static __inline void
  796 acpi_hp_free_buffer(ACPI_BUFFER* buf) {
  797         if (buf && buf->Pointer) {
  798                 AcpiOsFree(buf->Pointer);
  799         }
  800 }
  801 
  802 static void
  803 acpi_hp_notify(ACPI_HANDLE h, UINT32 notify, void *context)
  804 {
  805         device_t dev = context;
  806         ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
  807 
  808         struct acpi_hp_softc *sc = device_get_softc(dev);
  809         ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL };
  810         ACPI_OBJECT *obj;
  811         ACPI_WMI_GET_EVENT_DATA(sc->wmi_dev, notify, &response);
  812         obj = (ACPI_OBJECT*) response.Pointer;
  813         if (obj && obj->Type == ACPI_TYPE_BUFFER && obj->Buffer.Length == 8) {
  814                 if (*((UINT8 *) obj->Buffer.Pointer) == 0x5) {
  815                         acpi_hp_evaluate_auto_on_off(sc);
  816                 }
  817         }
  818         acpi_hp_free_buffer(&response);
  819 }
  820 
  821 static int
  822 acpi_hp_exec_wmi_command(device_t wmi_dev, int command, int is_write, int val)
  823 {
  824         UINT32          params[5] = { 0x55434553,
  825                             is_write?2:1,
  826                             command,
  827                             is_write?4:0,
  828                             val};
  829         UINT32*         result;
  830         ACPI_OBJECT     *obj;
  831         ACPI_BUFFER     in = { sizeof(params), &params };
  832         ACPI_BUFFER     out = { ACPI_ALLOCATE_BUFFER, NULL };
  833         int retval;
  834         
  835         if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev, ACPI_HP_WMI_BIOS_GUID,
  836                     0, 0x3, &in, &out))) {
  837                 acpi_hp_free_buffer(&out);
  838                 return (-EINVAL);
  839         }
  840         obj = out.Pointer;
  841         if (!obj || obj->Type != ACPI_TYPE_BUFFER) {
  842                 acpi_hp_free_buffer(&out);
  843                 return (-EINVAL);
  844         }
  845         result = (UINT32*) obj->Buffer.Pointer;
  846         retval = result[2];
  847         if (result[1] > 0) {
  848                 retval = result[1];
  849         }
  850         acpi_hp_free_buffer(&out);
  851 
  852         return (retval);
  853 }
  854 
  855 static __inline char*
  856 acpi_hp_get_string_from_object(ACPI_OBJECT* obj, char* dst, size_t size) {
  857         int     length;
  858 
  859         dst[0] = 0;
  860         if (obj->Type == ACPI_TYPE_STRING) {
  861                 length = obj->String.Length+1;
  862                 if (length > size) {
  863                         length = size - 1;
  864                 }
  865                 strlcpy(dst, obj->String.Pointer, length);
  866                 acpi_hp_hex_decode(dst);
  867         }
  868 
  869         return (dst);
  870 }
  871 
  872 
  873 /*
  874  * Read BIOS Setting block in instance "instance".
  875  * The block returned is ACPI_TYPE_PACKAGE which should contain the following
  876  * elements:
  877  * Index Meaning
  878  * 0        Setting Name [string]
  879  * 1        Value (comma separated, asterisk marks the current value) [string]
  880  * 2        Path within the bios hierarchy [string]
  881  * 3        IsReadOnly [int]
  882  * 4        DisplayInUI [int]
  883  * 5        RequiresPhysicalPresence [int]
  884  * 6        Sequence for ordering within the bios settings (absolute) [int]
  885  * 7        Length of prerequisites array [int]
  886  * 8..8+[7] PrerequisiteN [string]
  887  * 9+[7]    Current value (in case of enum) [string] / Array length [int]
  888  * 10+[7]   Enum length [int] / Array values
  889  * 11+[7]ff Enum value at index x [string]
  890  */
  891 static int
  892 acpi_hp_get_cmi_block(device_t wmi_dev, const char* guid, UINT8 instance,
  893     char* outbuf, size_t outsize, UINT32* sequence, int detail)
  894 {
  895         ACPI_OBJECT     *obj;
  896         ACPI_BUFFER     out = { ACPI_ALLOCATE_BUFFER, NULL };
  897         int             i;
  898         int             outlen;
  899         int             size = 255;
  900         int             has_enums = 0;
  901         int             valuebase = 0;
  902         char            string_buffer[size];
  903         int             enumbase;
  904 
  905         outlen = 0;
  906         outbuf[0] = 0;  
  907         if (ACPI_FAILURE(ACPI_WMI_GET_BLOCK(wmi_dev, guid, instance, &out))) {
  908                 acpi_hp_free_buffer(&out);
  909                 return (-EINVAL);
  910         }
  911         obj = out.Pointer;
  912         if (!obj || obj->Type != ACPI_TYPE_PACKAGE) {
  913                 acpi_hp_free_buffer(&out);
  914                 return (-EINVAL);
  915         }
  916 
  917         if (obj->Package.Count >= 8 &&
  918             obj->Package.Elements[7].Type == ACPI_TYPE_INTEGER) {
  919             valuebase = 8 + obj->Package.Elements[7].Integer.Value;
  920         }
  921 
  922         /* check if this matches our expectations based on limited knowledge */
  923         if (valuebase > 7 && obj->Package.Count > valuebase + 1 &&
  924             obj->Package.Elements[0].Type == ACPI_TYPE_STRING &&
  925             obj->Package.Elements[1].Type == ACPI_TYPE_STRING &&
  926             obj->Package.Elements[2].Type == ACPI_TYPE_STRING &&
  927             obj->Package.Elements[3].Type == ACPI_TYPE_INTEGER &&
  928             obj->Package.Elements[4].Type == ACPI_TYPE_INTEGER &&
  929             obj->Package.Elements[5].Type == ACPI_TYPE_INTEGER &&
  930             obj->Package.Elements[6].Type == ACPI_TYPE_INTEGER &&
  931             obj->Package.Elements[valuebase].Type == ACPI_TYPE_STRING &&
  932             obj->Package.Elements[valuebase+1].Type == ACPI_TYPE_INTEGER &&
  933             obj->Package.Count > valuebase + 
  934                 obj->Package.Elements[valuebase+1].Integer.Value
  935            ) {
  936                 enumbase = valuebase + 1;
  937                 if (detail & ACPI_HP_CMI_DETAIL_PATHS) {
  938                         strlcat(outbuf, acpi_hp_get_string_from_object(
  939                                 &obj->Package.Elements[2], string_buffer, size),
  940                                 outsize);
  941                         outlen += 48;
  942                         while (strlen(outbuf) < outlen)
  943                                 strlcat(outbuf, " ", outsize);
  944                 }
  945                 strlcat(outbuf, acpi_hp_get_string_from_object(
  946                                 &obj->Package.Elements[0], string_buffer, size),
  947                                 outsize);
  948                 outlen += 43;
  949                 while (strlen(outbuf) < outlen)
  950                         strlcat(outbuf, " ", outsize);
  951                 strlcat(outbuf, acpi_hp_get_string_from_object(
  952                                 &obj->Package.Elements[valuebase], string_buffer, 
  953                                 size),
  954                                 outsize);
  955                 outlen += 21;
  956                 while (strlen(outbuf) < outlen)
  957                         strlcat(outbuf, " ", outsize);
  958                 for (i = 0; i < strlen(outbuf); ++i)
  959                         if (outbuf[i] == '\\')
  960                                 outbuf[i] = '/';
  961                 if (detail & ACPI_HP_CMI_DETAIL_ENUMS) {
  962                         for (i = enumbase + 1; i < enumbase + 1 +
  963                             obj->Package.Elements[enumbase].Integer.Value;
  964                             ++i) {
  965                                 acpi_hp_get_string_from_object(
  966                                     &obj->Package.Elements[i], string_buffer,
  967                                     size);
  968                                 if (strlen(string_buffer) > 1 ||
  969                                     (strlen(string_buffer) == 1 &&
  970                                     string_buffer[0] != ' ')) {
  971                                         if (has_enums)
  972                                                 strlcat(outbuf, "/", outsize);
  973                                         else
  974                                                 strlcat(outbuf, " (", outsize);
  975                                         strlcat(outbuf, string_buffer, outsize);
  976                                         has_enums = 1;
  977                                 }
  978                         }
  979                 }
  980                 if (has_enums)
  981                         strlcat(outbuf, ")", outsize);
  982                 if (detail & ACPI_HP_CMI_DETAIL_FLAGS) {
  983                         strlcat(outbuf, obj->Package.Elements[3].Integer.Value?
  984                             " [ReadOnly]":"", outsize);
  985                         strlcat(outbuf, obj->Package.Elements[4].Integer.Value?
  986                             "":" [NOUI]", outsize);
  987                         strlcat(outbuf, obj->Package.Elements[5].Integer.Value?
  988                             " [RPP]":"", outsize);
  989                 }
  990                 *sequence = (UINT32) obj->Package.Elements[6].Integer.Value;
  991         }
  992         acpi_hp_free_buffer(&out);
  993 
  994         return (0);
  995 }
  996 
  997 
  998 
  999 /*
 1000  * Convert given two digit hex string (hexin) to an UINT8 referenced
 1001  * by byteout.
 1002  * Return != 0 if the was a problem (invalid input)
 1003  */
 1004 static __inline int acpi_hp_hex_to_int(const UINT8 *hexin, UINT8 *byteout)
 1005 {
 1006         unsigned int    hi;
 1007         unsigned int    lo;
 1008 
 1009         hi = hexin[0];
 1010         lo = hexin[1];
 1011         if ('' <= hi && hi <= '9')
 1012                 hi -= '';
 1013         else if ('A' <= hi && hi <= 'F')
 1014                 hi -= ('A' - 10);
 1015         else if ('a' <= hi && hi <= 'f')
 1016                 hi -= ('a' - 10);
 1017         else
 1018                 return (1);
 1019         if ('' <= lo && lo <= '9')
 1020                 lo -= '';
 1021         else if ('A' <= lo && lo <= 'F')
 1022                 lo -= ('A' - 10);
 1023         else if ('a' <= lo && lo <= 'f')
 1024                 lo -= ('a' - 10);
 1025         else
 1026                 return (1);
 1027         *byteout = (hi << 4) + lo;
 1028 
 1029         return (0);
 1030 }
 1031 
 1032 
 1033 static void
 1034 acpi_hp_hex_decode(char* buffer)
 1035 {
 1036         int     i;
 1037         int     length = strlen(buffer);
 1038         UINT8   *uin;
 1039         UINT8   uout;
 1040 
 1041         if (((int)length/2)*2 == length || length < 10) return;
 1042 
 1043         for (i = 0; i<length; ++i) {
 1044                 if (!((i+1)%3)) {
 1045                         if (buffer[i] != ' ')
 1046                                 return;
 1047                 }
 1048                 else
 1049                         if (!((buffer[i] >= '' && buffer[i] <= '9') ||
 1050                             (buffer[i] >= 'A' && buffer[i] <= 'F')))
 1051                                 return;                 
 1052         }
 1053 
 1054         for (i = 0; i<length; i += 3) {
 1055                 uin = &buffer[i];
 1056                 uout = 0;
 1057                 acpi_hp_hex_to_int(uin, &uout);
 1058                 buffer[i/3] = (char) uout;
 1059         }
 1060         buffer[(length+1)/3] = 0;
 1061 }
 1062 
 1063 
 1064 /*
 1065  * open hpcmi device
 1066  */
 1067 static int
 1068 acpi_hp_hpcmi_open(struct cdev* dev, int flags, int mode, struct thread *td)
 1069 {
 1070         struct acpi_hp_softc    *sc;
 1071         int                     ret;
 1072 
 1073         if (dev == NULL || dev->si_drv1 == NULL)
 1074                 return (EBADF);
 1075         sc = dev->si_drv1;
 1076 
 1077         ACPI_SERIAL_BEGIN(hp);
 1078         if (sc->hpcmi_open_pid != 0) {
 1079                 ret = EBUSY;
 1080         }
 1081         else {
 1082                 if (sbuf_new(&sc->hpcmi_sbuf, NULL, 4096, SBUF_AUTOEXTEND)
 1083                     == NULL) {
 1084                         ret = ENXIO;
 1085                 } else {
 1086                         sc->hpcmi_open_pid = td->td_proc->p_pid;
 1087                         sc->hpcmi_bufptr = 0;
 1088                         ret = 0;
 1089                 }
 1090         }
 1091         ACPI_SERIAL_END(hp);
 1092 
 1093         return (ret);
 1094 }
 1095 
 1096 /*
 1097  * close hpcmi device
 1098  */
 1099 static int
 1100 acpi_hp_hpcmi_close(struct cdev* dev, int flags, int mode, struct thread *td)
 1101 {
 1102         struct acpi_hp_softc    *sc;
 1103         int                     ret;
 1104 
 1105         if (dev == NULL || dev->si_drv1 == NULL)
 1106                 return (EBADF);
 1107         sc = dev->si_drv1;
 1108 
 1109         ACPI_SERIAL_BEGIN(hp);
 1110         if (sc->hpcmi_open_pid == 0) {
 1111                 ret = EBADF;
 1112         }
 1113         else {
 1114                 if (sc->hpcmi_bufptr != -1) {
 1115                         sbuf_delete(&sc->hpcmi_sbuf);
 1116                         sc->hpcmi_bufptr = -1;
 1117                 }
 1118                 sc->hpcmi_open_pid = 0;
 1119                 ret = 0;
 1120         }
 1121         ACPI_SERIAL_END(hp);
 1122 
 1123         return (ret);
 1124 }
 1125 
 1126 /*
 1127  * Read from hpcmi bios information
 1128  */
 1129 static int
 1130 acpi_hp_hpcmi_read(struct cdev *dev, struct uio *buf, int flag)
 1131 {
 1132         struct acpi_hp_softc    *sc;
 1133         int                     pos, i, l, ret;
 1134         UINT8                   instance;
 1135         UINT8                   maxInstance;
 1136         UINT32                  sequence;
 1137         int                     linesize = 1025;
 1138         char                    line[linesize];
 1139 
 1140         if (dev == NULL || dev->si_drv1 == NULL)
 1141                 return (EBADF);
 1142         sc = dev->si_drv1;
 1143         
 1144         ACPI_SERIAL_BEGIN(hp);
 1145         if (sc->hpcmi_open_pid != buf->uio_td->td_proc->p_pid
 1146             || sc->hpcmi_bufptr == -1) {
 1147                 ret = EBADF;
 1148         }
 1149         else {
 1150                 if (!sbuf_done(&sc->hpcmi_sbuf)) {
 1151                         if (sc->cmi_order_size < 0) {
 1152                                 maxInstance = sc->has_cmi;
 1153                                 if (!(sc->cmi_detail & 
 1154                                     ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE) &&
 1155                                     maxInstance > 0) {
 1156                                         maxInstance--;
 1157                                 }
 1158                                 sc->cmi_order_size = 0;
 1159                                 for (instance = 0; instance < maxInstance;
 1160                                     ++instance) {
 1161                                         if (acpi_hp_get_cmi_block(sc->wmi_dev,
 1162                                                 ACPI_HP_WMI_CMI_GUID, instance,
 1163                                                 line, linesize, &sequence,
 1164                                                 sc->cmi_detail)) {
 1165                                                 instance = maxInstance;
 1166                                         }
 1167                                         else {
 1168                                                 pos = sc->cmi_order_size;
 1169                                                 for (i=0;
 1170                                                   i<sc->cmi_order_size && i<127;
 1171                                                      ++i) {
 1172                                 if (sc->cmi_order[i].sequence > sequence) {
 1173                                                                 pos = i;
 1174                                                                 break;                                                  
 1175                                                         }
 1176                                                 }
 1177                                                 for (i=sc->cmi_order_size;
 1178                                                     i>pos;
 1179                                                     --i) {
 1180                                                 sc->cmi_order[i].sequence =
 1181                                                     sc->cmi_order[i-1].sequence;
 1182                                                 sc->cmi_order[i].instance =
 1183                                                     sc->cmi_order[i-1].instance;
 1184                                                 }
 1185                                                 sc->cmi_order[pos].sequence =
 1186                                                     sequence;
 1187                                                 sc->cmi_order[pos].instance =
 1188                                                     instance;
 1189                                                 sc->cmi_order_size++;
 1190                                         }
 1191                                 }
 1192                         }
 1193                         for (i=0; i<sc->cmi_order_size; ++i) {
 1194                                 if (!acpi_hp_get_cmi_block(sc->wmi_dev,
 1195                                     ACPI_HP_WMI_CMI_GUID,
 1196                                     sc->cmi_order[i].instance, line, linesize,
 1197                                     &sequence, sc->cmi_detail)) {
 1198                                         sbuf_printf(&sc->hpcmi_sbuf, "%s\n", line);
 1199                                 }
 1200                         }
 1201                         sbuf_finish(&sc->hpcmi_sbuf);
 1202                 }
 1203                 if (sbuf_len(&sc->hpcmi_sbuf) <= 0) {
 1204                         sbuf_delete(&sc->hpcmi_sbuf);
 1205                         sc->hpcmi_bufptr = -1;
 1206                         sc->hpcmi_open_pid = 0;
 1207                         ret = ENOMEM;
 1208                 } else {
 1209                         l = min(buf->uio_resid, sbuf_len(&sc->hpcmi_sbuf) -
 1210                             sc->hpcmi_bufptr);
 1211                         ret = (l > 0)?uiomove(sbuf_data(&sc->hpcmi_sbuf) +
 1212                             sc->hpcmi_bufptr, l, buf) : 0;
 1213                         sc->hpcmi_bufptr += l;
 1214                 }
 1215         }
 1216         ACPI_SERIAL_END(hp);
 1217 
 1218         return (ret);
 1219 }

Cache object: 789b57ebf140842cf47b07ef7ea0f709


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