[BACK]Return to acpi_ec.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / acpi

Annotation of src/sys/dev/acpi/acpi_ec.c, Revision 1.41.6.12

1.41.6.12! joerg       1: /*     $NetBSD: acpi_ec.c,v 1.41.6.11 2007/10/26 15:44:12 joerg Exp $  */
1.1       thorpej     2:
                      3: /*-
1.41.6.5  joerg       4:  * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
1.1       thorpej     5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
1.41.6.5  joerg      10:  *
1.1       thorpej    11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
1.41.6.5  joerg      14:  *    notice, this list of conditions and the following disclaimer in
                     15:  *    the documentation and/or other materials provided with the
                     16:  *    distribution.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
                     19:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     20:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
                     21:  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
                     22:  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
                     23:  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
                     24:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     25:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
                     26:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
                     27:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
                     28:  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1.1       thorpej    29:  * SUCH DAMAGE.
                     30:  */
                     31:
1.3       lukem      32: #include <sys/cdefs.h>
1.41.6.12! joerg      33: __KERNEL_RCSID(0, "$NetBSD: acpi_ec.c,v 1.41.6.11 2007/10/26 15:44:12 joerg Exp $");
1.1       thorpej    34:
                     35: #include <sys/param.h>
                     36: #include <sys/systm.h>
1.41.6.5  joerg      37: #include <sys/condvar.h>
1.1       thorpej    38: #include <sys/device.h>
                     39: #include <sys/kernel.h>
1.41.6.5  joerg      40: #include <sys/kthread.h>
                     41: #include <sys/mutex.h>
1.1       thorpej    42:
1.41.6.11  joerg      43: #include <sys/bus.h>
1.1       thorpej    44:
                     45: #include <dev/acpi/acpivar.h>
                     46:
1.41.6.7  joerg      47: /* Maximum time to wait for global ACPI lock in ms */
1.41.6.5  joerg      48: #define        EC_LOCK_TIMEOUT         5
1.23      kochi      49:
1.41.6.7  joerg      50: /* Maximum time to poll for completion of a command  in ms */
                     51: #define        EC_POLL_TIMEOUT         5
                     52:
1.41.6.5  joerg      53: /* From ACPI 3.0b, chapter 12.3 */
                     54: #define EC_COMMAND_READ                0x80
                     55: #define        EC_COMMAND_WRITE        0x81
                     56: #define        EC_COMMAND_BURST_EN     0x82
                     57: #define        EC_COMMAND_BURST_DIS    0x83
                     58: #define        EC_COMMAND_QUERY        0x84
                     59:
                     60: /* From ACPI 3.0b, chapter 12.2.1 */
                     61: #define        EC_STATUS_OBF           0x01
                     62: #define        EC_STATUS_IBF           0x02
                     63: #define        EC_STATUS_CMD           0x08
                     64: #define        EC_STATUS_BURST         0x10
                     65: #define        EC_STATUS_SCI           0x20
                     66: #define        EC_STATUS_SMI           0x40
1.1       thorpej    67:
1.41.6.5  joerg      68: static const char *ec_hid[] = {
                     69:        "PNP0C09",
                     70:        NULL,
                     71: };
1.1       thorpej    72:
1.41.6.5  joerg      73: enum ec_state_t {
                     74:        EC_STATE_QUERY,
1.41.6.7  joerg      75:        EC_STATE_QUERY_VAL,
1.41.6.5  joerg      76:        EC_STATE_READ,
1.41.6.7  joerg      77:        EC_STATE_READ_ADDR,
1.41.6.5  joerg      78:        EC_STATE_READ_VAL,
                     79:        EC_STATE_WRITE,
1.41.6.7  joerg      80:        EC_STATE_WRITE_ADDR,
1.41.6.5  joerg      81:        EC_STATE_WRITE_VAL,
                     82:        EC_STATE_FREE
                     83: };
1.1       thorpej    84:
1.41.6.5  joerg      85: struct acpiec_softc {
                     86:        ACPI_HANDLE sc_ech;
1.1       thorpej    87:
1.41.6.5  joerg      88:        ACPI_HANDLE sc_gpeh;
                     89:        UINT8 sc_gpebit;
1.1       thorpej    90:
1.41.6.5  joerg      91:        bus_space_tag_t sc_data_st;
                     92:        bus_space_handle_t sc_data_sh;
1.1       thorpej    93:
1.41.6.5  joerg      94:        bus_space_tag_t sc_csr_st;
                     95:        bus_space_handle_t sc_csr_sh;
1.17      mycroft    96:
1.41.6.5  joerg      97:        bool sc_need_global_lock;
                     98:        UINT32 sc_global_lock;
1.1       thorpej    99:
1.41.6.5  joerg     100:        kmutex_t sc_mtx, sc_access_mtx;
                    101:        kcondvar_t sc_cv, sc_cv_sci;
                    102:        enum ec_state_t sc_state;
                    103:        bool sc_got_sci;
                    104:
                    105:        uint8_t sc_cur_addr, sc_cur_val;
1.16      kochi     106: };
                    107:
1.41.6.5  joerg     108: static int acpiecdt_match(device_t, struct cfdata *, void *);
                    109: static void acpiecdt_attach(device_t, device_t, void *);
1.1       thorpej   110:
1.41.6.5  joerg     111: static int acpiec_match(device_t, struct cfdata *, void *);
                    112: static void acpiec_attach(device_t, device_t, void *);
                    113:
                    114: static void acpiec_common_attach(device_t, device_t, ACPI_HANDLE,
                    115:     bus_addr_t, bus_addr_t, ACPI_HANDLE, uint8_t);
                    116:
1.41.6.12! joerg     117: static bool acpiec_resume(device_t);
        !           118: static bool acpiec_suspend(device_t);
1.17      mycroft   119:
1.41.6.5  joerg     120: static bool acpiec_parse_gpe_package(device_t, ACPI_HANDLE,
                    121:     ACPI_HANDLE *, uint8_t *);
1.20      yamt      122:
1.41.6.5  joerg     123: static void acpiec_gpe_query(void *);
                    124: static UINT32 acpiec_gpe_handler(void *);
                    125: static ACPI_STATUS acpiec_space_setup(ACPI_HANDLE, UINT32, void *, void **);
                    126: static ACPI_STATUS acpiec_space_handler(UINT32, ACPI_PHYSICAL_ADDRESS,
                    127:     UINT32, ACPI_INTEGER *, void *, void *);
1.20      yamt      128:
1.41.6.5  joerg     129: static void acpiec_gpe_state_maschine(device_t);
1.20      yamt      130:
1.41.6.5  joerg     131: CFATTACH_DECL_NEW(acpiec, sizeof(struct acpiec_softc),
1.20      yamt      132:     acpiec_match, acpiec_attach, NULL, NULL);
                    133:
1.41.6.5  joerg     134: CFATTACH_DECL_NEW(acpiecdt, sizeof(struct acpiec_softc),
                    135:     acpiecdt_match, acpiecdt_attach, NULL, NULL);
1.23      kochi     136:
1.41.6.5  joerg     137: static device_t ec_singleton = NULL;
                    138: static bool acpiec_cold = false;
                    139:
                    140: static bool
                    141: acpiecdt_find(device_t parent, ACPI_HANDLE *ec_handle,
                    142:     bus_addr_t *cmd_reg, bus_addr_t *data_reg, uint8_t *gpebit)
1.9       tshiozak  143: {
1.41.6.6  jmcneill  144:        ACPI_TABLE_ECDT *ecdt;
1.41.6.5  joerg     145:        ACPI_STATUS rv;
                    146:
1.41.6.6  jmcneill  147:        rv = AcpiGetTable(ACPI_SIG_ECDT, 1, (ACPI_TABLE_HEADER **)&ecdt);
                    148:        if (ACPI_FAILURE(rv))
1.41.6.5  joerg     149:                return false;
                    150:
1.41.6.6  jmcneill  151:        if (ecdt->Control.BitWidth != 8 || ecdt->Data.BitWidth != 8) {
1.41.6.5  joerg     152:                aprint_error_dev(parent,
                    153:                    "ECDT register width invalid (%d/%d)\n",
1.41.6.6  jmcneill  154:                    ecdt->Control.BitWidth, ecdt->Data.BitWidth);
1.41.6.5  joerg     155:                return false;
                    156:        }
                    157:
1.41.6.6  jmcneill  158:        rv = AcpiGetHandle(ACPI_ROOT_OBJECT, ecdt->Id, ec_handle);
                    159:        if (ACPI_FAILURE(rv)) {
1.41.6.5  joerg     160:                aprint_error_dev(parent,
                    161:                    "failed to look up EC object %s: %s\n",
1.41.6.6  jmcneill  162:                    ecdt->Id, AcpiFormatException(rv));
1.41.6.5  joerg     163:                return false;
                    164:        }
                    165:
1.41.6.6  jmcneill  166:        *cmd_reg = ecdt->Control.Address;
                    167:        *data_reg = ecdt->Data.Address;
                    168:        *gpebit = ecdt->Gpe;
1.24      kochi     169:
1.41.6.5  joerg     170:        return true;
1.9       tshiozak  171: }
1.4       thorpej   172:
1.41.6.5  joerg     173: static int
                    174: acpiecdt_match(device_t parent, struct cfdata *match, void *aux)
1.1       thorpej   175: {
1.41.6.5  joerg     176:        ACPI_HANDLE ec_handle;
                    177:        bus_addr_t cmd_reg, data_reg;
                    178:        uint8_t gpebit;
1.20      yamt      179:
1.41.6.5  joerg     180:        if (acpiecdt_find(parent, &ec_handle, &cmd_reg, &data_reg, &gpebit))
                    181:                return 1;
                    182:        else
                    183:                return 0;
1.1       thorpej   184: }
                    185:
1.41.6.5  joerg     186: static void
                    187: acpiecdt_attach(device_t parent, device_t self, void *aux)
1.1       thorpej   188: {
1.41.6.5  joerg     189:        ACPI_HANDLE ec_handle;
                    190:        bus_addr_t cmd_reg, data_reg;
                    191:        uint8_t gpebit;
1.20      yamt      192:
1.41.6.5  joerg     193:        if (!acpiecdt_find(parent, &ec_handle, &cmd_reg, &data_reg, &gpebit))
                    194:                panic("ECDT disappeared");
                    195:
                    196:        aprint_naive(": ACPI Embedded Controller via ECDT\n");
                    197:        aprint_normal(": ACPI Embedded Controller via ECDT\n");
                    198:
                    199:        acpiec_common_attach(parent, self, ec_handle, cmd_reg, data_reg,
                    200:            NULL, gpebit);
1.1       thorpej   201: }
                    202:
1.31      kochi     203: static int
1.41.6.5  joerg     204: acpiec_match(device_t parent, struct cfdata *match, void *aux)
1.1       thorpej   205: {
                    206:        struct acpi_attach_args *aa = aux;
                    207:
                    208:        if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
1.25      kochi     209:                return 0;
1.1       thorpej   210:
1.25      kochi     211:        return acpi_match_hid(aa->aa_node->ad_devinfo, ec_hid);
1.1       thorpej   212: }
                    213:
1.41.6.5  joerg     214: static void
                    215: acpiec_attach(device_t parent, device_t self, void *aux)
1.17      mycroft   216: {
1.41.6.5  joerg     217:        struct acpi_attach_args *aa = aux;
                    218:        struct acpi_resources ec_res;
                    219:        struct acpi_io *io0, *io1;
                    220:        ACPI_HANDLE gpe_handle;
                    221:        uint8_t gpebit;
1.23      kochi     222:        ACPI_STATUS rv;
1.17      mycroft   223:
1.41.6.5  joerg     224:        if (ec_singleton != NULL) {
                    225:                aprint_naive(": ACPI Embedded Controller (disabled)\n");
                    226:                aprint_normal(": ACPI Embedded Controller (disabled)\n");
1.41.6.12! joerg     227:                if (!pnp_device_register(self, NULL, NULL))
        !           228:                        aprint_error_dev(self, "couldn't establish power handler\n");
1.23      kochi     229:                return;
                    230:        }
                    231:
1.41.6.5  joerg     232:        aprint_naive(": ACPI Embedded Controller\n");
                    233:        aprint_normal(": ACPI Embedded Controller\n");
1.23      kochi     234:
1.41.6.5  joerg     235:        if (!acpiec_parse_gpe_package(self, aa->aa_node->ad_handle,
                    236:                                      &gpe_handle, &gpebit))
                    237:                return;
1.23      kochi     238:
1.41.6.5  joerg     239:        rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS",
                    240:            &ec_res, &acpi_resource_parse_ops_default);
                    241:        if (rv != AE_OK) {
                    242:                aprint_error_dev(self, "resource parsing failed: %s\n",
1.23      kochi     243:                    AcpiFormatException(rv));
1.41.6.5  joerg     244:                return;
1.17      mycroft   245:        }
1.23      kochi     246:
1.41.6.5  joerg     247:        if ((io0 = acpi_res_io(&ec_res, 0)) == NULL) {
                    248:                aprint_error_dev(self, "no data register resource\n");
                    249:                goto free_res;
                    250:        }
                    251:        if ((io1 = acpi_res_io(&ec_res, 1)) == NULL) {
                    252:                aprint_error_dev(self, "no CSR register resource\n");
                    253:                goto free_res;
                    254:        }
1.23      kochi     255:
1.41.6.5  joerg     256:        acpiec_common_attach(parent, self, aa->aa_node->ad_handle,
                    257:            io1->ar_base, io0->ar_base, gpe_handle, gpebit);
1.23      kochi     258:
1.41.6.5  joerg     259: free_res:
                    260:        acpi_resource_cleanup(&ec_res);
1.17      mycroft   261: }
                    262:
1.31      kochi     263: static void
1.41.6.5  joerg     264: acpiec_common_attach(device_t parent, device_t self,
                    265:     ACPI_HANDLE ec_handle, bus_addr_t cmd_reg, bus_addr_t data_reg,
                    266:     ACPI_HANDLE gpe_handle, uint8_t gpebit)
1.1       thorpej   267: {
1.41.6.5  joerg     268:        struct acpiec_softc *sc = device_private(self);
1.1       thorpej   269:        ACPI_STATUS rv;
1.41.6.5  joerg     270:        ACPI_INTEGER val;
1.1       thorpej   271:
1.41.6.5  joerg     272:        sc->sc_ech = ec_handle;
                    273:        sc->sc_gpeh = gpe_handle;
                    274:        sc->sc_gpebit = gpebit;
                    275:
                    276:        sc->sc_state = EC_STATE_FREE;
                    277:        mutex_init(&sc->sc_mtx, MUTEX_DRIVER, IPL_TTY);
                    278:        mutex_init(&sc->sc_access_mtx, MUTEX_DEFAULT, IPL_NONE);
                    279:        cv_init(&sc->sc_cv, "eccv");
                    280:        cv_init(&sc->sc_cv_sci, "ecsci");
                    281:
                    282:        if (bus_space_map(sc->sc_data_st, data_reg, 1, 0,
                    283:            &sc->sc_data_sh) != 0) {
                    284:                aprint_error_dev(self, "unable to map data register\n");
                    285:                return;
                    286:        }
1.1       thorpej   287:
1.41.6.5  joerg     288:        if (bus_space_map(sc->sc_csr_st, cmd_reg, 1, 0, &sc->sc_csr_sh) != 0) {
                    289:                aprint_error_dev(self, "unable to map CSR register\n");
                    290:                goto post_data_map;
                    291:        }
1.17      mycroft   292:
1.41.6.5  joerg     293:        rv = acpi_eval_integer(sc->sc_ech, "_GLK", &val);
                    294:        if (rv == AE_OK) {
                    295:                sc->sc_need_global_lock = val != 0;
                    296:        } else if (rv != AE_NOT_FOUND) {
                    297:                aprint_error_dev(self, "unable to evaluate _GLK: %s\n",
                    298:                    AcpiFormatException(rv));
                    299:                goto post_csr_map;
                    300:        } else {
                    301:                sc->sc_need_global_lock = false;
                    302:        }
                    303:        if (sc->sc_need_global_lock)
                    304:                aprint_normal_dev(self, "using global ACPI lock\n");
1.1       thorpej   305:
1.41.6.5  joerg     306:        rv = AcpiInstallAddressSpaceHandler(sc->sc_ech, ACPI_ADR_SPACE_EC,
                    307:            acpiec_space_handler, acpiec_space_setup, self);
                    308:        if (rv != AE_OK) {
                    309:                aprint_error_dev(self,
                    310:                    "unable to install address space handler: %s\n",
                    311:                    AcpiFormatException(rv));
                    312:                goto post_csr_map;
                    313:        }
1.1       thorpej   314:
1.41.6.5  joerg     315:        rv = AcpiInstallGpeHandler(sc->sc_gpeh, sc->sc_gpebit,
                    316:            ACPI_GPE_EDGE_TRIGGERED, acpiec_gpe_handler, self);
                    317:        if (rv != AE_OK) {
                    318:                aprint_error_dev(self, "unable to install GPE handler: %s\n",
                    319:                    AcpiFormatException(rv));
                    320:                goto post_csr_map;
                    321:        }
1.23      kochi     322:
1.41.6.5  joerg     323:        rv = AcpiSetGpeType(sc->sc_gpeh, sc->sc_gpebit, ACPI_GPE_TYPE_RUNTIME);
                    324:        if (rv != AE_OK) {
                    325:                aprint_error_dev(self, "unable to set GPE type: %s\n",
                    326:                    AcpiFormatException(rv));
                    327:                goto post_csr_map;
1.1       thorpej   328:        }
                    329:
1.41.6.5  joerg     330:        rv = AcpiEnableGpe(sc->sc_gpeh, sc->sc_gpebit, ACPI_ISR);
                    331:        if (rv != AE_OK) {
                    332:                aprint_error_dev(self, "unable to enable GPE: %s\n",
                    333:                    AcpiFormatException(rv));
                    334:                goto post_csr_map;
                    335:        }
1.23      kochi     336:
1.41.6.5  joerg     337:        if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, acpiec_gpe_query,
                    338:                           self, NULL, "acpiec sci thread")) {
                    339:                aprint_error_dev(self, "unable to create query kthread\n");
                    340:                goto post_csr_map;
1.17      mycroft   341:        }
                    342:
1.41.6.5  joerg     343:        ec_singleton = self;
1.1       thorpej   344:
1.41.6.12! joerg     345:        if (!pnp_device_register(self, acpiec_suspend, acpiec_resume))
        !           346:                aprint_error_dev(self, "couldn't establish power handler\n");
1.1       thorpej   347:
1.41.6.5  joerg     348:        return;
1.1       thorpej   349:
1.41.6.5  joerg     350: post_csr_map:
                    351:        (void)AcpiRemoveGpeHandler(sc->sc_gpeh, sc->sc_gpebit,
                    352:            acpiec_gpe_handler);
                    353:        (void)AcpiRemoveAddressSpaceHandler(sc->sc_ech,
                    354:            ACPI_ADR_SPACE_EC, acpiec_space_handler);
                    355:        bus_space_unmap(sc->sc_csr_st, sc->sc_csr_sh, 1);
                    356: post_data_map:
                    357:        bus_space_unmap(sc->sc_data_st, sc->sc_data_sh, 1);
                    358: }
                    359:
1.41.6.12! joerg     360: static bool
        !           361: acpiec_suspend(device_t dv)
1.41.6.5  joerg     362: {
1.41.6.12! joerg     363:        acpiec_cold = true;
1.41.6.5  joerg     364:
1.41.6.12! joerg     365:        return true;
        !           366: }
1.1       thorpej   367:
1.41.6.12! joerg     368: static bool
        !           369: acpiec_resume(device_t dv)
        !           370: {
        !           371:        acpiec_cold = false;
        !           372:
        !           373:        return true;
1.1       thorpej   374: }
                    375:
1.41.6.5  joerg     376: static bool
                    377: acpiec_parse_gpe_package(device_t self, ACPI_HANDLE ec_handle,
                    378:     ACPI_HANDLE *gpe_handle, uint8_t *gpebit)
1.1       thorpej   379: {
1.41.6.5  joerg     380:        ACPI_BUFFER buf;
                    381:        ACPI_OBJECT *p, *c;
1.25      kochi     382:        ACPI_STATUS rv;
1.1       thorpej   383:
1.41.6.5  joerg     384:        rv = acpi_eval_struct(ec_handle, "_GPE", &buf);
                    385:        if (rv != AE_OK) {
                    386:                aprint_error_dev(self, "unable to evaluate _GPE: %s\n",
                    387:                    AcpiFormatException(rv));
                    388:                return false;
                    389:        }
                    390:
                    391:        p = buf.Pointer;
                    392:
                    393:        if (p->Type == ACPI_TYPE_INTEGER) {
                    394:                *gpe_handle = NULL;
                    395:                *gpebit = p->Integer.Value;
                    396:                AcpiOsFree(p);
                    397:                return true;
                    398:        }
                    399:
                    400:        if (p->Type != ACPI_TYPE_PACKAGE) {
                    401:                aprint_error_dev(self, "_GPE is neither integer nor package\n");
                    402:                AcpiOsFree(p);
                    403:                return false;
                    404:        }
                    405:
                    406:        if (p->Package.Count != 2) {
                    407:                aprint_error_dev(self, "_GPE package does not contain 2 elements\n");
                    408:                AcpiOsFree(p);
                    409:                return false;
1.1       thorpej   410:        }
1.33      kochi     411:
1.41.6.5  joerg     412:        c = &p->Package.Elements[0];
                    413:        switch (c->Type) {
                    414:        case ACPI_TYPE_LOCAL_REFERENCE:
                    415:        case ACPI_TYPE_ANY:
                    416:                *gpe_handle = c->Reference.Handle;
                    417:                break;
                    418:        case ACPI_TYPE_STRING:
                    419:                /* XXX should be using real scope here */
                    420:                rv = AcpiGetHandle(NULL, p->String.Pointer, gpe_handle);
                    421:                if (rv != AE_OK) {
                    422:                        aprint_error_dev(self,
                    423:                            "_GPE device reference unresolvable\n");
                    424:                        AcpiOsFree(p);
                    425:                        return false;
                    426:                }
                    427:                break;
                    428:        default:
                    429:                aprint_error_dev(self, "_GPE device reference incorrect\n");
                    430:                AcpiOsFree(p);
                    431:                return false;
                    432:        }
                    433:        c = &p->Package.Elements[1];
                    434:        if (c->Type != ACPI_TYPE_INTEGER) {
                    435:                aprint_error_dev(self,
                    436:                    "_GPE package needs integer as 2nd field\n");
                    437:                AcpiOsFree(p);
                    438:                return false;
                    439:        }
                    440:        *gpebit = c->Integer.Value;
                    441:        AcpiOsFree(p);
                    442:        return true;
1.1       thorpej   443: }
                    444:
1.41.6.5  joerg     445: static uint8_t
                    446: acpiec_read_data(struct acpiec_softc *sc)
1.1       thorpej   447: {
1.41.6.5  joerg     448:        return bus_space_read_1(sc->sc_data_st, sc->sc_data_sh, 0);
                    449: }
1.1       thorpej   450:
1.41.6.5  joerg     451: static void
                    452: acpiec_write_data(struct acpiec_softc *sc, uint8_t val)
                    453: {
                    454:        bus_space_write_1(sc->sc_data_st, sc->sc_data_sh, 0, val);
                    455: }
1.1       thorpej   456:
1.41.6.5  joerg     457: static uint8_t
                    458: acpiec_read_status(struct acpiec_softc *sc)
                    459: {
                    460:        return bus_space_read_1(sc->sc_csr_st, sc->sc_csr_sh, 0);
                    461: }
1.1       thorpej   462:
1.41.6.5  joerg     463: static void
                    464: acpiec_write_command(struct acpiec_softc *sc, uint8_t cmd)
                    465: {
                    466:        bus_space_write_1(sc->sc_csr_st, sc->sc_csr_sh, 0, cmd);
1.1       thorpej   467: }
                    468:
                    469: static ACPI_STATUS
1.41.6.5  joerg     470: acpiec_space_setup(ACPI_HANDLE region, UINT32 func, void *arg,
                    471:     void **region_arg)
1.1       thorpej   472: {
1.41.6.5  joerg     473:        if (func == ACPI_REGION_DEACTIVATE)
                    474:                *region_arg = NULL;
                    475:        else
                    476:                *region_arg = arg;
1.1       thorpej   477:
1.41.6.5  joerg     478:        return AE_OK;
                    479: }
1.1       thorpej   480:
1.41.6.5  joerg     481: static void
                    482: acpiec_lock(device_t dv)
                    483: {
                    484:        struct acpiec_softc *sc = device_private(dv);
                    485:        ACPI_STATUS rv;
1.1       thorpej   486:
1.41.6.5  joerg     487:        mutex_enter(&sc->sc_access_mtx);
1.1       thorpej   488:
1.41.6.5  joerg     489:        if (sc->sc_need_global_lock) {
                    490:                rv = AcpiAcquireGlobalLock(EC_LOCK_TIMEOUT, &sc->sc_global_lock);
                    491:                if (rv != AE_OK) {
1.41.6.10  joerg     492:                        aprint_error_dev(dv, "failed to acquire global lock: %s\n",
                    493:                            AcpiFormatException(rv));
1.41.6.5  joerg     494:                        return;
                    495:                }
                    496:        }
                    497: }
1.1       thorpej   498:
1.41.6.5  joerg     499: static void
                    500: acpiec_unlock(device_t dv)
                    501: {
                    502:        struct acpiec_softc *sc = device_private(dv);
                    503:        ACPI_STATUS rv;
                    504:
                    505:        if (sc->sc_need_global_lock) {
                    506:                rv = AcpiReleaseGlobalLock(sc->sc_global_lock);
                    507:                if (rv != AE_OK) {
1.41.6.10  joerg     508:                        aprint_error_dev(dv, "failed to release global lock: %s\n",
                    509:                            AcpiFormatException(rv));
1.41.6.5  joerg     510:                }
1.1       thorpej   511:        }
1.41.6.5  joerg     512:        mutex_exit(&sc->sc_access_mtx);
                    513: }
1.1       thorpej   514:
1.41.6.5  joerg     515: static ACPI_STATUS
                    516: acpiec_read(device_t dv, uint8_t addr, uint8_t *val)
                    517: {
                    518:        struct acpiec_softc *sc = device_private(dv);
1.41.6.7  joerg     519:        int i, timeouts = 0;
1.1       thorpej   520:
1.41.6.5  joerg     521:        acpiec_lock(dv);
                    522:        mutex_enter(&sc->sc_mtx);
1.1       thorpej   523:
1.41.6.5  joerg     524: retry:
                    525:        sc->sc_cur_addr = addr;
                    526:        sc->sc_state = EC_STATE_READ;
                    527:
1.41.6.7  joerg     528:        for (i = 0; i < EC_POLL_TIMEOUT; ++i) {
                    529:                acpiec_gpe_state_maschine(dv);
                    530:                if (sc->sc_state == EC_STATE_FREE)
                    531:                        goto done;
                    532:                delay(1);
                    533:        }
                    534:
1.41.6.5  joerg     535:        if (cold || acpiec_cold) {
1.41.6.7  joerg     536:                while (sc->sc_state != EC_STATE_FREE) {
                    537:                        delay(1);
1.41.6.5  joerg     538:                        acpiec_gpe_state_maschine(dv);
1.41.6.7  joerg     539:                }
1.41.6.5  joerg     540:        } else while (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, hz)) {
                    541:                mutex_exit(&sc->sc_mtx);
                    542:                AcpiClearGpe(sc->sc_gpeh, sc->sc_gpebit, ACPI_NOT_ISR);
                    543:                mutex_enter(&sc->sc_mtx);
                    544:                if (++timeouts < 5)
                    545:                        goto retry;
                    546:                mutex_exit(&sc->sc_mtx);
                    547:                acpiec_unlock(dv);
                    548:                aprint_error_dev(dv, "command takes over 5sec...\n");
                    549:                return AE_ERROR;
                    550:        }
                    551:
1.41.6.7  joerg     552: done:
                    553:        *val = sc->sc_cur_val;
1.41.6.5  joerg     554:
                    555:        mutex_exit(&sc->sc_mtx);
                    556:        acpiec_unlock(dv);
                    557:        return AE_OK;
1.1       thorpej   558: }
                    559:
                    560: static ACPI_STATUS
1.41.6.5  joerg     561: acpiec_write(device_t dv, uint8_t addr, uint8_t val)
1.1       thorpej   562: {
1.41.6.5  joerg     563:        struct acpiec_softc *sc = device_private(dv);
1.41.6.7  joerg     564:        int i, timeouts = 0;
1.1       thorpej   565:
1.41.6.5  joerg     566:        acpiec_lock(dv);
                    567:        mutex_enter(&sc->sc_mtx);
1.1       thorpej   568:
1.41.6.5  joerg     569: retry:
                    570:        sc->sc_cur_addr = addr;
                    571:        sc->sc_cur_val = val;
                    572:        sc->sc_state = EC_STATE_WRITE;
                    573:
1.41.6.7  joerg     574:        for (i = 0; i < EC_POLL_TIMEOUT; ++i) {
                    575:                acpiec_gpe_state_maschine(dv);
                    576:                if (sc->sc_state == EC_STATE_FREE)
                    577:                        goto done;
                    578:                delay(1);
                    579:        }
                    580:
1.41.6.5  joerg     581:        if (cold || acpiec_cold) {
1.41.6.7  joerg     582:                while (sc->sc_state != EC_STATE_FREE) {
                    583:                        delay(1);
1.41.6.5  joerg     584:                        acpiec_gpe_state_maschine(dv);
1.41.6.7  joerg     585:                }
1.41.6.5  joerg     586:        } else while (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, hz)) {
                    587:                mutex_exit(&sc->sc_mtx);
                    588:                AcpiClearGpe(sc->sc_gpeh, sc->sc_gpebit, ACPI_NOT_ISR);
                    589:                mutex_enter(&sc->sc_mtx);
                    590:                if (++timeouts < 5)
                    591:                        goto retry;
                    592:                mutex_exit(&sc->sc_mtx);
                    593:                acpiec_unlock(dv);
                    594:                aprint_error_dev(dv, "command takes over 5sec...\n");
                    595:                return AE_ERROR;
1.41.6.4  joerg     596:        }
                    597:
1.41.6.7  joerg     598: done:
1.41.6.5  joerg     599:        mutex_exit(&sc->sc_mtx);
                    600:        acpiec_unlock(dv);
                    601:        return AE_OK;
1.1       thorpej   602: }
                    603:
                    604: static ACPI_STATUS
1.41.6.5  joerg     605: acpiec_space_handler(UINT32 func, ACPI_PHYSICAL_ADDRESS paddr,
                    606:     UINT32 width, ACPI_INTEGER *value, void *arg, void *region_arg)
1.1       thorpej   607: {
1.41.6.5  joerg     608:        device_t dv;
                    609:        struct acpiec_softc *sc;
1.25      kochi     610:        ACPI_STATUS rv;
1.41.6.5  joerg     611:        uint8_t addr, reg;
                    612:        unsigned int i;
                    613:
                    614:        if (paddr > 0xff || width % 8 != 0 || value == NULL || arg == NULL ||
                    615:            paddr + width / 8 > 0xff)
                    616:                return AE_BAD_PARAMETER;
1.1       thorpej   617:
1.41.6.5  joerg     618:        addr = paddr;
                    619:        dv = arg;
                    620:        sc = device_private(dv);
                    621:
                    622:        rv = AE_OK;
                    623:
                    624:        switch (func) {
                    625:        case ACPI_READ:
1.41.6.8  joerg     626:                *value = 0;
1.41.6.5  joerg     627:                for (i = 0; i < width; i += 8, ++addr) {
                    628:                        rv = acpiec_read(dv, addr, &reg);
                    629:                        if (rv != AE_OK)
                    630:                                break;
                    631:                        *value |= (ACPI_INTEGER)reg << i;
                    632:                }
                    633:                break;
                    634:        case ACPI_WRITE:
                    635:                for (i = 0; i < width; i += 8, ++addr) {
                    636:                        reg = (*value >>i) & 0xff;
                    637:                        rv = acpiec_write(dv, addr, reg);
                    638:                        if (rv != AE_OK)
                    639:                                break;
                    640:                }
                    641:                break;
                    642:        default:
                    643:                aprint_error("%s: invalid Address Space function called: %x\n",
                    644:                    device_xname(dv), (unsigned int)func);
                    645:                return AE_BAD_PARAMETER;
                    646:        }
1.1       thorpej   647:
1.25      kochi     648:        return rv;
1.24      kochi     649: }
1.1       thorpej   650:
1.41.6.5  joerg     651: static void
                    652: acpiec_gpe_query(void *arg)
1.1       thorpej   653: {
1.41.6.5  joerg     654:        device_t dv = arg;
                    655:        struct acpiec_softc *sc = device_private(dv);
                    656:        uint8_t reg;
                    657:        char qxx[5];
1.25      kochi     658:        ACPI_STATUS rv;
1.41.6.7  joerg     659:        int i;
1.1       thorpej   660:
1.41.6.5  joerg     661: loop:
                    662:        mutex_enter(&sc->sc_mtx);
1.1       thorpej   663:
1.41.6.5  joerg     664:        if (sc->sc_got_sci == false)
                    665:                cv_wait(&sc->sc_cv_sci, &sc->sc_mtx);
                    666:        mutex_exit(&sc->sc_mtx);
1.1       thorpej   667:
1.41.6.5  joerg     668:        acpiec_lock(dv);
                    669:        mutex_enter(&sc->sc_mtx);
1.1       thorpej   670:
1.41.6.7  joerg     671:        /* The Query command can always be issued, so be defensive here. */
                    672:        sc->sc_got_sci = false;
1.41.6.5  joerg     673:        sc->sc_state = EC_STATE_QUERY;
1.1       thorpej   674:
1.41.6.7  joerg     675:        for (i = 0; i < EC_POLL_TIMEOUT; ++i) {
                    676:                acpiec_gpe_state_maschine(dv);
                    677:                if (sc->sc_state == EC_STATE_FREE)
                    678:                        goto done;
                    679:                delay(1);
                    680:        }
                    681:
1.41.6.5  joerg     682:        cv_wait(&sc->sc_cv, &sc->sc_mtx);
1.1       thorpej   683:
1.41.6.7  joerg     684: done:
                    685:        reg = sc->sc_cur_val;
1.1       thorpej   686:
1.41.6.5  joerg     687:        mutex_exit(&sc->sc_mtx);
                    688:        acpiec_unlock(dv);
                    689:
                    690:        if (reg == 0)
                    691:                goto loop; /* Spurious query result */
1.41.6.7  joerg     692:
1.41.6.5  joerg     693:        /*
                    694:         * Evaluate _Qxx to respond to the controller.
                    695:         */
                    696:        snprintf(qxx, sizeof(qxx), "_Q%02X", (unsigned int)reg);
                    697:        rv = AcpiEvaluateObject(sc->sc_ech, qxx, NULL, NULL);
                    698:        if (rv != AE_OK && rv != AE_NOT_FOUND) {
                    699:                aprint_error("%s: GPE query method %s failed: %s",
                    700:                    device_xname(dv), qxx, AcpiFormatException(rv));
                    701:        }
                    702:
                    703:        goto loop;
1.24      kochi     704: }
1.1       thorpej   705:
1.41.6.5  joerg     706: static void
                    707: acpiec_gpe_state_maschine(device_t dv)
1.1       thorpej   708: {
1.41.6.5  joerg     709:        struct acpiec_softc *sc = device_private(dv);
                    710:        uint8_t reg;
1.1       thorpej   711:
1.41.6.5  joerg     712:        reg = acpiec_read_status(sc);
1.1       thorpej   713:
1.41.6.5  joerg     714:        if (reg & EC_STATUS_SCI)
                    715:                sc->sc_got_sci = true;
1.1       thorpej   716:
1.41.6.5  joerg     717:        switch (sc->sc_state) {
                    718:        case EC_STATE_QUERY:
1.41.6.7  joerg     719:                if ((reg & EC_STATUS_IBF) != 0)
                    720:                        break; /* Nothing of interest here. */
                    721:                acpiec_write_command(sc, EC_COMMAND_QUERY);
                    722:                sc->sc_state = EC_STATE_QUERY_VAL;
                    723:                break;
                    724:
                    725:        case EC_STATE_QUERY_VAL:
1.41.6.5  joerg     726:                if ((reg & EC_STATUS_OBF) == 0)
                    727:                        break; /* Nothing of interest here. */
1.1       thorpej   728:
1.41.6.7  joerg     729:                sc->sc_cur_val = acpiec_read_data(sc);
                    730:                sc->sc_state = EC_STATE_FREE;
                    731:
1.41.6.5  joerg     732:                cv_signal(&sc->sc_cv);
                    733:                break;
1.1       thorpej   734:
1.41.6.5  joerg     735:        case EC_STATE_READ:
                    736:                if ((reg & EC_STATUS_IBF) != 0)
                    737:                        break; /* Nothing of interest here. */
1.1       thorpej   738:
1.41.6.7  joerg     739:                acpiec_write_command(sc, EC_COMMAND_READ);
                    740:                sc->sc_state = EC_STATE_READ_ADDR;
                    741:                break;
                    742:
                    743:        case EC_STATE_READ_ADDR:
                    744:                if ((reg & EC_STATUS_IBF) != 0)
                    745:                        break; /* Nothing of interest here. */
                    746:
1.41.6.5  joerg     747:                acpiec_write_data(sc, sc->sc_cur_addr);
                    748:                sc->sc_state = EC_STATE_READ_VAL;
                    749:                break;
1.1       thorpej   750:
1.41.6.5  joerg     751:        case EC_STATE_READ_VAL:
                    752:                if ((reg & EC_STATUS_OBF) == 0)
                    753:                        break; /* Nothing of interest here. */
1.41.6.7  joerg     754:                sc->sc_cur_val = acpiec_read_data(sc);
                    755:                sc->sc_state = EC_STATE_FREE;
                    756:
1.41.6.5  joerg     757:                cv_signal(&sc->sc_cv);
                    758:                break;
1.41.6.3  joerg     759:
1.41.6.5  joerg     760:        case EC_STATE_WRITE:
                    761:                if ((reg & EC_STATUS_IBF) != 0)
                    762:                        break; /* Nothing of interest here. */
1.41.6.7  joerg     763:
                    764:                acpiec_write_command(sc, EC_COMMAND_WRITE);
                    765:                sc->sc_state = EC_STATE_WRITE_ADDR;
                    766:                break;
                    767:
                    768:        case EC_STATE_WRITE_ADDR:
                    769:                if ((reg & EC_STATUS_IBF) != 0)
                    770:                        break; /* Nothing of interest here. */
1.41.6.5  joerg     771:                acpiec_write_data(sc, sc->sc_cur_addr);
                    772:                sc->sc_state = EC_STATE_WRITE_VAL;
                    773:                break;
1.41.6.3  joerg     774:
1.41.6.5  joerg     775:        case EC_STATE_WRITE_VAL:
                    776:                if ((reg & EC_STATUS_IBF) != 0)
                    777:                        break; /* Nothing of interest here. */
1.41.6.7  joerg     778:                sc->sc_state = EC_STATE_FREE;
1.41.6.5  joerg     779:                cv_signal(&sc->sc_cv);
1.41.6.3  joerg     780:
1.41.6.7  joerg     781:                acpiec_write_data(sc, sc->sc_cur_val);
1.41.6.3  joerg     782:                break;
                    783:
1.41.6.5  joerg     784:        case EC_STATE_FREE:
                    785:                if (sc->sc_got_sci)
                    786:                        cv_signal(&sc->sc_cv_sci);
1.41.6.3  joerg     787:                break;
1.41.6.5  joerg     788:        default:
                    789:                panic("invalid state");
1.41.6.3  joerg     790:        }
1.41.6.5  joerg     791: }
1.41.6.3  joerg     792:
1.41.6.5  joerg     793: static UINT32
                    794: acpiec_gpe_handler(void *arg)
                    795: {
                    796:        device_t dv = arg;
                    797:        struct acpiec_softc *sc = device_private(dv);
1.41.6.3  joerg     798:
1.41.6.5  joerg     799:        AcpiClearGpe(sc->sc_gpeh, sc->sc_gpebit, ACPI_ISR);
                    800:
                    801:        mutex_enter(&sc->sc_mtx);
                    802:        acpiec_gpe_state_maschine(dv);
                    803:        mutex_exit(&sc->sc_mtx);
                    804:
                    805:        return 0;
1.41.6.3  joerg     806: }

CVSweb <webmaster@jp.NetBSD.org>