xref: /openbsd-src/sys/dev/acpi/acpiac.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /* $OpenBSD: acpiac.c,v 1.27 2009/03/11 20:37:46 jordan Exp $ */
2 /*
3  * Copyright (c) 2005 Marco Peereboom <marco@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/systm.h>
20 #include <sys/device.h>
21 #include <sys/malloc.h>
22 
23 #include <machine/bus.h>
24 
25 #include <dev/acpi/acpireg.h>
26 #include <dev/acpi/acpivar.h>
27 #include <dev/acpi/acpidev.h>
28 #include <dev/acpi/amltypes.h>
29 #include <dev/acpi/dsdt.h>
30 
31 #include <sys/sensors.h>
32 
33 int  acpiac_match(struct device *, void *, void *);
34 void acpiac_attach(struct device *, struct device *, void *);
35 int  acpiac_notify(struct aml_node *, int, void *);
36 
37 void acpiac_refresh(void *);
38 int acpiac_getsta(struct acpiac_softc *);
39 
40 struct cfattach acpiac_ca = {
41 	sizeof(struct acpiac_softc), acpiac_match, acpiac_attach
42 };
43 
44 struct cfdriver acpiac_cd = {
45 	NULL, "acpiac", DV_DULL
46 };
47 
48 const char *acpiac_hids[] = { ACPI_DEV_AC, 0 };
49 
50 int
51 acpiac_match(struct device *parent, void *match, void *aux)
52 {
53 	struct acpi_attach_args *aa = aux;
54 	struct cfdata *cf = match;
55 
56 	/* sanity */
57 	return (acpi_matchhids(aa, acpiac_hids, cf->cf_driver->cd_name));
58 }
59 
60 void
61 acpiac_attach(struct device *parent, struct device *self, void *aux)
62 {
63 	struct acpiac_softc *sc = (struct acpiac_softc *)self;
64 	struct acpi_attach_args *aa = aux;
65 
66 	sc->sc_acpi = (struct acpi_softc *)parent;
67 	sc->sc_devnode = aa->aaa_node;
68 
69 	acpiac_getsta(sc);
70 	printf(": AC unit ");
71 	if (sc->sc_ac_stat == PSR_ONLINE)
72 		printf("online\n");
73 	else if (sc->sc_ac_stat == PSR_OFFLINE)
74 		printf("offline\n");
75 	else
76 		printf("in unknown state\n");
77 
78 	strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
79 	    sizeof(sc->sc_sensdev.xname));
80 	strlcpy(sc->sc_sens[0].desc, "power supply",
81 	    sizeof(sc->sc_sens[0].desc));
82 	sc->sc_sens[0].type = SENSOR_INDICATOR;
83 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[0]);
84 	sensordev_install(&sc->sc_sensdev);
85 	sc->sc_sens[0].value = sc->sc_ac_stat;
86 
87 	aml_register_notify(sc->sc_devnode, aa->aaa_dev,
88 	    acpiac_notify, sc, ACPIDEV_NOPOLL);
89 }
90 
91 void
92 acpiac_refresh(void *arg)
93 {
94 	struct acpiac_softc *sc = arg;
95 
96 	acpiac_getsta(sc);
97 	sc->sc_sens[0].value = sc->sc_ac_stat;
98 }
99 
100 int
101 acpiac_getsta(struct acpiac_softc *sc)
102 {
103 	int64_t sta;
104 
105 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, NULL)) {
106 		dnprintf(10, "%s: no _STA\n",
107 		    DEVNAME(sc));
108 	}
109 
110 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_PSR", 0, NULL, &sta)) {
111 		dnprintf(10, "%s: no _PSR\n",
112 		    DEVNAME(sc));
113 		return (1);
114 	}
115 	sc->sc_ac_stat = sta;
116 	return (0);
117 }
118 
119 int
120 acpiac_notify(struct aml_node *node, int notify_type, void *arg)
121 {
122 	struct acpiac_softc *sc = arg;
123 
124 	dnprintf(10, "acpiac_notify: %.2x %s\n", notify_type,
125 	    sc->sc_devnode->name);
126 
127 	switch (notify_type) {
128 	case 0x00:
129 	case 0x01:
130 	case 0x81:
131 		/*
132 		 * XXX some sony vaio's use the wrong notify type
133 		 * work around it by honoring it as a 0x80
134 		 */
135 		/* FALLTHROUGH */
136 	case 0x80:
137 		acpiac_refresh(sc);
138 		dnprintf(10, "A/C status: %d\n", sc->sc_ac_stat);
139 		break;
140 	}
141 	return (0);
142 }
143