root/dev/acpi/acpiec.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. acpiec_wait
  2. acpiec_status
  3. acpiec_write_data
  4. acpiec_write_cmd
  5. acpiec_read_data
  6. acpiec_sci_event
  7. acpiec_read_1
  8. acpiec_write_1
  9. acpiec_burst_enable
  10. acpiec_read
  11. acpiec_write
  12. acpiec_match
  13. acpiec_attach
  14. acpiec_get_events
  15. acpiec_gpehandler
  16. acpiec_getregister
  17. acpiec_getcrs
  18. acpiec_reg

    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 }

/* [<][>][^][v][top][bottom][index][help] */