1 |
/*- |
2 |
* Copyright (c) 2002 Sean Bullington <seanATstalker.org> |
3 |
* 2003-2006 Anish Mistry <amistry@am-productions.biz> |
4 |
* 2004 Mark Santcroos <marks@ripe.net> |
5 |
* All Rights Reserved. |
6 |
* |
7 |
* Redistribution and use in source and binary forms, with or without |
8 |
* modification, are permitted provided that the following conditions |
9 |
* are met: |
10 |
* 1. Redistributions of source code must retain the above copyright |
11 |
* notice, this list of conditions and the following disclaimer. |
12 |
* 2. Redistributions in binary form must reproduce the above copyright |
13 |
* notice, this list of conditions and the following disclaimer in the |
14 |
* documentation and/or other materials provided with the distribution. |
15 |
* |
16 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 |
* SUCH DAMAGE. |
27 |
* |
28 |
*/ |
29 |
|
30 |
#include <sys/cdefs.h> |
31 |
__FBSDID("$FreeBSD: src/sys/dev/acpi_support/acpi_fujitsu.c,v 1.5 2007/03/22 18:16:39 jkim Exp $"); |
32 |
|
33 |
#include "opt_acpi.h" |
34 |
#include <sys/param.h> |
35 |
#include <sys/kernel.h> |
36 |
#include <sys/bus.h> |
37 |
#include <sys/module.h> |
38 |
#include <sys/sysctl.h> |
39 |
|
40 |
#include <contrib/dev/acpica/acpi.h> |
41 |
#include <dev/acpica/acpivar.h> |
42 |
|
43 |
/* Hooks for the ACPI CA debugging infrastructure */ |
44 |
#define _COMPONENT ACPI_OEM |
45 |
ACPI_MODULE_NAME("Fujitsu") |
46 |
|
47 |
/* Change and update bits for the hotkeys */ |
48 |
#define VOLUME_MUTE_BIT 0x40000000 |
49 |
|
50 |
/* Values of settings */ |
51 |
#define GENERAL_SETTING_BITS 0x0fffffff |
52 |
#define MOUSE_SETTING_BITS GENERAL_SETTING_BITS |
53 |
#define VOLUME_SETTING_BITS GENERAL_SETTING_BITS |
54 |
#define BRIGHTNESS_SETTING_BITS GENERAL_SETTING_BITS |
55 |
|
56 |
/* Possible state changes */ |
57 |
/* |
58 |
* These are NOT arbitrary values. They are the |
59 |
* GHKS return value from the device that says which |
60 |
* hotkey is active. They should match up with a bit |
61 |
* from the GSIF bitmask. |
62 |
*/ |
63 |
#define BRIGHT_CHANGED 0x01 |
64 |
#define VOLUME_CHANGED 0x04 |
65 |
#define MOUSE_CHANGED 0x08 |
66 |
/* |
67 |
* It is unknown which hotkey this bit is supposed to indicate, but |
68 |
* according to values from GSIF this is a valid flag. |
69 |
*/ |
70 |
#define UNKNOWN_CHANGED 0x10 |
71 |
|
72 |
/* sysctl values */ |
73 |
#define FN_MUTE 0 |
74 |
#define FN_POINTER_ENABLE 1 |
75 |
#define FN_LCD_BRIGHTNESS 2 |
76 |
#define FN_VOLUME 3 |
77 |
|
78 |
/* Methods */ |
79 |
#define METHOD_GBLL 1 |
80 |
#define METHOD_GMOU 2 |
81 |
#define METHOD_GVOL 3 |
82 |
#define METHOD_MUTE 4 |
83 |
#define METHOD_RBLL 5 |
84 |
#define METHOD_RVOL 6 |
85 |
#define METHOD_GSIF 7 |
86 |
#define METHOD_GHKS 8 |
87 |
|
88 |
/* Notify event */ |
89 |
#define ACPI_NOTIFY_STATUS_CHANGED 0x80 |
90 |
|
91 |
/* |
92 |
* Holds a control method name and its associated integer value. |
93 |
* Only used for no-argument control methods which return a value. |
94 |
*/ |
95 |
struct int_nameval { |
96 |
char *name; |
97 |
int value; |
98 |
int exists; |
99 |
}; |
100 |
|
101 |
/* |
102 |
* Driver extension for the FUJITSU ACPI driver. |
103 |
*/ |
104 |
struct acpi_fujitsu_softc { |
105 |
device_t dev; |
106 |
ACPI_HANDLE handle; |
107 |
|
108 |
/* Control methods */ |
109 |
struct int_nameval _sta, /* unused */ |
110 |
gbll, /* brightness */ |
111 |
ghks, /* hotkey selector */ |
112 |
gbuf, /* unused (buffer?) */ |
113 |
gmou, /* mouse */ |
114 |
gsif, /* function key bitmask */ |
115 |
gvol, /* volume */ |
116 |
rbll, /* number of brightness levels (radix) */ |
117 |
rvol; /* number of volume levels (radix) */ |
118 |
|
119 |
/* State variables */ |
120 |
uint8_t bIsMuted; /* Is volume muted */ |
121 |
uint8_t bIntPtrEnabled; /* Is internal ptr enabled */ |
122 |
uint32_t lastValChanged; /* The last value updated */ |
123 |
|
124 |
/* sysctl tree */ |
125 |
struct sysctl_ctx_list sysctl_ctx; |
126 |
struct sysctl_oid *sysctl_tree; |
127 |
}; |
128 |
|
129 |
/* Driver entry point forward declarations. */ |
130 |
static int acpi_fujitsu_probe(device_t dev); |
131 |
static int acpi_fujitsu_attach(device_t dev); |
132 |
static int acpi_fujitsu_detach(device_t dev); |
133 |
static int acpi_fujitsu_suspend(device_t dev); |
134 |
static int acpi_fujitsu_resume(device_t dev); |
135 |
|
136 |
static void acpi_fujitsu_notify_status_changed(void *arg); |
137 |
static void acpi_fujitsu_notify_handler(ACPI_HANDLE h, uint32_t notify, void *context); |
138 |
static int acpi_fujitsu_sysctl(SYSCTL_HANDLER_ARGS); |
139 |
|
140 |
/* Utility function declarations */ |
141 |
static uint8_t acpi_fujitsu_update(struct acpi_fujitsu_softc *sc); |
142 |
static uint8_t acpi_fujitsu_init(struct acpi_fujitsu_softc *sc); |
143 |
static uint8_t acpi_fujitsu_check_hardware(struct acpi_fujitsu_softc *sc); |
144 |
|
145 |
/* Driver/Module specific structure definitions. */ |
146 |
static device_method_t acpi_fujitsu_methods[] = { |
147 |
/* Device interface */ |
148 |
DEVMETHOD(device_probe, acpi_fujitsu_probe), |
149 |
DEVMETHOD(device_attach, acpi_fujitsu_attach), |
150 |
DEVMETHOD(device_detach, acpi_fujitsu_detach), |
151 |
DEVMETHOD(device_suspend, acpi_fujitsu_suspend), |
152 |
DEVMETHOD(device_resume, acpi_fujitsu_resume), |
153 |
{0, 0} |
154 |
}; |
155 |
|
156 |
static driver_t acpi_fujitsu_driver = { |
157 |
"acpi_fujitsu", |
158 |
acpi_fujitsu_methods, |
159 |
sizeof(struct acpi_fujitsu_softc), |
160 |
}; |
161 |
|
162 |
/* Prototype for function hotkeys for getting/setting a value. */ |
163 |
static int acpi_fujitsu_method_get(struct acpi_fujitsu_softc *sc, int method); |
164 |
static int acpi_fujitsu_method_set(struct acpi_fujitsu_softc *sc, int method, int value); |
165 |
|
166 |
static char *fujitsu_ids[] = { "FUJ02B1", NULL }; |
167 |
|
168 |
ACPI_SERIAL_DECL(fujitsu, "Fujitsu Function Hotkeys"); |
169 |
|
170 |
/* sysctl names and function calls */ |
171 |
static struct { |
172 |
char *name; |
173 |
int method; |
174 |
char *description; |
175 |
} sysctl_table[] = { |
176 |
{ |
177 |
.name = "mute", |
178 |
.method = METHOD_MUTE, |
179 |
.description = "Speakers/headphones mute status" |
180 |
}, |
181 |
{ |
182 |
.name = "pointer_enable", |
183 |
.method = METHOD_GMOU, |
184 |
.description = "Enable and disable the internal pointer" |
185 |
}, |
186 |
{ |
187 |
.name = "lcd_brightness", |
188 |
.method = METHOD_GBLL, |
189 |
.description = "Brightness level of the LCD panel" |
190 |
}, |
191 |
{ |
192 |
.name = "volume", |
193 |
.method = METHOD_GVOL, |
194 |
.description = "Speakers/headphones volume level" |
195 |
}, |
196 |
{ |
197 |
.name = "volume_radix", |
198 |
.method = METHOD_RVOL, |
199 |
.description = "Number of volume level steps" |
200 |
}, |
201 |
{ |
202 |
.name = "lcd_brightness_radix", |
203 |
.method = METHOD_RBLL, |
204 |
.description = "Number of brightness level steps" |
205 |
}, |
206 |
|
207 |
{ NULL, 0, NULL } |
208 |
}; |
209 |
|
210 |
static devclass_t acpi_fujitsu_devclass; |
211 |
DRIVER_MODULE(acpi_fujitsu, acpi, acpi_fujitsu_driver, |
212 |
acpi_fujitsu_devclass, 0, 0); |
213 |
MODULE_DEPEND(acpi_fujitsu, acpi, 1, 1, 1); |
214 |
MODULE_VERSION(acpi_fujitsu, 1); |
215 |
|
216 |
static int |
217 |
acpi_fujitsu_probe(device_t dev) |
218 |
{ |
219 |
char *name; |
220 |
char buffer[64]; |
221 |
|
222 |
name = ACPI_ID_PROBE(device_get_parent(dev), dev, fujitsu_ids); |
223 |
if (acpi_disabled("fujitsu") || name == NULL || |
224 |
device_get_unit(dev) > 1) |
225 |
return (ENXIO); |
226 |
|
227 |
sprintf(buffer, "Fujitsu Function Hotkeys %s", name); |
228 |
device_set_desc_copy(dev, buffer); |
229 |
|
230 |
return (0); |
231 |
} |
232 |
|
233 |
static int |
234 |
acpi_fujitsu_attach(device_t dev) |
235 |
{ |
236 |
struct acpi_fujitsu_softc *sc; |
237 |
|
238 |
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); |
239 |
|
240 |
sc = device_get_softc(dev); |
241 |
sc->dev = dev; |
242 |
sc->handle = acpi_get_handle(dev); |
243 |
|
244 |
/* Install notification handler */ |
245 |
AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, |
246 |
acpi_fujitsu_notify_handler, sc); |
247 |
|
248 |
/* Snag our default values for the hotkys / hotkey states. */ |
249 |
ACPI_SERIAL_BEGIN(fujitsu); |
250 |
if (!acpi_fujitsu_init(sc)) |
251 |
device_printf(dev, "Couldn't initialize hotkey states!\n"); |
252 |
ACPI_SERIAL_END(fujitsu); |
253 |
|
254 |
return (0); |
255 |
} |
256 |
|
257 |
/* |
258 |
* Called when the system is being suspended, simply |
259 |
* set an event to be signalled when we wake up. |
260 |
*/ |
261 |
static int |
262 |
acpi_fujitsu_suspend(device_t dev) |
263 |
{ |
264 |
|
265 |
return (0); |
266 |
} |
267 |
|
268 |
static int |
269 |
acpi_fujitsu_resume(device_t dev) |
270 |
{ |
271 |
struct acpi_fujitsu_softc *sc; |
272 |
ACPI_STATUS status; |
273 |
|
274 |
sc = device_get_softc(dev); |
275 |
|
276 |
/* |
277 |
* The pointer needs to be re-enabled for |
278 |
* some revisions of the P series (2120). |
279 |
*/ |
280 |
ACPI_SERIAL_BEGIN(fujitsu); |
281 |
|
282 |
if(sc->gmou.exists) { |
283 |
status = acpi_SetInteger(sc->handle, "SMOU", 1); |
284 |
if (ACPI_FAILURE(status)) |
285 |
device_printf(sc->dev, "Couldn't enable pointer\n"); |
286 |
} |
287 |
ACPI_SERIAL_END(fujitsu); |
288 |
|
289 |
return (0); |
290 |
} |
291 |
|
292 |
static void |
293 |
acpi_fujitsu_notify_status_changed(void *arg) |
294 |
{ |
295 |
struct acpi_fujitsu_softc *sc; |
296 |
|
297 |
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); |
298 |
|
299 |
sc = (struct acpi_fujitsu_softc *)arg; |
300 |
|
301 |
/* |
302 |
* Since our notify function is called, we know something has |
303 |
* happened. So the only reason for acpi_fujitsu_update to fail |
304 |
* is if we can't find what has changed or an error occurs. |
305 |
*/ |
306 |
ACPI_SERIAL_BEGIN(fujitsu); |
307 |
acpi_fujitsu_update(sc); |
308 |
ACPI_SERIAL_END(fujitsu); |
309 |
} |
310 |
|
311 |
|
312 |
static void |
313 |
acpi_fujitsu_notify_handler(ACPI_HANDLE h, uint32_t notify, void *context) |
314 |
{ |
315 |
struct acpi_fujitsu_softc *sc; |
316 |
|
317 |
ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); |
318 |
|
319 |
sc = (struct acpi_fujitsu_softc *)context; |
320 |
|
321 |
switch (notify) { |
322 |
case ACPI_NOTIFY_STATUS_CHANGED: |
323 |
AcpiOsExecute(OSL_NOTIFY_HANDLER, |
324 |
acpi_fujitsu_notify_status_changed, sc); |
325 |
break; |
326 |
default: |
327 |
/* unknown notification value */ |
328 |
break; |
329 |
} |
330 |
} |
331 |
|
332 |
static int |
333 |
acpi_fujitsu_detach(device_t dev) |
334 |
{ |
335 |
struct acpi_fujitsu_softc *sc; |
336 |
|
337 |
sc = device_get_softc(dev); |
338 |
AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, |
339 |
acpi_fujitsu_notify_handler); |
340 |
|
341 |
sysctl_ctx_free(&sc->sysctl_ctx); |
342 |
|
343 |
return (0); |
344 |
} |
345 |
|
346 |
/* |
347 |
* Initializes the names of the ACPI control methods and grabs |
348 |
* the current state of all of the ACPI hotkeys into the softc. |
349 |
*/ |
350 |
static uint8_t |
351 |
acpi_fujitsu_init(struct acpi_fujitsu_softc *sc) |
352 |
{ |
353 |
struct acpi_softc *acpi_sc; |
354 |
int i, exists; |
355 |
|
356 |
ACPI_SERIAL_ASSERT(fujitsu); |
357 |
|
358 |
/* Setup all of the names for each control method */ |
359 |
sc->_sta.name = "_STA"; |
360 |
sc->gbll.name = "GBLL"; |
361 |
sc->ghks.name = "GHKS"; |
362 |
sc->gmou.name = "GMOU"; |
363 |
sc->gsif.name = "GSIF"; |
364 |
sc->gvol.name = "GVOL"; |
365 |
sc->ghks.name = "GHKS"; |
366 |
sc->gsif.name = "GSIF"; |
367 |
sc->rbll.name = "RBLL"; |
368 |
sc->rvol.name = "RVOL"; |
369 |
|
370 |
/* Determine what hardware functionality is available */ |
371 |
acpi_fujitsu_check_hardware(sc); |
372 |
|
373 |
/* Build the sysctl tree */ |
374 |
acpi_sc = acpi_device_get_parent_softc(sc->dev); |
375 |
sysctl_ctx_init(&sc->sysctl_ctx); |
376 |
sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, |
377 |
SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), |
378 |
OID_AUTO, "fujitsu", CTLFLAG_RD, 0, ""); |
379 |
|
380 |
for (i = 0; sysctl_table[i].name != NULL; i++) { |
381 |
exists = 0; |
382 |
switch(sysctl_table[i].method) { |
383 |
case METHOD_GMOU: |
384 |
exists = sc->gmou.exists; |
385 |
break; |
386 |
case METHOD_GBLL: |
387 |
exists = sc->gbll.exists; |
388 |
break; |
389 |
case METHOD_GVOL: |
390 |
case METHOD_MUTE: |
391 |
exists = sc->gvol.exists; |
392 |
break; |
393 |
case METHOD_RVOL: |
394 |
exists = sc->rvol.exists; |
395 |
break; |
396 |
case METHOD_RBLL: |
397 |
exists = sc->rbll.exists; |
398 |
break; |
399 |
default: |
400 |
/* Allow by default */ |
401 |
exists = 1; |
402 |
break; |
403 |
} |
404 |
if(!exists) |
405 |
continue; |
406 |
SYSCTL_ADD_PROC(&sc->sysctl_ctx, |
407 |
SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, |
408 |
sysctl_table[i].name, |
409 |
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, |
410 |
sc, i, acpi_fujitsu_sysctl, "I", |
411 |
sysctl_table[i].description); |
412 |
} |
413 |
|
414 |
|
415 |
/* Set the hotkeys to their initial states */ |
416 |
if (!acpi_fujitsu_update(sc)) { |
417 |
device_printf(sc->dev, "Couldn't init hotkey states\n"); |
418 |
return (FALSE); |
419 |
} |
420 |
|
421 |
return (TRUE); |
422 |
} |
423 |
|
424 |
static int |
425 |
acpi_fujitsu_sysctl(SYSCTL_HANDLER_ARGS) |
426 |
{ |
427 |
struct acpi_fujitsu_softc *sc; |
428 |
int method; |
429 |
int arg; |
430 |
int function_num, error = 0; |
431 |
|
432 |
sc = (struct acpi_fujitsu_softc *)oidp->oid_arg1; |
433 |
function_num = oidp->oid_arg2; |
434 |
method = sysctl_table[function_num].method; |
435 |
|
436 |
ACPI_SERIAL_BEGIN(fujitsu); |
437 |
|
438 |
/* Get the current value */ |
439 |
arg = acpi_fujitsu_method_get(sc, method); |
440 |
error = sysctl_handle_int(oidp, &arg, 0, req); |
441 |
|
442 |
if (error != 0 || req->newptr == NULL) |
443 |
goto out; |
444 |
|
445 |
/* Update the value */ |
446 |
error = acpi_fujitsu_method_set(sc, method, arg); |
447 |
|
448 |
out: |
449 |
ACPI_SERIAL_END(fujitsu); |
450 |
return (error); |
451 |
} |
452 |
|
453 |
static int |
454 |
acpi_fujitsu_method_get(struct acpi_fujitsu_softc *sc, int method) |
455 |
{ |
456 |
struct int_nameval nv; |
457 |
ACPI_STATUS status; |
458 |
|
459 |
ACPI_SERIAL_ASSERT(fujitsu); |
460 |
|
461 |
switch (method) { |
462 |
case METHOD_GBLL: |
463 |
nv = sc->gbll; |
464 |
break; |
465 |
case METHOD_GMOU: |
466 |
nv = sc->gmou; |
467 |
break; |
468 |
case METHOD_GVOL: |
469 |
case METHOD_MUTE: |
470 |
nv = sc->gvol; |
471 |
break; |
472 |
case METHOD_GHKS: |
473 |
nv = sc->ghks; |
474 |
break; |
475 |
case METHOD_GSIF: |
476 |
nv = sc->gsif; |
477 |
break; |
478 |
case METHOD_RBLL: |
479 |
nv = sc->rbll; |
480 |
break; |
481 |
case METHOD_RVOL: |
482 |
nv = sc->rvol; |
483 |
break; |
484 |
default: |
485 |
return (FALSE); |
486 |
} |
487 |
|
488 |
if(!nv.exists) |
489 |
return (EINVAL); |
490 |
|
491 |
status = acpi_GetInteger(sc->handle, nv.name, &nv.value); |
492 |
if (ACPI_FAILURE(status)) { |
493 |
device_printf(sc->dev, "Couldn't query method (%s)\n", nv.name); |
494 |
return (FALSE); |
495 |
} |
496 |
|
497 |
if (method == METHOD_MUTE) { |
498 |
sc->bIsMuted = (uint8_t)((nv.value & VOLUME_MUTE_BIT) != 0); |
499 |
return (sc->bIsMuted); |
500 |
} |
501 |
|
502 |
nv.value &= GENERAL_SETTING_BITS; |
503 |
return (nv.value); |
504 |
} |
505 |
|
506 |
static int |
507 |
acpi_fujitsu_method_set(struct acpi_fujitsu_softc *sc, int method, int value) |
508 |
{ |
509 |
struct int_nameval nv; |
510 |
ACPI_STATUS status; |
511 |
char *control; |
512 |
int changed; |
513 |
|
514 |
ACPI_SERIAL_ASSERT(fujitsu); |
515 |
|
516 |
switch (method) { |
517 |
case METHOD_GBLL: |
518 |
changed = BRIGHT_CHANGED; |
519 |
control = "SBLL"; |
520 |
nv = sc->gbll; |
521 |
break; |
522 |
case METHOD_GMOU: |
523 |
changed = MOUSE_CHANGED; |
524 |
control = "SMOU"; |
525 |
nv = sc->gmou; |
526 |
break; |
527 |
case METHOD_GVOL: |
528 |
case METHOD_MUTE: |
529 |
changed = VOLUME_CHANGED; |
530 |
control = "SVOL"; |
531 |
nv = sc->gvol; |
532 |
break; |
533 |
default: |
534 |
return (EINVAL); |
535 |
} |
536 |
|
537 |
if(!nv.exists) |
538 |
return (EINVAL); |
539 |
|
540 |
if (method == METHOD_MUTE) { |
541 |
if (value == 1) |
542 |
value = nv.value | VOLUME_MUTE_BIT; |
543 |
else if (value == 0) |
544 |
value = nv.value & ~VOLUME_MUTE_BIT; |
545 |
else |
546 |
return (EINVAL); |
547 |
} |
548 |
|
549 |
status = acpi_SetInteger(sc->handle, control, value); |
550 |
if (ACPI_FAILURE(status)) { |
551 |
device_printf(sc->dev, "Couldn't update %s\n", control); |
552 |
return (FALSE); |
553 |
} |
554 |
|
555 |
sc->lastValChanged = changed; |
556 |
return (0); |
557 |
} |
558 |
|
559 |
/* |
560 |
* Query the get methods to determine what functionality is available |
561 |
* from the hardware function hotkeys. |
562 |
*/ |
563 |
static uint8_t |
564 |
acpi_fujitsu_check_hardware(struct acpi_fujitsu_softc *sc) |
565 |
{ |
566 |
int val; |
567 |
struct acpi_softc *acpi_sc; |
568 |
|
569 |
acpi_sc = acpi_device_get_parent_softc(sc->dev); |
570 |
|
571 |
ACPI_SERIAL_ASSERT(fujitsu); |
572 |
/* save the hotkey bitmask */ |
573 |
if (ACPI_FAILURE(acpi_GetInteger(sc->handle, |
574 |
sc->gsif.name, &(sc->gsif.value)))) { |
575 |
sc->gsif.exists = 0; |
576 |
device_printf(sc->dev, "Couldn't query bitmask value\n"); |
577 |
} else { |
578 |
sc->gsif.exists = 1; |
579 |
} |
580 |
|
581 |
/* System Volume Level */ |
582 |
if (ACPI_FAILURE(acpi_GetInteger(sc->handle, |
583 |
sc->gvol.name, &val))) { |
584 |
sc->gvol.exists = 0; |
585 |
} else { |
586 |
sc->gvol.exists = 1; |
587 |
} |
588 |
|
589 |
if (ACPI_FAILURE(acpi_GetInteger(sc->handle, |
590 |
sc->gbll.name, &val))) { |
591 |
sc->gbll.exists = 0; |
592 |
} else { |
593 |
sc->gbll.exists = 1; |
594 |
} |
595 |
|
596 |
if (ACPI_FAILURE(acpi_GetInteger(sc->handle, |
597 |
sc->ghks.name, &val))) { |
598 |
sc->ghks.exists = 0; |
599 |
} else { |
600 |
sc->ghks.exists = 1; |
601 |
} |
602 |
|
603 |
if (ACPI_FAILURE(acpi_GetInteger(sc->handle, |
604 |
sc->gmou.name, &val))) { |
605 |
sc->gmou.exists = 0; |
606 |
} else { |
607 |
sc->gmou.exists = 1; |
608 |
} |
609 |
|
610 |
if (ACPI_FAILURE(acpi_GetInteger(sc->handle, |
611 |
sc->rbll.name, &val))) { |
612 |
sc->rbll.exists = 0; |
613 |
} else { |
614 |
sc->rbll.exists = 1; |
615 |
} |
616 |
|
617 |
if (ACPI_FAILURE(acpi_GetInteger(sc->handle, |
618 |
sc->rvol.name, &val))) { |
619 |
sc->rvol.exists = 0; |
620 |
} else { |
621 |
sc->rvol.exists = 1; |
622 |
} |
623 |
|
624 |
return (TRUE); |
625 |
} |
626 |
|
627 |
/* |
628 |
* Query each of the ACPI control methods that contain information we're |
629 |
* interested in. We check the return values from the control methods and |
630 |
* adjust any state variables if they should be adjusted. |
631 |
*/ |
632 |
static uint8_t |
633 |
acpi_fujitsu_update(struct acpi_fujitsu_softc *sc) |
634 |
{ |
635 |
int changed; |
636 |
struct acpi_softc *acpi_sc; |
637 |
|
638 |
acpi_sc = acpi_device_get_parent_softc(sc->dev); |
639 |
|
640 |
ACPI_SERIAL_ASSERT(fujitsu); |
641 |
if(sc->gsif.exists) |
642 |
changed = sc->gsif.value & acpi_fujitsu_method_get(sc,METHOD_GHKS); |
643 |
else |
644 |
changed = 0; |
645 |
|
646 |
/* System Volume Level */ |
647 |
if(sc->gvol.exists) { |
648 |
if (ACPI_FAILURE(acpi_GetInteger(sc->handle, |
649 |
sc->gvol.name, &(sc->gvol.value)))) { |
650 |
device_printf(sc->dev, "Couldn't query volume level\n"); |
651 |
return (FALSE); |
652 |
} |
653 |
|
654 |
if (changed & VOLUME_CHANGED) { |
655 |
sc->bIsMuted = |
656 |
(uint8_t)((sc->gvol.value & VOLUME_MUTE_BIT) != 0); |
657 |
|
658 |
/* Clear the modification bit */ |
659 |
sc->gvol.value &= VOLUME_SETTING_BITS; |
660 |
|
661 |
if (sc->bIsMuted) { |
662 |
acpi_UserNotify("FUJITSU", sc->handle, FN_MUTE); |
663 |
ACPI_VPRINT(sc->dev, acpi_sc, "Volume is now mute\n"); |
664 |
} else |
665 |
ACPI_VPRINT(sc->dev, acpi_sc, "Volume is now %d\n", |
666 |
sc->gvol.value); |
667 |
|
668 |
acpi_UserNotify("FUJITSU", sc->handle, FN_VOLUME); |
669 |
} |
670 |
} |
671 |
|
672 |
/* Internal mouse pointer (eraserhead) */ |
673 |
if(sc->gmou.exists) { |
674 |
if (ACPI_FAILURE(acpi_GetInteger(sc->handle, |
675 |
sc->gmou.name, &(sc->gmou.value)))) { |
676 |
device_printf(sc->dev, "Couldn't query pointer state\n"); |
677 |
return (FALSE); |
678 |
} |
679 |
|
680 |
if (changed & MOUSE_CHANGED) { |
681 |
sc->bIntPtrEnabled = (uint8_t)(sc->gmou.value & 0x1); |
682 |
|
683 |
/* Clear the modification bit */ |
684 |
sc->gmou.value &= MOUSE_SETTING_BITS; |
685 |
|
686 |
acpi_UserNotify("FUJITSU", sc->handle, FN_POINTER_ENABLE); |
687 |
|
688 |
ACPI_VPRINT(sc->dev, acpi_sc, "Internal pointer is now %s\n", |
689 |
(sc->bIntPtrEnabled) ? "enabled" : "disabled"); |
690 |
} |
691 |
} |
692 |
|
693 |
/* Screen Brightness Level */ |
694 |
if(sc->gbll.exists) { |
695 |
if (ACPI_FAILURE(acpi_GetInteger(sc->handle, |
696 |
sc->gbll.name, &(sc->gbll.value)))) { |
697 |
device_printf(sc->dev, "Couldn't query brightness level\n"); |
698 |
return (FALSE); |
699 |
} |
700 |
|
701 |
if (changed & BRIGHT_CHANGED) { |
702 |
/* No state to record here. */ |
703 |
|
704 |
/* Clear the modification bit */ |
705 |
sc->gbll.value &= BRIGHTNESS_SETTING_BITS; |
706 |
|
707 |
acpi_UserNotify("FUJITSU", sc->handle, FN_LCD_BRIGHTNESS); |
708 |
|
709 |
ACPI_VPRINT(sc->dev, acpi_sc, "Brightness level is now %d\n", |
710 |
sc->gbll.value); |
711 |
} |
712 |
} |
713 |
|
714 |
sc->lastValChanged = changed; |
715 |
return (TRUE); |
716 |
} |