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

          Line data    Source code
       1             : /* $OpenBSD: acpipwrres.c,v 1.7 2014/09/14 14:17:24 jsg Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2013 Martin Pieuchot <mpi@openbsd.org>
       5             :  * Copyright (c) 2009 Paul Irofti <pirofti@openbsd.org>
       6             :  *
       7             :  * Permission to use, copy, modify, and distribute this software for any
       8             :  * purpose with or without fee is hereby granted, provided that the above
       9             :  * copyright notice and this permission notice appear in all copies.
      10             :  *
      11             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      12             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      13             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      14             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      15             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      16             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      17             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      18             :  */
      19             : 
      20             : #include <sys/param.h>
      21             : #include <sys/signalvar.h>
      22             : #include <sys/systm.h>
      23             : #include <sys/device.h>
      24             : #include <sys/malloc.h>
      25             : 
      26             : #include <machine/bus.h>
      27             : 
      28             : #include <dev/acpi/acpireg.h>
      29             : #include <dev/acpi/acpivar.h>
      30             : #include <dev/acpi/acpidev.h>
      31             : #include <dev/acpi/amltypes.h>
      32             : #include <dev/acpi/dsdt.h>
      33             : 
      34             : int     acpipwrres_match(struct device *, void *, void *);
      35             : void    acpipwrres_attach(struct device *, struct device *, void *);
      36             : 
      37             : #ifdef ACPIPWRRES_DEBUG
      38             : #define DPRINTF(x)      printf x
      39             : #else
      40             : #define DPRINTF(x)
      41             : #endif
      42             : 
      43             : struct acpipwrres_softc {
      44             :         struct device           sc_dev;
      45             : 
      46             :         bus_space_tag_t         sc_iot;
      47             :         bus_space_handle_t      sc_ioh;
      48             : 
      49             :         struct acpi_softc       *sc_acpi;
      50             :         struct aml_node         *sc_devnode;
      51             : 
      52             :         SIMPLEQ_HEAD(, acpipwrres_consumer)     sc_cons;
      53             :         int                                     sc_cons_ref;
      54             : 
      55             :         int     sc_level;
      56             :         int     sc_order;
      57             :         int     sc_state;
      58             : #define ACPIPWRRES_OFF          0
      59             : #define ACPIPWRRES_ON           1
      60             : #define ACPIPWRRES_UNK          -1
      61             : };
      62             : 
      63             : struct acpipwrres_consumer {
      64             :         struct aml_node                         *cs_node;
      65             :         SIMPLEQ_ENTRY(acpipwrres_consumer)      cs_next;
      66             : };
      67             : 
      68             : struct cfattach acpipwrres_ca = {
      69             :         sizeof(struct acpipwrres_softc), acpipwrres_match, acpipwrres_attach
      70             : };
      71             : 
      72             : struct cfdriver acpipwrres_cd = {
      73             :         NULL, "acpipwrres", DV_DULL
      74             : };
      75             : 
      76             : int     acpipwrres_hascons(struct acpipwrres_softc *, struct aml_node *);
      77             : int     acpipwrres_addcons(struct acpipwrres_softc *, struct aml_node *);
      78             : int     acpipwrres_foundcons(struct aml_node *, void *);
      79             : 
      80             : int
      81           0 : acpipwrres_match(struct device *parent, void *match, void *aux)
      82             : {
      83           0 :         struct acpi_attach_args *aaa = aux;
      84           0 :         struct cfdata           *cf = match;
      85             : 
      86           0 :         if (aaa->aaa_name == NULL || strcmp(aaa->aaa_name,
      87           0 :             cf->cf_driver->cd_name) != 0 || aaa->aaa_table != NULL)
      88           0 :                 return (0);
      89             : 
      90           0 :         return (1);
      91           0 : }
      92             : 
      93             : void
      94           0 : acpipwrres_attach(struct device *parent, struct device *self, void *aux)
      95             : {
      96           0 :         struct acpipwrres_softc         *sc = (struct acpipwrres_softc *)self;
      97           0 :         struct acpi_attach_args         *aaa = aux;
      98           0 :         struct aml_value                res;
      99             :         struct acpipwrres_consumer      *cons;
     100             : 
     101             :         extern struct aml_node  aml_root;
     102             : 
     103           0 :         sc->sc_acpi = (struct acpi_softc *)parent;
     104           0 :         sc->sc_devnode = aaa->aaa_node;
     105           0 :         memset(&res, 0, sizeof res);
     106             : 
     107           0 :         printf(": %s", sc->sc_devnode->name);
     108             : 
     109           0 :         if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &res)) {
     110           0 :                 sc->sc_state = (int)aml_val2int(&res);
     111           0 :                 if (sc->sc_state != ACPIPWRRES_ON &&
     112           0 :                     sc->sc_state != ACPIPWRRES_OFF)
     113           0 :                         sc->sc_state = ACPIPWRRES_UNK;
     114             :         } else
     115           0 :                 sc->sc_state = ACPIPWRRES_UNK;
     116             :         DPRINTF(("\n%s: state = %d\n", DEVNAME(sc), sc->sc_state));
     117           0 :         if (aml_evalnode(sc->sc_acpi, aaa->aaa_node, 0, NULL, &res) == 0) {
     118           0 :                 sc->sc_level = res.v_powerrsrc.pwr_level;
     119           0 :                 sc->sc_order = res.v_powerrsrc.pwr_order;
     120             :                 DPRINTF(("%s: level = %d, order %d\n", DEVNAME(sc),
     121             :                     sc->sc_level, sc->sc_order));
     122           0 :                 aml_freevalue(&res);
     123           0 :         }
     124             : 
     125             :         /* Get the list of consumers */
     126           0 :         SIMPLEQ_INIT(&sc->sc_cons);
     127             : #if notyet
     128             :         aml_find_node(&aml_root, "_PRW", acpipwrres_foundcons, sc);
     129             : #endif
     130           0 :         aml_find_node(&aml_root, "_PR0", acpipwrres_foundcons, sc);
     131           0 :         aml_find_node(&aml_root, "_PR1", acpipwrres_foundcons, sc);
     132           0 :         aml_find_node(&aml_root, "_PR2", acpipwrres_foundcons, sc);
     133           0 :         aml_find_node(&aml_root, "_PR3", acpipwrres_foundcons, sc);
     134             : 
     135             :         DPRINTF(("%s", DEVNAME(sc)));
     136           0 :         if (!SIMPLEQ_EMPTY(&sc->sc_cons)) {
     137           0 :                 printf(", resource for");
     138           0 :                 SIMPLEQ_FOREACH(cons, &sc->sc_cons, cs_next)
     139           0 :                         printf(" %s%s", cons->cs_node->name,
     140           0 :                            (SIMPLEQ_NEXT(cons, cs_next) == NULL) ? "" : ",");
     141             :         }
     142           0 :         printf("\n");
     143           0 : }
     144             : 
     145             : int
     146           0 : acpipwrres_ref_incr(struct acpipwrres_softc *sc, struct aml_node *node)
     147             : {
     148           0 :         struct aml_value                res;
     149             : 
     150           0 :         if (!acpipwrres_hascons(sc, node))
     151           0 :                 return (1);
     152             : 
     153             :         DPRINTF(("%s: dev %s ON %d\n", DEVNAME(sc), node->name,
     154             :             sc->sc_cons_ref));
     155             : 
     156           0 :         if (sc->sc_cons_ref++ == 0) {
     157           0 :                 memset(&res, 0, sizeof(res));
     158           0 :                 aml_evalname(sc->sc_acpi, sc->sc_devnode, "_ON", 0,
     159             :                     NULL, &res);
     160           0 :                 aml_freevalue(&res);
     161           0 :         }
     162             : 
     163           0 :         return (0);
     164           0 : }
     165             : 
     166             : int
     167           0 : acpipwrres_ref_decr(struct acpipwrres_softc *sc, struct aml_node *node)
     168             : {
     169           0 :         struct aml_value                res;
     170             : 
     171           0 :         if (!acpipwrres_hascons(sc, node))
     172           0 :                 return (1);
     173             : 
     174             :         DPRINTF(("%s: dev %s OFF %d\n", DEVNAME(sc), node->name,
     175             :             sc->sc_cons_ref));
     176             : 
     177           0 :         if (--sc->sc_cons_ref == 0) {
     178           0 :                 memset(&res, 0, sizeof(res));
     179           0 :                 aml_evalname(sc->sc_acpi, sc->sc_devnode, "_OFF", 0,
     180             :                     NULL, &res);
     181           0 :                 aml_freevalue(&res);
     182           0 :         }
     183             : 
     184           0 :         return (0);
     185           0 : }
     186             : 
     187             : int
     188           0 : acpipwrres_hascons(struct acpipwrres_softc *sc, struct aml_node *node)
     189             : {
     190             :         struct acpipwrres_consumer      *cons;
     191             : 
     192           0 :         SIMPLEQ_FOREACH(cons, &sc->sc_cons, cs_next) {
     193           0 :                 if (cons->cs_node == node)
     194           0 :                         return (1);
     195             :         }
     196             : 
     197           0 :         return (0);
     198           0 : }
     199             : 
     200             : int
     201           0 : acpipwrres_addcons(struct acpipwrres_softc *sc, struct aml_node *node)
     202             : {
     203             :         struct acpipwrres_consumer      *cons;
     204             :         struct acpi_pwrres              *pr;
     205             :         int                             state;
     206             : 
     207             :         /*
     208             :          * Add handlers to put the device into Dx states.
     209             :          *
     210             :          * XXX What about PRW?
     211             :          */
     212           0 :         if (strcmp(node->name, "_PR0") == 0) {
     213             :                 state = ACPI_STATE_D0;
     214           0 :         } else if (strcmp(node->name, "_PR1") == 0) {
     215             :                 state = ACPI_STATE_D1;
     216           0 :         } else if (strcmp(node->name, "_PR2") == 0) {
     217             :                 state = ACPI_STATE_D2;
     218           0 :         } else if (strcmp(node->name, "_PR3") == 0) {
     219             :                 state = ACPI_STATE_D3;
     220             :         } else {
     221           0 :                 return (0);
     222             :         }
     223             : 
     224           0 :         if (!acpipwrres_hascons(sc, node->parent)) {
     225           0 :                 cons = malloc(sizeof(*cons), M_DEVBUF, M_NOWAIT | M_ZERO);
     226           0 :                 if (cons == NULL)
     227           0 :                         return (ENOMEM);
     228             : 
     229           0 :                 cons->cs_node = node->parent;
     230           0 :                 SIMPLEQ_INSERT_TAIL(&sc->sc_cons, cons, cs_next);
     231           0 :         }
     232             : 
     233             :         DPRINTF(("%s: resource for %s (D%d) \n", DEVNAME(sc),
     234             :             node->parent->name, state));
     235             : 
     236             :         /*
     237             :          * Make sure we attach only once the same Power Resource for a
     238             :          * given state.
     239             :          */
     240           0 :         SIMPLEQ_FOREACH(pr, &sc->sc_acpi->sc_pwrresdevs, p_next) {
     241           0 :                 if (pr->p_node == node->parent &&
     242           0 :                     pr->p_res_state == state &&
     243           0 :                     pr->p_res_sc == sc) {
     244             :                         DPRINTF(("error: pr for %s already set\n",
     245             :                            aml_nodename(pr->p_node)));
     246           0 :                         return (EINVAL);
     247             :                 }
     248             :         }
     249             : 
     250           0 :         pr = malloc(sizeof(struct acpi_pwrres), M_DEVBUF, M_NOWAIT | M_ZERO);
     251           0 :         if (pr == NULL)
     252           0 :                 return (ENOMEM);
     253             : 
     254           0 :         pr->p_node = node->parent;
     255           0 :         pr->p_state = -1;
     256           0 :         pr->p_res_state = state;
     257           0 :         pr->p_res_sc = sc;
     258             : 
     259           0 :         SIMPLEQ_INSERT_TAIL(&sc->sc_acpi->sc_pwrresdevs, pr, p_next);
     260             : 
     261           0 :         return (0);
     262           0 : }
     263             : 
     264             : int
     265           0 : acpipwrres_foundcons(struct aml_node *node, void *arg)
     266             : {
     267           0 :         struct acpipwrres_softc         *sc = (struct acpipwrres_softc *)arg;
     268           0 :         struct aml_value                res, *ref;
     269             :         int                             i = 0;
     270             : 
     271             :         extern struct aml_node  aml_root;
     272             : 
     273           0 :         memset(&res, 0, sizeof(res));
     274             : 
     275           0 :         if (aml_evalnode(sc->sc_acpi, node, 0, NULL, &res) == -1) {
     276             :                 DPRINTF(("pwr: consumer not found\n"));
     277           0 :                 return (1);
     278             :         }
     279             : 
     280           0 :         if (res.type != AML_OBJTYPE_PACKAGE) {
     281             :                 DPRINTF(("%s: %s is not a package\n", DEVNAME(sc),
     282             :                     aml_nodename(node)));
     283           0 :                 aml_freevalue(&res);
     284           0 :                 return (1);
     285             :         }
     286             : 
     287             :         DPRINTF(("%s: node name %s\n", DEVNAME(sc), aml_nodename(node)));
     288           0 :         if (!strcmp(node->name, "_PRW"))
     289           0 :                 i = 2;          /* _PRW first two values are ints */
     290             : 
     291           0 :         for (; i < res.length; i++) {
     292           0 :                 ref = res.v_package[i];
     293             : 
     294           0 :                 if (ref->type == AML_OBJTYPE_STRING) {
     295             :                         struct aml_node *pnode;
     296             : 
     297           0 :                         pnode = aml_searchrel(&aml_root, ref->v_string);
     298           0 :                         if (pnode == NULL) {
     299             :                                 DPRINTF(("%s: device %s not found\n",
     300             :                                     DEVNAME(sc), ref->v_string));
     301           0 :                                 continue;
     302             :                         }
     303           0 :                         ref = pnode->value;
     304           0 :                 }
     305             : 
     306           0 :                 if (ref->type == AML_OBJTYPE_OBJREF)
     307           0 :                         ref = ref->v_objref.ref;
     308             : 
     309           0 :                 if (ref->type != AML_OBJTYPE_POWERRSRC) {
     310             :                         DPRINTF(("%s: object reference has a wrong type (%d)\n",
     311             :                             DEVNAME(sc), ref->type));
     312             :                         continue;
     313             :                 }
     314             : 
     315           0 :                 if (ref->node == sc->sc_devnode)
     316           0 :                         (void)acpipwrres_addcons(sc, node);
     317             :         }
     318           0 :         aml_freevalue(&res);
     319             : 
     320           0 :         return (0);
     321           0 : }

Generated by: LCOV version 1.13