LCOV - code coverage report
Current view: top level - dev/isa - aps.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 179 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: aps.c,v 1.26 2017/03/02 10:38:10 natano Exp $ */
       2             : /*
       3             :  * Copyright (c) 2005 Jonathan Gray <jsg@openbsd.org>
       4             :  * Copyright (c) 2008 Can Erkin Acar <canacar@openbsd.org>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : /*
      20             :  * A driver for the ThinkPad Active Protection System based on notes from
      21             :  * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html
      22             :  */
      23             : 
      24             : #include <sys/param.h>
      25             : #include <sys/systm.h>
      26             : #include <sys/device.h>
      27             : #include <sys/kernel.h>
      28             : #include <sys/sensors.h>
      29             : #include <sys/timeout.h>
      30             : #include <machine/bus.h>
      31             : #include <sys/event.h>
      32             : 
      33             : #include <dev/isa/isavar.h>
      34             : 
      35             : #ifdef __i386__
      36             : #include "apm.h"
      37             : #include <machine/acpiapm.h>
      38             : #include <machine/biosvar.h>
      39             : #include <machine/apmvar.h>
      40             : #endif
      41             : 
      42             : #if defined(APSDEBUG)
      43             : #define DPRINTF(x)              do { printf x; } while (0)
      44             : #else
      45             : #define DPRINTF(x)
      46             : #endif
      47             : 
      48             : 
      49             : /*
      50             :  * EC interface on Thinkpad Laptops, from Linux HDAPS driver notes.
      51             :  * From Renesans H8S/2140B Group Hardware Manual
      52             :  * http://documentation.renesas.com/eng/products/mpumcu/rej09b0300_2140bhm.pdf
      53             :  *
      54             :  * EC uses LPC Channel 3 registers TWR0..15
      55             :  */
      56             : 
      57             : /* STR3 status register */
      58             : #define APS_STR3                0x04
      59             : 
      60             : #define APS_STR3_IBF3B  0x80    /* Input buffer full (host->slave) */
      61             : #define APS_STR3_OBF3B  0x40    /* Output buffer full (slave->host)*/
      62             : #define APS_STR3_MWMF   0x20    /* Master write mode */
      63             : #define APS_STR3_SWMF   0x10    /* Slave write mode */
      64             : 
      65             : 
      66             : /* Base address of TWR registers */
      67             : #define APS_TWR_BASE            0x10
      68             : #define APS_TWR_RET             0x1f
      69             : 
      70             : /* TWR registers */
      71             : #define APS_CMD                 0x00
      72             : #define APS_ARG1                0x01
      73             : #define APS_ARG2                0x02
      74             : #define APS_ARG3                0x03
      75             : #define APS_RET                 0x0f
      76             : 
      77             : /* Sensor values */
      78             : #define APS_STATE               0x01
      79             : #define APS_XACCEL              0x02
      80             : #define APS_YACCEL              0x04
      81             : #define APS_TEMP                0x06
      82             : #define APS_XVAR                0x07
      83             : #define APS_YVAR                0x09
      84             : #define APS_TEMP2               0x0b
      85             : #define APS_UNKNOWN             0x0c
      86             : #define APS_INPUT               0x0d
      87             : 
      88             : /* write masks for I/O, send command + 0-3 arguments*/
      89             : #define APS_WRITE_0             0x0001
      90             : #define APS_WRITE_1             0x0003
      91             : #define APS_WRITE_2             0x0007
      92             : #define APS_WRITE_3             0x000f
      93             : 
      94             : /* read masks for I/O, read 0-3 values (skip command byte) */
      95             : #define APS_READ_0              0x0000
      96             : #define APS_READ_1              0x0002
      97             : #define APS_READ_2              0x0006
      98             : #define APS_READ_3              0x000e
      99             : 
     100             : #define APS_READ_RET            0x8000
     101             : #define APS_READ_ALL            0xffff
     102             : 
     103             : /* Bit definitions for APS_INPUT value */
     104             : #define APS_INPUT_KB            (1 << 5)
     105             : #define APS_INPUT_MS            (1 << 6)
     106             : #define APS_INPUT_LIDOPEN       (1 << 7)
     107             : 
     108             : #define APS_ADDR_SIZE           0x1f
     109             : 
     110             : struct sensor_rec {
     111             :         u_int8_t        state;
     112             :         u_int16_t       x_accel;
     113             :         u_int16_t       y_accel;
     114             :         u_int8_t        temp1;
     115             :         u_int16_t       x_var;
     116             :         u_int16_t       y_var;
     117             :         u_int8_t        temp2;
     118             :         u_int8_t        unk;
     119             :         u_int8_t        input;
     120             : };
     121             : 
     122             : #define APS_NUM_SENSORS         9
     123             : 
     124             : #define APS_SENSOR_XACCEL       0
     125             : #define APS_SENSOR_YACCEL       1
     126             : #define APS_SENSOR_XVAR         2
     127             : #define APS_SENSOR_YVAR         3
     128             : #define APS_SENSOR_TEMP1        4
     129             : #define APS_SENSOR_TEMP2        5
     130             : #define APS_SENSOR_KBACT        6
     131             : #define APS_SENSOR_MSACT        7
     132             : #define APS_SENSOR_LIDOPEN      8
     133             : 
     134             : struct aps_softc {
     135             :         struct device sc_dev;
     136             : 
     137             :         bus_space_tag_t aps_iot;
     138             :         bus_space_handle_t aps_ioh;
     139             : 
     140             :         struct ksensor sensors[APS_NUM_SENSORS];
     141             :         struct ksensordev sensordev;
     142             :         void (*refresh_sensor_data)(struct aps_softc *);
     143             : 
     144             :         struct sensor_rec aps_data;
     145             : };
     146             : 
     147             : int      aps_match(struct device *, void *, void *);
     148             : void     aps_attach(struct device *, struct device *, void *);
     149             : int      aps_activate(struct device *, int);
     150             : 
     151             : int      aps_init(bus_space_tag_t, bus_space_handle_t);
     152             : int      aps_read_data(struct aps_softc *);
     153             : void     aps_refresh_sensor_data(struct aps_softc *);
     154             : void     aps_refresh(void *);
     155             : int      aps_do_io(bus_space_tag_t, bus_space_handle_t,
     156             :                    unsigned char *, int, int);
     157             : 
     158             : struct cfattach aps_ca = {
     159             :         sizeof(struct aps_softc),
     160             :         aps_match, aps_attach, NULL, aps_activate
     161             : };
     162             : 
     163             : struct cfdriver aps_cd = {
     164             :         NULL, "aps", DV_DULL
     165             : };
     166             : 
     167             : struct timeout aps_timeout;
     168             : 
     169             : 
     170             : 
     171             : /* properly communicate with the controller, writing a set of memory
     172             :  * locations and reading back another set  */
     173             : int
     174           0 : aps_do_io(bus_space_tag_t iot, bus_space_handle_t ioh,
     175             :           unsigned char *buf, int wmask, int rmask)
     176             : {
     177             :         int bp, stat, n;
     178             : 
     179             :         DPRINTF(("aps_do_io: CMD: 0x%02x, wmask: 0x%04x, rmask: 0x%04x\n",
     180             :                buf[0], wmask, rmask));
     181             : 
     182             :         /* write init byte using arbitration */     
     183           0 :         for (n = 0; n < 100; n++) {
     184           0 :                 stat = bus_space_read_1(iot, ioh, APS_STR3);
     185           0 :                 if (stat & (APS_STR3_OBF3B | APS_STR3_SWMF)) {
     186           0 :                         bus_space_read_1(iot, ioh, APS_TWR_RET);
     187           0 :                         continue;
     188             :                 }
     189           0 :                 bus_space_write_1(iot, ioh, APS_TWR_BASE, buf[0]);
     190           0 :                 stat = bus_space_read_1(iot, ioh, APS_STR3);
     191           0 :                 if (stat & (APS_STR3_MWMF))
     192             :                         break;
     193           0 :                 delay(1);
     194           0 :         }
     195             : 
     196           0 :         if (n == 100) {
     197             :                 DPRINTF(("aps_do_io: Failed to get bus\n"));
     198           0 :                 return (1);
     199             :         }
     200             : 
     201             :         /* write data bytes, init already sent */
     202             :         /* make sure last bye is always written as this will trigger slave */
     203           0 :         wmask |= APS_READ_RET;
     204           0 :         buf[APS_RET] = 0x01;
     205             : 
     206           0 :         for (n = 1, bp = 2; n < 16; bp <<= 1, n++) {
     207           0 :                 if (wmask & bp) {
     208           0 :                         bus_space_write_1(iot, ioh, APS_TWR_BASE + n, buf[n]);
     209             :                         DPRINTF(("aps_do_io:  write %2d 0x%02x\n", n, buf[n]));
     210           0 :                 }
     211             :         }
     212             : 
     213           0 :         for (n = 0; n < 100; n++) {
     214           0 :                 stat = bus_space_read_1(iot, ioh, APS_STR3);
     215           0 :                 if (stat & (APS_STR3_OBF3B))
     216             :                         break;
     217           0 :                 delay(5 * 100);
     218             :         }
     219             : 
     220           0 :         if (n == 100) {
     221             :                 DPRINTF(("aps_do_io: timeout waiting response\n"));
     222           0 :                 return (1);
     223             :         }
     224             :         /* wait for data available */
     225             :         /* make sure to read the final byte to clear status */
     226           0 :         rmask |= APS_READ_RET;
     227             : 
     228             :         /* read cmd and data bytes */
     229           0 :         for (n = 0, bp = 1; n < 16; bp <<= 1, n++) {
     230           0 :                 if (rmask & bp) {
     231           0 :                         buf[n] = bus_space_read_1(iot, ioh, APS_TWR_BASE + n);
     232             :                         DPRINTF(("aps_do_io:  read %2d 0x%02x\n", n, buf[n]));
     233           0 :                 }
     234             :         }
     235             : 
     236           0 :         return (0);
     237           0 : }
     238             : 
     239             : int
     240           0 : aps_match(struct device *parent, void *match, void *aux)
     241             : {
     242           0 :         struct isa_attach_args *ia = aux;
     243           0 :         bus_space_tag_t iot = ia->ia_iot;
     244           0 :         bus_space_handle_t ioh;
     245           0 :         int iobase = ia->ipa_io[0].base;
     246             :         u_int8_t cr;
     247           0 :         unsigned char iobuf[16];
     248             : 
     249           0 :         if (bus_space_map(iot, iobase, APS_ADDR_SIZE, 0, &ioh)) {
     250             :                 DPRINTF(("aps: can't map i/o space\n"));
     251           0 :                 return (0);
     252             :         }
     253             :         /* get APS mode */
     254           0 :         iobuf[APS_CMD] = 0x13;
     255           0 :         if (aps_do_io(iot, ioh, iobuf, APS_WRITE_0, APS_READ_1)) {
     256           0 :                 bus_space_unmap(iot, ioh, APS_ADDR_SIZE);
     257           0 :                 return (0);
     258             :         }
     259             : 
     260             :         /*
     261             :          * Observed values from Linux driver:
     262             :          * 0x01: T42
     263             :          * 0x02: chip already initialised
     264             :          * 0x03: T41
     265             :          * 0x05: T61
     266             :          */
     267             : 
     268           0 :         cr = iobuf[APS_ARG1];
     269             :         DPRINTF(("aps: state register 0x%x\n", cr));
     270             : 
     271           0 :         if (aps_init(iot, ioh)) {
     272             :                 bus_space_unmap(iot, ioh, APS_ADDR_SIZE);
     273           0 :                 return (0);
     274             :         }
     275             : 
     276             :         bus_space_unmap(iot, ioh, APS_ADDR_SIZE);
     277             : 
     278           0 :         if (iobuf[APS_RET] != 0 || cr < 1 || cr > 5) {
     279             :                 DPRINTF(("aps0: unsupported state %d\n", cr));
     280           0 :                 return (0);
     281             :         }
     282             : 
     283           0 :         ia->ipa_nio = 1;
     284           0 :         ia->ipa_io[0].length = APS_ADDR_SIZE;
     285           0 :         ia->ipa_nmem = 0;
     286           0 :         ia->ipa_nirq = 0;
     287           0 :         ia->ipa_ndrq = 0;
     288           0 :         return (1);
     289           0 : }
     290             : 
     291             : void
     292           0 : aps_attach(struct device *parent, struct device *self, void *aux)
     293             : {
     294           0 :         struct aps_softc *sc = (void *)self;
     295             :         int iobase, i;
     296             :         bus_space_tag_t iot;
     297             :         bus_space_handle_t ioh;
     298           0 :         struct isa_attach_args *ia = aux;
     299             : 
     300           0 :         iobase = ia->ipa_io[0].base;
     301           0 :         iot = sc->aps_iot = ia->ia_iot;
     302             : 
     303           0 :         if (bus_space_map(iot, iobase, APS_ADDR_SIZE, 0, &sc->aps_ioh)) {
     304           0 :                 printf(": can't map i/o space\n");
     305           0 :                 return;
     306             :         }
     307             : 
     308             :         ioh = sc->aps_ioh;
     309             : 
     310           0 :         printf("\n");
     311             : 
     312           0 :         sc->sensors[APS_SENSOR_XACCEL].type = SENSOR_INTEGER;
     313           0 :         snprintf(sc->sensors[APS_SENSOR_XACCEL].desc,
     314             :             sizeof(sc->sensors[APS_SENSOR_XACCEL].desc), "X_ACCEL");
     315             : 
     316           0 :         sc->sensors[APS_SENSOR_YACCEL].type = SENSOR_INTEGER;
     317           0 :         snprintf(sc->sensors[APS_SENSOR_YACCEL].desc,
     318             :             sizeof(sc->sensors[APS_SENSOR_YACCEL].desc), "Y_ACCEL");
     319             : 
     320           0 :         sc->sensors[APS_SENSOR_TEMP1].type = SENSOR_TEMP;
     321           0 :         sc->sensors[APS_SENSOR_TEMP2].type = SENSOR_TEMP;
     322             : 
     323           0 :         sc->sensors[APS_SENSOR_XVAR].type = SENSOR_INTEGER;
     324           0 :         snprintf(sc->sensors[APS_SENSOR_XVAR].desc,
     325             :             sizeof(sc->sensors[APS_SENSOR_XVAR].desc), "X_VAR");
     326             : 
     327           0 :         sc->sensors[APS_SENSOR_YVAR].type = SENSOR_INTEGER;
     328           0 :         snprintf(sc->sensors[APS_SENSOR_YVAR].desc,
     329             :             sizeof(sc->sensors[APS_SENSOR_YVAR].desc), "Y_VAR");
     330             : 
     331           0 :         sc->sensors[APS_SENSOR_KBACT].type = SENSOR_INDICATOR;
     332           0 :         snprintf(sc->sensors[APS_SENSOR_KBACT].desc,
     333             :             sizeof(sc->sensors[APS_SENSOR_KBACT].desc), "Keyboard Active");
     334             : 
     335           0 :         sc->sensors[APS_SENSOR_MSACT].type = SENSOR_INDICATOR;
     336           0 :         snprintf(sc->sensors[APS_SENSOR_MSACT].desc,
     337             :             sizeof(sc->sensors[APS_SENSOR_MSACT].desc), "Mouse Active");
     338             : 
     339           0 :         sc->sensors[APS_SENSOR_LIDOPEN].type = SENSOR_INDICATOR;
     340           0 :         snprintf(sc->sensors[APS_SENSOR_LIDOPEN].desc,
     341             :             sizeof(sc->sensors[APS_SENSOR_LIDOPEN].desc), "Lid Open");
     342             : 
     343             :         /* stop hiding and report to the authorities */
     344           0 :         strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
     345             :             sizeof(sc->sensordev.xname));
     346           0 :         for (i = 0; i < APS_NUM_SENSORS ; i++) {
     347           0 :                 sensor_attach(&sc->sensordev, &sc->sensors[i]);
     348             :         }
     349           0 :         sensordev_install(&sc->sensordev);
     350             : 
     351             :         /* Refresh sensor data every 0.5 seconds */
     352           0 :         timeout_set(&aps_timeout, aps_refresh, sc);
     353           0 :         timeout_add_msec(&aps_timeout, 500);
     354           0 : }
     355             : 
     356             : int
     357           0 : aps_init(bus_space_tag_t iot, bus_space_handle_t ioh)
     358             : {
     359           0 :         unsigned char iobuf[16];
     360             : 
     361             : 
     362             :         /* command 0x17/0x81: check EC */
     363           0 :         iobuf[APS_CMD] = 0x17;
     364           0 :         iobuf[APS_ARG1] = 0x81;
     365             : 
     366           0 :         if (aps_do_io(iot, ioh, iobuf, APS_WRITE_1, APS_READ_3))
     367           0 :                 return (1);
     368             : 
     369           0 :         if (iobuf[APS_RET] != 0 ||iobuf[APS_ARG3] != 0)
     370           0 :                 return (2);
     371             : 
     372             :         /* Test values from the Linux driver */
     373           0 :         if ((iobuf[APS_ARG1] != 0 || iobuf[APS_ARG2] != 0x60) &&
     374           0 :             (iobuf[APS_ARG1] != 1 || iobuf[APS_ARG2] != 0))
     375           0 :                 return (3);
     376             : 
     377             :         /* command 0x14: set power */
     378           0 :         iobuf[APS_CMD] = 0x14;
     379           0 :         iobuf[APS_ARG1] = 0x01;
     380             : 
     381           0 :         if (aps_do_io(iot, ioh, iobuf, APS_WRITE_1, APS_READ_0))
     382           0 :                 return (4);
     383             : 
     384           0 :         if (iobuf[APS_RET] != 0)
     385           0 :                 return (5);
     386             : 
     387             :         /* command 0x10: set config (sample rate and order) */
     388           0 :         iobuf[APS_CMD] = 0x10;
     389           0 :         iobuf[APS_ARG1] = 0xc8;
     390           0 :         iobuf[APS_ARG2] = 0x00;
     391           0 :         iobuf[APS_ARG3] = 0x02;
     392             : 
     393           0 :         if (aps_do_io(iot, ioh, iobuf, APS_WRITE_3, APS_READ_0))
     394           0 :                 return (6);
     395             : 
     396           0 :         if (iobuf[APS_RET] != 0)
     397           0 :                 return (7);
     398             : 
     399             :         /* command 0x11: refresh data */
     400           0 :         iobuf[APS_CMD] = 0x11;
     401           0 :         if (aps_do_io(iot, ioh, iobuf, APS_WRITE_0, APS_READ_1))
     402           0 :                 return (8);
     403             : 
     404           0 :         return (0);
     405           0 : }
     406             : 
     407             : int
     408           0 : aps_read_data(struct aps_softc *sc)
     409             : {
     410           0 :         bus_space_tag_t iot = sc->aps_iot;
     411           0 :         bus_space_handle_t ioh = sc->aps_ioh;
     412           0 :         unsigned char iobuf[16];
     413             : 
     414             :         /* command 0x11: refresh data */
     415           0 :         iobuf[APS_CMD] = 0x11;
     416           0 :         if (aps_do_io(iot, ioh, iobuf, APS_WRITE_0, APS_READ_ALL))
     417           0 :                 return (1);
     418             : 
     419           0 :         sc->aps_data.state = iobuf[APS_STATE];
     420           0 :         sc->aps_data.x_accel = iobuf[APS_XACCEL] + 256 * iobuf[APS_XACCEL + 1];
     421           0 :         sc->aps_data.y_accel = iobuf[APS_YACCEL] + 256 * iobuf[APS_YACCEL + 1];
     422           0 :         sc->aps_data.temp1 = iobuf[APS_TEMP];
     423           0 :         sc->aps_data.x_var = iobuf[APS_XVAR] + 256 * iobuf[APS_XVAR + 1];
     424           0 :         sc->aps_data.y_var = iobuf[APS_YVAR] + 256 * iobuf[APS_YVAR + 1];
     425           0 :         sc->aps_data.temp2 = iobuf[APS_TEMP2];
     426           0 :         sc->aps_data.input = iobuf[APS_INPUT];
     427             : 
     428           0 :         return (0);
     429           0 : }
     430             : 
     431             : void
     432           0 : aps_refresh_sensor_data(struct aps_softc *sc)
     433             : {
     434             :         int64_t temp;
     435             :         int i;
     436             : #if NAPM > 0
     437             :         extern int lid_action;
     438             :         extern int apm_lidclose;
     439             : #endif
     440             : 
     441           0 :         if (aps_read_data(sc))
     442           0 :                 return;
     443             : 
     444           0 :         for (i = 0; i < APS_NUM_SENSORS; i++) {
     445           0 :                 sc->sensors[i].flags &= ~SENSOR_FINVALID;
     446             :         }
     447             : 
     448           0 :         sc->sensors[APS_SENSOR_XACCEL].value = sc->aps_data.x_accel;
     449           0 :         sc->sensors[APS_SENSOR_YACCEL].value = sc->aps_data.y_accel;
     450             : 
     451             :         /* convert to micro (mu) degrees */
     452           0 :         temp = sc->aps_data.temp1 * 1000000; 
     453             :         /* convert to kelvin */
     454           0 :         temp += 273150000; 
     455           0 :         sc->sensors[APS_SENSOR_TEMP1].value = temp;
     456             : 
     457             :         /* convert to micro (mu) degrees */
     458           0 :         temp = sc->aps_data.temp2 * 1000000; 
     459             :         /* convert to kelvin */
     460           0 :         temp += 273150000; 
     461           0 :         sc->sensors[APS_SENSOR_TEMP2].value = temp;
     462             : 
     463           0 :         sc->sensors[APS_SENSOR_XVAR].value = sc->aps_data.x_var;
     464           0 :         sc->sensors[APS_SENSOR_YVAR].value = sc->aps_data.y_var;
     465           0 :         sc->sensors[APS_SENSOR_KBACT].value =
     466           0 :             (sc->aps_data.input &  APS_INPUT_KB) ? 1 : 0;
     467           0 :         sc->sensors[APS_SENSOR_MSACT].value =
     468           0 :             (sc->aps_data.input & APS_INPUT_MS) ? 1 : 0;
     469             : #if NAPM > 0
     470             :         if (lid_action &&
     471             :             (sc->sensors[APS_SENSOR_LIDOPEN].value == 1) &&
     472             :             (sc->aps_data.input & APS_INPUT_LIDOPEN) == 0)
     473             :                 /* Inform APM that the lid has closed */
     474             :                 apm_lidclose = 1;
     475             : #endif
     476           0 :         sc->sensors[APS_SENSOR_LIDOPEN].value =
     477           0 :             (sc->aps_data.input & APS_INPUT_LIDOPEN) ? 1 : 0;
     478           0 : }
     479             : 
     480             : void
     481           0 : aps_refresh(void *arg)
     482             : {
     483           0 :         struct aps_softc *sc = (struct aps_softc *)arg;
     484             : 
     485           0 :         aps_refresh_sensor_data(sc);
     486           0 :         timeout_add_msec(&aps_timeout, 500);
     487           0 : }
     488             : 
     489             : int
     490           0 : aps_activate(struct device *self, int act)
     491             : {
     492           0 :         struct aps_softc *sc = (struct aps_softc *)self;
     493           0 :         bus_space_tag_t iot = sc->aps_iot;
     494           0 :         bus_space_handle_t ioh = sc->aps_ioh;
     495           0 :         unsigned char iobuf[16];
     496             : 
     497             :         /* check if we bombed during attach */
     498           0 :         if (!timeout_initialized(&aps_timeout))
     499           0 :                 return (0);
     500             : 
     501           0 :         switch (act) {
     502             :         case DVACT_SUSPEND:
     503           0 :                 timeout_del(&aps_timeout);
     504           0 :                 break;
     505             :         case DVACT_RESUME:
     506             :                 /*
     507             :                  * Redo the init sequence on resume, because APS is 
     508             :                  * as forgetful as it is deaf.
     509             :                  */
     510             : 
     511             :                 /* get APS mode */
     512           0 :                 iobuf[APS_CMD] = 0x13;
     513           0 :                 aps_do_io(iot, ioh, iobuf, APS_WRITE_0, APS_READ_1);
     514             : 
     515           0 :                 aps_init(iot, ioh);
     516           0 :                 timeout_add_msec(&aps_timeout, 500);
     517           0 :                 break;
     518             :         }
     519           0 :         return (0);
     520           0 : }

Generated by: LCOV version 1.13