1/*- 2 * Copyright (c) 2003 Hiroyuki Aizu <aizu@navi.org> 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 28#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2003 Hiroyuki Aizu <aizu@navi.org> 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 28#include <sys/cdefs.h>
|
29__FBSDID("$FreeBSD: head/sys/dev/acpi_support/acpi_toshiba.c 124442 2004-01-12 19:35:31Z njl $");
| 29__FBSDID("$FreeBSD: head/sys/dev/acpi_support/acpi_toshiba.c 126517 2004-03-03 03:02:17Z njl $");
|
30 31#include "opt_acpi.h" 32#include <sys/param.h> 33#include <sys/kernel.h> 34#include <sys/bus.h> 35 36#include "acpi.h" 37#include <dev/acpica/acpivar.h> 38
| 30 31#include "opt_acpi.h" 32#include <sys/param.h> 33#include <sys/kernel.h> 34#include <sys/bus.h> 35 36#include "acpi.h" 37#include <dev/acpica/acpivar.h> 38
|
39#define _COMPONENT ACPI_TOSHIBA 40ACPI_MODULE_NAME("TOSHIBA") 41
| |
42/* 43 * Toshiba HCI interface definitions 44 * 45 * HCI is Toshiba's "Hardware Control Interface" which is supposed to 46 * be uniform across all their models. Ideally we would just call 47 * dedicated ACPI methods instead of using this primitive interface. 48 * However, the ACPI methods seem to be incomplete in some areas (for 49 * example they allow setting, but not reading, the LCD brightness 50 * value), so this is still useful. 51 */ 52 53#define METHOD_HCI "GHCI" 54#define METHOD_HCI_ENABLE "ENAB" 55 56/* Operations */ 57#define HCI_SET 0xFF00 58#define HCI_GET 0xFE00 59 60/* Return codes */ 61#define HCI_SUCCESS 0x0000 62#define HCI_FAILURE 0x1000 63#define HCI_NOT_SUPPORTED 0x8000 64#define HCI_EMPTY 0x8C00 65 66/* Functions */ 67#define HCI_REG_LCD_BACKLIGHT 0x0002 68#define HCI_REG_FAN 0x0004 69#define HCI_REG_SYSTEM_EVENT 0x0016 70#define HCI_REG_VIDEO_OUTPUT 0x001C 71#define HCI_REG_HOTKEY_EVENT 0x001E 72#define HCI_REG_LCD_BRIGHTNESS 0x002A 73#define HCI_REG_CPU_SPEED 0x0032 74 75/* Field definitions */ 76#define HCI_FAN_SHIFT 7 77#define HCI_LCD_BRIGHTNESS_BITS 3 78#define HCI_LCD_BRIGHTNESS_SHIFT (16 - HCI_LCD_BRIGHTNESS_BITS) 79#define HCI_LCD_BRIGHTNESS_MAX ((1 << HCI_LCD_BRIGHTNESS_BITS) - 1) 80#define HCI_VIDEO_OUTPUT_FLAG 0x0100 81#define HCI_VIDEO_OUTPUT_LCD 0x1 82#define HCI_VIDEO_OUTPUT_CRT 0x2 83#define HCI_VIDEO_OUTPUT_TV 0x4 84#define HCI_CPU_SPEED_BITS 3 85#define HCI_CPU_SPEED_SHIFT (16 - HCI_CPU_SPEED_BITS) 86#define HCI_CPU_SPEED_MAX ((1 << HCI_CPU_SPEED_BITS) - 1) 87 88/* Key press/release events. */ 89#define FN_F1_PRESS 0x013B 90#define FN_F1_RELEASE 0x01BB 91#define FN_F2_PRESS 0x013C 92#define FN_F2_RELEASE 0x01BC 93#define FN_F3_PRESS 0x013D 94#define FN_F3_RELEASE 0x01BD 95#define FN_F4_PRESS 0x013E 96#define FN_F4_RELEASE 0x01BE 97#define FN_F5_PRESS 0x013F 98#define FN_F5_RELEASE 0x01BF 99#define FN_F6_PRESS 0x0140 100#define FN_F6_RELEASE 0x01C0 101#define FN_F7_PRESS 0x0141 102#define FN_F7_RELEASE 0x01C1 103#define FN_F8_PRESS 0x0142 104#define FN_F8_RELEASE 0x01C2 105#define FN_F9_PRESS 0x0143 106#define FN_F9_RELEASE 0x01C3 107#define FN_BS_PRESS 0x010E 108#define FN_BS_RELEASE 0x018E 109#define FN_ESC_PRESS 0x0101 110#define FN_ESC_RELEASE 0x0181 111#define FN_KNJ_PRESS 0x0129 112#define FN_KNJ_RELEASE 0x01A9 113 114/* HCI register definitions. */ 115#define HCI_WORDS 6 /* Number of registers */ 116#define HCI_REG_AX 0 /* Operation, then return value */ 117#define HCI_REG_BX 1 /* Function */ 118#define HCI_REG_CX 2 /* Argument (in or out) */ 119#define HCI_REG_DX 3 /* Unused? */ 120#define HCI_REG_SI 4 /* Unused? */ 121#define HCI_REG_DI 5 /* Unused? */ 122 123struct acpi_toshiba_softc { 124 device_t dev; 125 ACPI_HANDLE handle; 126 struct sysctl_ctx_list sysctl_ctx; 127 struct sysctl_oid *sysctl_tree; 128}; 129 130/* Prototype for HCI functions for getting/setting a value. */ 131typedef int hci_fn_t(ACPI_HANDLE, int, UINT32 *); 132 133static int acpi_toshiba_probe(device_t dev); 134static int acpi_toshiba_attach(device_t dev); 135static int acpi_toshiba_detach(device_t dev); 136static int acpi_toshiba_sysctl(SYSCTL_HANDLER_ARGS); 137static hci_fn_t hci_force_fan; 138static hci_fn_t hci_video_output; 139static hci_fn_t hci_lcd_brightness; 140static hci_fn_t hci_lcd_backlight; 141static hci_fn_t hci_cpu_speed; 142static int hci_call(ACPI_HANDLE h, int op, int function, UINT32 *arg); 143static void hci_key_action(ACPI_HANDLE h, UINT32 key); 144static void acpi_toshiba_notify(ACPI_HANDLE h, UINT32 notify, 145 void *context); 146 147/* Table of sysctl names and HCI functions to call. */ 148static struct { 149 char *name; 150 hci_fn_t *handler; 151} sysctl_table[] = { 152 /* name, handler */ 153 {"force_fan", hci_force_fan}, 154 {"video_output", hci_video_output}, 155 {"lcd_brightness", hci_lcd_brightness}, 156 {"lcd_backlight", hci_lcd_backlight}, 157 {"cpu_speed", hci_cpu_speed}, 158 {NULL, NULL} 159}; 160 161static device_method_t acpi_toshiba_methods[] = { 162 DEVMETHOD(device_probe, acpi_toshiba_probe), 163 DEVMETHOD(device_attach, acpi_toshiba_attach), 164 DEVMETHOD(device_detach, acpi_toshiba_detach), 165 166 {0, 0} 167}; 168 169static driver_t acpi_toshiba_driver = { 170 "acpi_toshiba", 171 acpi_toshiba_methods, 172 sizeof(struct acpi_toshiba_softc), 173}; 174 175static devclass_t acpi_toshiba_devclass; 176DRIVER_MODULE(acpi_toshiba, acpi, acpi_toshiba_driver, acpi_toshiba_devclass, 177 0, 0); 178MODULE_DEPEND(acpi_toshiba, acpi, 100, 100, 100); 179 180static int enable_fn_keys = 1; 181TUNABLE_INT("hw.acpi.toshiba.enable_fn_keys", &enable_fn_keys); 182 183/* 184 * HID Model 185 * ------------------------------------- 186 * TOS6200 Libretto L Series 187 * Dynabook Satellite 2455 188 * Dynabook SS 3500 189 * TOS6207 Dynabook SS2110 Series 190 */ 191static int 192acpi_toshiba_probe(device_t dev) 193{ 194 int ret = ENXIO; 195 196 if (!acpi_disabled("toshiba") && 197 acpi_get_type(dev) == ACPI_TYPE_DEVICE && 198 device_get_unit(dev) == 0 && 199 (acpi_MatchHid(dev, "TOS6200") || 200 acpi_MatchHid(dev, "TOS6207"))) { 201 device_set_desc(dev, "Toshiba HCI Extras"); 202 ret = 0; 203 } 204 205 return (ret); 206} 207 208static int 209acpi_toshiba_attach(device_t dev) 210{ 211 struct acpi_toshiba_softc *sc; 212 struct acpi_softc *acpi_sc; 213 ACPI_STATUS status; 214 int i; 215
| 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 50#define METHOD_HCI "GHCI" 51#define METHOD_HCI_ENABLE "ENAB" 52 53/* Operations */ 54#define HCI_SET 0xFF00 55#define HCI_GET 0xFE00 56 57/* Return codes */ 58#define HCI_SUCCESS 0x0000 59#define HCI_FAILURE 0x1000 60#define HCI_NOT_SUPPORTED 0x8000 61#define HCI_EMPTY 0x8C00 62 63/* Functions */ 64#define HCI_REG_LCD_BACKLIGHT 0x0002 65#define HCI_REG_FAN 0x0004 66#define HCI_REG_SYSTEM_EVENT 0x0016 67#define HCI_REG_VIDEO_OUTPUT 0x001C 68#define HCI_REG_HOTKEY_EVENT 0x001E 69#define HCI_REG_LCD_BRIGHTNESS 0x002A 70#define HCI_REG_CPU_SPEED 0x0032 71 72/* Field definitions */ 73#define HCI_FAN_SHIFT 7 74#define HCI_LCD_BRIGHTNESS_BITS 3 75#define HCI_LCD_BRIGHTNESS_SHIFT (16 - HCI_LCD_BRIGHTNESS_BITS) 76#define HCI_LCD_BRIGHTNESS_MAX ((1 << HCI_LCD_BRIGHTNESS_BITS) - 1) 77#define HCI_VIDEO_OUTPUT_FLAG 0x0100 78#define HCI_VIDEO_OUTPUT_LCD 0x1 79#define HCI_VIDEO_OUTPUT_CRT 0x2 80#define HCI_VIDEO_OUTPUT_TV 0x4 81#define HCI_CPU_SPEED_BITS 3 82#define HCI_CPU_SPEED_SHIFT (16 - HCI_CPU_SPEED_BITS) 83#define HCI_CPU_SPEED_MAX ((1 << HCI_CPU_SPEED_BITS) - 1) 84 85/* Key press/release events. */ 86#define FN_F1_PRESS 0x013B 87#define FN_F1_RELEASE 0x01BB 88#define FN_F2_PRESS 0x013C 89#define FN_F2_RELEASE 0x01BC 90#define FN_F3_PRESS 0x013D 91#define FN_F3_RELEASE 0x01BD 92#define FN_F4_PRESS 0x013E 93#define FN_F4_RELEASE 0x01BE 94#define FN_F5_PRESS 0x013F 95#define FN_F5_RELEASE 0x01BF 96#define FN_F6_PRESS 0x0140 97#define FN_F6_RELEASE 0x01C0 98#define FN_F7_PRESS 0x0141 99#define FN_F7_RELEASE 0x01C1 100#define FN_F8_PRESS 0x0142 101#define FN_F8_RELEASE 0x01C2 102#define FN_F9_PRESS 0x0143 103#define FN_F9_RELEASE 0x01C3 104#define FN_BS_PRESS 0x010E 105#define FN_BS_RELEASE 0x018E 106#define FN_ESC_PRESS 0x0101 107#define FN_ESC_RELEASE 0x0181 108#define FN_KNJ_PRESS 0x0129 109#define FN_KNJ_RELEASE 0x01A9 110 111/* HCI register definitions. */ 112#define HCI_WORDS 6 /* Number of registers */ 113#define HCI_REG_AX 0 /* Operation, then return value */ 114#define HCI_REG_BX 1 /* Function */ 115#define HCI_REG_CX 2 /* Argument (in or out) */ 116#define HCI_REG_DX 3 /* Unused? */ 117#define HCI_REG_SI 4 /* Unused? */ 118#define HCI_REG_DI 5 /* Unused? */ 119 120struct acpi_toshiba_softc { 121 device_t dev; 122 ACPI_HANDLE handle; 123 struct sysctl_ctx_list sysctl_ctx; 124 struct sysctl_oid *sysctl_tree; 125}; 126 127/* Prototype for HCI functions for getting/setting a value. */ 128typedef int hci_fn_t(ACPI_HANDLE, int, UINT32 *); 129 130static int acpi_toshiba_probe(device_t dev); 131static int acpi_toshiba_attach(device_t dev); 132static int acpi_toshiba_detach(device_t dev); 133static int acpi_toshiba_sysctl(SYSCTL_HANDLER_ARGS); 134static hci_fn_t hci_force_fan; 135static hci_fn_t hci_video_output; 136static hci_fn_t hci_lcd_brightness; 137static hci_fn_t hci_lcd_backlight; 138static hci_fn_t hci_cpu_speed; 139static int hci_call(ACPI_HANDLE h, int op, int function, UINT32 *arg); 140static void hci_key_action(ACPI_HANDLE h, UINT32 key); 141static void acpi_toshiba_notify(ACPI_HANDLE h, UINT32 notify, 142 void *context); 143 144/* Table of sysctl names and HCI functions to call. */ 145static struct { 146 char *name; 147 hci_fn_t *handler; 148} sysctl_table[] = { 149 /* name, handler */ 150 {"force_fan", hci_force_fan}, 151 {"video_output", hci_video_output}, 152 {"lcd_brightness", hci_lcd_brightness}, 153 {"lcd_backlight", hci_lcd_backlight}, 154 {"cpu_speed", hci_cpu_speed}, 155 {NULL, NULL} 156}; 157 158static device_method_t acpi_toshiba_methods[] = { 159 DEVMETHOD(device_probe, acpi_toshiba_probe), 160 DEVMETHOD(device_attach, acpi_toshiba_attach), 161 DEVMETHOD(device_detach, acpi_toshiba_detach), 162 163 {0, 0} 164}; 165 166static driver_t acpi_toshiba_driver = { 167 "acpi_toshiba", 168 acpi_toshiba_methods, 169 sizeof(struct acpi_toshiba_softc), 170}; 171 172static devclass_t acpi_toshiba_devclass; 173DRIVER_MODULE(acpi_toshiba, acpi, acpi_toshiba_driver, acpi_toshiba_devclass, 174 0, 0); 175MODULE_DEPEND(acpi_toshiba, acpi, 100, 100, 100); 176 177static int enable_fn_keys = 1; 178TUNABLE_INT("hw.acpi.toshiba.enable_fn_keys", &enable_fn_keys); 179 180/* 181 * HID Model 182 * ------------------------------------- 183 * TOS6200 Libretto L Series 184 * Dynabook Satellite 2455 185 * Dynabook SS 3500 186 * TOS6207 Dynabook SS2110 Series 187 */ 188static int 189acpi_toshiba_probe(device_t dev) 190{ 191 int ret = ENXIO; 192 193 if (!acpi_disabled("toshiba") && 194 acpi_get_type(dev) == ACPI_TYPE_DEVICE && 195 device_get_unit(dev) == 0 && 196 (acpi_MatchHid(dev, "TOS6200") || 197 acpi_MatchHid(dev, "TOS6207"))) { 198 device_set_desc(dev, "Toshiba HCI Extras"); 199 ret = 0; 200 } 201 202 return (ret); 203} 204 205static int 206acpi_toshiba_attach(device_t dev) 207{ 208 struct acpi_toshiba_softc *sc; 209 struct acpi_softc *acpi_sc; 210 ACPI_STATUS status; 211 int i; 212
|
216 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 217
| |
218 sc = device_get_softc(dev); 219 sc->dev = dev; 220 sc->handle = acpi_get_handle(dev); 221 222 acpi_sc = acpi_device_get_parent_softc(dev); 223 sysctl_ctx_init(&sc->sysctl_ctx); 224 sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 225 SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, 226 "toshiba", CTLFLAG_RD, 0, ""); 227 228 for (i = 0; sysctl_table[i].name != NULL; i++) { 229 SYSCTL_ADD_PROC(&sc->sysctl_ctx, 230 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 231 sysctl_table[i].name, 232 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 233 sc, i, acpi_toshiba_sysctl, "I", ""); 234 } 235 236 if (enable_fn_keys != 0) { 237 status = AcpiEvaluateObject(sc->handle, METHOD_HCI_ENABLE, 238 NULL, NULL); 239 if (ACPI_FAILURE(status)) { 240 device_printf(dev, "enable FN keys failed\n"); 241 sysctl_ctx_free(&sc->sysctl_ctx); 242 return (ENXIO); 243 } 244 AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, 245 acpi_toshiba_notify, sc); 246 } 247 248 return (0); 249} 250 251static int 252acpi_toshiba_detach(device_t dev) 253{ 254 struct acpi_toshiba_softc *sc; 255
| 213 sc = device_get_softc(dev); 214 sc->dev = dev; 215 sc->handle = acpi_get_handle(dev); 216 217 acpi_sc = acpi_device_get_parent_softc(dev); 218 sysctl_ctx_init(&sc->sysctl_ctx); 219 sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 220 SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, 221 "toshiba", CTLFLAG_RD, 0, ""); 222 223 for (i = 0; sysctl_table[i].name != NULL; i++) { 224 SYSCTL_ADD_PROC(&sc->sysctl_ctx, 225 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 226 sysctl_table[i].name, 227 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 228 sc, i, acpi_toshiba_sysctl, "I", ""); 229 } 230 231 if (enable_fn_keys != 0) { 232 status = AcpiEvaluateObject(sc->handle, METHOD_HCI_ENABLE, 233 NULL, NULL); 234 if (ACPI_FAILURE(status)) { 235 device_printf(dev, "enable FN keys failed\n"); 236 sysctl_ctx_free(&sc->sysctl_ctx); 237 return (ENXIO); 238 } 239 AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, 240 acpi_toshiba_notify, sc); 241 } 242 243 return (0); 244} 245 246static int 247acpi_toshiba_detach(device_t dev) 248{ 249 struct acpi_toshiba_softc *sc; 250
|
256 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 257
| |
258 sc = device_get_softc(dev); 259 if (enable_fn_keys != 0) { 260 AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, 261 acpi_toshiba_notify); 262 } 263 sysctl_ctx_free(&sc->sysctl_ctx); 264 265 return (0); 266} 267 268static int 269acpi_toshiba_sysctl(SYSCTL_HANDLER_ARGS) 270{ 271 struct acpi_toshiba_softc *sc; 272 UINT32 arg; 273 int function, error = 0; 274 hci_fn_t *handler; 275 276 sc = (struct acpi_toshiba_softc *)oidp->oid_arg1; 277 function = oidp->oid_arg2; 278 handler = sysctl_table[function].handler; 279 280 /* Get the current value from the appropriate function. */ 281 error = handler(sc->handle, HCI_GET, &arg); 282 if (error != 0) 283 return (error); 284 285 /* Send the current value to the user and return if no new value. */ 286 error = sysctl_handle_int(oidp, &arg, 0, req); 287 if (error != 0 || req->newptr == NULL) 288 return (error); 289 290 /* Set the new value via the appropriate function. */ 291 error = handler(sc->handle, HCI_SET, &arg); 292 293 return (error); 294} 295 296static int 297hci_force_fan(ACPI_HANDLE h, int op, UINT32 *state) 298{ 299 int ret; 300 301 if (op == HCI_SET) { 302 if (*state < 0 || *state > 1) 303 return (EINVAL); 304 *state <<= HCI_FAN_SHIFT; 305 } 306 ret = hci_call(h, op, HCI_REG_FAN, state); 307 if (ret == 0 && op == HCI_GET) 308 *state >>= HCI_FAN_SHIFT; 309 return (ret); 310} 311 312static int 313hci_video_output(ACPI_HANDLE h, int op, UINT32 *video_output) 314{ 315 int ret; 316 317 if (op == HCI_SET) { 318 if (*video_output < 1 || *video_output > 7) 319 return (EINVAL); 320 *video_output |= HCI_VIDEO_OUTPUT_FLAG; 321 } 322 ret = hci_call(h, op, HCI_REG_VIDEO_OUTPUT, video_output); 323 if (ret == 0 && op == HCI_GET) 324 *video_output &= 0xff; 325 return (ret); 326} 327 328static int 329hci_lcd_brightness(ACPI_HANDLE h, int op, UINT32 *brightness) 330{ 331 int ret; 332 333 if (op == HCI_SET) { 334 if (*brightness < 0 || *brightness > HCI_LCD_BRIGHTNESS_MAX) 335 return (EINVAL); 336 *brightness <<= HCI_LCD_BRIGHTNESS_SHIFT; 337 } 338 ret = hci_call(h, op, HCI_REG_LCD_BRIGHTNESS, brightness); 339 if (ret == 0 && op == HCI_GET) 340 *brightness >>= HCI_LCD_BRIGHTNESS_SHIFT; 341 return (ret); 342} 343 344static int 345hci_lcd_backlight(ACPI_HANDLE h, int op, UINT32 *backlight) 346{ 347 if (op == HCI_SET) { 348 if (*backlight < 0 || *backlight > 1) 349 return (EINVAL); 350 } 351 return (hci_call(h, op, HCI_REG_LCD_BACKLIGHT, backlight)); 352} 353 354static int 355hci_cpu_speed(ACPI_HANDLE h, int op, UINT32 *speed) 356{ 357 int ret; 358 359 if (op == HCI_SET) { 360 if (*speed < 0 || *speed > HCI_CPU_SPEED_MAX) 361 return (EINVAL); 362 *speed <<= HCI_CPU_SPEED_SHIFT; 363 } 364 ret = hci_call(h, op, HCI_REG_CPU_SPEED, speed); 365 if (ret == 0 && op == HCI_GET) 366 *speed >>= HCI_CPU_SPEED_SHIFT; 367 return (ret); 368} 369 370static int 371hci_call(ACPI_HANDLE h, int op, int function, UINT32 *arg) 372{ 373 ACPI_OBJECT_LIST args; 374 ACPI_BUFFER results; 375 ACPI_OBJECT obj[HCI_WORDS]; 376 ACPI_OBJECT *res; 377 int status, i, ret; 378 379 status = ENXIO; 380 381 for (i = 0; i < HCI_WORDS; i++) { 382 obj[i].Type = ACPI_TYPE_INTEGER; 383 obj[i].Integer.Value = 0; 384 } 385 obj[HCI_REG_AX].Integer.Value = op; 386 obj[HCI_REG_BX].Integer.Value = function; 387 if (op == HCI_SET) 388 obj[HCI_REG_CX].Integer.Value = *arg; 389 390 args.Count = HCI_WORDS; 391 args.Pointer = obj; 392 results.Pointer = NULL; 393 results.Length = ACPI_ALLOCATE_BUFFER; 394 if (ACPI_FAILURE(AcpiEvaluateObject(h, METHOD_HCI, &args, &results))) 395 goto end; 396 res = (ACPI_OBJECT *)results.Pointer; 397 if (!ACPI_PKG_VALID(res, HCI_WORDS)) { 398 printf("toshiba: invalid package!\n"); 399 return (ENXIO); 400 } 401 402 acpi_PkgInt32(res, HCI_REG_AX, &ret); 403 if (ret == HCI_SUCCESS) { 404 if (op == HCI_GET) 405 acpi_PkgInt32(res, HCI_REG_CX, arg); 406 status = 0; 407 } else if (function == HCI_REG_SYSTEM_EVENT && op == HCI_GET && 408 ret == HCI_NOT_SUPPORTED) { 409 /* 410 * Sometimes system events are disabled without us requesting 411 * it. This workaround attempts to re-enable them. 412 */ 413 i = 1; 414 hci_call(h, HCI_SET, HCI_REG_SYSTEM_EVENT, &i); 415 } 416 417end: 418 if (results.Pointer != NULL) 419 AcpiOsFree(results.Pointer); 420 421 return (status); 422} 423 424/* 425 * Perform a few actions based on the keypress. Users can extend this 426 * functionality by reading the keystrokes we send to devd(8). 427 */ 428static void 429hci_key_action(ACPI_HANDLE h, UINT32 key) 430{ 431 UINT32 arg; 432 433 switch (key) { 434 case FN_F6_RELEASE: 435 /* Decrease LCD brightness. */ 436 hci_lcd_brightness(h, HCI_GET, &arg); 437 if (arg-- == 0) 438 arg = 0; 439 else 440 hci_lcd_brightness(h, HCI_SET, &arg); 441 break; 442 case FN_F7_RELEASE: 443 /* Increase LCD brightness. */ 444 hci_lcd_brightness(h, HCI_GET, &arg); 445 if (arg++ == 7) 446 arg = 7; 447 else 448 hci_lcd_brightness(h, HCI_SET, &arg); 449 break; 450 case FN_F5_RELEASE: 451 /* Cycle through video outputs. */ 452 hci_video_output(h, HCI_GET, &arg); 453 arg = (arg + 1) % 7; 454 hci_video_output(h, HCI_SET, &arg); 455 break; 456 case FN_F8_RELEASE: 457 /* Toggle LCD backlight. */ 458 hci_lcd_backlight(h, HCI_GET, &arg); 459 arg = (arg != 0) ? 0 : 1; 460 hci_lcd_backlight(h, HCI_SET, &arg); 461 break; 462 case FN_ESC_RELEASE: 463 /* Toggle forcing fan on. */ 464 hci_force_fan(h, HCI_GET, &arg); 465 arg = (arg != 0) ? 0 : 1; 466 hci_force_fan(h, HCI_SET, &arg); 467 break; 468 } 469} 470 471static void 472acpi_toshiba_notify(ACPI_HANDLE h, UINT32 notify, void *context) 473{ 474 struct acpi_toshiba_softc *sc; 475 UINT32 key; 476 477 sc = (struct acpi_toshiba_softc *)context; 478 479 if (notify == 0x80) { 480 while (hci_call(h, HCI_GET, HCI_REG_SYSTEM_EVENT, &key) == 0) { 481 hci_key_action(h, key); 482 acpi_UserNotify("TOSHIBA", h, (uint8_t)key); 483 } 484 } else { 485 device_printf(sc->dev, "unknown notify: 0x%x\n", notify); 486 } 487}
| 251 sc = device_get_softc(dev); 252 if (enable_fn_keys != 0) { 253 AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, 254 acpi_toshiba_notify); 255 } 256 sysctl_ctx_free(&sc->sysctl_ctx); 257 258 return (0); 259} 260 261static int 262acpi_toshiba_sysctl(SYSCTL_HANDLER_ARGS) 263{ 264 struct acpi_toshiba_softc *sc; 265 UINT32 arg; 266 int function, error = 0; 267 hci_fn_t *handler; 268 269 sc = (struct acpi_toshiba_softc *)oidp->oid_arg1; 270 function = oidp->oid_arg2; 271 handler = sysctl_table[function].handler; 272 273 /* Get the current value from the appropriate function. */ 274 error = handler(sc->handle, HCI_GET, &arg); 275 if (error != 0) 276 return (error); 277 278 /* Send the current value to the user and return if no new value. */ 279 error = sysctl_handle_int(oidp, &arg, 0, req); 280 if (error != 0 || req->newptr == NULL) 281 return (error); 282 283 /* Set the new value via the appropriate function. */ 284 error = handler(sc->handle, HCI_SET, &arg); 285 286 return (error); 287} 288 289static int 290hci_force_fan(ACPI_HANDLE h, int op, UINT32 *state) 291{ 292 int ret; 293 294 if (op == HCI_SET) { 295 if (*state < 0 || *state > 1) 296 return (EINVAL); 297 *state <<= HCI_FAN_SHIFT; 298 } 299 ret = hci_call(h, op, HCI_REG_FAN, state); 300 if (ret == 0 && op == HCI_GET) 301 *state >>= HCI_FAN_SHIFT; 302 return (ret); 303} 304 305static int 306hci_video_output(ACPI_HANDLE h, int op, UINT32 *video_output) 307{ 308 int ret; 309 310 if (op == HCI_SET) { 311 if (*video_output < 1 || *video_output > 7) 312 return (EINVAL); 313 *video_output |= HCI_VIDEO_OUTPUT_FLAG; 314 } 315 ret = hci_call(h, op, HCI_REG_VIDEO_OUTPUT, video_output); 316 if (ret == 0 && op == HCI_GET) 317 *video_output &= 0xff; 318 return (ret); 319} 320 321static int 322hci_lcd_brightness(ACPI_HANDLE h, int op, UINT32 *brightness) 323{ 324 int ret; 325 326 if (op == HCI_SET) { 327 if (*brightness < 0 || *brightness > HCI_LCD_BRIGHTNESS_MAX) 328 return (EINVAL); 329 *brightness <<= HCI_LCD_BRIGHTNESS_SHIFT; 330 } 331 ret = hci_call(h, op, HCI_REG_LCD_BRIGHTNESS, brightness); 332 if (ret == 0 && op == HCI_GET) 333 *brightness >>= HCI_LCD_BRIGHTNESS_SHIFT; 334 return (ret); 335} 336 337static int 338hci_lcd_backlight(ACPI_HANDLE h, int op, UINT32 *backlight) 339{ 340 if (op == HCI_SET) { 341 if (*backlight < 0 || *backlight > 1) 342 return (EINVAL); 343 } 344 return (hci_call(h, op, HCI_REG_LCD_BACKLIGHT, backlight)); 345} 346 347static int 348hci_cpu_speed(ACPI_HANDLE h, int op, UINT32 *speed) 349{ 350 int ret; 351 352 if (op == HCI_SET) { 353 if (*speed < 0 || *speed > HCI_CPU_SPEED_MAX) 354 return (EINVAL); 355 *speed <<= HCI_CPU_SPEED_SHIFT; 356 } 357 ret = hci_call(h, op, HCI_REG_CPU_SPEED, speed); 358 if (ret == 0 && op == HCI_GET) 359 *speed >>= HCI_CPU_SPEED_SHIFT; 360 return (ret); 361} 362 363static int 364hci_call(ACPI_HANDLE h, int op, int function, UINT32 *arg) 365{ 366 ACPI_OBJECT_LIST args; 367 ACPI_BUFFER results; 368 ACPI_OBJECT obj[HCI_WORDS]; 369 ACPI_OBJECT *res; 370 int status, i, ret; 371 372 status = ENXIO; 373 374 for (i = 0; i < HCI_WORDS; i++) { 375 obj[i].Type = ACPI_TYPE_INTEGER; 376 obj[i].Integer.Value = 0; 377 } 378 obj[HCI_REG_AX].Integer.Value = op; 379 obj[HCI_REG_BX].Integer.Value = function; 380 if (op == HCI_SET) 381 obj[HCI_REG_CX].Integer.Value = *arg; 382 383 args.Count = HCI_WORDS; 384 args.Pointer = obj; 385 results.Pointer = NULL; 386 results.Length = ACPI_ALLOCATE_BUFFER; 387 if (ACPI_FAILURE(AcpiEvaluateObject(h, METHOD_HCI, &args, &results))) 388 goto end; 389 res = (ACPI_OBJECT *)results.Pointer; 390 if (!ACPI_PKG_VALID(res, HCI_WORDS)) { 391 printf("toshiba: invalid package!\n"); 392 return (ENXIO); 393 } 394 395 acpi_PkgInt32(res, HCI_REG_AX, &ret); 396 if (ret == HCI_SUCCESS) { 397 if (op == HCI_GET) 398 acpi_PkgInt32(res, HCI_REG_CX, arg); 399 status = 0; 400 } else if (function == HCI_REG_SYSTEM_EVENT && op == HCI_GET && 401 ret == HCI_NOT_SUPPORTED) { 402 /* 403 * Sometimes system events are disabled without us requesting 404 * it. This workaround attempts to re-enable them. 405 */ 406 i = 1; 407 hci_call(h, HCI_SET, HCI_REG_SYSTEM_EVENT, &i); 408 } 409 410end: 411 if (results.Pointer != NULL) 412 AcpiOsFree(results.Pointer); 413 414 return (status); 415} 416 417/* 418 * Perform a few actions based on the keypress. Users can extend this 419 * functionality by reading the keystrokes we send to devd(8). 420 */ 421static void 422hci_key_action(ACPI_HANDLE h, UINT32 key) 423{ 424 UINT32 arg; 425 426 switch (key) { 427 case FN_F6_RELEASE: 428 /* Decrease LCD brightness. */ 429 hci_lcd_brightness(h, HCI_GET, &arg); 430 if (arg-- == 0) 431 arg = 0; 432 else 433 hci_lcd_brightness(h, HCI_SET, &arg); 434 break; 435 case FN_F7_RELEASE: 436 /* Increase LCD brightness. */ 437 hci_lcd_brightness(h, HCI_GET, &arg); 438 if (arg++ == 7) 439 arg = 7; 440 else 441 hci_lcd_brightness(h, HCI_SET, &arg); 442 break; 443 case FN_F5_RELEASE: 444 /* Cycle through video outputs. */ 445 hci_video_output(h, HCI_GET, &arg); 446 arg = (arg + 1) % 7; 447 hci_video_output(h, HCI_SET, &arg); 448 break; 449 case FN_F8_RELEASE: 450 /* Toggle LCD backlight. */ 451 hci_lcd_backlight(h, HCI_GET, &arg); 452 arg = (arg != 0) ? 0 : 1; 453 hci_lcd_backlight(h, HCI_SET, &arg); 454 break; 455 case FN_ESC_RELEASE: 456 /* Toggle forcing fan on. */ 457 hci_force_fan(h, HCI_GET, &arg); 458 arg = (arg != 0) ? 0 : 1; 459 hci_force_fan(h, HCI_SET, &arg); 460 break; 461 } 462} 463 464static void 465acpi_toshiba_notify(ACPI_HANDLE h, UINT32 notify, void *context) 466{ 467 struct acpi_toshiba_softc *sc; 468 UINT32 key; 469 470 sc = (struct acpi_toshiba_softc *)context; 471 472 if (notify == 0x80) { 473 while (hci_call(h, HCI_GET, HCI_REG_SYSTEM_EVENT, &key) == 0) { 474 hci_key_action(h, key); 475 acpi_UserNotify("TOSHIBA", h, (uint8_t)key); 476 } 477 } else { 478 device_printf(sc->dev, "unknown notify: 0x%x\n", notify); 479 } 480}
|