After discussions with Theo we decided to walk the table where needed instead of using the soft state variables.
Also adding all the Samsung models to the quirks table (as per the Linux EC quirks table). Index: acpiec.c =================================================================== RCS file: /cvs/src/sys/dev/acpi/acpiec.c,v retrieving revision 1.49 diff -u -p -r1.49 acpiec.c --- acpiec.c 21 May 2014 02:14:07 -0000 1.49 +++ acpiec.c 10 Jun 2014 15:18:59 -0000 @@ -34,6 +34,7 @@ int acpiec_match(struct device *, void *, void *); void acpiec_attach(struct device *, struct device *, void *); +int acpiec_activate(struct device *, int); u_int8_t acpiec_status(struct acpiec_softc *); u_int8_t acpiec_read_data(struct acpiec_softc *); @@ -54,6 +55,7 @@ int acpiec_getregister(const u_int8_t * void acpiec_wait(struct acpiec_softc *, u_int8_t, u_int8_t); void acpiec_sci_event(struct acpiec_softc *); +void acpiec_clear_events(struct acpiec_softc *); void acpiec_get_events(struct acpiec_softc *); @@ -82,7 +84,8 @@ void acpiec_unlock(struct acpiec_softc int acpiec_reg(struct acpiec_softc *); struct cfattach acpiec_ca = { - sizeof(struct acpiec_softc), acpiec_match, acpiec_attach + sizeof(struct acpiec_softc), acpiec_match, acpiec_attach, + NULL, acpiec_activate }; struct cfdriver acpiec_cd = { @@ -91,6 +94,34 @@ struct cfdriver acpiec_cd = { const char *acpiec_hids[] = { ACPI_DEV_ECD, 0 }; +/* needed by acpiec_clear_events */ +extern char *hw_vendor, *hw_prod; + +struct ec_quirks_description { + char *vendor; + char *prod; +}; + +static const struct ec_quirks_description ec_quirks[] = { + /* + * Header description: + * + * The entries define the machine model based on information + * from BIOS in the following order: VENDOR, PRODUCT + * + */ + + /* ThinkPad x120e */ + { "LENOVO", "05962PU" }, + + /* + * All Samsung models require this according to Linux + * https://bugzilla.kernel.org/show_bug.cgi?id=44161 + */ + { "SAMSUNG ELECTRONICS CO., LTD.", NULL } +}; + + void acpiec_wait(struct acpiec_softc *sc, u_int8_t mask, u_int8_t val) { @@ -274,6 +305,8 @@ acpiec_attach(struct device *parent, str struct acpi_attach_args *aa = aux; struct aml_value res; + int i; + sc->sc_acpi = (struct acpi_softc *)parent; sc->sc_devnode = aa->aaa_node; @@ -297,7 +330,16 @@ acpiec_attach(struct device *parent, str acpi_set_gpehandler(sc->sc_acpi, sc->sc_gpe, acpiec_gpehandler, sc, 1); #endif - + + for (i = 0; i < nitems(ec_quirks); i++) + if ((!strcmp(hw_vendor, ec_quirks[i].vendor)) && + (ec_quirks[i].prod == NULL || + (!strcmp(hw_prod, ec_quirks[i].prod)))) { + acpiec_clear_events(sc); + break; + } + + if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_GLK", 0, NULL, &res)) sc->sc_glk = 0; else if (res.type != AML_OBJTYPE_INTEGER) @@ -308,6 +350,26 @@ acpiec_attach(struct device *parent, str printf("\n"); } +int +acpiec_activate(struct device *self, int act) +{ + struct acpiec_softc *sc = (struct acpiec_softc *)self; + int i; + + switch (act) { + case DVACT_RESUME: + for (i = 0; i < nitems(ec_quirks); i++) + if ((!strcmp(hw_vendor, ec_quirks[i].vendor)) && + (ec_quirks[i].prod == NULL || + (!strcmp(hw_prod, ec_quirks[i].prod)))) { + acpiec_clear_events(sc); + break; + } + break; + } + return (0); +} + void acpiec_get_events(struct acpiec_softc *sc) { @@ -553,4 +615,17 @@ acpiec_unlock(struct acpiec_softc *sc) } sc->sc_ecbusy = 0; +} + +void +acpiec_clear_events(struct acpiec_softc *sc) +{ + int i; + + for (i = 0; i < 100; i++) { + acpiec_write_cmd(sc, EC_CMD_QR); + sc->sc_gotsci = 0; + if ((acpiec_status(sc) & EC_STAT_SCI_EVT) != EC_STAT_SCI_EVT) + break; + } }