LCOV - code coverage report
Current view: top level - dev/acpi - acpibtn.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 98 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 8 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* $OpenBSD: acpibtn.c,v 1.45 2018/07/01 19:40:49 mlarkin Exp $ */
       2             : /*
       3             :  * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
       4             :  *
       5             :  * Permission to use, copy, modify, and distribute this software for any
       6             :  * purpose with or without fee is hereby granted, provided that the above
       7             :  * copyright notice and this permission notice appear in all copies.
       8             :  *
       9             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      10             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      11             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      12             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      13             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      14             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      15             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      16             :  */
      17             : 
      18             : #include <sys/param.h>
      19             : #include <sys/signalvar.h>
      20             : #include <sys/systm.h>
      21             : #include <sys/device.h>
      22             : #include <sys/malloc.h>
      23             : 
      24             : #include <machine/bus.h>
      25             : #include <machine/apmvar.h>
      26             : 
      27             : #include <dev/acpi/acpireg.h>
      28             : #include <dev/acpi/acpivar.h>
      29             : #include <dev/acpi/acpidev.h>
      30             : #include <dev/acpi/amltypes.h>
      31             : #include <dev/acpi/dsdt.h>
      32             : 
      33             : #include <sys/sensors.h>
      34             : 
      35             : int     acpibtn_match(struct device *, void *, void *);
      36             : void    acpibtn_attach(struct device *, struct device *, void *);
      37             : int     acpibtn_notify(struct aml_node *, int, void *);
      38             : int     acpibtn_activate(struct device *, int);
      39             : 
      40             : struct acpibtn_softc {
      41             :         struct device           sc_dev;
      42             : 
      43             :         bus_space_tag_t         sc_iot;
      44             :         bus_space_handle_t      sc_ioh;
      45             : 
      46             :         struct acpi_softc       *sc_acpi;
      47             :         struct aml_node         *sc_devnode;
      48             : 
      49             :         struct ksensor          sc_sens;
      50             :         struct ksensordev       sc_sensdev;
      51             : 
      52             :         int                     sc_btn_type;
      53             : #define ACPIBTN_UNKNOWN 0
      54             : #define ACPIBTN_LID     1
      55             : #define ACPIBTN_POWER   2
      56             : #define ACPIBTN_SLEEP   3
      57             : };
      58             : 
      59             : int     acpibtn_setpsw(struct acpibtn_softc *, int);
      60             : 
      61             : struct acpi_lid {
      62             :         struct acpibtn_softc    *abl_softc;
      63             :         SLIST_ENTRY(acpi_lid)   abl_link;
      64             : };
      65             : SLIST_HEAD(acpi_lid_head, acpi_lid) acpibtn_lids =
      66             :     SLIST_HEAD_INITIALIZER(acpibtn_lids);
      67             : 
      68             : struct cfattach acpibtn_ca = {
      69             :         sizeof(struct acpibtn_softc), acpibtn_match, acpibtn_attach, NULL,
      70             :         acpibtn_activate
      71             : };
      72             : 
      73             : struct cfdriver acpibtn_cd = {
      74             :         NULL, "acpibtn", DV_DULL
      75             : };
      76             : 
      77             : const char *acpibtn_hids[] = {
      78             :         ACPI_DEV_LD,
      79             :         ACPI_DEV_PBD,
      80             :         ACPI_DEV_SBD,
      81             :         NULL
      82             : };
      83             : 
      84             : /*
      85             :  * acpibtn_numopenlids
      86             :  *
      87             :  * Return the number of _LID devices that are in the "open" state.
      88             :  * Used to determine if we should go back to sleep/hibernate if we
      89             :  * woke up with the all the lids still closed for some reason. If
      90             :  * the machine has no lids, returns -1.
      91             :  */
      92             : int
      93           0 : acpibtn_numopenlids(void)
      94             : {
      95             :         struct acpi_lid *lid;
      96           0 :         int64_t val;
      97             :         int ct = 0;
      98             : 
      99             :         /* If we have no lids ... */
     100           0 :         if (SLIST_EMPTY(&acpibtn_lids))
     101           0 :                 return (-1);
     102             : 
     103             :         /*
     104             :          * Determine how many lids are open. Assumes _LID evals to
     105             :          * non-0 or 0, for on / off (which is what the spec says).
     106             :          */
     107           0 :         SLIST_FOREACH(lid, &acpibtn_lids, abl_link)
     108           0 :                 if (!aml_evalinteger(lid->abl_softc->sc_acpi,
     109           0 :                     lid->abl_softc->sc_devnode, "_LID", 0, NULL, &val) &&
     110           0 :                     val != 0)
     111           0 :                         ct++;
     112           0 :         return (ct);
     113           0 : }
     114             : 
     115             : int
     116           0 : acpibtn_setpsw(struct acpibtn_softc *sc, int psw)
     117             : {
     118           0 :         struct aml_value        val;
     119             : 
     120           0 :         bzero(&val, sizeof val);
     121           0 :         val.type = AML_OBJTYPE_INTEGER;
     122           0 :         val.v_integer = psw;
     123           0 :         val.length = 1;
     124             : 
     125           0 :         return (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSW", 1, &val,
     126             :             NULL));
     127           0 : }
     128             : 
     129             : void
     130           0 : acpibtn_disable_psw(void)
     131             : {
     132             :         struct acpi_lid *lid;
     133             : 
     134             :         /* disable _LID for wakeup */
     135           0 :         SLIST_FOREACH(lid, &acpibtn_lids, abl_link)
     136           0 :                 acpibtn_setpsw(lid->abl_softc, 0);
     137           0 : }
     138             : 
     139             : void
     140           0 : acpibtn_enable_psw(void)
     141             : {
     142             :         struct acpi_lid         *lid;
     143             : 
     144             :         /* enable _LID for wakeup */
     145           0 :         SLIST_FOREACH(lid, &acpibtn_lids, abl_link)
     146           0 :                 acpibtn_setpsw(lid->abl_softc, 1);
     147           0 : }
     148             : 
     149             : int
     150           0 : acpibtn_match(struct device *parent, void *match, void *aux)
     151             : {
     152           0 :         struct acpi_attach_args *aa = aux;
     153           0 :         struct cfdata           *cf = match;
     154             : 
     155             :         /* sanity */
     156           0 :         return (acpi_matchhids(aa, acpibtn_hids, cf->cf_driver->cd_name));
     157             : }
     158             : 
     159             : void
     160           0 : acpibtn_attach(struct device *parent, struct device *self, void *aux)
     161             : {
     162           0 :         struct acpibtn_softc    *sc = (struct acpibtn_softc *)self;
     163           0 :         struct acpi_attach_args *aa = aux;
     164             :         struct acpi_lid         *lid;
     165           0 :         int64_t                 lid_open = 1;
     166           0 :         int64_t                 st;
     167             : 
     168           0 :         sc->sc_acpi = (struct acpi_softc *)parent;
     169           0 :         sc->sc_devnode = aa->aaa_node;
     170             : 
     171           0 :         printf(": %s\n", sc->sc_devnode->name);
     172             : 
     173           0 :         if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &st))
     174           0 :                 st = STA_PRESENT | STA_ENABLED | STA_DEV_OK;
     175           0 :         if ((st & (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) !=
     176             :             (STA_PRESENT | STA_ENABLED | STA_DEV_OK))
     177           0 :                 return;
     178             : 
     179           0 :         if (!strcmp(aa->aaa_dev, ACPI_DEV_LD)) {
     180           0 :                 sc->sc_btn_type = ACPIBTN_LID;
     181             : 
     182             :                 /* Set PSW (if present) to disable wake on this LID */
     183           0 :                 (void)acpibtn_setpsw(sc, 0);
     184           0 :                 lid = malloc(sizeof(*lid), M_DEVBUF, M_WAITOK | M_ZERO);
     185           0 :                 lid->abl_softc = sc;
     186           0 :                 SLIST_INSERT_HEAD(&acpibtn_lids, lid, abl_link);
     187           0 :         } else if (!strcmp(aa->aaa_dev, ACPI_DEV_PBD))
     188           0 :                 sc->sc_btn_type = ACPIBTN_POWER;
     189           0 :         else if (!strcmp(aa->aaa_dev, ACPI_DEV_SBD))
     190           0 :                 sc->sc_btn_type = ACPIBTN_SLEEP;
     191             : 
     192           0 :         if (sc->sc_btn_type == ACPIBTN_LID) {
     193           0 :                 strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
     194             :                     sizeof(sc->sc_sensdev.xname));
     195           0 :                 strlcpy(sc->sc_sens.desc, "lid open",
     196             :                     sizeof(sc->sc_sens.desc));
     197           0 :                 sc->sc_sens.type = SENSOR_INDICATOR;
     198           0 :                 sensor_attach(&sc->sc_sensdev, &sc->sc_sens);
     199           0 :                 sensordev_install(&sc->sc_sensdev);
     200             : 
     201           0 :                 aml_evalinteger(sc->sc_acpi, sc->sc_devnode,
     202             :                     "_LID", 0, NULL, &lid_open);
     203           0 :                 sc->sc_sens.value = lid_open;
     204           0 :         }
     205             : 
     206           0 :         aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpibtn_notify,
     207           0 :             sc, ACPIDEV_NOPOLL);
     208           0 : }
     209             : 
     210             : int
     211           0 : acpibtn_notify(struct aml_node *node, int notify_type, void *arg)
     212             : {
     213           0 :         struct acpibtn_softc    *sc = arg;
     214             : #ifndef SMALL_KERNEL
     215             :         extern int lid_action;
     216           0 :         int64_t lid;
     217             : #endif
     218             : 
     219             :         dnprintf(10, "acpibtn_notify: %.2x %s\n", notify_type,
     220             :             sc->sc_devnode->name);
     221             : 
     222           0 :         switch (sc->sc_btn_type) {
     223             :         case ACPIBTN_LID:
     224             : #ifndef SMALL_KERNEL
     225             :                 /*
     226             :                  * Notification of 0x80 for lid opens or closes.  We
     227             :                  * need to check the current status by calling the
     228             :                  * _LID method.  0 means the lid is closed and we
     229             :                  * should go to sleep.
     230             :                  */
     231           0 :                 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode,
     232             :                     "_LID", 0, NULL, &lid))
     233           0 :                         return (0);
     234           0 :                 sc->sc_sens.value = lid;
     235             : 
     236           0 :                 if (lid != 0)
     237             :                         break;
     238             : 
     239           0 :                 switch (lid_action) {
     240             :                 case 1:
     241             :                         goto sleep;
     242             : #ifdef HIBERNATE
     243             :                 case 2:
     244             :                         /* Request to go to sleep */
     245           0 :                         if (acpi_record_event(sc->sc_acpi, APM_USER_HIBERNATE_REQ))
     246           0 :                                 acpi_addtask(sc->sc_acpi, acpi_sleep_task,
     247           0 :                                     sc->sc_acpi, ACPI_SLEEP_HIBERNATE);
     248             :                         break;
     249             : #endif
     250             :                 default:
     251             :                         break;
     252             :                 }
     253             : #endif /* SMALL_KERNEL */
     254             :                 break;
     255             :         case ACPIBTN_SLEEP:
     256             : #ifndef SMALL_KERNEL
     257           0 :                 switch (notify_type) {
     258             :                 case 0x02:
     259             :                         /* "something" has been taken care of by the system */
     260             :                         break;
     261             :                 case 0x80:
     262             : sleep:
     263             :                         /* Request to go to sleep */
     264           0 :                         if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ))
     265           0 :                                 acpi_addtask(sc->sc_acpi, acpi_sleep_task,
     266           0 :                                     sc->sc_acpi, ACPI_SLEEP_SUSPEND);
     267             :                         break;
     268             :                 }
     269             : #endif /* SMALL_KERNEL */
     270             :                 break;
     271             :         case ACPIBTN_POWER:
     272           0 :                 if (notify_type == 0x80)
     273           0 :                         acpi_addtask(sc->sc_acpi, acpi_powerdown_task,
     274           0 :                             sc->sc_acpi, 0);
     275             :                 break;
     276             :         default:
     277           0 :                 printf("%s: spurious acpi button interrupt %i\n", DEVNAME(sc),
     278             :                     sc->sc_btn_type);
     279           0 :                 break;
     280             :         }
     281             : 
     282           0 :         return (0);
     283           0 : }
     284             : 
     285             : int
     286           0 : acpibtn_activate(struct device *self, int act)
     287             : {
     288           0 :         struct acpibtn_softc    *sc = (struct acpibtn_softc *)self;
     289           0 :         int64_t                 lid_open = 1;
     290             : 
     291           0 :         switch (act) {
     292             :         case DVACT_WAKEUP:
     293           0 :                 switch (sc->sc_btn_type) {
     294             :                 case ACPIBTN_LID:
     295           0 :                         aml_evalinteger(sc->sc_acpi, sc->sc_devnode,
     296             :                             "_LID", 0, NULL, &lid_open);
     297           0 :                         sc->sc_sens.value = lid_open;
     298           0 :                         break;
     299             :                 }
     300             :                 break;
     301             :         }
     302           0 :         return (0);
     303           0 : }

Generated by: LCOV version 1.13