Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/acpi As explained in the new ACPICA documentation, a...



details:   https://anonhg.NetBSD.org/src/rev/3ced66737a41
branches:  trunk
changeset: 762231:3ced66737a41
user:      jruoho <jruoho%NetBSD.org@localhost>
date:      Thu Feb 17 19:36:49 2011 +0000

description:
As explained in the new ACPICA documentation, as of ACPICA 20101207, the
_PRW methods are no longer automatically executed as part of the ACPICA
initialization. Refactor and rewrite the wake-device code to account this.

diffstat:

 sys/dev/acpi/acpi.c         |   24 ++-
 sys/dev/acpi/acpi_wakedev.c |  408 +++++++++++++++++++++++++------------------
 sys/dev/acpi/acpi_wakedev.h |   17 +-
 sys/dev/acpi/acpivar.h      |    5 +-
 4 files changed, 273 insertions(+), 181 deletions(-)

diffs (truncated from 596 to 300 lines):

diff -r a55d04e32201 -r 3ced66737a41 sys/dev/acpi/acpi.c
--- a/sys/dev/acpi/acpi.c       Thu Feb 17 19:29:41 2011 +0000
+++ b/sys/dev/acpi/acpi.c       Thu Feb 17 19:36:49 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: acpi.c,v 1.235 2011/02/15 20:24:11 jruoho Exp $        */
+/*     $NetBSD: acpi.c,v 1.236 2011/02/17 19:36:49 jruoho Exp $        */
 
 /*-
  * Copyright (c) 2003, 2007 The NetBSD Foundation, Inc.
@@ -100,7 +100,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.235 2011/02/15 20:24:11 jruoho Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.236 2011/02/17 19:36:49 jruoho Exp $");
 
 #include "opt_acpi.h"
 #include "opt_pcifixup.h"
@@ -685,6 +685,14 @@
        (void)acpi_rescan(sc->sc_dev, NULL, NULL);
 
        /*
+        * Update GPE information.
+        *
+        * Note that this must be called after
+        * all GPE handlers have been installed.
+        */
+       (void)AcpiUpdateAllGpes();
+
+       /*
         * Defer rest of the configuration.
         */
        (void)config_defer(sc->sc_dev, acpi_rescan_capabilities);
@@ -724,6 +732,7 @@
                ad->ad_device = NULL;
                ad->ad_notify = NULL;
                ad->ad_pciinfo = NULL;
+               ad->ad_wakedev = NULL;
 
                ad->ad_type = type;
                ad->ad_handle = handle;
@@ -735,6 +744,13 @@
                acpi_set_node(ad);
                acpi_make_name(ad, devinfo->Name);
 
+               /*
+                * Identify wake GPEs from the _PRW. Note that
+                * AcpiUpdateAllGpes() must be called afterwards.
+                */
+               if (ad->ad_devinfo->Type == ACPI_TYPE_DEVICE)
+                       acpi_wakedev_init(ad);
+
                SIMPLEQ_INIT(&ad->ad_child_head);
                SIMPLEQ_INSERT_TAIL(&sc->ad_head, ad, ad_list);
 
@@ -940,9 +956,7 @@
                /*
                 * Scan wake-up capabilities.
                 */
-               rv = AcpiGetHandle(ad->ad_handle, "_PRW", &tmp);
-
-               if (ACPI_SUCCESS(rv)) {
+               if (ad->ad_wakedev != NULL) {
                        ad->ad_flags |= ACPI_DEVICE_WAKEUP;
                        acpi_wakedev_add(ad);
                }
diff -r a55d04e32201 -r 3ced66737a41 sys/dev/acpi/acpi_wakedev.c
--- a/sys/dev/acpi/acpi_wakedev.c       Thu Feb 17 19:29:41 2011 +0000
+++ b/sys/dev/acpi/acpi_wakedev.c       Thu Feb 17 19:36:49 2011 +0000
@@ -1,7 +1,7 @@
-/* $NetBSD: acpi_wakedev.c,v 1.21 2011/02/17 10:49:29 jruoho Exp $ */
+/* $NetBSD: acpi_wakedev.c,v 1.22 2011/02/17 19:36:49 jruoho Exp $ */
 
 /*-
- * Copyright (c) 2009, 2010 Jared D. McNeill <jmcneill%invisible.ca@localhost>
+ * Copyright (c) 2009, 2010, 2011 Jared D. McNeill <jmcneill%invisible.ca@localhost>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,12 +27,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_wakedev.c,v 1.21 2011/02/17 10:49:29 jruoho Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_wakedev.c,v 1.22 2011/02/17 19:36:49 jruoho Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
 #include <sys/sysctl.h>
 #include <sys/systm.h>
+#include <sys/malloc.h>
 
 #include <dev/acpi/acpireg.h>
 #include <dev/acpi/acpivar.h>
@@ -51,12 +52,191 @@
        NULL,
 };
 
+MALLOC_DECLARE(M_ACPI);
+
 static int32_t acpi_wakedev_acpinode = CTL_EOL;
 static int32_t acpi_wakedev_wakenode = CTL_EOL;
 
-static void    acpi_wakedev_method(struct acpi_devnode *, int, int);
-static void    acpi_wakedev_gpe(struct acpi_devnode *, int, int);
 static void    acpi_wakedev_power(struct acpi_devnode *, ACPI_OBJECT *);
+static void    acpi_wakedev_set(struct acpi_devnode *, int);
+static void    acpi_wakedev_method(struct acpi_devnode *, int);
+
+void
+acpi_wakedev_init(struct acpi_devnode *ad)
+{
+       ACPI_OBJECT *elm, *obj;
+       ACPI_HANDLE hdl = NULL;
+       ACPI_INTEGER val = 0;
+       ACPI_BUFFER buf;
+       ACPI_STATUS rv;
+
+       rv = acpi_eval_struct(ad->ad_handle, "_PRW", &buf);
+
+       if (ACPI_FAILURE(rv))
+               goto out;
+
+       obj = buf.Pointer;
+
+       if (obj->Type != ACPI_TYPE_PACKAGE) {
+               rv = AE_TYPE;
+               goto out;
+       }
+
+       if (obj->Package.Count < 2) {
+               rv = AE_LIMIT;
+               goto out;
+       }
+
+       /*
+        * As noted in ACPI 3.0 (section 7.2.10), the _PRW object is
+        * a package in which the first element is either an integer
+        * or again a package. In the latter case the package inside
+        * the package element has two elements, a reference handle
+        * and the GPE number.
+        */
+       elm = &obj->Package.Elements[0];
+
+       switch (elm->Type) {
+
+       case ACPI_TYPE_INTEGER:
+               val = elm->Integer.Value;
+               break;
+
+       case ACPI_TYPE_PACKAGE:
+
+               if (elm->Package.Count < 2) {
+                       rv = AE_LIMIT;
+                       goto out;
+               }
+
+               rv = AE_TYPE;
+
+               if (elm->Package.Elements[0].Type != ACPI_TYPE_LOCAL_REFERENCE)
+                       goto out;
+
+               if (elm->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
+                       goto out;
+
+               hdl = elm->Package.Elements[0].Reference.Handle;
+               val = elm->Package.Elements[1].Integer.Value;
+               break;
+
+       default:
+               rv = AE_TYPE;
+               goto out;
+       }
+
+       ad->ad_wakedev = malloc(sizeof(*ad->ad_wakedev),
+           M_ACPI, M_NOWAIT | M_ZERO);
+
+       if (ad->ad_wakedev == NULL)
+               return;
+
+       ad->ad_wakedev->aw_handle = hdl;
+       ad->ad_wakedev->aw_number = val;
+
+       /*
+        * The second element in _PRW is an integer
+        * that contains the lowest sleep state that
+        * can be entered while still providing wakeup.
+        */
+       elm = &obj->Package.Elements[1];
+
+       if (elm->Type == ACPI_TYPE_INTEGER)
+               ad->ad_wakedev->aw_sleep = elm->Integer.Value;
+
+       /*
+        * Rest of the elements are references
+        * to power resources. Store these.
+        */
+       acpi_wakedev_power(ad, obj);
+
+       /*
+        * Last but not least, mark GPEs for wake.
+        */
+       rv = AcpiSetupGpeForWake(ad->ad_handle, hdl, val);
+
+out:
+       if (buf.Pointer != NULL)
+               ACPI_FREE(buf.Pointer);
+
+       if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND)
+               aprint_error_dev(ad->ad_root, "failed to evaluate _PRW "
+                   "for %s: %s\n", ad->ad_name, AcpiFormatException(rv));
+}
+
+static void
+acpi_wakedev_power(struct acpi_devnode *ad, ACPI_OBJECT *obj)
+{
+       struct acpi_wakedev *aw = ad->ad_wakedev;
+       uint32_t i, j, n;
+       ACPI_OBJECT *elm;
+       ACPI_HANDLE hdl;
+       ACPI_STATUS rv;
+
+       for (i = 0; i < __arraycount(aw->aw_power); i++)
+               aw->aw_power[i] = NULL;
+
+       n = obj->Package.Count;
+
+       if (n < 3 || n - 2 > __arraycount(aw->aw_power))
+               return;
+
+       for (i = 2, j = 0; i < n; i++, j++) {
+
+               elm = &obj->Package.Elements[i];
+               rv = acpi_eval_reference_handle(elm, &hdl);
+
+               if (ACPI_FAILURE(rv))
+                       continue;
+
+               ad->ad_wakedev->aw_power[j] = hdl;
+       }
+}
+
+void
+acpi_wakedev_add(struct acpi_devnode *ad)
+{
+       struct acpi_wakedev *aw;
+       const char *str = NULL;
+       device_t dev;
+       int err;
+
+       KASSERT(ad != NULL && ad->ad_wakedev != NULL);
+       KASSERT((ad->ad_flags & ACPI_DEVICE_WAKEUP) != 0);
+
+       aw = ad->ad_wakedev;
+       aw->aw_enable = false;
+
+       if (acpi_match_hid(ad->ad_devinfo, acpi_wakedev_default))
+               ad->ad_wakedev->aw_enable = true;
+
+       if (acpi_wakedev_acpinode == CTL_EOL ||
+           acpi_wakedev_wakenode == CTL_EOL)
+               return;
+
+       if (ad->ad_device != NULL)
+               str = device_xname(ad->ad_device);
+       else {
+               dev = acpi_pcidev_find_dev(ad);
+
+               if (dev != NULL)
+                       str = device_xname(dev);
+       }
+
+       if (str == NULL)
+               return;
+
+       err = sysctl_createv(NULL, 0, NULL, NULL,
+           CTLFLAG_READWRITE, CTLTYPE_BOOL, str,
+           NULL, NULL, 0, &ad->ad_wakedev->aw_enable, 0, CTL_HW,
+           acpi_wakedev_acpinode, acpi_wakedev_wakenode,
+           CTL_CREATE, CTL_EOL);
+
+       if (err != 0)
+               aprint_error_dev(ad->ad_root, "sysctl_createv"
+                   "(hw.acpi.wake.%s) failed (err %d)\n", str, err);
+}
 
 SYSCTL_SETUP(sysctl_acpi_wakedev_setup, "sysctl hw.acpi.wake subtree setup")
 {
@@ -94,48 +274,6 @@
 }
 
 void
-acpi_wakedev_add(struct acpi_devnode *ad)
-{
-       const char *str = NULL;
-       device_t dev;
-       int err;
-
-       KASSERT(ad != NULL && ad->ad_root != NULL);
-       KASSERT((ad->ad_flags & ACPI_DEVICE_WAKEUP) != 0);



Home | Main Index | Thread Index | Old Index