Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/acpi_support/atk0110.c
39536 views
1
/* $NetBSD: atk0110.c,v 1.4 2010/02/11 06:54:57 cnst Exp $ */
2
/* $OpenBSD: atk0110.c,v 1.1 2009/07/23 01:38:16 cnst Exp $ */
3
4
/*
5
* Copyright (c) 2009, 2010 Constantine A. Murenin <[email protected]>
6
*
7
* Permission to use, copy, modify, and distribute this software for any
8
* purpose with or without fee is hereby granted, provided that the above
9
* copyright notice and this permission notice appear in all copies.
10
*
11
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
*/
19
20
#include <sys/cdefs.h>
21
#include <machine/_inttypes.h>
22
#include <sys/param.h>
23
#include <sys/systm.h>
24
#include <sys/kernel.h>
25
#include <sys/bus.h>
26
#include <sys/module.h>
27
#include <sys/malloc.h>
28
#include <sys/sysctl.h>
29
#include <sys/stdint.h>
30
31
#include <contrib/dev/acpica/include/acpi.h>
32
#include <dev/acpica/acpivar.h>
33
34
/*
35
* ASUSTeK AI Booster (ACPI ASOC ATK0110).
36
*
37
* This code was originally written for OpenBSD after the techniques
38
* described in the Linux's asus_atk0110.c and FreeBSD's Takanori Watanabe's
39
* acpi_aiboost.c were verified to be accurate on the actual hardware kindly
40
* provided by Sam Fourman Jr. It was subsequently ported from OpenBSD to
41
* DragonFly BSD, to NetBSD's sysmon_envsys(9) and to FreeBSD's sysctl(9).
42
*
43
* -- Constantine A. Murenin <http://cnst.su/>
44
*/
45
46
#define _COMPONENT ACPI_OEM
47
ACPI_MODULE_NAME("aibs");
48
ACPI_SERIAL_DECL(aibs, "aibs");
49
50
#define AIBS_MORE_SENSORS
51
#define AIBS_VERBOSE
52
53
#define AIBS_GROUP_SENSORS 0x06
54
55
#define AIBS_SENS_TYPE(x) (((x) >> 16) & 0xff)
56
#define AIBS_SENS_TYPE_VOLT 2
57
#define AIBS_SENS_TYPE_TEMP 3
58
#define AIBS_SENS_TYPE_FAN 4
59
60
#define AIBS_SENS_TYPE_VOLT_NAME "volt"
61
#define AIBS_SENS_TYPE_VOLT_TEMP "temp"
62
#define AIBS_SENS_TYPE_VOLT_FAN "fan"
63
64
struct aibs_sensor {
65
ACPI_INTEGER v;
66
ACPI_INTEGER i;
67
ACPI_INTEGER l;
68
ACPI_INTEGER h;
69
int t;
70
};
71
72
struct aibs_softc {
73
device_t sc_dev;
74
ACPI_HANDLE sc_ah;
75
76
struct aibs_sensor *sc_asens_volt;
77
struct aibs_sensor *sc_asens_temp;
78
struct aibs_sensor *sc_asens_fan;
79
struct aibs_sensor *sc_asens_all;
80
81
struct sysctl_oid *sc_volt_sysctl;
82
struct sysctl_oid *sc_temp_sysctl;
83
struct sysctl_oid *sc_fan_sysctl;
84
85
bool sc_ggrp_method;
86
};
87
88
static int aibs_probe(device_t);
89
static int aibs_attach(device_t);
90
static int aibs_detach(device_t);
91
static int aibs_sysctl(SYSCTL_HANDLER_ARGS);
92
static int aibs_sysctl_ggrp(SYSCTL_HANDLER_ARGS);
93
94
static int aibs_attach_ggrp(struct aibs_softc *);
95
static int aibs_attach_sif(struct aibs_softc *, int);
96
97
static device_method_t aibs_methods[] = {
98
DEVMETHOD(device_probe, aibs_probe),
99
DEVMETHOD(device_attach, aibs_attach),
100
DEVMETHOD(device_detach, aibs_detach),
101
{ NULL, NULL }
102
};
103
104
static driver_t aibs_driver = {
105
"aibs",
106
aibs_methods,
107
sizeof(struct aibs_softc)
108
};
109
110
DRIVER_MODULE(aibs, acpi, aibs_driver, NULL, NULL);
111
MODULE_DEPEND(aibs, acpi, 1, 1, 1);
112
113
static char* aibs_hids[] = {
114
"ATK0110",
115
NULL
116
};
117
118
static int
119
aibs_probe(device_t dev)
120
{
121
int rv;
122
123
if (acpi_disabled("aibs"))
124
return (ENXIO);
125
rv = ACPI_ID_PROBE(device_get_parent(dev), dev, aibs_hids, NULL);
126
if (rv <= 0 )
127
device_set_desc(dev, "ASUSTeK AI Booster (ACPI ASOC ATK0110)");
128
return (rv);
129
}
130
131
static int
132
aibs_attach(device_t dev)
133
{
134
struct aibs_softc *sc = device_get_softc(dev);
135
int err;
136
137
sc->sc_dev = dev;
138
sc->sc_ah = acpi_get_handle(dev);
139
140
sc->sc_ggrp_method = false;
141
err = aibs_attach_sif(sc, AIBS_SENS_TYPE_VOLT);
142
if (err == 0)
143
err = aibs_attach_sif(sc, AIBS_SENS_TYPE_TEMP);
144
if (err == 0)
145
err = aibs_attach_sif(sc, AIBS_SENS_TYPE_FAN);
146
147
if (err == 0)
148
return (0);
149
150
/* Clean up whatever was allocated earlier. */
151
if (sc->sc_volt_sysctl != NULL)
152
sysctl_remove_oid(sc->sc_volt_sysctl, true, true);
153
if (sc->sc_temp_sysctl != NULL)
154
sysctl_remove_oid(sc->sc_temp_sysctl, true, true);
155
if (sc->sc_fan_sysctl != NULL)
156
sysctl_remove_oid(sc->sc_fan_sysctl, true, true);
157
aibs_detach(dev);
158
159
sc->sc_ggrp_method = true;
160
err = aibs_attach_ggrp(sc);
161
return (err);
162
}
163
164
static int
165
aibs_add_sensor(struct aibs_softc *sc, ACPI_OBJECT *o,
166
struct aibs_sensor* sensor, const char ** descr)
167
{
168
int off;
169
170
/*
171
* Packages for the old and new methods are quite
172
* similar except that the new package has two
173
* new (unknown / unused) fields after the name field.
174
*/
175
if (sc->sc_ggrp_method)
176
off = 4;
177
else
178
off = 2;
179
180
if (o->Type != ACPI_TYPE_PACKAGE) {
181
device_printf(sc->sc_dev,
182
"sensor object is not a package: %i type\n",
183
o->Type);
184
return (ENXIO);
185
}
186
if (o[0].Package.Count != (off + 3) ||
187
o->Package.Elements[0].Type != ACPI_TYPE_INTEGER ||
188
o->Package.Elements[1].Type != ACPI_TYPE_STRING ||
189
o->Package.Elements[off].Type != ACPI_TYPE_INTEGER ||
190
o->Package.Elements[off + 1].Type != ACPI_TYPE_INTEGER ||
191
o->Package.Elements[off + 2].Type != ACPI_TYPE_INTEGER) {
192
device_printf(sc->sc_dev, "unexpected package content\n");
193
return (ENXIO);
194
}
195
196
sensor->i = o->Package.Elements[0].Integer.Value;
197
*descr = o->Package.Elements[1].String.Pointer;
198
sensor->l = o->Package.Elements[off].Integer.Value;
199
sensor->h = o->Package.Elements[off + 1].Integer.Value;
200
/* For the new method the second value is a range size. */
201
if (sc->sc_ggrp_method)
202
sensor->h += sensor->l;
203
sensor->t = AIBS_SENS_TYPE(sensor->i);
204
205
switch (sensor->t) {
206
case AIBS_SENS_TYPE_VOLT:
207
case AIBS_SENS_TYPE_TEMP:
208
case AIBS_SENS_TYPE_FAN:
209
return (0);
210
default:
211
device_printf(sc->sc_dev, "unknown sensor type 0x%x",
212
sensor->t);
213
return (ENXIO);
214
}
215
}
216
217
static void
218
aibs_sensor_added(struct aibs_softc *sc, struct sysctl_oid *so,
219
const char *type_name, int idx, struct aibs_sensor *sensor,
220
const char *descr)
221
{
222
char sysctl_name[8];
223
224
snprintf(sysctl_name, sizeof(sysctl_name), "%i", idx);
225
#ifdef AIBS_VERBOSE
226
device_printf(sc->sc_dev, "%c%i: 0x%08jx %20s %5jd / %5jd\n",
227
type_name[0], idx,
228
(uintmax_t)sensor->i, descr, (intmax_t)sensor->l,
229
(intmax_t)sensor->h);
230
#endif
231
SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->sc_dev),
232
SYSCTL_CHILDREN(so), idx, sysctl_name,
233
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, (uintptr_t)sensor,
234
sc->sc_ggrp_method ? aibs_sysctl_ggrp : aibs_sysctl,
235
sensor->t == AIBS_SENS_TYPE_TEMP ? "IK" : "I", descr);
236
}
237
238
static int
239
aibs_attach_ggrp(struct aibs_softc *sc)
240
{
241
ACPI_STATUS s;
242
ACPI_BUFFER buf;
243
ACPI_HANDLE h;
244
ACPI_OBJECT id;
245
ACPI_OBJECT *bp;
246
ACPI_OBJECT_LIST arg;
247
int i;
248
int t, v, f;
249
int err;
250
int *s_idx;
251
const char *name;
252
const char *descr;
253
struct aibs_sensor *sensor;
254
struct sysctl_oid **so;
255
256
/* First see if GITM is available. */
257
s = AcpiGetHandle(sc->sc_ah, "GITM", &h);
258
if (ACPI_FAILURE(s)) {
259
if (bootverbose)
260
device_printf(sc->sc_dev, "GITM not found\n");
261
return (ENXIO);
262
}
263
264
/*
265
* Now call GGRP with the appropriate argument to list sensors.
266
* The method lists different groups of entities depending on
267
* the argument.
268
*/
269
id.Integer.Value = AIBS_GROUP_SENSORS;
270
id.Type = ACPI_TYPE_INTEGER;
271
arg.Count = 1;
272
arg.Pointer = &id;
273
buf.Length = ACPI_ALLOCATE_BUFFER;
274
buf.Pointer = NULL;
275
s = AcpiEvaluateObjectTyped(sc->sc_ah, "GGRP", &arg, &buf,
276
ACPI_TYPE_PACKAGE);
277
if (ACPI_FAILURE(s)) {
278
device_printf(sc->sc_dev, "GGRP not found\n");
279
return (ENXIO);
280
}
281
282
bp = buf.Pointer;
283
sc->sc_asens_all = malloc(sizeof(*sc->sc_asens_all) * bp->Package.Count,
284
M_DEVBUF, M_WAITOK | M_ZERO);
285
v = t = f = 0;
286
for (i = 0; i < bp->Package.Count; i++) {
287
sensor = &sc->sc_asens_all[i];
288
err = aibs_add_sensor(sc, &bp->Package.Elements[i], sensor,
289
&descr);
290
if (err != 0)
291
continue;
292
293
switch (sensor->t) {
294
case AIBS_SENS_TYPE_VOLT:
295
name = "volt";
296
so = &sc->sc_volt_sysctl;
297
s_idx = &v;
298
break;
299
case AIBS_SENS_TYPE_TEMP:
300
name = "temp";
301
so = &sc->sc_temp_sysctl;
302
s_idx = &t;
303
break;
304
case AIBS_SENS_TYPE_FAN:
305
name = "fan";
306
so = &sc->sc_fan_sysctl;
307
s_idx = &f;
308
break;
309
default:
310
panic("add_sensor succeeded for unknown sensor type %d",
311
sensor->t);
312
}
313
314
if (*so == NULL) {
315
/* sysctl subtree for sensors of this type */
316
*so = SYSCTL_ADD_NODE(device_get_sysctl_ctx(sc->sc_dev),
317
SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)),
318
sensor->t, name, CTLFLAG_RD | CTLFLAG_MPSAFE,
319
NULL, NULL);
320
}
321
aibs_sensor_added(sc, *so, name, *s_idx, sensor, descr);
322
*s_idx += 1;
323
}
324
325
AcpiOsFree(buf.Pointer);
326
return (0);
327
}
328
329
static int
330
aibs_attach_sif(struct aibs_softc *sc, int st)
331
{
332
char name[] = "?SIF";
333
ACPI_STATUS s;
334
ACPI_BUFFER b;
335
ACPI_OBJECT *bp, *o;
336
const char *node;
337
struct aibs_sensor *as;
338
struct sysctl_oid **so;
339
int i, n;
340
int err;
341
342
switch (st) {
343
case AIBS_SENS_TYPE_VOLT:
344
node = "volt";
345
name[0] = 'V';
346
so = &sc->sc_volt_sysctl;
347
break;
348
case AIBS_SENS_TYPE_TEMP:
349
node = "temp";
350
name[0] = 'T';
351
so = &sc->sc_temp_sysctl;
352
break;
353
case AIBS_SENS_TYPE_FAN:
354
node = "fan";
355
name[0] = 'F';
356
so = &sc->sc_fan_sysctl;
357
break;
358
default:
359
panic("Unsupported sensor type %d", st);
360
}
361
362
b.Length = ACPI_ALLOCATE_BUFFER;
363
s = AcpiEvaluateObjectTyped(sc->sc_ah, name, NULL, &b,
364
ACPI_TYPE_PACKAGE);
365
if (ACPI_FAILURE(s)) {
366
device_printf(sc->sc_dev, "%s not found\n", name);
367
return (ENXIO);
368
}
369
370
bp = b.Pointer;
371
o = bp->Package.Elements;
372
if (o[0].Type != ACPI_TYPE_INTEGER) {
373
device_printf(sc->sc_dev, "%s[0]: invalid type\n", name);
374
AcpiOsFree(b.Pointer);
375
return (ENXIO);
376
}
377
378
n = o[0].Integer.Value;
379
if (bp->Package.Count - 1 < n) {
380
device_printf(sc->sc_dev, "%s: invalid package\n", name);
381
AcpiOsFree(b.Pointer);
382
return (ENXIO);
383
} else if (bp->Package.Count - 1 > n) {
384
int on = n;
385
386
#ifdef AIBS_MORE_SENSORS
387
n = bp->Package.Count - 1;
388
#endif
389
device_printf(sc->sc_dev, "%s: malformed package: %i/%i"
390
", assume %i\n", name, on, bp->Package.Count - 1, n);
391
}
392
if (n < 1) {
393
device_printf(sc->sc_dev, "%s: no members in the package\n",
394
name);
395
AcpiOsFree(b.Pointer);
396
return (ENXIO);
397
}
398
399
as = malloc(sizeof(*as) * n, M_DEVBUF, M_WAITOK | M_ZERO);
400
switch (st) {
401
case AIBS_SENS_TYPE_VOLT:
402
sc->sc_asens_volt = as;
403
break;
404
case AIBS_SENS_TYPE_TEMP:
405
sc->sc_asens_temp = as;
406
break;
407
case AIBS_SENS_TYPE_FAN:
408
sc->sc_asens_fan = as;
409
break;
410
}
411
412
/* sysctl subtree for sensors of this type */
413
*so = SYSCTL_ADD_NODE(device_get_sysctl_ctx(sc->sc_dev),
414
SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)), st,
415
node, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, NULL);
416
417
for (i = 0, o++; i < n; i++, o++) {
418
const char *descr;
419
420
err = aibs_add_sensor(sc, o, &as[i], &descr);
421
if (err == 0)
422
aibs_sensor_added(sc, *so, node, i, &as[i], descr);
423
}
424
425
AcpiOsFree(b.Pointer);
426
return (0);
427
}
428
429
static int
430
aibs_detach(device_t dev)
431
{
432
struct aibs_softc *sc = device_get_softc(dev);
433
434
if (sc->sc_asens_volt != NULL)
435
free(sc->sc_asens_volt, M_DEVBUF);
436
if (sc->sc_asens_temp != NULL)
437
free(sc->sc_asens_temp, M_DEVBUF);
438
if (sc->sc_asens_fan != NULL)
439
free(sc->sc_asens_fan, M_DEVBUF);
440
if (sc->sc_asens_all != NULL)
441
free(sc->sc_asens_all, M_DEVBUF);
442
return (0);
443
}
444
445
#ifdef AIBS_VERBOSE
446
#define ddevice_printf(x...) device_printf(x)
447
#else
448
#define ddevice_printf(x...)
449
#endif
450
451
static int
452
aibs_sysctl(SYSCTL_HANDLER_ARGS)
453
{
454
struct aibs_softc *sc = arg1;
455
struct aibs_sensor *sensor = (void *)(intptr_t)arg2;
456
int i = oidp->oid_number;
457
ACPI_STATUS rs;
458
ACPI_OBJECT p, *bp;
459
ACPI_OBJECT_LIST mp;
460
ACPI_BUFFER b;
461
char *name;
462
ACPI_INTEGER v, l, h;
463
int so[3];
464
465
switch (sensor->t) {
466
case AIBS_SENS_TYPE_VOLT:
467
name = "RVLT";
468
break;
469
case AIBS_SENS_TYPE_TEMP:
470
name = "RTMP";
471
break;
472
case AIBS_SENS_TYPE_FAN:
473
name = "RFAN";
474
break;
475
default:
476
return (ENOENT);
477
}
478
l = sensor->l;
479
h = sensor->h;
480
p.Type = ACPI_TYPE_INTEGER;
481
p.Integer.Value = sensor->i;
482
mp.Count = 1;
483
mp.Pointer = &p;
484
b.Length = ACPI_ALLOCATE_BUFFER;
485
ACPI_SERIAL_BEGIN(aibs);
486
rs = AcpiEvaluateObjectTyped(sc->sc_ah, name, &mp, &b,
487
ACPI_TYPE_INTEGER);
488
if (ACPI_FAILURE(rs)) {
489
ddevice_printf(sc->sc_dev,
490
"%s: %i: evaluation failed\n",
491
name, i);
492
ACPI_SERIAL_END(aibs);
493
return (EIO);
494
}
495
bp = b.Pointer;
496
v = bp->Integer.Value;
497
AcpiOsFree(b.Pointer);
498
ACPI_SERIAL_END(aibs);
499
500
switch (sensor->t) {
501
case AIBS_SENS_TYPE_VOLT:
502
break;
503
case AIBS_SENS_TYPE_TEMP:
504
v += 2731;
505
l += 2731;
506
h += 2731;
507
break;
508
case AIBS_SENS_TYPE_FAN:
509
break;
510
}
511
so[0] = v;
512
so[1] = l;
513
so[2] = h;
514
return (sysctl_handle_opaque(oidp, &so, sizeof(so), req));
515
}
516
517
static int
518
aibs_sysctl_ggrp(SYSCTL_HANDLER_ARGS)
519
{
520
struct aibs_softc *sc = arg1;
521
struct aibs_sensor *sensor = (void *)(intptr_t)arg2;
522
ACPI_STATUS rs;
523
ACPI_OBJECT p, *bp;
524
ACPI_OBJECT_LIST arg;
525
ACPI_BUFFER buf;
526
ACPI_INTEGER v, l, h;
527
int so[3];
528
uint32_t *ret;
529
uint32_t cmd[3];
530
531
cmd[0] = sensor->i;
532
cmd[1] = 0;
533
cmd[2] = 0;
534
p.Type = ACPI_TYPE_BUFFER;
535
p.Buffer.Pointer = (void *)cmd;
536
p.Buffer.Length = sizeof(cmd);
537
arg.Count = 1;
538
arg.Pointer = &p;
539
buf.Pointer = NULL;
540
buf.Length = ACPI_ALLOCATE_BUFFER;
541
ACPI_SERIAL_BEGIN(aibs);
542
rs = AcpiEvaluateObjectTyped(sc->sc_ah, "GITM", &arg, &buf,
543
ACPI_TYPE_BUFFER);
544
ACPI_SERIAL_END(aibs);
545
if (ACPI_FAILURE(rs)) {
546
device_printf(sc->sc_dev, "GITM evaluation failed\n");
547
return (EIO);
548
}
549
bp = buf.Pointer;
550
if (bp->Buffer.Length < 8) {
551
device_printf(sc->sc_dev, "GITM returned short buffer\n");
552
return (EIO);
553
}
554
ret = (uint32_t *)bp->Buffer.Pointer;
555
if (ret[0] == 0) {
556
device_printf(sc->sc_dev, "GITM returned error status\n");
557
return (EINVAL);
558
}
559
v = ret[1];
560
AcpiOsFree(buf.Pointer);
561
562
l = sensor->l;
563
h = sensor->h;
564
565
switch (sensor->t) {
566
case AIBS_SENS_TYPE_VOLT:
567
break;
568
case AIBS_SENS_TYPE_TEMP:
569
v += 2731;
570
l += 2731;
571
h += 2731;
572
break;
573
case AIBS_SENS_TYPE_FAN:
574
break;
575
}
576
so[0] = v;
577
so[1] = l;
578
so[2] = h;
579
return (sysctl_handle_opaque(oidp, &so, sizeof(so), req));
580
}
581
582