Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/acpi_support/acpi_hp.c
39492 views
1
/*-
2
* Copyright (c) 2009 Michael Gmelin <[email protected]>
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
/*
29
* Driver for extra ACPI-controlled features found on HP laptops
30
* that use a WMI enabled BIOS (e.g. HP Compaq 8510p and 6510p).
31
* Allows to control and read status of integrated hardware and read
32
* BIOS settings through CMI.
33
* Inspired by the hp-wmi driver, which implements a subset of these
34
* features (hotkeys) on Linux.
35
*
36
* HP CMI whitepaper:
37
* http://h20331.www2.hp.com/Hpsub/downloads/cmi_whitepaper.pdf
38
* wmi-hp for Linux:
39
* http://www.kernel.org
40
* WMI and ACPI:
41
* http://www.microsoft.com/whdc/system/pnppwr/wmi/wmi-acpi.mspx
42
*/
43
44
#include "opt_acpi.h"
45
#include <sys/param.h>
46
#include <sys/conf.h>
47
#include <sys/uio.h>
48
#include <sys/proc.h>
49
#include <sys/kernel.h>
50
#include <sys/bus.h>
51
#include <sys/sbuf.h>
52
#include <sys/module.h>
53
#include <sys/sysctl.h>
54
55
#include <contrib/dev/acpica/include/acpi.h>
56
#include <contrib/dev/acpica/include/accommon.h>
57
#include <dev/acpica/acpivar.h>
58
#include "acpi_wmi_if.h"
59
60
#define _COMPONENT ACPI_OEM
61
ACPI_MODULE_NAME("HP")
62
63
#define ACPI_HP_WMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
64
#define ACPI_HP_WMI_BIOS_GUID "5FB7F034-2C63-45E9-BE91-3D44E2C707E4"
65
#define ACPI_HP_WMI_CMI_GUID "2D114B49-2DFB-4130-B8FE-4A3C09E75133"
66
67
#define ACPI_HP_WMI_DISPLAY_COMMAND 0x1
68
#define ACPI_HP_WMI_HDDTEMP_COMMAND 0x2
69
#define ACPI_HP_WMI_ALS_COMMAND 0x3
70
#define ACPI_HP_WMI_DOCK_COMMAND 0x4
71
#define ACPI_HP_WMI_WIRELESS_COMMAND 0x5
72
#define ACPI_HP_WMI_BIOS_COMMAND 0x9
73
#define ACPI_HP_WMI_FEATURE_COMMAND 0xb
74
#define ACPI_HP_WMI_HOTKEY_COMMAND 0xc
75
#define ACPI_HP_WMI_FEATURE2_COMMAND 0xd
76
#define ACPI_HP_WMI_WIRELESS2_COMMAND 0x1b
77
#define ACPI_HP_WMI_POSTCODEERROR_COMMAND 0x2a
78
79
#define ACPI_HP_METHOD_WLAN_ENABLED 1
80
#define ACPI_HP_METHOD_WLAN_RADIO 2
81
#define ACPI_HP_METHOD_WLAN_ON_AIR 3
82
#define ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON 4
83
#define ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF 5
84
#define ACPI_HP_METHOD_BLUETOOTH_ENABLED 6
85
#define ACPI_HP_METHOD_BLUETOOTH_RADIO 7
86
#define ACPI_HP_METHOD_BLUETOOTH_ON_AIR 8
87
#define ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON 9
88
#define ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF 10
89
#define ACPI_HP_METHOD_WWAN_ENABLED 11
90
#define ACPI_HP_METHOD_WWAN_RADIO 12
91
#define ACPI_HP_METHOD_WWAN_ON_AIR 13
92
#define ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON 14
93
#define ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF 15
94
#define ACPI_HP_METHOD_ALS 16
95
#define ACPI_HP_METHOD_DISPLAY 17
96
#define ACPI_HP_METHOD_HDDTEMP 18
97
#define ACPI_HP_METHOD_DOCK 19
98
#define ACPI_HP_METHOD_CMI_DETAIL 20
99
#define ACPI_HP_METHOD_VERBOSE 21
100
101
#define HP_MASK_WWAN_ON_AIR 0x1000000
102
#define HP_MASK_BLUETOOTH_ON_AIR 0x10000
103
#define HP_MASK_WLAN_ON_AIR 0x100
104
#define HP_MASK_WWAN_RADIO 0x8000000
105
#define HP_MASK_BLUETOOTH_RADIO 0x80000
106
#define HP_MASK_WLAN_RADIO 0x800
107
#define HP_MASK_WWAN_ENABLED 0x2000000
108
#define HP_MASK_BLUETOOTH_ENABLED 0x20000
109
#define HP_MASK_WLAN_ENABLED 0x200
110
111
#define ACPI_HP_EVENT_DOCK 0x01
112
#define ACPI_HP_EVENT_PARK_HDD 0x02
113
#define ACPI_HP_EVENT_SMART_ADAPTER 0x03
114
#define ACPI_HP_EVENT_BEZEL_BUTTON 0x04
115
#define ACPI_HP_EVENT_WIRELESS 0x05
116
#define ACPI_HP_EVENT_CPU_BATTERY_THROTTLE 0x06
117
#define ACPI_HP_EVENT_LOCK_SWITCH 0x07
118
#define ACPI_HP_EVENT_LID_SWITCH 0x08
119
#define ACPI_HP_EVENT_SCREEN_ROTATION 0x09
120
#define ACPI_HP_EVENT_COOLSENSE_SYSTEM_MOBILE 0x0A
121
#define ACPI_HP_EVENT_COOLSENSE_SYSTEM_HOT 0x0B
122
#define ACPI_HP_EVENT_PROXIMITY_SENSOR 0x0C
123
#define ACPI_HP_EVENT_BACKLIT_KB_BRIGHTNESS 0x0D
124
#define ACPI_HP_EVENT_PEAKSHIFT_PERIOD 0x0F
125
#define ACPI_HP_EVENT_BATTERY_CHARGE_PERIOD 0x10
126
127
#define ACPI_HP_CMI_DETAIL_PATHS 0x01
128
#define ACPI_HP_CMI_DETAIL_ENUMS 0x02
129
#define ACPI_HP_CMI_DETAIL_FLAGS 0x04
130
#define ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE 0x08
131
132
#define ACPI_HP_WMI_RET_WRONG_SIGNATURE 0x02
133
#define ACPI_HP_WMI_RET_UNKNOWN_COMMAND 0x03
134
#define ACPI_HP_WMI_RET_UNKNOWN_CMDTYPE 0x04
135
#define ACPI_HP_WMI_RET_INVALID_PARAMETERS 0x05
136
137
struct acpi_hp_inst_seq_pair {
138
UINT32 sequence; /* sequence number as suggested by cmi bios */
139
UINT8 instance; /* object instance on guid */
140
};
141
142
struct acpi_hp_softc {
143
device_t dev;
144
device_t wmi_dev;
145
int has_notify; /* notification GUID found */
146
int has_cmi; /* CMI GUID found */
147
int has_wireless; /* Wireless command found */
148
int cmi_detail; /* CMI detail level
149
(set by sysctl) */
150
int verbose; /* add debug output */
151
int wlan_enable_if_radio_on; /* set by sysctl */
152
int wlan_disable_if_radio_off; /* set by sysctl */
153
int bluetooth_enable_if_radio_on; /* set by sysctl */
154
int bluetooth_disable_if_radio_off; /* set by sysctl */
155
int wwan_enable_if_radio_on; /* set by sysctl */
156
int wwan_disable_if_radio_off; /* set by sysctl */
157
int was_wlan_on_air; /* last known WLAN
158
on air status */
159
int was_bluetooth_on_air; /* last known BT
160
on air status */
161
int was_wwan_on_air; /* last known WWAN
162
on air status */
163
struct sysctl_ctx_list *sysctl_ctx;
164
struct sysctl_oid *sysctl_tree;
165
struct cdev *hpcmi_dev_t; /* hpcmi device handle */
166
struct sbuf hpcmi_sbuf; /* /dev/hpcmi output sbuf */
167
pid_t hpcmi_open_pid; /* pid operating on
168
/dev/hpcmi */
169
int hpcmi_bufptr; /* current pointer position
170
in /dev/hpcmi output buffer
171
*/
172
int cmi_order_size; /* size of cmi_order list */
173
struct acpi_hp_inst_seq_pair cmi_order[128]; /* list of CMI
174
instances ordered by BIOS suggested sequence */
175
};
176
177
static struct {
178
char *name;
179
int method;
180
char *description;
181
int flag_rdonly;
182
} acpi_hp_sysctls[] = {
183
{
184
.name = "wlan_enabled",
185
.method = ACPI_HP_METHOD_WLAN_ENABLED,
186
.description = "Enable/Disable WLAN (WiFi)",
187
},
188
{
189
.name = "wlan_radio",
190
.method = ACPI_HP_METHOD_WLAN_RADIO,
191
.description = "WLAN radio status",
192
.flag_rdonly = 1
193
},
194
{
195
.name = "wlan_on_air",
196
.method = ACPI_HP_METHOD_WLAN_ON_AIR,
197
.description = "WLAN radio ready to use (enabled and radio)",
198
.flag_rdonly = 1
199
},
200
{
201
.name = "wlan_enable_if_radio_on",
202
.method = ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON,
203
.description = "Enable WLAN if radio is turned on",
204
},
205
{
206
.name = "wlan_disable_if_radio_off",
207
.method = ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF,
208
.description = "Disable WLAN if radio is turned off",
209
},
210
{
211
.name = "bt_enabled",
212
.method = ACPI_HP_METHOD_BLUETOOTH_ENABLED,
213
.description = "Enable/Disable Bluetooth",
214
},
215
{
216
.name = "bt_radio",
217
.method = ACPI_HP_METHOD_BLUETOOTH_RADIO,
218
.description = "Bluetooth radio status",
219
.flag_rdonly = 1
220
},
221
{
222
.name = "bt_on_air",
223
.method = ACPI_HP_METHOD_BLUETOOTH_ON_AIR,
224
.description = "Bluetooth radio ready to use"
225
" (enabled and radio)",
226
.flag_rdonly = 1
227
},
228
{
229
.name = "bt_enable_if_radio_on",
230
.method = ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON,
231
.description = "Enable bluetooth if radio is turned on",
232
},
233
{
234
.name = "bt_disable_if_radio_off",
235
.method = ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF,
236
.description = "Disable bluetooth if radio is turned off",
237
},
238
{
239
.name = "wwan_enabled",
240
.method = ACPI_HP_METHOD_WWAN_ENABLED,
241
.description = "Enable/Disable WWAN (UMTS)",
242
},
243
{
244
.name = "wwan_radio",
245
.method = ACPI_HP_METHOD_WWAN_RADIO,
246
.description = "WWAN radio status",
247
.flag_rdonly = 1
248
},
249
{
250
.name = "wwan_on_air",
251
.method = ACPI_HP_METHOD_WWAN_ON_AIR,
252
.description = "WWAN radio ready to use (enabled and radio)",
253
.flag_rdonly = 1
254
},
255
{
256
.name = "wwan_enable_if_radio_on",
257
.method = ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON,
258
.description = "Enable WWAN if radio is turned on",
259
},
260
{
261
.name = "wwan_disable_if_radio_off",
262
.method = ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF,
263
.description = "Disable WWAN if radio is turned off",
264
},
265
{
266
.name = "als_enabled",
267
.method = ACPI_HP_METHOD_ALS,
268
.description = "Enable/Disable ALS (Ambient light sensor)",
269
},
270
{
271
.name = "display",
272
.method = ACPI_HP_METHOD_DISPLAY,
273
.description = "Display status",
274
.flag_rdonly = 1
275
},
276
{
277
.name = "hdd_temperature",
278
.method = ACPI_HP_METHOD_HDDTEMP,
279
.description = "HDD temperature",
280
.flag_rdonly = 1
281
},
282
{
283
.name = "is_docked",
284
.method = ACPI_HP_METHOD_DOCK,
285
.description = "Docking station status",
286
.flag_rdonly = 1
287
},
288
{
289
.name = "cmi_detail",
290
.method = ACPI_HP_METHOD_CMI_DETAIL,
291
.description = "Details shown in CMI output "
292
"(cat /dev/hpcmi)",
293
},
294
{
295
.name = "verbose",
296
.method = ACPI_HP_METHOD_VERBOSE,
297
.description = "Verbosity level",
298
},
299
{ NULL, 0, NULL, 0 }
300
};
301
302
ACPI_SERIAL_DECL(hp, "HP ACPI-WMI Mapping");
303
304
static void acpi_hp_identify(driver_t *driver, device_t parent);
305
static int acpi_hp_probe(device_t dev);
306
static int acpi_hp_attach(device_t dev);
307
static int acpi_hp_detach(device_t dev);
308
309
static void acpi_hp_evaluate_auto_on_off(struct acpi_hp_softc* sc);
310
static int acpi_hp_sysctl(SYSCTL_HANDLER_ARGS);
311
static int acpi_hp_sysctl_set(struct acpi_hp_softc *sc, int method,
312
int arg, int oldarg);
313
static int acpi_hp_sysctl_get(struct acpi_hp_softc *sc, int method);
314
static int acpi_hp_exec_wmi_command(device_t wmi_dev, int command,
315
int is_write, int val, int *retval);
316
static void acpi_hp_notify(ACPI_HANDLE h, UINT32 notify, void *context);
317
static int acpi_hp_get_cmi_block(device_t wmi_dev, const char* guid,
318
UINT8 instance, char* outbuf, size_t outsize,
319
UINT32* sequence, int detail);
320
static void acpi_hp_hex_decode(char* buffer);
321
322
static d_open_t acpi_hp_hpcmi_open;
323
static d_close_t acpi_hp_hpcmi_close;
324
static d_read_t acpi_hp_hpcmi_read;
325
326
/* handler /dev/hpcmi device */
327
static struct cdevsw hpcmi_cdevsw = {
328
.d_version = D_VERSION,
329
.d_open = acpi_hp_hpcmi_open,
330
.d_close = acpi_hp_hpcmi_close,
331
.d_read = acpi_hp_hpcmi_read,
332
.d_name = "hpcmi",
333
};
334
335
static device_method_t acpi_hp_methods[] = {
336
DEVMETHOD(device_identify, acpi_hp_identify),
337
DEVMETHOD(device_probe, acpi_hp_probe),
338
DEVMETHOD(device_attach, acpi_hp_attach),
339
DEVMETHOD(device_detach, acpi_hp_detach),
340
341
DEVMETHOD_END
342
};
343
344
static driver_t acpi_hp_driver = {
345
"acpi_hp",
346
acpi_hp_methods,
347
sizeof(struct acpi_hp_softc),
348
};
349
350
DRIVER_MODULE(acpi_hp, acpi_wmi, acpi_hp_driver, 0, 0);
351
MODULE_DEPEND(acpi_hp, acpi_wmi, 1, 1, 1);
352
MODULE_DEPEND(acpi_hp, acpi, 1, 1, 1);
353
354
static void
355
acpi_hp_evaluate_auto_on_off(struct acpi_hp_softc *sc)
356
{
357
int res;
358
int wireless;
359
int new_wlan_status;
360
int new_bluetooth_status;
361
int new_wwan_status;
362
363
res = acpi_hp_exec_wmi_command(sc->wmi_dev,
364
ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0, &wireless);
365
if (res != 0) {
366
device_printf(sc->wmi_dev, "Wireless command error %x\n", res);
367
return;
368
}
369
new_wlan_status = -1;
370
new_bluetooth_status = -1;
371
new_wwan_status = -1;
372
373
if (sc->verbose)
374
device_printf(sc->wmi_dev, "Wireless status is %x\n", wireless);
375
if (sc->wlan_disable_if_radio_off && !(wireless & HP_MASK_WLAN_RADIO)
376
&& (wireless & HP_MASK_WLAN_ENABLED)) {
377
acpi_hp_exec_wmi_command(sc->wmi_dev,
378
ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x100, NULL);
379
new_wlan_status = 0;
380
}
381
else if (sc->wlan_enable_if_radio_on && (wireless & HP_MASK_WLAN_RADIO)
382
&& !(wireless & HP_MASK_WLAN_ENABLED)) {
383
acpi_hp_exec_wmi_command(sc->wmi_dev,
384
ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x101, NULL);
385
new_wlan_status = 1;
386
}
387
if (sc->bluetooth_disable_if_radio_off &&
388
!(wireless & HP_MASK_BLUETOOTH_RADIO) &&
389
(wireless & HP_MASK_BLUETOOTH_ENABLED)) {
390
acpi_hp_exec_wmi_command(sc->wmi_dev,
391
ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x200, NULL);
392
new_bluetooth_status = 0;
393
}
394
else if (sc->bluetooth_enable_if_radio_on &&
395
(wireless & HP_MASK_BLUETOOTH_RADIO) &&
396
!(wireless & HP_MASK_BLUETOOTH_ENABLED)) {
397
acpi_hp_exec_wmi_command(sc->wmi_dev,
398
ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x202, NULL);
399
new_bluetooth_status = 1;
400
}
401
if (sc->wwan_disable_if_radio_off &&
402
!(wireless & HP_MASK_WWAN_RADIO) &&
403
(wireless & HP_MASK_WWAN_ENABLED)) {
404
acpi_hp_exec_wmi_command(sc->wmi_dev,
405
ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x400, NULL);
406
new_wwan_status = 0;
407
}
408
else if (sc->wwan_enable_if_radio_on &&
409
(wireless & HP_MASK_WWAN_RADIO) &&
410
!(wireless & HP_MASK_WWAN_ENABLED)) {
411
acpi_hp_exec_wmi_command(sc->wmi_dev,
412
ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x404, NULL);
413
new_wwan_status = 1;
414
}
415
416
if (new_wlan_status == -1) {
417
new_wlan_status = (wireless & HP_MASK_WLAN_ON_AIR);
418
if ((new_wlan_status?1:0) != sc->was_wlan_on_air) {
419
sc->was_wlan_on_air = sc->was_wlan_on_air?0:1;
420
if (sc->verbose)
421
device_printf(sc->wmi_dev,
422
"WLAN on air changed to %i "
423
"(new_wlan_status is %i)\n",
424
sc->was_wlan_on_air, new_wlan_status);
425
acpi_UserNotify("HP", ACPI_ROOT_OBJECT,
426
0xc0+sc->was_wlan_on_air);
427
}
428
}
429
if (new_bluetooth_status == -1) {
430
new_bluetooth_status = (wireless & HP_MASK_BLUETOOTH_ON_AIR);
431
if ((new_bluetooth_status?1:0) != sc->was_bluetooth_on_air) {
432
sc->was_bluetooth_on_air = sc->was_bluetooth_on_air?
433
0:1;
434
if (sc->verbose)
435
device_printf(sc->wmi_dev,
436
"BLUETOOTH on air changed"
437
" to %i (new_bluetooth_status is %i)\n",
438
sc->was_bluetooth_on_air,
439
new_bluetooth_status);
440
acpi_UserNotify("HP", ACPI_ROOT_OBJECT,
441
0xd0+sc->was_bluetooth_on_air);
442
}
443
}
444
if (new_wwan_status == -1) {
445
new_wwan_status = (wireless & HP_MASK_WWAN_ON_AIR);
446
if ((new_wwan_status?1:0) != sc->was_wwan_on_air) {
447
sc->was_wwan_on_air = sc->was_wwan_on_air?0:1;
448
if (sc->verbose)
449
device_printf(sc->wmi_dev,
450
"WWAN on air changed to %i"
451
" (new_wwan_status is %i)\n",
452
sc->was_wwan_on_air, new_wwan_status);
453
acpi_UserNotify("HP", ACPI_ROOT_OBJECT,
454
0xe0+sc->was_wwan_on_air);
455
}
456
}
457
}
458
459
static void
460
acpi_hp_identify(driver_t *driver, device_t parent)
461
{
462
463
/* Don't do anything if driver is disabled. */
464
if (acpi_disabled("hp"))
465
return;
466
467
/* Add only a single device instance. */
468
if (device_find_child(parent, "acpi_hp", DEVICE_UNIT_ANY) != NULL)
469
return;
470
471
/* Check BIOS GUID to see whether system is compatible. */
472
if (!ACPI_WMI_PROVIDES_GUID_STRING(parent,
473
ACPI_HP_WMI_BIOS_GUID))
474
return;
475
476
if (BUS_ADD_CHILD(parent, 0, "acpi_hp", DEVICE_UNIT_ANY) == NULL)
477
device_printf(parent, "add acpi_hp child failed\n");
478
}
479
480
static int
481
acpi_hp_probe(device_t dev)
482
{
483
484
device_set_desc(dev, "HP ACPI-WMI Mapping");
485
return (0);
486
}
487
488
static int
489
acpi_hp_attach(device_t dev)
490
{
491
struct acpi_hp_softc *sc;
492
int arg;
493
494
ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
495
496
sc = device_get_softc(dev);
497
sc->dev = dev;
498
sc->has_notify = 0;
499
sc->has_cmi = 0;
500
sc->bluetooth_enable_if_radio_on = 0;
501
sc->bluetooth_disable_if_radio_off = 0;
502
sc->wlan_enable_if_radio_on = 0;
503
sc->wlan_disable_if_radio_off = 0;
504
sc->wlan_enable_if_radio_on = 0;
505
sc->wlan_disable_if_radio_off = 0;
506
sc->was_wlan_on_air = 0;
507
sc->was_bluetooth_on_air = 0;
508
sc->was_wwan_on_air = 0;
509
sc->cmi_detail = 0;
510
sc->cmi_order_size = -1;
511
sc->verbose = bootverbose;
512
memset(sc->cmi_order, 0, sizeof(sc->cmi_order));
513
514
sc->wmi_dev = device_get_parent(dev);
515
if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
516
ACPI_HP_WMI_BIOS_GUID)) {
517
device_printf(dev,
518
"WMI device does not provide the HP BIOS GUID\n");
519
return (EINVAL);
520
}
521
if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
522
ACPI_HP_WMI_EVENT_GUID)) {
523
device_printf(dev,
524
"HP event GUID detected, installing event handler\n");
525
if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev,
526
ACPI_HP_WMI_EVENT_GUID, acpi_hp_notify, dev)) {
527
device_printf(dev,
528
"Could not install notification handler!\n");
529
}
530
else {
531
sc->has_notify = 1;
532
}
533
}
534
if ((sc->has_cmi =
535
ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, ACPI_HP_WMI_CMI_GUID)
536
)) {
537
device_printf(dev, "HP CMI GUID detected\n");
538
}
539
540
if (sc->has_cmi) {
541
sc->hpcmi_dev_t = make_dev(&hpcmi_cdevsw, 0, UID_ROOT,
542
GID_WHEEL, 0644, "hpcmi");
543
sc->hpcmi_dev_t->si_drv1 = sc;
544
sc->hpcmi_open_pid = 0;
545
sc->hpcmi_bufptr = -1;
546
}
547
548
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
549
ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0, NULL) == 0)
550
sc->has_wireless = 1;
551
552
ACPI_SERIAL_BEGIN(hp);
553
554
sc->sysctl_ctx = device_get_sysctl_ctx(dev);
555
sc->sysctl_tree = device_get_sysctl_tree(dev);
556
for (int i = 0; acpi_hp_sysctls[i].name != NULL; ++i) {
557
arg = 0;
558
if (((!sc->has_notify || !sc->has_wireless) &&
559
(acpi_hp_sysctls[i].method ==
560
ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON ||
561
acpi_hp_sysctls[i].method ==
562
ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF ||
563
acpi_hp_sysctls[i].method ==
564
ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON ||
565
acpi_hp_sysctls[i].method ==
566
ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF ||
567
acpi_hp_sysctls[i].method ==
568
ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON ||
569
acpi_hp_sysctls[i].method ==
570
ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF)) ||
571
(arg = acpi_hp_sysctl_get(sc,
572
acpi_hp_sysctls[i].method)) < 0) {
573
continue;
574
}
575
if (acpi_hp_sysctls[i].method == ACPI_HP_METHOD_WLAN_ON_AIR) {
576
sc->was_wlan_on_air = arg;
577
}
578
else if (acpi_hp_sysctls[i].method ==
579
ACPI_HP_METHOD_BLUETOOTH_ON_AIR) {
580
sc->was_bluetooth_on_air = arg;
581
}
582
else if (acpi_hp_sysctls[i].method ==
583
ACPI_HP_METHOD_WWAN_ON_AIR) {
584
sc->was_wwan_on_air = arg;
585
}
586
587
if (acpi_hp_sysctls[i].flag_rdonly != 0) {
588
SYSCTL_ADD_PROC(sc->sysctl_ctx,
589
SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
590
acpi_hp_sysctls[i].name,
591
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
592
sc, i, acpi_hp_sysctl, "I",
593
acpi_hp_sysctls[i].description);
594
} else {
595
SYSCTL_ADD_PROC(sc->sysctl_ctx,
596
SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
597
acpi_hp_sysctls[i].name,
598
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
599
sc, i, acpi_hp_sysctl, "I",
600
acpi_hp_sysctls[i].description);
601
}
602
}
603
ACPI_SERIAL_END(hp);
604
605
return (0);
606
}
607
608
static int
609
acpi_hp_detach(device_t dev)
610
{
611
struct acpi_hp_softc *sc;
612
613
ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
614
sc = device_get_softc(dev);
615
if (sc->has_cmi && sc->hpcmi_open_pid != 0)
616
return (EBUSY);
617
618
if (sc->has_notify) {
619
ACPI_WMI_REMOVE_EVENT_HANDLER(sc->wmi_dev,
620
ACPI_HP_WMI_EVENT_GUID);
621
}
622
623
if (sc->has_cmi) {
624
if (sc->hpcmi_bufptr != -1) {
625
sbuf_delete(&sc->hpcmi_sbuf);
626
sc->hpcmi_bufptr = -1;
627
}
628
sc->hpcmi_open_pid = 0;
629
destroy_dev(sc->hpcmi_dev_t);
630
}
631
632
return (0);
633
}
634
635
static int
636
acpi_hp_sysctl(SYSCTL_HANDLER_ARGS)
637
{
638
struct acpi_hp_softc *sc;
639
int arg;
640
int oldarg;
641
int error = 0;
642
int function;
643
int method;
644
645
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
646
647
sc = (struct acpi_hp_softc *)oidp->oid_arg1;
648
function = oidp->oid_arg2;
649
method = acpi_hp_sysctls[function].method;
650
651
ACPI_SERIAL_BEGIN(hp);
652
arg = acpi_hp_sysctl_get(sc, method);
653
oldarg = arg;
654
error = sysctl_handle_int(oidp, &arg, 0, req);
655
if (!error && req->newptr != NULL) {
656
error = acpi_hp_sysctl_set(sc, method, arg, oldarg);
657
}
658
ACPI_SERIAL_END(hp);
659
660
return (error);
661
}
662
663
static int
664
acpi_hp_sysctl_get(struct acpi_hp_softc *sc, int method)
665
{
666
int val = 0;
667
668
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
669
ACPI_SERIAL_ASSERT(hp);
670
671
switch (method) {
672
case ACPI_HP_METHOD_WLAN_ENABLED:
673
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
674
ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0, &val))
675
return (-EINVAL);
676
val = ((val & HP_MASK_WLAN_ENABLED) != 0);
677
break;
678
case ACPI_HP_METHOD_WLAN_RADIO:
679
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
680
ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0, &val))
681
return (-EINVAL);
682
val = ((val & HP_MASK_WLAN_RADIO) != 0);
683
break;
684
case ACPI_HP_METHOD_WLAN_ON_AIR:
685
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
686
ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0, &val))
687
return (-EINVAL);
688
val = ((val & HP_MASK_WLAN_ON_AIR) != 0);
689
break;
690
case ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON:
691
val = sc->wlan_enable_if_radio_on;
692
break;
693
case ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF:
694
val = sc->wlan_disable_if_radio_off;
695
break;
696
case ACPI_HP_METHOD_BLUETOOTH_ENABLED:
697
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
698
ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0, &val))
699
return (-EINVAL);
700
val = ((val & HP_MASK_BLUETOOTH_ENABLED) != 0);
701
break;
702
case ACPI_HP_METHOD_BLUETOOTH_RADIO:
703
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
704
ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0, &val))
705
return (-EINVAL);
706
val = ((val & HP_MASK_BLUETOOTH_RADIO) != 0);
707
break;
708
case ACPI_HP_METHOD_BLUETOOTH_ON_AIR:
709
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
710
ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0, &val))
711
return (-EINVAL);
712
val = ((val & HP_MASK_BLUETOOTH_ON_AIR) != 0);
713
break;
714
case ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON:
715
val = sc->bluetooth_enable_if_radio_on;
716
break;
717
case ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF:
718
val = sc->bluetooth_disable_if_radio_off;
719
break;
720
case ACPI_HP_METHOD_WWAN_ENABLED:
721
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
722
ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0, &val))
723
return (-EINVAL);
724
val = ((val & HP_MASK_WWAN_ENABLED) != 0);
725
break;
726
case ACPI_HP_METHOD_WWAN_RADIO:
727
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
728
ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0, &val))
729
return (-EINVAL);
730
val = ((val & HP_MASK_WWAN_RADIO) != 0);
731
break;
732
case ACPI_HP_METHOD_WWAN_ON_AIR:
733
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
734
ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0, &val))
735
return (-EINVAL);
736
val = ((val & HP_MASK_WWAN_ON_AIR) != 0);
737
break;
738
case ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON:
739
val = sc->wwan_enable_if_radio_on;
740
break;
741
case ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF:
742
val = sc->wwan_disable_if_radio_off;
743
break;
744
case ACPI_HP_METHOD_ALS:
745
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
746
ACPI_HP_WMI_ALS_COMMAND, 0, 0, &val))
747
return (-EINVAL);
748
break;
749
case ACPI_HP_METHOD_DISPLAY:
750
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
751
ACPI_HP_WMI_DISPLAY_COMMAND, 0, 0, &val))
752
return (-EINVAL);
753
break;
754
case ACPI_HP_METHOD_HDDTEMP:
755
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
756
ACPI_HP_WMI_HDDTEMP_COMMAND, 0, 0, &val))
757
return (-EINVAL);
758
break;
759
case ACPI_HP_METHOD_DOCK:
760
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
761
ACPI_HP_WMI_DOCK_COMMAND, 0, 0, &val))
762
return (-EINVAL);
763
break;
764
case ACPI_HP_METHOD_CMI_DETAIL:
765
val = sc->cmi_detail;
766
break;
767
case ACPI_HP_METHOD_VERBOSE:
768
val = sc->verbose;
769
break;
770
}
771
772
return (val);
773
}
774
775
static int
776
acpi_hp_sysctl_set(struct acpi_hp_softc *sc, int method, int arg, int oldarg)
777
{
778
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
779
ACPI_SERIAL_ASSERT(hp);
780
781
if (method != ACPI_HP_METHOD_CMI_DETAIL &&
782
method != ACPI_HP_METHOD_VERBOSE)
783
arg = arg?1:0;
784
785
if (arg != oldarg) {
786
switch (method) {
787
case ACPI_HP_METHOD_WLAN_ENABLED:
788
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
789
ACPI_HP_WMI_WIRELESS_COMMAND, 1,
790
arg?0x101:0x100, NULL))
791
return (-EINVAL);
792
break;
793
case ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON:
794
sc->wlan_enable_if_radio_on = arg;
795
acpi_hp_evaluate_auto_on_off(sc);
796
break;
797
case ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF:
798
sc->wlan_disable_if_radio_off = arg;
799
acpi_hp_evaluate_auto_on_off(sc);
800
break;
801
case ACPI_HP_METHOD_BLUETOOTH_ENABLED:
802
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
803
ACPI_HP_WMI_WIRELESS_COMMAND, 1,
804
arg?0x202:0x200, NULL))
805
return (-EINVAL);
806
break;
807
case ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON:
808
sc->bluetooth_enable_if_radio_on = arg;
809
acpi_hp_evaluate_auto_on_off(sc);
810
break;
811
case ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF:
812
sc->bluetooth_disable_if_radio_off = arg?1:0;
813
acpi_hp_evaluate_auto_on_off(sc);
814
break;
815
case ACPI_HP_METHOD_WWAN_ENABLED:
816
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
817
ACPI_HP_WMI_WIRELESS_COMMAND, 1,
818
arg?0x404:0x400, NULL))
819
return (-EINVAL);
820
break;
821
case ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON:
822
sc->wwan_enable_if_radio_on = arg?1:0;
823
acpi_hp_evaluate_auto_on_off(sc);
824
break;
825
case ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF:
826
sc->wwan_disable_if_radio_off = arg?1:0;
827
acpi_hp_evaluate_auto_on_off(sc);
828
break;
829
case ACPI_HP_METHOD_ALS:
830
if (acpi_hp_exec_wmi_command(sc->wmi_dev,
831
ACPI_HP_WMI_ALS_COMMAND, 1, arg?1:0, NULL))
832
return (-EINVAL);
833
break;
834
case ACPI_HP_METHOD_CMI_DETAIL:
835
sc->cmi_detail = arg;
836
if ((arg & ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE) !=
837
(oldarg & ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE)) {
838
sc->cmi_order_size = -1;
839
}
840
break;
841
case ACPI_HP_METHOD_VERBOSE:
842
sc->verbose = arg;
843
break;
844
}
845
}
846
847
return (0);
848
}
849
850
static __inline void
851
acpi_hp_free_buffer(ACPI_BUFFER* buf) {
852
if (buf && buf->Pointer) {
853
AcpiOsFree(buf->Pointer);
854
}
855
}
856
857
static void
858
acpi_hp_notify(ACPI_HANDLE h, UINT32 notify, void *context)
859
{
860
device_t dev = context;
861
ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
862
863
struct acpi_hp_softc *sc = device_get_softc(dev);
864
ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL };
865
ACPI_OBJECT *obj;
866
ACPI_WMI_GET_EVENT_DATA(sc->wmi_dev, notify, &response);
867
obj = (ACPI_OBJECT*) response.Pointer;
868
if (obj && obj->Type == ACPI_TYPE_BUFFER && obj->Buffer.Length == 8) {
869
switch (*((UINT8 *) obj->Buffer.Pointer)) {
870
case ACPI_HP_EVENT_WIRELESS:
871
acpi_hp_evaluate_auto_on_off(sc);
872
break;
873
default:
874
if (sc->verbose) {
875
device_printf(sc->dev, "Event %02x\n",
876
*((UINT8 *) obj->Buffer.Pointer));
877
}
878
break;
879
}
880
}
881
acpi_hp_free_buffer(&response);
882
}
883
884
static int
885
acpi_hp_exec_wmi_command(device_t wmi_dev, int command, int is_write,
886
int val, int *retval)
887
{
888
UINT32 params[4+32] = { 0x55434553, is_write ? 2 : 1,
889
command, 4, val};
890
UINT32* result;
891
ACPI_OBJECT *obj;
892
ACPI_BUFFER in = { sizeof(params), &params };
893
ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL };
894
int res;
895
896
if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev, ACPI_HP_WMI_BIOS_GUID,
897
0, 0x3, &in, &out))) {
898
acpi_hp_free_buffer(&out);
899
return (-EINVAL);
900
}
901
obj = out.Pointer;
902
if (!obj || obj->Type != ACPI_TYPE_BUFFER) {
903
acpi_hp_free_buffer(&out);
904
return (-EINVAL);
905
}
906
result = (UINT32*) obj->Buffer.Pointer;
907
res = result[1];
908
if (res == 0 && retval != NULL)
909
*retval = result[2];
910
acpi_hp_free_buffer(&out);
911
912
return (res);
913
}
914
915
static __inline char*
916
acpi_hp_get_string_from_object(ACPI_OBJECT* obj, char* dst, size_t size) {
917
int length;
918
919
dst[0] = 0;
920
if (obj->Type == ACPI_TYPE_STRING) {
921
length = obj->String.Length+1;
922
if (length > size) {
923
length = size - 1;
924
}
925
strlcpy(dst, obj->String.Pointer, length);
926
acpi_hp_hex_decode(dst);
927
}
928
929
return (dst);
930
}
931
932
/*
933
* Read BIOS Setting block in instance "instance".
934
* The block returned is ACPI_TYPE_PACKAGE which should contain the following
935
* elements:
936
* Index Meaning
937
* 0 Setting Name [string]
938
* 1 Value (comma separated, asterisk marks the current value) [string]
939
* 2 Path within the bios hierarchy [string]
940
* 3 IsReadOnly [int]
941
* 4 DisplayInUI [int]
942
* 5 RequiresPhysicalPresence [int]
943
* 6 Sequence for ordering within the bios settings (absolute) [int]
944
* 7 Length of prerequisites array [int]
945
* 8..8+[7] PrerequisiteN [string]
946
* 9+[7] Current value (in case of enum) [string] / Array length [int]
947
* 10+[7] Enum length [int] / Array values
948
* 11+[7]ff Enum value at index x [string]
949
*/
950
static int
951
acpi_hp_get_cmi_block(device_t wmi_dev, const char* guid, UINT8 instance,
952
char* outbuf, size_t outsize, UINT32* sequence, int detail)
953
{
954
ACPI_OBJECT *obj;
955
ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL };
956
int i;
957
int outlen;
958
int has_enums = 0;
959
int valuebase = 0;
960
char string_buffer[255];
961
int enumbase;
962
963
outlen = 0;
964
outbuf[0] = 0;
965
if (ACPI_FAILURE(ACPI_WMI_GET_BLOCK(wmi_dev, guid, instance, &out))) {
966
acpi_hp_free_buffer(&out);
967
return (-EINVAL);
968
}
969
obj = out.Pointer;
970
if (!obj || obj->Type != ACPI_TYPE_PACKAGE) {
971
acpi_hp_free_buffer(&out);
972
return (-EINVAL);
973
}
974
975
/* Check if first 6 bytes matches our expectations. */
976
if (obj->Package.Count < 8 ||
977
obj->Package.Elements[0].Type != ACPI_TYPE_STRING ||
978
obj->Package.Elements[1].Type != ACPI_TYPE_STRING ||
979
obj->Package.Elements[2].Type != ACPI_TYPE_STRING ||
980
obj->Package.Elements[3].Type != ACPI_TYPE_INTEGER ||
981
obj->Package.Elements[4].Type != ACPI_TYPE_INTEGER ||
982
obj->Package.Elements[5].Type != ACPI_TYPE_INTEGER ||
983
obj->Package.Elements[6].Type != ACPI_TYPE_INTEGER ||
984
obj->Package.Elements[7].Type != ACPI_TYPE_INTEGER) {
985
acpi_hp_free_buffer(&out);
986
return (-EINVAL);
987
}
988
989
/* Skip prerequisites and optionally array. */
990
valuebase = 8 + obj->Package.Elements[7].Integer.Value;
991
if (obj->Package.Count <= valuebase) {
992
acpi_hp_free_buffer(&out);
993
return (-EINVAL);
994
}
995
if (obj->Package.Elements[valuebase].Type == ACPI_TYPE_INTEGER)
996
valuebase += 1 + obj->Package.Elements[valuebase].Integer.Value;
997
998
/* Check if we have value and enum. */
999
if (obj->Package.Count <= valuebase + 1 ||
1000
obj->Package.Elements[valuebase].Type != ACPI_TYPE_STRING ||
1001
obj->Package.Elements[valuebase+1].Type != ACPI_TYPE_INTEGER) {
1002
acpi_hp_free_buffer(&out);
1003
return (-EINVAL);
1004
}
1005
enumbase = valuebase + 1;
1006
if (obj->Package.Count <= valuebase +
1007
obj->Package.Elements[enumbase].Integer.Value) {
1008
acpi_hp_free_buffer(&out);
1009
return (-EINVAL);
1010
}
1011
1012
if (detail & ACPI_HP_CMI_DETAIL_PATHS) {
1013
strlcat(outbuf, acpi_hp_get_string_from_object(
1014
&obj->Package.Elements[2],
1015
string_buffer, sizeof(string_buffer)), outsize);
1016
outlen += 48;
1017
while (strlen(outbuf) < outlen)
1018
strlcat(outbuf, " ", outsize);
1019
}
1020
strlcat(outbuf, acpi_hp_get_string_from_object(
1021
&obj->Package.Elements[0],
1022
string_buffer, sizeof(string_buffer)), outsize);
1023
outlen += 43;
1024
while (strlen(outbuf) < outlen)
1025
strlcat(outbuf, " ", outsize);
1026
strlcat(outbuf, acpi_hp_get_string_from_object(
1027
&obj->Package.Elements[valuebase],
1028
string_buffer, sizeof(string_buffer)), outsize);
1029
outlen += 21;
1030
while (strlen(outbuf) < outlen)
1031
strlcat(outbuf, " ", outsize);
1032
for (i = 0; i < strlen(outbuf); ++i)
1033
if (outbuf[i] == '\\')
1034
outbuf[i] = '/';
1035
if (detail & ACPI_HP_CMI_DETAIL_ENUMS) {
1036
for (i = enumbase + 1; i < enumbase + 1 +
1037
obj->Package.Elements[enumbase].Integer.Value; ++i) {
1038
acpi_hp_get_string_from_object(
1039
&obj->Package.Elements[i],
1040
string_buffer, sizeof(string_buffer));
1041
if (strlen(string_buffer) > 1 ||
1042
(strlen(string_buffer) == 1 &&
1043
string_buffer[0] != ' ')) {
1044
if (has_enums)
1045
strlcat(outbuf, "/", outsize);
1046
else
1047
strlcat(outbuf, " (", outsize);
1048
strlcat(outbuf, string_buffer, outsize);
1049
has_enums = 1;
1050
}
1051
}
1052
}
1053
if (has_enums)
1054
strlcat(outbuf, ")", outsize);
1055
if (detail & ACPI_HP_CMI_DETAIL_FLAGS) {
1056
strlcat(outbuf, obj->Package.Elements[3].Integer.Value ?
1057
" [ReadOnly]" : "", outsize);
1058
strlcat(outbuf, obj->Package.Elements[4].Integer.Value ?
1059
"" : " [NOUI]", outsize);
1060
strlcat(outbuf, obj->Package.Elements[5].Integer.Value ?
1061
" [RPP]" : "", outsize);
1062
}
1063
*sequence = (UINT32) obj->Package.Elements[6].Integer.Value;
1064
acpi_hp_free_buffer(&out);
1065
1066
return (0);
1067
}
1068
1069
/*
1070
* Convert given two digit hex string (hexin) to an UINT8 referenced
1071
* by byteout.
1072
* Return != 0 if the was a problem (invalid input)
1073
*/
1074
static __inline int acpi_hp_hex_to_int(const UINT8 *hexin, UINT8 *byteout)
1075
{
1076
unsigned int hi;
1077
unsigned int lo;
1078
1079
hi = hexin[0];
1080
lo = hexin[1];
1081
if ('0' <= hi && hi <= '9')
1082
hi -= '0';
1083
else if ('A' <= hi && hi <= 'F')
1084
hi -= ('A' - 10);
1085
else if ('a' <= hi && hi <= 'f')
1086
hi -= ('a' - 10);
1087
else
1088
return (1);
1089
if ('0' <= lo && lo <= '9')
1090
lo -= '0';
1091
else if ('A' <= lo && lo <= 'F')
1092
lo -= ('A' - 10);
1093
else if ('a' <= lo && lo <= 'f')
1094
lo -= ('a' - 10);
1095
else
1096
return (1);
1097
*byteout = (hi << 4) + lo;
1098
1099
return (0);
1100
}
1101
1102
static void
1103
acpi_hp_hex_decode(char* buffer)
1104
{
1105
int i;
1106
int length = strlen(buffer);
1107
UINT8 *uin;
1108
UINT8 uout;
1109
1110
if (rounddown((int)length, 2) == length || length < 10)
1111
return;
1112
1113
for (i = 0; i<length; ++i) {
1114
if (!((i+1)%3)) {
1115
if (buffer[i] != ' ')
1116
return;
1117
}
1118
else
1119
if (!((buffer[i] >= '0' && buffer[i] <= '9') ||
1120
(buffer[i] >= 'A' && buffer[i] <= 'F')))
1121
return;
1122
}
1123
1124
for (i = 0; i<length; i += 3) {
1125
uin = &buffer[i];
1126
uout = 0;
1127
acpi_hp_hex_to_int(uin, &uout);
1128
buffer[i/3] = (char) uout;
1129
}
1130
buffer[(length+1)/3] = 0;
1131
}
1132
1133
/*
1134
* open hpcmi device
1135
*/
1136
static int
1137
acpi_hp_hpcmi_open(struct cdev* dev, int flags, int mode, struct thread *td)
1138
{
1139
struct acpi_hp_softc *sc;
1140
int ret;
1141
1142
if (dev == NULL || dev->si_drv1 == NULL)
1143
return (EBADF);
1144
sc = dev->si_drv1;
1145
1146
ACPI_SERIAL_BEGIN(hp);
1147
if (sc->hpcmi_open_pid != 0) {
1148
ret = EBUSY;
1149
}
1150
else {
1151
if (sbuf_new(&sc->hpcmi_sbuf, NULL, 4096, SBUF_AUTOEXTEND)
1152
== NULL) {
1153
ret = ENXIO;
1154
} else {
1155
sc->hpcmi_open_pid = td->td_proc->p_pid;
1156
sc->hpcmi_bufptr = 0;
1157
ret = 0;
1158
}
1159
}
1160
ACPI_SERIAL_END(hp);
1161
1162
return (ret);
1163
}
1164
1165
/*
1166
* close hpcmi device
1167
*/
1168
static int
1169
acpi_hp_hpcmi_close(struct cdev* dev, int flags, int mode, struct thread *td)
1170
{
1171
struct acpi_hp_softc *sc;
1172
int ret;
1173
1174
if (dev == NULL || dev->si_drv1 == NULL)
1175
return (EBADF);
1176
sc = dev->si_drv1;
1177
1178
ACPI_SERIAL_BEGIN(hp);
1179
if (sc->hpcmi_open_pid == 0) {
1180
ret = EBADF;
1181
}
1182
else {
1183
if (sc->hpcmi_bufptr != -1) {
1184
sbuf_delete(&sc->hpcmi_sbuf);
1185
sc->hpcmi_bufptr = -1;
1186
}
1187
sc->hpcmi_open_pid = 0;
1188
ret = 0;
1189
}
1190
ACPI_SERIAL_END(hp);
1191
1192
return (ret);
1193
}
1194
1195
/*
1196
* Read from hpcmi bios information
1197
*/
1198
static int
1199
acpi_hp_hpcmi_read(struct cdev *dev, struct uio *buf, int flag)
1200
{
1201
struct acpi_hp_softc *sc;
1202
int pos, i, l, ret;
1203
UINT8 instance;
1204
UINT8 maxInstance;
1205
UINT32 sequence;
1206
char line[1025];
1207
1208
if (dev == NULL || dev->si_drv1 == NULL)
1209
return (EBADF);
1210
sc = dev->si_drv1;
1211
1212
ACPI_SERIAL_BEGIN(hp);
1213
if (sc->hpcmi_open_pid != buf->uio_td->td_proc->p_pid
1214
|| sc->hpcmi_bufptr == -1) {
1215
ret = EBADF;
1216
}
1217
else {
1218
if (!sbuf_done(&sc->hpcmi_sbuf)) {
1219
if (sc->cmi_order_size < 0) {
1220
maxInstance = sc->has_cmi;
1221
if (!(sc->cmi_detail &
1222
ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE) &&
1223
maxInstance > 0) {
1224
maxInstance--;
1225
}
1226
sc->cmi_order_size = 0;
1227
for (instance = 0; instance < maxInstance;
1228
++instance) {
1229
if (acpi_hp_get_cmi_block(sc->wmi_dev,
1230
ACPI_HP_WMI_CMI_GUID, instance,
1231
line, sizeof(line), &sequence,
1232
sc->cmi_detail)) {
1233
instance = maxInstance;
1234
}
1235
else {
1236
pos = sc->cmi_order_size;
1237
for (i=0;
1238
i<sc->cmi_order_size && i<127;
1239
++i) {
1240
if (sc->cmi_order[i].sequence > sequence) {
1241
pos = i;
1242
break;
1243
}
1244
}
1245
for (i=sc->cmi_order_size;
1246
i>pos;
1247
--i) {
1248
sc->cmi_order[i].sequence =
1249
sc->cmi_order[i-1].sequence;
1250
sc->cmi_order[i].instance =
1251
sc->cmi_order[i-1].instance;
1252
}
1253
sc->cmi_order[pos].sequence =
1254
sequence;
1255
sc->cmi_order[pos].instance =
1256
instance;
1257
sc->cmi_order_size++;
1258
}
1259
}
1260
}
1261
for (i=0; i<sc->cmi_order_size; ++i) {
1262
if (!acpi_hp_get_cmi_block(sc->wmi_dev,
1263
ACPI_HP_WMI_CMI_GUID,
1264
sc->cmi_order[i].instance, line, sizeof(line),
1265
&sequence, sc->cmi_detail)) {
1266
sbuf_printf(&sc->hpcmi_sbuf, "%s\n", line);
1267
}
1268
}
1269
sbuf_finish(&sc->hpcmi_sbuf);
1270
}
1271
if (sbuf_len(&sc->hpcmi_sbuf) <= 0) {
1272
sbuf_delete(&sc->hpcmi_sbuf);
1273
sc->hpcmi_bufptr = -1;
1274
sc->hpcmi_open_pid = 0;
1275
ret = ENOMEM;
1276
} else {
1277
l = min(buf->uio_resid, sbuf_len(&sc->hpcmi_sbuf) -
1278
sc->hpcmi_bufptr);
1279
ret = (l > 0)?uiomove(sbuf_data(&sc->hpcmi_sbuf) +
1280
sc->hpcmi_bufptr, l, buf) : 0;
1281
sc->hpcmi_bufptr += l;
1282
}
1283
}
1284
ACPI_SERIAL_END(hp);
1285
1286
return (ret);
1287
}
1288
1289