Hi,

This is adding vendor-based support to my initial acpiec(4) clear events
work[1].

It seems some machines need this only during resume, while other need it
at attach (boot) as well. And then there's the group of machines that
completely rely on having events in the queue on both boot and resume.

And so, with this diff, we'll be able to pick where to enable event clearing.

I added a first example based on the feedback I got during the first version
of this diff.

Any comments? Okay? 

[1] - http://marc.info/?l=openbsd-tech&m=139586828926337&w=2

Index: acpidev.h
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpidev.h,v
retrieving revision 1.34
diff -u -p -r1.34 acpidev.h
--- acpidev.h   23 May 2014 19:17:39 -0000      1.34
+++ acpidev.h   10 Jun 2014 12:42:00 -0000
@@ -333,6 +333,10 @@ struct acpiec_softc {
        struct acpiec_event     sc_events[ACPIEC_MAX_EVENTS];
        int                     sc_gotsci;
        int                     sc_glk;
+
+       /* Quirks: clear events on attatch/resume */
+       char                    sc_clear_attatch;
+       char                    sc_clear_resume;
 };
 
 void           acpibtn_disable_psw(void);
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 12:42:00 -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,32 @@ 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;
+       char attatch;
+       char resume;
+};
+
+static const struct ec_quirks_description ec_quirks[] = {
+       /*
+        * Header description:
+        *
+        * The first two entries define the machine model based on information
+        * from BIOS in the following order: VENDOR, PRODUCT
+        *
+        * The last two values state if and when clearing events should be done:
+        * during attatch and/or during resume.
+        */
+
+       /* ThinkPad x120e */
+       { "LENOVO", "05962PU", 1, 1, },
+};
+
+
 void
 acpiec_wait(struct acpiec_softc *sc, u_int8_t mask, u_int8_t val)
 {
@@ -274,6 +303,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,6 +328,17 @@ 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)) &&
+                   (!strcmp(hw_prod, ec_quirks[i].prod))) {
+                       sc->sc_clear_attatch = ec_quirks[i].attatch;
+                       sc->sc_clear_resume = ec_quirks[i].resume;
+                       break;
+               }
+
+       if (sc->sc_clear_attatch)
+               acpiec_clear_events(sc);
        
        if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_GLK", 0, NULL, &res))
                sc->sc_glk = 0;
@@ -308,6 +350,21 @@ acpiec_attach(struct device *parent, str
        printf("\n");
 }
 
+int
+acpiec_activate(struct device *self, int act)
+{
+       struct acpiec_softc *sc = (struct acpiec_softc *)self;
+
+
+       switch (act) {
+       case DVACT_RESUME:
+               if (sc->sc_clear_resume)
+                       acpiec_clear_events(sc);
+               break;
+       }
+       return (0);
+}
+
 void
 acpiec_get_events(struct acpiec_softc *sc)
 {
@@ -553,4 +610,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;
+       }
 }

Reply via email to