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

Annotation of sys/dev/acpi/acpiec.c, Revision 1.1.1.1

1.1       nbrk        1: /* $OpenBSD: acpiec.c,v 1.18 2007/02/21 20:46:57 marco Exp $ */
                      2: /*
                      3:  * Copyright (c) 2006 Can Erkin Acar <canacar@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: #include <sys/param.h>
                     19: #include <sys/proc.h>
                     20: #include <sys/signalvar.h>
                     21: #include <sys/systm.h>
                     22: #include <sys/device.h>
                     23: #include <sys/malloc.h>
                     24:
                     25: #include <machine/bus.h>
                     26:
                     27: #include <dev/acpi/acpireg.h>
                     28: #include <dev/acpi/acpivar.h>
                     29: #include <dev/acpi/acpidev.h>
                     30: #include <dev/acpi/amltypes.h>
                     31: #include <dev/acpi/dsdt.h>
                     32:
                     33: #include <sys/sensors.h>
                     34:
                     35: int            acpiec_match(struct device *, void *, void *);
                     36: void           acpiec_attach(struct device *, struct device *, void *);
                     37:
                     38: u_int8_t       acpiec_status(struct acpiec_softc *);
                     39: u_int8_t       acpiec_read_data(struct acpiec_softc *);
                     40: void           acpiec_write_cmd(struct acpiec_softc *, u_int8_t);
                     41: void           acpiec_write_data(struct acpiec_softc *, u_int8_t);
                     42: void           acpiec_burst_enable(struct acpiec_softc *sc);
                     43:
                     44: u_int8_t       acpiec_read_1(struct acpiec_softc *, u_int8_t);
                     45: void           acpiec_write_1(struct acpiec_softc *, u_int8_t, u_int8_t);
                     46:
                     47: void           acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
                     48: void           acpiec_write(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
                     49:
                     50: int            acpiec_getcrs(struct acpiec_softc *,
                     51:                    struct acpi_attach_args *);
                     52: int            acpiec_getregister(const u_int8_t *, int, int *, bus_size_t *);
                     53:
                     54: void           acpiec_wait(struct acpiec_softc *, u_int8_t, u_int8_t);
                     55: void           acpiec_sci_event(struct acpiec_softc *);
                     56:
                     57: void           acpiec_get_events(struct acpiec_softc *);
                     58:
                     59: int            acpiec_gpehandler(struct acpi_softc *, int, void *);
                     60:
                     61: struct aml_node        *aml_find_name(struct acpi_softc *, struct aml_node *,
                     62:                    const char *);
                     63:
                     64: /* EC Status bits */
                     65: #define                EC_STAT_SMI_EVT 0x40    /* SMI event pending */
                     66: #define                EC_STAT_SCI_EVT 0x20    /* SCI event pending */
                     67: #define                EC_STAT_BURST   0x10    /* Controller in burst mode */
                     68: #define                EC_STAT_CMD     0x08    /* data is command */
                     69: #define                EC_STAT_IBF     0x02    /* input buffer full */
                     70: #define                EC_STAT_OBF     0x01    /* output buffer full */
                     71:
                     72: /* EC Commands */
                     73: #define                EC_CMD_RD       0x80    /* Read */
                     74: #define                EC_CMD_WR       0x81    /* Write */
                     75: #define                EC_CMD_BE       0x82    /* Burst Enable */
                     76: #define                EC_CMD_BD       0x83    /* Burst Disable */
                     77: #define                EC_CMD_QR       0x84    /* Query */
                     78:
                     79: #define                REG_TYPE_EC     3
                     80:
                     81: #define ACPIEC_MAX_EVENTS      256
                     82:
                     83: struct acpiec_event {
                     84:        struct aml_node *event;
                     85: };
                     86:
                     87: struct acpiec_softc {
                     88:        struct device           sc_dev;
                     89:
                     90:        /* command/status register */
                     91:        bus_space_tag_t         sc_cmd_bt;
                     92:        bus_space_handle_t      sc_cmd_bh;
                     93:
                     94:        /* data register */
                     95:        bus_space_tag_t         sc_data_bt;
                     96:        bus_space_handle_t      sc_data_bh;
                     97:
                     98:        struct acpi_softc       *sc_acpi;
                     99:        struct aml_node         *sc_devnode;
                    100:        u_int32_t               sc_gpe;
                    101:        struct acpiec_event     sc_events[ACPIEC_MAX_EVENTS];
                    102:        int                     sc_gotsci;
                    103: };
                    104:
                    105:
                    106: int    acpiec_reg(struct acpiec_softc *);
                    107:
                    108: struct cfattach acpiec_ca = {
                    109:        sizeof(struct acpiec_softc), acpiec_match, acpiec_attach
                    110: };
                    111:
                    112: struct cfdriver acpiec_cd = {
                    113:        NULL, "acpiec", DV_DULL
                    114: };
                    115:
                    116:
                    117: void
                    118: acpiec_wait(struct acpiec_softc *sc, u_int8_t mask, u_int8_t val)
                    119: {
                    120:        u_int8_t                stat;
                    121:
                    122:        dnprintf(40, "%s: EC wait_ns for: %b == %02x\n",
                    123:            DEVNAME(sc), (int)mask,
                    124:            "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF", (int)val);
                    125:
                    126:        while (((stat = acpiec_status(sc)) & mask) != val) {
                    127:                if (stat & EC_STAT_SCI_EVT)
                    128:                        sc->sc_gotsci = 1;
                    129:                if (cold)
                    130:                        delay(1);
                    131:                else
                    132:                        tsleep(sc, PWAIT, "ecwait", 1);
                    133:        }
                    134:
                    135:        dnprintf(40, "%s: EC wait_ns, stat: %b\n", DEVNAME(sc), (int)stat,
                    136:            "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
                    137: }
                    138:
                    139: u_int8_t
                    140: acpiec_status(struct acpiec_softc *sc)
                    141: {
                    142:        return (bus_space_read_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0));
                    143: }
                    144:
                    145: void
                    146: acpiec_write_data(struct acpiec_softc *sc, u_int8_t val)
                    147: {
                    148:        acpiec_wait(sc, EC_STAT_IBF, 0);
                    149:        dnprintf(40, "acpiec: write_data -- %d\n", (int)val);
                    150:        bus_space_write_1(sc->sc_data_bt, sc->sc_data_bh, 0, val);
                    151: }
                    152:
                    153: void
                    154: acpiec_write_cmd(struct acpiec_softc *sc, u_int8_t val)
                    155: {
                    156:        acpiec_wait(sc, EC_STAT_IBF, 0);
                    157:        dnprintf(40, "acpiec: write_cmd -- %d\n", (int)val);
                    158:        bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, val);
                    159: }
                    160:
                    161: u_int8_t
                    162: acpiec_read_data(struct acpiec_softc *sc)
                    163: {
                    164:        u_int8_t                val;
                    165:
                    166:        acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF);
                    167:        dnprintf(40, "acpiec: read_data\n", (int)val);
                    168:        val = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
                    169:
                    170:        return (val);
                    171: }
                    172:
                    173: void
                    174: acpiec_sci_event(struct acpiec_softc *sc)
                    175: {
                    176:        u_int8_t                evt;
                    177:
                    178:        sc->sc_gotsci = 0;
                    179:
                    180:        acpiec_wait(sc, EC_STAT_IBF, 0);
                    181:        bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, EC_CMD_QR);
                    182:
                    183:        acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF);
                    184:        evt = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
                    185:
                    186:        if (evt) {
                    187:                dnprintf(10, "%s: sci_event: 0x%02x\n", DEVNAME(sc), (int)evt);
                    188:                aml_evalnode(sc->sc_acpi, sc->sc_events[evt].event, 0, NULL,
                    189:                    NULL);
                    190:        }
                    191: }
                    192:
                    193: u_int8_t
                    194: acpiec_read_1(struct acpiec_softc *sc, u_int8_t addr)
                    195: {
                    196:        u_int8_t                val;
                    197:
                    198:        if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT)
                    199:                sc->sc_gotsci = 1;
                    200:
                    201:        acpiec_write_cmd(sc, EC_CMD_RD);
                    202:        acpiec_write_data(sc, addr);
                    203:
                    204:        val = acpiec_read_data(sc);
                    205:
                    206:        return (val);
                    207: }
                    208:
                    209: void
                    210: acpiec_write_1(struct acpiec_softc *sc, u_int8_t addr, u_int8_t data)
                    211: {
                    212:        if ((acpiec_status(sc) & EC_STAT_SCI_EVT)  == EC_STAT_SCI_EVT)
                    213:                sc->sc_gotsci = 1;
                    214:
                    215:        acpiec_write_cmd(sc, EC_CMD_WR);
                    216:        acpiec_write_data(sc, addr);
                    217:        acpiec_write_data(sc, data);
                    218: }
                    219:
                    220: void
                    221: acpiec_burst_enable(struct acpiec_softc *sc)
                    222: {
                    223:        acpiec_write_cmd(sc, EC_CMD_BE);
                    224:        acpiec_read_data(sc);
                    225: }
                    226:
                    227: void
                    228: acpiec_read(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer)
                    229: {
                    230:        int                     reg;
                    231:
                    232:        /*
                    233:         * this works because everything runs in the acpi thread context.
                    234:         * at some point add a lock to deal with concurrency so that a
                    235:         * transaction does not get interrupted.
                    236:         */
                    237:        acpiec_burst_enable(sc);
                    238:        dnprintf(20, "%s: read %d, %d\n", DEVNAME(sc), (int)addr, len);
                    239:
                    240:        for (reg = 0; reg < len; reg++)
                    241:                buffer[reg] = acpiec_read_1(sc, addr + reg);
                    242: }
                    243:
                    244: void
                    245: acpiec_write(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer)
                    246: {
                    247:        int                     reg;
                    248:
                    249:        /*
                    250:         * this works because everything runs in the acpi thread context.
                    251:         * at some point add a lock to deal with concurrency so that a
                    252:         * transaction does not get interrupted.
                    253:         */
                    254:        acpiec_burst_enable(sc);
                    255:        dnprintf(20, "%s: write %d, %d\n", DEVNAME(sc), (int)addr, len);
                    256:        for (reg = 0; reg < len; reg++)
                    257:                acpiec_write_1(sc, addr + reg, buffer[reg]);
                    258: }
                    259:
                    260: int
                    261: acpiec_match(struct device *parent, void *match, void *aux)
                    262: {
                    263:        struct acpi_attach_args *aa = aux;
                    264:        struct cfdata           *cf = match;
                    265:
                    266:        /* sanity */
                    267:        if (aa->aaa_name == NULL ||
                    268:            strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
                    269:            aa->aaa_table != NULL)
                    270:                return (0);
                    271:
                    272:        return (1);
                    273: }
                    274:
                    275: void
                    276: acpiec_attach(struct device *parent, struct device *self, void *aux)
                    277: {
                    278:        struct acpiec_softc     *sc = (struct acpiec_softc *)self;
                    279:        struct acpi_attach_args *aa = aux;
                    280:
                    281:        sc->sc_acpi = (struct acpi_softc *)parent;
                    282:        sc->sc_devnode = aa->aaa_node->child;
                    283:
                    284:        if (sc->sc_acpi->sc_ec != NULL) {
                    285:                printf(": Only single EC is supported!\n");
                    286:                return;
                    287:        }
                    288:
                    289:        if (acpiec_getcrs(sc, aa)) {
                    290:                printf(": Failed to read resource settings\n");
                    291:                return;
                    292:        }
                    293:
                    294:        if (acpiec_reg(sc)) {
                    295:                printf(": Failed to register address space\n");
                    296:                return;
                    297:        }
                    298:
                    299:        acpiec_get_events(sc);
                    300:
                    301:        sc->sc_acpi->sc_ec = sc;
                    302:
                    303:        dnprintf(10, "%s: GPE: %d\n", DEVNAME(sc), sc->sc_gpe);
                    304:
                    305: #ifndef SMALL_KERNEL
                    306:        acpi_set_gpehandler(sc->sc_acpi, sc->sc_gpe, acpiec_gpehandler,
                    307:            sc, "acpiec");
                    308: #endif
                    309:
                    310:        printf(": %s\n", sc->sc_devnode->parent->name);
                    311: }
                    312:
                    313: void
                    314: acpiec_get_events(struct acpiec_softc *sc)
                    315: {
                    316:        int                     idx;
                    317:        char                    name[16];
                    318:
                    319:        memset(sc->sc_events, 0, sizeof(sc->sc_events));
                    320:        for (idx = 0; idx < ACPIEC_MAX_EVENTS; idx++) {
                    321:                snprintf(name, sizeof(name), "_Q%02X", idx);
                    322:                sc->sc_events[idx].event = aml_searchname(sc->sc_devnode, name);
                    323:                if (sc->sc_events[idx].event != NULL)
                    324:                        dnprintf(10, "%s: Found event %s\n", DEVNAME(sc), name);
                    325:        }
                    326: }
                    327:
                    328: int
                    329: acpiec_gpehandler(struct acpi_softc *acpi_sc, int gpe, void *arg)
                    330: {
                    331:        struct acpiec_softc     *sc = arg;
                    332:        u_int8_t                mask, stat;
                    333:
                    334:        dnprintf(10, "ACPIEC: got gpe\n");
                    335:
                    336:        /* Reset GPE event */
                    337:        mask = (1L << (gpe & 7));
                    338:        acpi_write_pmreg(acpi_sc, ACPIREG_GPE_STS, gpe>>3, mask);
                    339:        acpi_write_pmreg(acpi_sc, ACPIREG_GPE_EN,  gpe>>3, mask);
                    340:
                    341:        do {
                    342:                if (sc->sc_gotsci)
                    343:                        acpiec_sci_event(sc);
                    344:
                    345:                stat = acpiec_status(sc);
                    346:                dnprintf(40, "%s: EC interrupt, stat: %b\n",
                    347:                    DEVNAME(sc), (int)stat,
                    348:                    "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
                    349:
                    350:                if (stat & EC_STAT_SCI_EVT)
                    351:                        sc->sc_gotsci = 1;
                    352:        } while (sc->sc_gotsci);
                    353:
                    354:        return (0);
                    355: }
                    356:
                    357: /* parse the resource buffer to get a 'register' value */
                    358: int
                    359: acpiec_getregister(const u_int8_t *buf, int size, int *type, bus_size_t *addr)
                    360: {
                    361:        int                     len, hlen;
                    362:
                    363: #define RES_TYPE_MASK 0x80
                    364: #define RES_LENGTH_MASK 0x07
                    365: #define RES_TYPE_IOPORT        0x47
                    366: #define RES_TYPE_ENDTAG        0x79
                    367:
                    368:        if (size <= 0)
                    369:                return (0);
                    370:
                    371:        if (*buf & RES_TYPE_MASK) {
                    372:                /* large resource */
                    373:                if (size < 3)
                    374:                        return (1);
                    375:                len = (int)buf[1] + 256 * (int)buf[2];
                    376:                hlen = 3;
                    377:        } else {
                    378:                /* small resource */
                    379:                len = buf[0] & RES_LENGTH_MASK;
                    380:                hlen = 1;
                    381:        }
                    382:
                    383:        /* XXX todo: decode other types */
                    384:        if (*buf != RES_TYPE_IOPORT)
                    385:                return (0);
                    386:
                    387:        if (size < hlen + len)
                    388:                return (0);
                    389:
                    390:        /* XXX validate? */
                    391:        *type = GAS_SYSTEM_IOSPACE;
                    392:        *addr = (int)buf[2] + 256 * (int)buf[3];
                    393:
                    394:        return (hlen + len);
                    395: }
                    396:
                    397: int
                    398: acpiec_getcrs(struct acpiec_softc *sc, struct acpi_attach_args *aa)
                    399: {
                    400:        struct aml_value        res;
                    401:        bus_size_t              ec_sc, ec_data;
                    402:        int                     type1, type2;
                    403:        char                    *buf;
                    404:        int                     size, ret;
                    405:
                    406:        if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_GPE", 0, NULL, &res)) {
                    407:                dnprintf(10, "%s: no _GPE\n", DEVNAME(sc));
                    408:                return (1);
                    409:        }
                    410:
                    411:        sc->sc_gpe = aml_val2int(&res);
                    412:        aml_freevalue(&res);
                    413:
                    414:        if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
                    415:                dnprintf(10, "%s: no _CRS\n", DEVNAME(sc));
                    416:                return (1);
                    417:        }
                    418:
                    419:        /* Parse CRS to get control and data registers */
                    420:
                    421:        if (res.type != AML_OBJTYPE_BUFFER) {
                    422:                dnprintf(10, "%s: unknown _CRS type %d\n",
                    423:                    DEVNAME(sc), res.type);
                    424:                aml_freevalue(&res);
                    425:                return (1);
                    426:        }
                    427:
                    428:        size = res.length;
                    429:        buf = res.v_buffer;
                    430:
                    431:        ret = acpiec_getregister(buf, size, &type1, &ec_data);
                    432:        if (ret <= 0) {
                    433:                dnprintf(10, "%s: failed to read DATA from _CRS\n",
                    434:                    DEVNAME(sc));
                    435:                aml_freevalue(&res);
                    436:                return (1);
                    437:        }
                    438:
                    439:        buf += ret;
                    440:        size -= ret;
                    441:
                    442:        ret = acpiec_getregister(buf, size, &type2,  &ec_sc);
                    443:        if (ret <= 0) {
                    444:                dnprintf(10, "%s: failed to read S/C from _CRS\n",
                    445:                    DEVNAME(sc));
                    446:                aml_freevalue(&res);
                    447:                return (1);
                    448:        }
                    449:
                    450:        buf += ret;
                    451:        size -= ret;
                    452:
                    453:        if (size != 2 || *buf != RES_TYPE_ENDTAG) {
                    454:                dnprintf(10, "%s: no _CRS end tag\n", DEVNAME(sc));
                    455:                aml_freevalue(&res);
                    456:                return (1);
                    457:        }
                    458:        aml_freevalue(&res);
                    459:
                    460:        /* XXX: todo - validate _CRS checksum? */
                    461:
                    462:        dnprintf(10, "%s: Data: 0x%x, S/C: 0x%x\n",
                    463:            DEVNAME(sc), ec_data, ec_sc);
                    464:
                    465:        if (type1 == GAS_SYSTEM_IOSPACE)
                    466:                sc->sc_cmd_bt = aa->aaa_iot;
                    467:        else
                    468:                sc->sc_cmd_bt = aa->aaa_memt;
                    469:
                    470:        if (bus_space_map(sc->sc_cmd_bt, ec_sc, 1, 0, &sc->sc_cmd_bh)) {
                    471:                dnprintf(10, "%s: failed to map S/C reg.\n", DEVNAME(sc));
                    472:                return (1);
                    473:        }
                    474:
                    475:        if (type2 == GAS_SYSTEM_IOSPACE)
                    476:                sc->sc_data_bt = aa->aaa_iot;
                    477:        else
                    478:                sc->sc_data_bt = aa->aaa_memt;
                    479:
                    480:        if (bus_space_map(sc->sc_data_bt, ec_data, 1, 0, &sc->sc_data_bh)) {
                    481:                dnprintf(10, "%s: failed to map DATA reg.\n", DEVNAME(sc));
                    482:                bus_space_unmap(sc->sc_cmd_bt, sc->sc_cmd_bh, 1);
                    483:                return (1);
                    484:        }
                    485:
                    486:        return (0);
                    487: }
                    488:
                    489: int
                    490: acpiec_reg(struct acpiec_softc *sc)
                    491: {
                    492:        struct aml_value        arg[2];
                    493:        struct aml_node         *root;
                    494:
                    495:        memset(&arg, 0, sizeof(arg));
                    496:
                    497:        arg[0].type = AML_OBJTYPE_INTEGER;
                    498:        arg[0].v_integer = REG_TYPE_EC;
                    499:        arg[1].type = AML_OBJTYPE_INTEGER;
                    500:        arg[1].v_integer = 1;
                    501:
                    502:        root = aml_searchname(sc->sc_devnode, "_REG");
                    503:        if (root == NULL) {
                    504:                dnprintf(10, "%s: no _REG method\n", DEVNAME(sc));
                    505:                return (1);
                    506:        }
                    507:
                    508:        if (aml_evalnode(sc->sc_acpi, root, 2, arg, NULL) != 0) {
                    509:                dnprintf(10, "%s: eval method _REG failed\n", DEVNAME(sc));
                    510:                return (1);
                    511:        }
                    512:
                    513:        return (0);
                    514: }

CVSweb