Line data Source code
1 : /* $OpenBSD: acpitoshiba.c,v 1.11 2018/07/01 19:40:49 mlarkin Exp $ */
2 : /*-
3 : * Copyright (c) 2003 Hiroyuki Aizu <aizu@navi.org>
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : * 1. Redistributions of source code must retain the above copyright
10 : * notice, this list of conditions and the following disclaimer.
11 : * 2. Redistributions in binary form must reproduce the above copyright
12 : * notice, this list of conditions and the following disclaimer in the
13 : * documentation and/or other materials provided with the distribution.
14 : *
15 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 : * SUCH DAMAGE.
26 : *
27 : */
28 : #include <sys/param.h>
29 : #include <sys/systm.h>
30 :
31 : #include <dev/acpi/acpivar.h>
32 : #include <dev/acpi/acpidev.h>
33 : #include <dev/acpi/amltypes.h>
34 : #include <dev/acpi/dsdt.h>
35 :
36 : #include <machine/apmvar.h>
37 : #include <dev/wscons/wsconsio.h>
38 :
39 : /*
40 : * Toshiba HCI interface definitions
41 : *
42 : * HCI is Toshiba's "Hardware Control Interface" which is supposed to
43 : * be uniform across all their models. Ideally we would just call
44 : * dedicated ACPI methods instead of using this primitive interface.
45 : * However, the ACPI methods seem to be incomplete in some areas (for
46 : * example they allow setting, but not reading, the LCD brightness
47 : * value), so this is still useful.
48 : */
49 : #define METHOD_HCI "GHCI"
50 : #define METHOD_HCI_ENABLE "ENAB"
51 :
52 : /* Operations */
53 : #define HCI_SET 0xFF00
54 : #define HCI_GET 0xFE00
55 :
56 : /* Functions */
57 : #define HCI_REG_SYSTEM_EVENT 0x0016
58 : #define HCI_REG_VIDEO_OUTPUT 0x001C
59 : #define HCI_REG_LCD_BRIGHTNESS 0x002A
60 :
61 : /* Field definitions */
62 : #define HCI_LCD_BRIGHTNESS_BITS 3
63 : #define HCI_LCD_BRIGHTNESS_SHIFT (16 - HCI_LCD_BRIGHTNESS_BITS)
64 : #define HCI_LCD_BRIGHTNESS_MAX ((1 << HCI_LCD_BRIGHTNESS_BITS) - 1)
65 : #define HCI_LCD_BRIGHTNESS_MIN 0
66 : #define HCI_VIDEO_OUTPUT_FLAG 0x0100
67 : #define HCI_VIDEO_OUTPUT_CYCLE_MIN 0
68 : #define HCI_VIDEO_OUTPUT_CYCLE_MAX 7
69 :
70 : /* HCI register definitions */
71 : #define HCI_WORDS 6 /* Number of register */
72 : #define HCI_REG_AX 0 /* Operation, then return value */
73 : #define HCI_REG_BX 1 /* Function */
74 : #define HCI_REG_CX 2 /* Argument (in or out) */
75 :
76 : /* Return codes */
77 : #define HCI_FAILURE -1
78 : #define HCI_SUCCESS 0
79 :
80 : /* Toshiba fn_keys events */
81 : #define FN_KEY_SUSPEND 0x01BD
82 : #define FN_KEY_HIBERNATE 0x01BE
83 : #define FN_KEY_VIDEO_OUTPUT 0x01BF
84 : #define FN_KEY_BRIGHTNESS_DOWN 0x01C0
85 : #define FN_KEY_BRIGHTNESS_UP 0x01C1
86 :
87 : struct acpitoshiba_softc {
88 : struct device sc_dev;
89 : struct acpi_softc *sc_acpi;
90 : struct aml_node *sc_devnode;
91 : };
92 :
93 : int toshiba_enable_events(struct acpitoshiba_softc *);
94 : int toshiba_read_events(struct acpitoshiba_softc *);
95 : int toshiba_match(struct device *, void *, void *);
96 : void toshiba_attach(struct device *, struct device *, void *);
97 : int toshiba_hotkey(struct aml_node *, int, void *);
98 : int toshiba_get_brightness(struct acpitoshiba_softc *, uint32_t *);
99 : int toshiba_set_brightness(struct acpitoshiba_softc *, uint32_t *);
100 : int toshiba_get_video_output(struct acpitoshiba_softc *, uint32_t *);
101 : int toshiba_set_video_output(struct acpitoshiba_softc *, uint32_t *);
102 : int toshiba_find_brightness(struct acpitoshiba_softc *, int *);
103 : int toshiba_fn_key_brightness_up(struct acpitoshiba_softc *);
104 : int toshiba_fn_key_brightness_down(struct acpitoshiba_softc *);
105 : int toshiba_fn_key_video_output(struct acpitoshiba_softc *);
106 :
107 : /* wconsole hook functions */
108 : int acpitoshiba_get_param(struct wsdisplay_param *);
109 : int acpitoshiba_set_param(struct wsdisplay_param *);
110 : extern int (*ws_get_param)(struct wsdisplay_param *);
111 : extern int (*ws_set_param)(struct wsdisplay_param *);
112 : int get_param_brightness(struct wsdisplay_param *);
113 : int set_param_brightness(struct wsdisplay_param *);
114 :
115 : struct cfattach acpitoshiba_ca = {
116 : sizeof(struct acpitoshiba_softc), toshiba_match, toshiba_attach
117 : };
118 :
119 : struct cfdriver acpitoshiba_cd = {
120 : NULL, "acpitoshiba", DV_DULL
121 : };
122 :
123 : const char *acpitoshiba_hids[] = {
124 : "TOS6200", /* Libretto */
125 : "TOS6207", /* Dynabook */
126 : "TOS6208", /* SPA40 */
127 : NULL
128 : };
129 :
130 : int
131 0 : get_param_brightness(struct wsdisplay_param *dp)
132 : {
133 : struct acpitoshiba_softc *sc = NULL;
134 : int i, ret;
135 :
136 0 : for (i = 0; i < acpitoshiba_cd.cd_ndevs; i++) {
137 0 : if (acpitoshiba_cd.cd_devs[i] == NULL)
138 : continue;
139 :
140 0 : sc = (struct acpitoshiba_softc *)acpitoshiba_cd.cd_devs[i];
141 0 : }
142 :
143 0 : if (sc != NULL) {
144 0 : rw_enter_write(&sc->sc_acpi->sc_lck);
145 :
146 : /* default settings */
147 0 : dp->min = HCI_LCD_BRIGHTNESS_MIN;
148 0 : dp->max = HCI_LCD_BRIGHTNESS_MAX;
149 :
150 0 : ret = toshiba_get_brightness(sc, &dp->curval);
151 :
152 0 : rw_exit_write(&sc->sc_acpi->sc_lck);
153 :
154 0 : if ((dp->curval != -1) && (ret != HCI_FAILURE) )
155 0 : return (0);
156 : }
157 :
158 0 : return (1);
159 0 : }
160 :
161 : int
162 0 : acpitoshiba_get_param(struct wsdisplay_param *dp)
163 : {
164 : int ret;
165 :
166 0 : switch (dp->param) {
167 : case WSDISPLAYIO_PARAM_BRIGHTNESS:
168 0 : ret = get_param_brightness(dp);
169 0 : return (ret);
170 : default:
171 0 : return (1);
172 : }
173 0 : }
174 :
175 : int
176 0 : set_param_brightness(struct wsdisplay_param *dp)
177 : {
178 : struct acpitoshiba_softc *sc = NULL;
179 : int i, ret;
180 :
181 0 : for (i = 0; i < acpitoshiba_cd.cd_ndevs; i++) {
182 0 : if (acpitoshiba_cd.cd_devs[i] == NULL)
183 : continue;
184 :
185 0 : sc = (struct acpitoshiba_softc *)acpitoshiba_cd.cd_devs[i];
186 0 : }
187 :
188 0 : if (sc != NULL) {
189 0 : rw_enter_write(&sc->sc_acpi->sc_lck);
190 0 : ret = toshiba_find_brightness(sc, &dp->curval);
191 0 : rw_exit_write(&sc->sc_acpi->sc_lck);
192 :
193 0 : if ((dp->curval != -1) && ( ret != HCI_FAILURE))
194 0 : return (0);
195 :
196 : }
197 :
198 0 : return (1);
199 0 : }
200 :
201 : int
202 0 : acpitoshiba_set_param(struct wsdisplay_param *dp)
203 : {
204 : int ret;
205 :
206 0 : switch (dp->param) {
207 : case WSDISPLAYIO_PARAM_BRIGHTNESS:
208 0 : ret = set_param_brightness(dp);
209 0 : return (ret);
210 : default:
211 0 : return (1);
212 : }
213 0 : }
214 :
215 : int
216 0 : toshiba_find_brightness(struct acpitoshiba_softc *sc, int *new_blevel)
217 : {
218 0 : int ret, current_blevel;
219 :
220 0 : ret = toshiba_get_brightness(sc, ¤t_blevel);
221 0 : if ( ret != HCI_SUCCESS)
222 0 : return (1);
223 :
224 0 : if ( current_blevel != *new_blevel) {
225 0 : if ( *new_blevel >= HCI_LCD_BRIGHTNESS_MAX)
226 0 : *new_blevel = current_blevel = HCI_LCD_BRIGHTNESS_MAX;
227 0 : else if (*new_blevel <= HCI_LCD_BRIGHTNESS_MIN)
228 0 : *new_blevel = current_blevel = HCI_LCD_BRIGHTNESS_MIN;
229 : else
230 0 : current_blevel = *new_blevel;
231 :
232 0 : ret = toshiba_set_brightness(sc, ¤t_blevel);
233 0 : if ( ret != HCI_SUCCESS)
234 0 : return (1);
235 : }
236 :
237 0 : return (0);
238 0 : }
239 :
240 : int
241 0 : toshiba_match(struct device *parent, void *match, void *aux)
242 : {
243 0 : struct acpi_attach_args *aa = aux;
244 0 : struct cfdata *cf = match;
245 :
246 0 : if (acpi_matchhids(aa, acpitoshiba_hids, cf->cf_driver->cd_name))
247 0 : return (1);
248 :
249 0 : if ( aa->aaa_name == NULL ||
250 0 : strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
251 0 : aa->aaa_table != NULL)
252 0 : return (0);
253 :
254 0 : return (1);
255 :
256 0 : }
257 :
258 : int
259 0 : toshiba_enable_events(struct acpitoshiba_softc *sc)
260 : {
261 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI_ENABLE,
262 : 0, NULL, NULL)) {
263 0 : printf("%s: couldn't toggle METHOD_HCI_ENABLE\n", DEVNAME(sc));
264 0 : return (HCI_FAILURE);
265 : }
266 :
267 0 : return (HCI_SUCCESS);
268 0 : }
269 :
270 : int
271 0 : toshiba_read_events(struct acpitoshiba_softc *sc)
272 : {
273 0 : struct aml_value args[HCI_WORDS];
274 0 : struct aml_value res;
275 : int i, val;
276 :
277 0 : bzero(args, sizeof(args));
278 0 : bzero(&res, sizeof(res));
279 :
280 0 : for (i = 0; i < HCI_WORDS; ++i)
281 0 : args[i].type = AML_OBJTYPE_INTEGER;
282 :
283 0 : args[HCI_REG_AX].v_integer = HCI_GET;
284 0 : args[HCI_REG_BX].v_integer = HCI_REG_SYSTEM_EVENT;
285 :
286 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
287 : i, args, &res)) {
288 0 : printf("%s: couldn't toggle METHOD_HCI\n", DEVNAME(sc));
289 0 : return (HCI_FAILURE);
290 : }
291 :
292 : /*
293 : * We receive a package type so we need to get the event
294 : * value from the HCI_REG_CX.
295 : */
296 0 : val = aml_val2int(res.v_package[HCI_REG_CX]);
297 0 : aml_freevalue(&res);
298 :
299 0 : return (val);
300 0 : }
301 :
302 : void
303 0 : toshiba_attach(struct device *parent, struct device *self, void *aux)
304 : {
305 0 : struct acpitoshiba_softc *sc = (struct acpitoshiba_softc *)self;
306 0 : struct acpi_attach_args *aa = aux;
307 : int ret;
308 :
309 0 : sc->sc_acpi = (struct acpi_softc *)parent;
310 0 : sc->sc_devnode = aa->aaa_node;
311 :
312 0 : printf("\n");
313 :
314 : /* enable events and hotkeys */
315 0 : ret = toshiba_enable_events(sc);
316 0 : if ( ret != HCI_FAILURE) {
317 : /* Run toshiba_hotkey on button presses */
318 0 : aml_register_notify(sc->sc_devnode, aa->aaa_dev,
319 0 : toshiba_hotkey, sc, ACPIDEV_NOPOLL);
320 :
321 : /* wsconsctl purpose */
322 0 : ws_get_param = acpitoshiba_get_param;
323 0 : ws_set_param = acpitoshiba_set_param;
324 0 : }
325 :
326 0 : }
327 :
328 : int
329 0 : toshiba_fn_key_brightness_up(struct acpitoshiba_softc *sc)
330 : {
331 0 : uint32_t brightness_level;
332 : int ret;
333 :
334 0 : ret = toshiba_get_brightness(sc, &brightness_level);
335 0 : if ( ret != HCI_FAILURE) {
336 :
337 0 : if (brightness_level++ == HCI_LCD_BRIGHTNESS_MAX)
338 0 : brightness_level = HCI_LCD_BRIGHTNESS_MAX;
339 : else
340 0 : ret = toshiba_set_brightness(sc, &brightness_level);
341 : }
342 :
343 0 : return (ret);
344 0 : }
345 :
346 : int
347 0 : toshiba_fn_key_brightness_down(struct acpitoshiba_softc *sc)
348 : {
349 0 : uint32_t brightness_level;
350 : int ret;
351 :
352 0 : ret = toshiba_get_brightness(sc, &brightness_level);
353 0 : if ( ret != HCI_FAILURE) {
354 0 : if (brightness_level-- == HCI_LCD_BRIGHTNESS_MIN)
355 0 : brightness_level = HCI_LCD_BRIGHTNESS_MIN;
356 : else
357 0 : ret = toshiba_set_brightness(sc, &brightness_level);
358 : }
359 :
360 0 : return (ret);
361 0 : }
362 :
363 : int
364 0 : toshiba_fn_key_video_output(struct acpitoshiba_softc *sc)
365 : {
366 0 : uint32_t video_output;
367 : int ret;
368 :
369 0 : ret = toshiba_get_video_output(sc, &video_output);
370 0 : if ( ret != HCI_FAILURE) {
371 0 : video_output = (video_output + 1) % HCI_VIDEO_OUTPUT_CYCLE_MAX;
372 :
373 0 : ret = toshiba_set_video_output(sc, &video_output);
374 0 : }
375 :
376 0 : return (ret);
377 :
378 0 : }
379 :
380 : int
381 0 : toshiba_hotkey(struct aml_node *node, int notify, void *arg)
382 : {
383 0 : struct acpitoshiba_softc *sc = arg;
384 : int event, ret = HCI_FAILURE;
385 :
386 0 : event = toshiba_read_events(sc);
387 0 : if (!event)
388 0 : return (0);
389 :
390 0 : switch (event) {
391 : case FN_KEY_BRIGHTNESS_UP:
392 : /* Increase brightness */
393 0 : ret = toshiba_fn_key_brightness_up(sc);
394 0 : break;
395 : case FN_KEY_BRIGHTNESS_DOWN:
396 : /* Decrease brightness */
397 0 : ret = toshiba_fn_key_brightness_down(sc);
398 0 : break;
399 : case FN_KEY_SUSPEND:
400 : #ifndef SMALL_KERNEL
401 0 : if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) {
402 0 : acpi_addtask(sc->sc_acpi, acpi_sleep_task,
403 0 : sc->sc_acpi, ACPI_SLEEP_SUSPEND);
404 : ret = HCI_SUCCESS;
405 0 : }
406 : #endif
407 : break;
408 : case FN_KEY_HIBERNATE:
409 : #if defined(HIBERNATE) && !defined(SMALL_KERNEL)
410 0 : if (acpi_record_event(sc->sc_acpi, APM_USER_HIBERNATE_REQ)) {
411 0 : acpi_addtask(sc->sc_acpi, acpi_sleep_task,
412 0 : sc->sc_acpi, ACPI_SLEEP_HIBERNATE);
413 : ret = HCI_SUCCESS;
414 0 : }
415 : #endif
416 : break;
417 : case FN_KEY_VIDEO_OUTPUT:
418 : /* Cycle through video outputs. */
419 0 : ret = toshiba_fn_key_video_output(sc);
420 0 : break;
421 : default:
422 : break;
423 : }
424 :
425 0 : if ( ret != HCI_SUCCESS)
426 0 : return (1);
427 :
428 0 : return (0);
429 0 : }
430 :
431 : int
432 0 : toshiba_set_brightness(struct acpitoshiba_softc *sc, uint32_t *brightness)
433 : {
434 0 : struct aml_value args[HCI_WORDS];
435 : int i;
436 :
437 0 : bzero(args, sizeof(args));
438 :
439 0 : for (i = 0; i < HCI_WORDS; ++i)
440 0 : args[i].type = AML_OBJTYPE_INTEGER;
441 :
442 0 : if ((*brightness < HCI_LCD_BRIGHTNESS_MIN) ||
443 0 : (*brightness > HCI_LCD_BRIGHTNESS_MAX))
444 0 : return (HCI_FAILURE);
445 :
446 0 : *brightness <<= HCI_LCD_BRIGHTNESS_SHIFT;
447 :
448 0 : args[HCI_REG_AX].v_integer = HCI_SET;
449 0 : args[HCI_REG_BX].v_integer = HCI_REG_LCD_BRIGHTNESS;
450 0 : args[HCI_REG_CX].v_integer = *brightness;
451 :
452 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
453 : i, args, NULL)) {
454 0 : printf("%s: set brightness failed\n", DEVNAME(sc));
455 0 : return (HCI_FAILURE);
456 : }
457 :
458 0 : return (HCI_SUCCESS);
459 0 : }
460 :
461 : int
462 0 : toshiba_get_brightness(struct acpitoshiba_softc *sc, uint32_t *brightness)
463 : {
464 0 : struct aml_value args[HCI_WORDS];
465 0 : struct aml_value res;
466 : int i;
467 :
468 0 : bzero(args, sizeof(args));
469 0 : bzero(&res, sizeof(res));
470 :
471 0 : for (i = 0; i < HCI_WORDS; ++i)
472 0 : args[i].type = AML_OBJTYPE_INTEGER;
473 :
474 0 : args[HCI_REG_AX].v_integer = HCI_GET;
475 0 : args[HCI_REG_BX].v_integer = HCI_REG_LCD_BRIGHTNESS;
476 :
477 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
478 : i, args, &res)) {
479 0 : printf("%s: get brightness failed\n", DEVNAME(sc));
480 0 : return (HCI_FAILURE);
481 : }
482 :
483 : /*
484 : * We receive a package type so we need to get the event
485 : * value from the HCI_REG_CX.
486 : */
487 0 : *brightness = aml_val2int(res.v_package[HCI_REG_CX]);
488 :
489 0 : *brightness >>= HCI_LCD_BRIGHTNESS_SHIFT;
490 :
491 0 : aml_freevalue(&res);
492 :
493 0 : return (HCI_SUCCESS);
494 0 : }
495 :
496 : int
497 0 : toshiba_get_video_output(struct acpitoshiba_softc *sc, uint32_t *video_output)
498 : {
499 0 : struct aml_value res, args[HCI_WORDS];
500 : int i;
501 :
502 0 : bzero(args, sizeof(args));
503 0 : bzero(&res, sizeof(res));
504 :
505 0 : for (i = 0; i < HCI_WORDS; ++i)
506 0 : args[i].type = AML_OBJTYPE_INTEGER;
507 :
508 0 : args[HCI_REG_AX].v_integer = HCI_GET;
509 0 : args[HCI_REG_BX].v_integer = HCI_REG_VIDEO_OUTPUT;
510 :
511 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
512 : i, args, &res)) {
513 0 : printf("%s: get video output failed\n", DEVNAME(sc));
514 0 : return (HCI_FAILURE);
515 : }
516 :
517 : /*
518 : * We receive a package type so we need to get the event
519 : * value from the HCI_REG_CX.
520 : */
521 0 : *video_output = aml_val2int(res.v_package[HCI_REG_CX]);
522 :
523 0 : *video_output &= 0xff;
524 :
525 0 : aml_freevalue(&res);
526 :
527 0 : return (HCI_SUCCESS);
528 0 : }
529 :
530 : int
531 0 : toshiba_set_video_output(struct acpitoshiba_softc *sc, uint32_t *video_output)
532 : {
533 0 : struct aml_value args[HCI_WORDS];
534 : int i;
535 :
536 0 : bzero(args, sizeof(args));
537 :
538 0 : if ((*video_output < HCI_VIDEO_OUTPUT_CYCLE_MIN) ||
539 0 : (*video_output > HCI_VIDEO_OUTPUT_CYCLE_MAX))
540 0 : return (HCI_FAILURE);
541 :
542 0 : *video_output |= HCI_VIDEO_OUTPUT_FLAG;
543 :
544 0 : for (i = 0; i < HCI_WORDS; ++i)
545 0 : args[i].type = AML_OBJTYPE_INTEGER;
546 :
547 0 : args[HCI_REG_AX].v_integer = HCI_SET;
548 0 : args[HCI_REG_BX].v_integer = HCI_REG_VIDEO_OUTPUT;
549 0 : args[HCI_REG_CX].v_integer = *video_output;
550 :
551 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
552 : i, args, NULL)) {
553 0 : printf("%s: set video output failed\n", DEVNAME(sc));
554 0 : return (HCI_FAILURE);
555 : }
556 :
557 0 : return (HCI_SUCCESS);
558 0 : }
|