[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     ! 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