[BACK]Return to aps.c CVS log [TXT][DIR] Up to [local] / sys / dev / isa

Annotation of sys/dev/isa/aps.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: aps.c,v 1.15 2007/05/19 19:14:11 tedu Exp $   */
                      2: /*
                      3:  * Copyright (c) 2005 Jonathan Gray <jsg@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: /*
                     19:  * A driver for the ThinkPad Active Protection System based on notes from
                     20:  * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html
                     21:  */
                     22:
                     23: #include <sys/param.h>
                     24: #include <sys/systm.h>
                     25: #include <sys/device.h>
                     26: #include <sys/kernel.h>
                     27: #include <sys/sensors.h>
                     28: #include <sys/timeout.h>
                     29: #include <machine/bus.h>
                     30:
                     31: #include <dev/isa/isareg.h>
                     32: #include <dev/isa/isavar.h>
                     33:
                     34: #if defined(APSDEBUG)
                     35: #define DPRINTF(x)             do { printf x; } while (0)
                     36: #else
                     37: #define DPRINTF(x)
                     38: #endif
                     39:
                     40: #define APS_ACCEL_STATE                0x04
                     41: #define APS_INIT               0x10
                     42: #define APS_STATE              0x11
                     43: #define        APS_XACCEL              0x12
                     44: #define APS_YACCEL             0x14
                     45: #define APS_TEMP               0x16
                     46: #define        APS_XVAR                0x17
                     47: #define APS_YVAR               0x19
                     48: #define APS_TEMP2              0x1b
                     49: #define APS_UNKNOWN            0x1c
                     50: #define APS_INPUT              0x1d
                     51: #define APS_CMD                        0x1f
                     52:
                     53: #define        APS_STATE_NEWDATA       0x50
                     54:
                     55: #define APS_CMD_START          0x01
                     56:
                     57: #define APS_INPUT_KB           (1 << 5)
                     58: #define APS_INPUT_MS           (1 << 6)
                     59: #define APS_INPUT_LIDOPEN      (1 << 7)
                     60:
                     61: #define APS_ADDR_SIZE          0x1f
                     62:
                     63: struct sensor_rec {
                     64:        u_int8_t        state;
                     65:        u_int16_t       x_accel;
                     66:        u_int16_t       y_accel;
                     67:        u_int8_t        temp1;
                     68:        u_int16_t       x_var;
                     69:        u_int16_t       y_var;
                     70:        u_int8_t        temp2;
                     71:        u_int8_t        unk;
                     72:        u_int8_t        input;
                     73: };
                     74:
                     75: #define APS_NUM_SENSORS                9
                     76:
                     77: #define APS_SENSOR_XACCEL      0
                     78: #define APS_SENSOR_YACCEL      1
                     79: #define APS_SENSOR_XVAR                2
                     80: #define APS_SENSOR_YVAR                3
                     81: #define APS_SENSOR_TEMP1       4
                     82: #define APS_SENSOR_TEMP2       5
                     83: #define APS_SENSOR_KBACT       6
                     84: #define APS_SENSOR_MSACT       7
                     85: #define APS_SENSOR_LIDOPEN     8
                     86:
                     87: struct aps_softc {
                     88:        struct device sc_dev;
                     89:
                     90:        bus_space_tag_t aps_iot;
                     91:        bus_space_handle_t aps_ioh;
                     92:
                     93:        struct ksensor sensors[APS_NUM_SENSORS];
                     94:        struct ksensordev sensordev;
                     95:        void (*refresh_sensor_data)(struct aps_softc *);
                     96:
                     97:        struct sensor_rec aps_data;
                     98: };
                     99:
                    100: int     aps_match(struct device *, void *, void *);
                    101: void    aps_attach(struct device *, struct device *, void *);
                    102:
                    103: int     aps_init(bus_space_tag_t, bus_space_handle_t);
                    104: u_int8_t aps_mem_read_1(bus_space_tag_t, bus_space_handle_t, int, u_int8_t);
                    105: int     aps_read_data(struct aps_softc *);
                    106: void    aps_refresh_sensor_data(struct aps_softc *sc);
                    107: void    aps_refresh(void *);
                    108: void    aps_power(int, void *);
                    109:
                    110: struct cfattach aps_ca = {
                    111:        sizeof(struct aps_softc),
                    112:        aps_match,
                    113:        aps_attach
                    114: };
                    115:
                    116: struct cfdriver aps_cd = {
                    117:        NULL, "aps", DV_DULL
                    118: };
                    119:
                    120: struct timeout aps_timeout;
                    121:
                    122: int
                    123: aps_match(struct device *parent, void *match, void *aux)
                    124: {
                    125:        bus_space_tag_t iot;
                    126:        bus_space_handle_t ioh;
                    127:        struct isa_attach_args *ia = aux;
                    128:        int iobase, i;
                    129:        u_int8_t cr;
                    130:
                    131:        iot = ia->ia_iot;
                    132:        iobase = ia->ipa_io[0].base;
                    133:
                    134:        if (bus_space_map(iot, iobase, APS_ADDR_SIZE, 0, &ioh)) {
                    135:                DPRINTF(("aps: can't map i/o space\n"));
                    136:                return (0);
                    137:        }
                    138:
                    139:        /* See if this machine has APS */
                    140:        bus_space_write_1(iot, ioh, APS_INIT, 0x13);
                    141:        bus_space_write_1(iot, ioh, APS_CMD, 0x01);
                    142:
                    143:        /* ask again as the X40 is slightly deaf in one ear */
                    144:        bus_space_read_1(iot, ioh, APS_CMD);
                    145:        bus_space_write_1(iot, ioh, APS_INIT, 0x13);
                    146:        bus_space_write_1(iot, ioh, APS_CMD, 0x01);
                    147:
                    148:        if (!aps_mem_read_1(iot, ioh, APS_CMD, 0x00)) {
                    149:                bus_space_unmap(iot, ioh, APS_ADDR_SIZE);
                    150:                return (0);
                    151:        }
                    152:
                    153:        /*
                    154:         * Observed values from Linux driver:
                    155:         * 0x01: T42
                    156:         * 0x02: chip already initialised
                    157:         * 0x03: T41
                    158:         */
                    159:        for (i = 0; i < 10; i++) {
                    160:                cr = bus_space_read_1(iot, ioh, APS_STATE);
                    161:                if (cr > 0 && cr < 6)
                    162:                        break;
                    163:                delay(5 * 1000);
                    164:        }
                    165:
                    166:        bus_space_unmap(iot, ioh, APS_ADDR_SIZE);
                    167:        DPRINTF(("aps: state register 0x%x\n", cr));
                    168:        if (cr < 1 || cr > 5) {
                    169:                DPRINTF(("aps0: unsupported state %d\n", cr));
                    170:                return (0);
                    171:        }
                    172:
                    173:        ia->ipa_nio = 1;
                    174:        ia->ipa_io[0].length = APS_ADDR_SIZE;
                    175:        ia->ipa_nmem = 0;
                    176:        ia->ipa_nirq = 0;
                    177:        ia->ipa_ndrq = 0;
                    178:
                    179:        return (1);
                    180: }
                    181:
                    182: void
                    183: aps_attach(struct device *parent, struct device *self, void *aux)
                    184: {
                    185:        struct aps_softc *sc = (void *)self;
                    186:        int iobase, i;
                    187:        bus_space_tag_t iot;
                    188:        bus_space_handle_t ioh;
                    189:        struct isa_attach_args *ia = aux;
                    190:
                    191:        iobase = ia->ipa_io[0].base;
                    192:        iot = sc->aps_iot = ia->ia_iot;
                    193:
                    194:        if (bus_space_map(iot, iobase, APS_ADDR_SIZE, 0, &sc->aps_ioh)) {
                    195:                printf(": can't map i/o space\n");
                    196:                return;
                    197:        }
                    198:
                    199:        ioh = sc->aps_ioh;
                    200:
                    201:        printf("\n");
                    202:
                    203:        if (!aps_init(iot, ioh))
                    204:                goto out;
                    205:
                    206:        sc->sensors[APS_SENSOR_XACCEL].type = SENSOR_INTEGER;
                    207:        snprintf(sc->sensors[APS_SENSOR_XACCEL].desc,
                    208:            sizeof(sc->sensors[APS_SENSOR_XACCEL].desc), "X_ACCEL");
                    209:
                    210:        sc->sensors[APS_SENSOR_YACCEL].type = SENSOR_INTEGER;
                    211:        snprintf(sc->sensors[APS_SENSOR_YACCEL].desc,
                    212:            sizeof(sc->sensors[APS_SENSOR_YACCEL].desc), "Y_ACCEL");
                    213:
                    214:        sc->sensors[APS_SENSOR_TEMP1].type = SENSOR_TEMP;
                    215:        sc->sensors[APS_SENSOR_TEMP2].type = SENSOR_TEMP;
                    216:
                    217:        sc->sensors[APS_SENSOR_XVAR].type = SENSOR_INTEGER;
                    218:        snprintf(sc->sensors[APS_SENSOR_XVAR].desc,
                    219:            sizeof(sc->sensors[APS_SENSOR_XVAR].desc), "X_VAR");
                    220:
                    221:        sc->sensors[APS_SENSOR_YVAR].type = SENSOR_INTEGER;
                    222:        snprintf(sc->sensors[APS_SENSOR_YVAR].desc,
                    223:            sizeof(sc->sensors[APS_SENSOR_YVAR].desc), "Y_VAR");
                    224:
                    225:        sc->sensors[APS_SENSOR_KBACT].type = SENSOR_INDICATOR;
                    226:        snprintf(sc->sensors[APS_SENSOR_KBACT].desc,
                    227:            sizeof(sc->sensors[APS_SENSOR_KBACT].desc), "Keyboard Active");
                    228:
                    229:        sc->sensors[APS_SENSOR_MSACT].type = SENSOR_INDICATOR;
                    230:        snprintf(sc->sensors[APS_SENSOR_MSACT].desc,
                    231:            sizeof(sc->sensors[APS_SENSOR_MSACT].desc), "Mouse Active");
                    232:
                    233:        sc->sensors[APS_SENSOR_LIDOPEN].type = SENSOR_INDICATOR;
                    234:        snprintf(sc->sensors[APS_SENSOR_LIDOPEN].desc,
                    235:            sizeof(sc->sensors[APS_SENSOR_LIDOPEN].desc), "Lid Open");
                    236:
                    237:        /* stop hiding and report to the authorities */
                    238:        strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
                    239:            sizeof(sc->sensordev.xname));
                    240:        for (i = 0; i < APS_NUM_SENSORS ; i++) {
                    241:                sensor_attach(&sc->sensordev, &sc->sensors[i]);
                    242:        }
                    243:        sensordev_install(&sc->sensordev);
                    244:
                    245:        powerhook_establish(aps_power, (void *)sc);
                    246:
                    247:        /* Refresh sensor data every 0.5 seconds */
                    248:        timeout_set(&aps_timeout, aps_refresh, sc);
                    249:        timeout_add(&aps_timeout, (5 * hz) / 10);
                    250:        return;
                    251: out:
                    252:        printf("%s: failed to initialise\n", sc->sc_dev.dv_xname);
                    253:        return;
                    254: }
                    255:
                    256: int
                    257: aps_init(bus_space_tag_t iot, bus_space_handle_t ioh)
                    258: {
                    259:        bus_space_write_1(iot, ioh, APS_INIT, 0x17);
                    260:        bus_space_write_1(iot, ioh, APS_STATE, 0x81);
                    261:        bus_space_write_1(iot, ioh, APS_CMD, 0x01);
                    262:        if (!aps_mem_read_1(iot, ioh, APS_CMD, 0x00))
                    263:                return (0);
                    264:        if (!aps_mem_read_1(iot, ioh, APS_STATE, 0x00))
                    265:                return (0);
                    266:        if (!aps_mem_read_1(iot, ioh, APS_XACCEL, 0x60))
                    267:                return (0);
                    268:        if (!aps_mem_read_1(iot, ioh, APS_XACCEL + 1, 0x00))
                    269:                return (0);
                    270:        bus_space_write_1(iot, ioh, APS_INIT, 0x14);
                    271:        bus_space_write_1(iot, ioh, APS_STATE, 0x01);
                    272:        bus_space_write_1(iot, ioh, APS_CMD, 0x01);
                    273:        if (!aps_mem_read_1(iot, ioh, APS_CMD, 0x00))
                    274:                return (0);
                    275:        bus_space_write_1(iot, ioh, APS_INIT, 0x10);
                    276:        bus_space_write_1(iot, ioh, APS_STATE, 0xc8);
                    277:        bus_space_write_1(iot, ioh, APS_XACCEL, 0x00);
                    278:        bus_space_write_1(iot, ioh, APS_XACCEL + 1, 0x02);
                    279:        bus_space_write_1(iot, ioh, APS_CMD, 0x01);
                    280:        if (!aps_mem_read_1(iot, ioh, APS_CMD, 0x00))
                    281:                return (0);
                    282:        /* refresh data */
                    283:        bus_space_write_1(iot, ioh, APS_INIT, 0x11);
                    284:        bus_space_write_1(iot, ioh, APS_CMD, 0x01);
                    285:        if (!aps_mem_read_1(iot, ioh, APS_ACCEL_STATE, 0x50))
                    286:                return (0);
                    287:        if (!aps_mem_read_1(iot, ioh, APS_STATE, 0x00))
                    288:                return (0);
                    289:
                    290:        return (1);
                    291: }
                    292:
                    293: u_int8_t
                    294: aps_mem_read_1(bus_space_tag_t iot, bus_space_handle_t ioh, int reg,
                    295:     u_int8_t val)
                    296: {
                    297:        int i;
                    298:        u_int8_t cr;
                    299:        /* should take no longer than 50 microseconds */
                    300:        for (i = 0; i < 10; i++) {
                    301:                cr = bus_space_read_1(iot, ioh, reg);
                    302:                if (cr == val)
                    303:                        return (1);
                    304:                delay(5 * 1000);
                    305:        }
                    306:        DPRINTF(("aps: reg 0x%x not val 0x%x!\n", reg, val));
                    307:        return (0);
                    308: }
                    309:
                    310: int
                    311: aps_read_data(struct aps_softc *sc)
                    312: {
                    313:        bus_space_tag_t iot = sc->aps_iot;
                    314:        bus_space_handle_t ioh = sc->aps_ioh;
                    315:
                    316:        sc->aps_data.state = bus_space_read_1(iot, ioh, APS_STATE);
                    317:        sc->aps_data.x_accel = bus_space_read_2(iot, ioh, APS_XACCEL);
                    318:        sc->aps_data.y_accel = bus_space_read_2(iot, ioh, APS_YACCEL);
                    319:        sc->aps_data.temp1 = bus_space_read_1(iot, ioh, APS_TEMP);
                    320:        sc->aps_data.x_var = bus_space_read_2(iot, ioh, APS_XVAR);
                    321:        sc->aps_data.y_var = bus_space_read_2(iot, ioh, APS_YVAR);
                    322:        sc->aps_data.temp2 = bus_space_read_1(iot, ioh, APS_TEMP2);
                    323:        sc->aps_data.input = bus_space_read_1(iot, ioh, APS_INPUT);
                    324:
                    325:        return (1);
                    326: }
                    327:
                    328: void
                    329: aps_refresh_sensor_data(struct aps_softc *sc)
                    330: {
                    331:        bus_space_tag_t iot = sc->aps_iot;
                    332:        bus_space_handle_t ioh = sc->aps_ioh;
                    333:        int64_t temp;
                    334:        int i;
                    335:
                    336:        /* ask for new data */
                    337:        bus_space_write_1(iot, ioh, APS_INIT, 0x11);
                    338:        bus_space_write_1(iot, ioh, APS_CMD, 0x01);
                    339:        if (!aps_mem_read_1(iot, ioh, APS_ACCEL_STATE, 0x50))
                    340:                return;
                    341:        aps_read_data(sc);
                    342:        bus_space_write_1(iot, ioh, APS_INIT, 0x11);
                    343:        bus_space_write_1(iot, ioh, APS_CMD, 0x01);
                    344:
                    345:        /* tell accelerometer we're done reading from it */
                    346:        bus_space_read_1(iot, ioh, APS_CMD);
                    347:        bus_space_read_1(iot, ioh, APS_ACCEL_STATE);
                    348:
                    349:        for (i = 0; i < APS_NUM_SENSORS; i++) {
                    350:                sc->sensors[i].flags &= ~SENSOR_FINVALID;
                    351:        }
                    352:
                    353:        sc->sensors[APS_SENSOR_XACCEL].value = sc->aps_data.x_accel;
                    354:        sc->sensors[APS_SENSOR_YACCEL].value = sc->aps_data.y_accel;
                    355:
                    356:        /* convert to micro (mu) degrees */
                    357:        temp = sc->aps_data.temp1 * 1000000;
                    358:        /* convert to kelvin */
                    359:        temp += 273150000;
                    360:        sc->sensors[APS_SENSOR_TEMP1].value = temp;
                    361:
                    362:        /* convert to micro (mu) degrees */
                    363:        temp = sc->aps_data.temp2 * 1000000;
                    364:        /* convert to kelvin */
                    365:        temp += 273150000;
                    366:        sc->sensors[APS_SENSOR_TEMP2].value = temp;
                    367:
                    368:        sc->sensors[APS_SENSOR_XVAR].value = sc->aps_data.x_var;
                    369:        sc->sensors[APS_SENSOR_YVAR].value = sc->aps_data.y_var;
                    370:        sc->sensors[APS_SENSOR_KBACT].value =
                    371:            (sc->aps_data.input &  APS_INPUT_KB) ? 1 : 0;
                    372:        sc->sensors[APS_SENSOR_MSACT].value =
                    373:            (sc->aps_data.input & APS_INPUT_MS) ? 1 : 0;
                    374:        sc->sensors[APS_SENSOR_LIDOPEN].value =
                    375:            (sc->aps_data.input & APS_INPUT_LIDOPEN) ? 1 : 0;
                    376: }
                    377:
                    378: void
                    379: aps_refresh(void *arg)
                    380: {
                    381:        struct aps_softc *sc = (struct aps_softc *)arg;
                    382:
                    383:        aps_refresh_sensor_data(sc);
                    384:        timeout_add(&aps_timeout, (5 * hz) / 10);
                    385: }
                    386:
                    387: void
                    388: aps_power(int why, void *arg)
                    389: {
                    390:        struct aps_softc *sc = (struct aps_softc *)arg;
                    391:        bus_space_tag_t iot = sc->aps_iot;
                    392:        bus_space_handle_t ioh = sc->aps_ioh;
                    393:
                    394:        if (why != PWR_RESUME) {
                    395:                if (timeout_pending(&aps_timeout))
                    396:                        timeout_del(&aps_timeout);
                    397:        } else {
                    398:                /*
                    399:                 * Redo the init sequence on resume, because APS is
                    400:                 * as forgetful as it is deaf.
                    401:                 */
                    402:                bus_space_write_1(iot, ioh, APS_INIT, 0x13);
                    403:                bus_space_write_1(iot, ioh, APS_CMD, 0x01);
                    404:                bus_space_read_1(iot, ioh, APS_CMD);
                    405:                bus_space_write_1(iot, ioh, APS_INIT, 0x13);
                    406:                bus_space_write_1(iot, ioh, APS_CMD, 0x01);
                    407:
                    408:                if (aps_mem_read_1(iot, ioh, APS_CMD, 0x00) &&
                    409:                    aps_init(iot, ioh))
                    410:                        timeout_add(&aps_timeout, (5 * hz) / 10);
                    411:                else
                    412:                        printf("aps: failed to wake up\n");
                    413:        }
                    414: }
                    415:

CVSweb