Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/acpica/acpi_acad.c
39535 views
1
/*-
2
* Copyright (c) 2000 Takanori Watanabe
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
#include <sys/cdefs.h>
28
#include "opt_acpi.h"
29
#include <sys/param.h>
30
#include <sys/kernel.h>
31
#include <sys/bus.h>
32
33
#include <machine/bus.h>
34
#include <sys/rman.h>
35
#include <sys/eventhandler.h>
36
#include <sys/ioccom.h>
37
#include <sys/malloc.h>
38
#include <sys/module.h>
39
#include <sys/conf.h>
40
#include <sys/power.h>
41
42
#include <contrib/dev/acpica/include/acpi.h>
43
44
#include <dev/acpica/acpivar.h>
45
#include <dev/acpica/acpiio.h>
46
#include <isa/isavar.h>
47
#include <isa/pnpvar.h>
48
49
/* Hooks for the ACPI CA debugging infrastructure */
50
#define _COMPONENT ACPI_AC_ADAPTER
51
ACPI_MODULE_NAME("AC_ADAPTER")
52
53
/* Number of times to retry initialization before giving up. */
54
#define ACPI_ACAD_RETRY_MAX 6
55
56
#define ACPI_POWERSOURCE_STAT_CHANGE 0x80
57
58
struct acpi_acad_softc {
59
int status;
60
};
61
62
static void acpi_acad_get_status(void *);
63
static void acpi_acad_notify_handler(ACPI_HANDLE, UINT32, void *);
64
static int acpi_acad_probe(device_t);
65
static int acpi_acad_attach(device_t);
66
static int acpi_acad_ioctl(u_long, caddr_t, void *);
67
static int acpi_acad_sysctl(SYSCTL_HANDLER_ARGS);
68
static void acpi_acad_init_acline(void *arg);
69
static void acpi_acad_ac_only(void *arg);
70
71
static device_method_t acpi_acad_methods[] = {
72
/* Device interface */
73
DEVMETHOD(device_probe, acpi_acad_probe),
74
DEVMETHOD(device_attach, acpi_acad_attach),
75
76
DEVMETHOD_END
77
};
78
79
static driver_t acpi_acad_driver = {
80
"acpi_acad",
81
acpi_acad_methods,
82
sizeof(struct acpi_acad_softc),
83
};
84
85
DRIVER_MODULE(acpi_acad, acpi, acpi_acad_driver, 0, 0);
86
MODULE_DEPEND(acpi_acad, acpi, 1, 1, 1);
87
88
ACPI_SERIAL_DECL(acad, "ACPI AC adapter");
89
90
SYSINIT(acad, SI_SUB_KTHREAD_IDLE, SI_ORDER_FIRST, acpi_acad_ac_only, NULL);
91
92
static void
93
acpi_acad_get_status(void *context)
94
{
95
struct acpi_acad_softc *sc;
96
device_t dev;
97
ACPI_HANDLE h;
98
int newstatus;
99
100
dev = context;
101
sc = device_get_softc(dev);
102
h = acpi_get_handle(dev);
103
newstatus = -1;
104
acpi_GetInteger(h, "_PSR", &newstatus);
105
106
/* If status is valid and has changed, notify the system. */
107
ACPI_SERIAL_BEGIN(acad);
108
if (newstatus != -1 && sc->status != newstatus) {
109
sc->status = newstatus;
110
ACPI_SERIAL_END(acad);
111
power_profile_set_state(newstatus ? POWER_PROFILE_PERFORMANCE :
112
POWER_PROFILE_ECONOMY);
113
ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
114
"%s Line\n", newstatus ? "On" : "Off");
115
acpi_UserNotify("ACAD", h, newstatus);
116
EVENTHANDLER_INVOKE(acpi_acad_event, newstatus);
117
} else
118
ACPI_SERIAL_END(acad);
119
}
120
121
static void
122
acpi_acad_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
123
{
124
device_t dev;
125
126
dev = (device_t)context;
127
switch (notify) {
128
case ACPI_NOTIFY_BUS_CHECK:
129
case ACPI_NOTIFY_DEVICE_CHECK:
130
case ACPI_POWERSOURCE_STAT_CHANGE:
131
/* Temporarily. It is better to notify policy manager */
132
AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_acad_get_status, context);
133
break;
134
default:
135
device_printf(dev, "unknown notify %#x\n", notify);
136
break;
137
}
138
}
139
140
static int
141
acpi_acad_probe(device_t dev)
142
{
143
static char *acad_ids[] = { "ACPI0003", NULL };
144
int rv;
145
146
if (acpi_disabled("acad"))
147
return (ENXIO);
148
rv = ACPI_ID_PROBE(device_get_parent(dev), dev, acad_ids, NULL);
149
if (rv <= 0)
150
device_set_desc(dev, "AC Adapter");
151
return (rv);
152
}
153
154
static int
155
acpi_acad_attach(device_t dev)
156
{
157
struct acpi_acad_softc *sc;
158
struct acpi_softc *acpi_sc;
159
ACPI_HANDLE handle;
160
int error;
161
162
sc = device_get_softc(dev);
163
handle = acpi_get_handle(dev);
164
165
error = acpi_register_ioctl(ACPIIO_ACAD_GET_STATUS, acpi_acad_ioctl, dev);
166
if (error != 0)
167
return (error);
168
169
if (device_get_unit(dev) == 0) {
170
acpi_sc = acpi_device_get_parent_softc(dev);
171
SYSCTL_ADD_PROC(&acpi_sc->acpi_sysctl_ctx,
172
SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, "acline",
173
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 0,
174
acpi_acad_sysctl, "I", "");
175
}
176
177
/* Get initial status after whole system is up. */
178
sc->status = -1;
179
180
/*
181
* Install both system and device notify handlers since the Casio
182
* FIVA needs them.
183
*/
184
AcpiInstallNotifyHandler(handle, ACPI_ALL_NOTIFY,
185
acpi_acad_notify_handler, dev);
186
AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_acad_init_acline, dev);
187
188
return (0);
189
}
190
191
static int
192
acpi_acad_ioctl(u_long cmd, caddr_t addr, void *arg)
193
{
194
struct acpi_acad_softc *sc;
195
device_t dev;
196
197
dev = (device_t)arg;
198
sc = device_get_softc(dev);
199
200
/*
201
* No security check required: information retrieval only. If
202
* new functions are added here, a check might be required.
203
*/
204
switch (cmd) {
205
case ACPIIO_ACAD_GET_STATUS:
206
acpi_acad_get_status(dev);
207
*(int *)addr = sc->status;
208
break;
209
default:
210
break;
211
}
212
213
return (0);
214
}
215
216
static int
217
acpi_acad_sysctl(SYSCTL_HANDLER_ARGS)
218
{
219
device_t dev = oidp->oid_arg1;
220
struct acpi_acad_softc *sc = device_get_softc(dev);
221
int val;
222
223
acpi_acad_get_status(dev);
224
val = sc->status;
225
return (sysctl_handle_int(oidp, &val, 0, req));
226
}
227
228
static void
229
acpi_acad_init_acline(void *arg)
230
{
231
struct acpi_acad_softc *sc;
232
device_t dev;
233
int retry;
234
235
dev = (device_t)arg;
236
sc = device_get_softc(dev);
237
ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
238
"acline initialization start\n");
239
240
for (retry = 0; retry < ACPI_ACAD_RETRY_MAX; retry++) {
241
acpi_acad_get_status(dev);
242
if (sc->status != -1)
243
break;
244
AcpiOsSleep(10000);
245
}
246
247
ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
248
"acline initialization done, tried %d times\n", retry + 1);
249
}
250
251
/*
252
* If no AC line devices detected after boot, create an "online" event
253
* so that userland code can adjust power settings accordingly. The default
254
* power profile is "performance" so we don't need to repeat that here.
255
*/
256
static void
257
acpi_acad_ac_only(void __unused *arg)
258
{
259
260
if (devclass_get_count(devclass_find("acpi_acad")) == 0)
261
acpi_UserNotify("ACAD", ACPI_ROOT_OBJECT, 1);
262
}
263
264
/*
265
* Public interfaces.
266
*/
267
int
268
acpi_acad_get_acline(int *status)
269
{
270
struct acpi_acad_softc *sc;
271
device_t dev;
272
273
dev = devclass_get_device(devclass_find("acpi_acad"), 0);
274
if (dev == NULL)
275
return (ENXIO);
276
sc = device_get_softc(dev);
277
278
acpi_acad_get_status(dev);
279
*status = sc->status;
280
281
return (0);
282
}
283
284