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

          Line data    Source code
       1             : /*      $OpenBSD: acpivout.c,v 1.12 2016/03/29 17:52:04 kettenis Exp $  */
       2             : /*
       3             :  * Copyright (c) 2009 Paul Irofti <pirofti@openbsd.org>
       4             :  *
       5             :  * Permission to use, copy, modify, and/or 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/systm.h>
      20             : #include <sys/device.h>
      21             : #include <sys/malloc.h>
      22             : 
      23             : #include <machine/bus.h>
      24             : 
      25             : #include <dev/acpi/acpivar.h>
      26             : #include <dev/acpi/acpidev.h>
      27             : #include <dev/acpi/amltypes.h>
      28             : #include <dev/acpi/dsdt.h>
      29             : 
      30             : #include <dev/wscons/wsconsio.h>
      31             : 
      32             : int     acpivout_match(struct device *, void *, void *);
      33             : void    acpivout_attach(struct device *, struct device *, void *);
      34             : int     acpivout_notify(struct aml_node *, int, void *);
      35             : 
      36             : #ifdef ACPIVIDEO_DEBUG
      37             : #define DPRINTF(x)      printf x
      38             : #else
      39             : #define DPRINTF(x)
      40             : #endif
      41             : 
      42             : /* Notifications for Output Devices */
      43             : #define NOTIFY_BRIGHTNESS_CYCLE         0x85
      44             : #define NOTIFY_BRIGHTNESS_UP            0x86
      45             : #define NOTIFY_BRIGHTNESS_DOWN          0x87
      46             : #define NOTIFY_BRIGHTNESS_ZERO          0x88
      47             : #define NOTIFY_DISPLAY_OFF              0x89
      48             : 
      49             : struct acpivout_softc {
      50             :         struct device           sc_dev;
      51             : 
      52             :         bus_space_tag_t         sc_iot;
      53             :         bus_space_handle_t      sc_ioh;
      54             : 
      55             :         struct acpi_softc       *sc_acpi;
      56             :         struct aml_node         *sc_devnode;
      57             : 
      58             :         int     *sc_bcl;
      59             :         size_t  sc_bcl_len;
      60             : };
      61             : 
      62             : void    acpivout_brightness_cycle(struct acpivout_softc *);
      63             : void    acpivout_brightness_up(struct acpivout_softc *);
      64             : void    acpivout_brightness_down(struct acpivout_softc *);
      65             : void    acpivout_brightness_zero(struct acpivout_softc *);
      66             : int     acpivout_get_brightness(struct acpivout_softc *);
      67             : int     acpivout_find_brightness(struct acpivout_softc *, int);
      68             : void    acpivout_set_brightness(struct acpivout_softc *, int);
      69             : void    acpivout_get_bcl(struct acpivout_softc *);
      70             : 
      71             : /* wconsole hook functions */
      72             : int     acpivout_get_param(struct wsdisplay_param *);
      73             : int     acpivout_set_param(struct wsdisplay_param *);
      74             : 
      75             : extern int (*ws_get_param)(struct wsdisplay_param *);
      76             : extern int (*ws_set_param)(struct wsdisplay_param *);
      77             : 
      78             : struct cfattach acpivout_ca = {
      79             :         sizeof(struct acpivout_softc), acpivout_match, acpivout_attach
      80             : };
      81             : 
      82             : struct cfdriver acpivout_cd = {
      83             :         NULL, "acpivout", DV_DULL
      84             : };
      85             : 
      86             : int
      87           0 : acpivout_match(struct device *parent, void *match, void *aux)
      88             : {
      89           0 :         struct acpi_attach_args *aaa = aux;
      90           0 :         struct cfdata           *cf = match;
      91             : 
      92           0 :         if (aaa->aaa_name == NULL ||
      93           0 :             strcmp(aaa->aaa_name, cf->cf_driver->cd_name) != 0 ||
      94           0 :             aaa->aaa_table != NULL)
      95           0 :                 return (0);
      96             : 
      97           0 :         if (ws_get_param || ws_set_param)
      98           0 :                 return (0);
      99             : 
     100           0 :         return (1);
     101           0 : }
     102             : 
     103             : void
     104           0 : acpivout_attach(struct device *parent, struct device *self, void *aux)
     105             : {
     106           0 :         struct acpivout_softc   *sc = (struct acpivout_softc *)self;
     107           0 :         struct acpi_attach_args *aaa = aux;
     108             : 
     109           0 :         sc->sc_acpi = ((struct acpivideo_softc *)parent)->sc_acpi;
     110           0 :         sc->sc_devnode = aaa->aaa_node;
     111             : 
     112           0 :         printf(": %s\n", sc->sc_devnode->name);
     113             : 
     114           0 :         aml_register_notify(sc->sc_devnode, aaa->aaa_dev,
     115           0 :             acpivout_notify, sc, ACPIDEV_NOPOLL);
     116             : 
     117           0 :         ws_get_param = acpivout_get_param;
     118           0 :         ws_set_param = acpivout_set_param;
     119             : 
     120           0 :         acpivout_get_bcl(sc);
     121           0 : }
     122             : 
     123             : int
     124           0 : acpivout_notify(struct aml_node *node, int notify, void *arg)
     125             : {
     126           0 :         struct acpivout_softc *sc = arg;
     127             : 
     128           0 :         switch (notify) {
     129             :         case NOTIFY_BRIGHTNESS_CYCLE:
     130           0 :                 acpivout_brightness_cycle(sc);
     131           0 :                 break;
     132             :         case NOTIFY_BRIGHTNESS_UP:
     133           0 :                 acpivout_brightness_up(sc);
     134           0 :                 break;
     135             :         case NOTIFY_BRIGHTNESS_DOWN:
     136           0 :                 acpivout_brightness_down(sc);
     137           0 :                 break;
     138             :         case NOTIFY_BRIGHTNESS_ZERO:
     139           0 :                 acpivout_brightness_zero(sc);
     140           0 :                 break;
     141             :         case NOTIFY_DISPLAY_OFF:
     142             :                 /* TODO: D3 state change */
     143             :                 break;
     144             :         default:
     145           0 :                 printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify);
     146           0 :                 break;
     147             :         }
     148             : 
     149           0 :         return (0);
     150             : }
     151             : 
     152             : void
     153           0 : acpivout_brightness_cycle(struct acpivout_softc *sc)
     154             : {
     155             :         int     cur_level;
     156             : 
     157           0 :         if (sc->sc_bcl_len == 0)
     158           0 :                 return;
     159           0 :         cur_level = acpivout_get_brightness(sc);
     160           0 :         if (cur_level == sc->sc_bcl[sc->sc_bcl_len - 1])
     161           0 :                 acpivout_brightness_zero(sc);
     162             :         else
     163           0 :                 acpivout_brightness_up(sc);
     164           0 : }
     165             : 
     166             : void
     167           0 : acpivout_brightness_up(struct acpivout_softc *sc)
     168             : {
     169             :         int i, cur_level;
     170             : 
     171           0 :         if (sc->sc_bcl_len == 0)
     172           0 :                 return;
     173           0 :         cur_level = acpivout_get_brightness(sc);
     174           0 :         if (cur_level == -1)
     175           0 :                 return;
     176             : 
     177             :         /* check for max brightness level */
     178           0 :         if (cur_level == sc->sc_bcl[sc->sc_bcl_len - 1])
     179           0 :                 return;
     180             : 
     181           0 :         for (i = 0; i < sc->sc_bcl_len && cur_level != sc->sc_bcl[i]; i++);
     182           0 :         acpivout_set_brightness(sc, sc->sc_bcl[i + 1]);
     183           0 : }
     184             : 
     185             : void
     186           0 : acpivout_brightness_down(struct acpivout_softc *sc)
     187             : {
     188             :         int i, cur_level;
     189             : 
     190           0 :         if (sc->sc_bcl_len == 0)
     191           0 :                 return;
     192           0 :         cur_level = acpivout_get_brightness(sc);
     193           0 :         if (cur_level == -1)
     194           0 :                 return;
     195             : 
     196             :         /* check for min brightness level */
     197           0 :         if (cur_level == sc->sc_bcl[0])
     198           0 :                 return;
     199             : 
     200           0 :         for (i = 0; i < sc->sc_bcl_len && cur_level != sc->sc_bcl[i]; i++);
     201           0 :         acpivout_set_brightness(sc, sc->sc_bcl[i - 1]);
     202           0 : }
     203             : 
     204             : void
     205           0 : acpivout_brightness_zero(struct acpivout_softc *sc)
     206             : {
     207           0 :         if (sc->sc_bcl_len == 0)
     208             :                 return;
     209           0 :         acpivout_set_brightness(sc, sc->sc_bcl[0]);
     210           0 : }
     211             : 
     212             : int
     213           0 : acpivout_get_brightness(struct acpivout_softc *sc)
     214             : {
     215           0 :         struct aml_value res;
     216             :         int level;
     217             : 
     218           0 :         aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BQC", 0, NULL, &res);
     219           0 :         level = aml_val2int(&res);
     220           0 :         aml_freevalue(&res);
     221             :         DPRINTF(("%s: BQC = %d\n", DEVNAME(sc), level));
     222             : 
     223           0 :         if (level < sc->sc_bcl[0] || level > sc->sc_bcl[sc->sc_bcl_len -1])
     224           0 :                 level = -1;
     225             : 
     226           0 :         return (level);
     227           0 : }
     228             : 
     229             : int
     230           0 : acpivout_find_brightness(struct acpivout_softc *sc, int level)
     231             : {
     232             :         int i, mid;
     233             : 
     234           0 :         for (i = 0; i < sc->sc_bcl_len - 1; i++) {
     235           0 :                 mid = sc->sc_bcl[i] + (sc->sc_bcl[i + 1] - sc->sc_bcl[i]) / 2;
     236           0 :                 if (sc->sc_bcl[i] <= level && level <=  mid)
     237           0 :                         return sc->sc_bcl[i];
     238           0 :                 if  (mid < level && level <= sc->sc_bcl[i + 1])
     239           0 :                         return sc->sc_bcl[i + 1];
     240             :         }
     241           0 :         if (level < sc->sc_bcl[0])
     242           0 :                 return sc->sc_bcl[0];
     243             :         else
     244           0 :                 return sc->sc_bcl[i];
     245           0 : }
     246             : 
     247             : void
     248           0 : acpivout_set_brightness(struct acpivout_softc *sc, int level)
     249             : {
     250           0 :         struct aml_value args, res;
     251             : 
     252           0 :         memset(&args, 0, sizeof(args));
     253           0 :         args.v_integer = level;
     254           0 :         args.type = AML_OBJTYPE_INTEGER;
     255             : 
     256             :         DPRINTF(("%s: BCM = %d\n", DEVNAME(sc), level));
     257           0 :         aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BCM", 1, &args, &res);
     258             : 
     259           0 :         aml_freevalue(&res);
     260           0 : }
     261             : 
     262             : void
     263           0 : acpivout_get_bcl(struct acpivout_softc *sc)
     264             : {
     265             :         int     i, j, value;
     266           0 :         struct aml_value res;
     267             : 
     268             :         DPRINTF(("Getting _BCL!"));
     269           0 :         aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BCL", 0, NULL, &res);
     270           0 :         if (res.type != AML_OBJTYPE_PACKAGE) {
     271           0 :                 sc->sc_bcl_len = 0;
     272           0 :                 goto err;
     273             :         }
     274             :         /*
     275             :          * Per the ACPI spec section B.6.2 the _BCL method returns a package.
     276             :          * The first integer in the package is the brightness level
     277             :          * when the computer has full power, and the second is the
     278             :          * brightness level when the computer is on batteries.
     279             :          * All other levels may be used by OSPM.
     280             :          * So we skip the first two integers in the package.
     281             :          */
     282           0 :         if (res.length <= 2) {
     283           0 :                 sc->sc_bcl_len = 0;
     284           0 :                 goto err;
     285             :         }
     286           0 :         sc->sc_bcl_len = res.length - 2;
     287             : 
     288           0 :         sc->sc_bcl = mallocarray(sc->sc_bcl_len, sizeof(int), M_DEVBUF,
     289             :             M_WAITOK | M_ZERO);
     290             : 
     291           0 :         for (i = 0; i < sc->sc_bcl_len; i++) {
     292             :                 /* Sort darkest to brightest */
     293           0 :                 value = aml_val2int(res.v_package[i + 2]);
     294           0 :                 for (j = i; j > 0 && sc->sc_bcl[j - 1] > value; j--)
     295           0 :                         sc->sc_bcl[j] = sc->sc_bcl[j - 1];
     296           0 :                  sc->sc_bcl[j] = value;
     297             :         }
     298             : 
     299             : err:
     300           0 :         aml_freevalue(&res);
     301           0 : }
     302             : 
     303             : 
     304             : int
     305           0 : acpivout_get_param(struct wsdisplay_param *dp)
     306             : {
     307             :         struct acpivout_softc   *sc = NULL;
     308             :         int i;
     309             : 
     310           0 :         switch (dp->param) {
     311             :         case WSDISPLAYIO_PARAM_BRIGHTNESS:
     312           0 :                 for (i = 0; i < acpivout_cd.cd_ndevs; i++) {
     313           0 :                         if (acpivout_cd.cd_devs[i] == NULL)
     314             :                                 continue;
     315           0 :                         sc = (struct acpivout_softc *)acpivout_cd.cd_devs[i];
     316             :                         /* Ignore device if not connected. */
     317           0 :                         if (sc->sc_bcl_len != 0)
     318             :                                 break;
     319             :                 }
     320           0 :                 if (sc != NULL && sc->sc_bcl_len != 0) {
     321           0 :                         dp->min = 0;
     322           0 :                         dp->max =  sc->sc_bcl[sc->sc_bcl_len - 1];
     323           0 :                         rw_enter_write(&sc->sc_acpi->sc_lck);
     324           0 :                         dp->curval = acpivout_get_brightness(sc);
     325           0 :                         rw_exit_write(&sc->sc_acpi->sc_lck);
     326           0 :                         if (dp->curval != -1)
     327           0 :                                 return 0;
     328             :                 }
     329           0 :                 return -1;
     330             :         default:
     331           0 :                 return -1;
     332             :         }
     333           0 : }
     334             : 
     335             : int
     336           0 : acpivout_set_param(struct wsdisplay_param *dp)
     337             : {
     338             :         struct acpivout_softc   *sc = NULL;
     339             :         int i, exact;
     340             : 
     341           0 :         switch (dp->param) {
     342             :         case WSDISPLAYIO_PARAM_BRIGHTNESS:
     343           0 :                 for (i = 0; i < acpivout_cd.cd_ndevs; i++) {
     344           0 :                         if (acpivout_cd.cd_devs[i] == NULL)
     345             :                                 continue;
     346           0 :                         sc = (struct acpivout_softc *)acpivout_cd.cd_devs[i];
     347             :                         /* Ignore device if not connected. */
     348           0 :                         if (sc->sc_bcl_len != 0)
     349             :                                 break;
     350             :                 }
     351           0 :                 if (sc != NULL && sc->sc_bcl_len != 0) {
     352           0 :                         rw_enter_write(&sc->sc_acpi->sc_lck);
     353           0 :                         exact = acpivout_find_brightness(sc, dp->curval);
     354           0 :                         acpivout_set_brightness(sc, exact);
     355           0 :                         rw_exit_write(&sc->sc_acpi->sc_lck);
     356           0 :                         return 0;
     357             :                 }
     358           0 :                 return -1;
     359             :         default:
     360           0 :                 return -1;
     361             :         }
     362           0 : }

Generated by: LCOV version 1.13