1 /*- 2 * Copyright (c) 2004 Takanori Watanabe 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 * $FreeBSD$ 27 */ 28 29 #include "opt_acpi.h" 30 #include <sys/param.h> 31 #include <sys/kernel.h> 32 #include <sys/bus.h> 33 #include <machine/cpufunc.h> 34 #include "acpi.h" 35 #include "acpi_if.h" 36 #include <sys/module.h> 37 #include <dev/acpica/acpivar.h> 38 #include <sys/sysctl.h> 39 #include <machine/clock.h> 40 41 #define _COMPONENT ACPI_OEM 42 ACPI_MODULE_NAME("IBM") 43 44 #define IBM_RTC_MISCKEY 0x65 45 #define IBM_RTC_BRIGHTNESS 0x6c 46 #define IBM_RTC_MASK_BRI 0x7 47 #define IBM_RTC_MASK_BRKEY 0x40 48 #define IBM_RTC_KEYLIGHT 0x66 49 #define IBM_RTC_MASK_KEYLIGHT 0x10 50 #define IBM_RTC_VOLUME 0x6e 51 #define IBM_RTC_MASK_VOL 0xf 52 #define IBM_RTC_MASK_MUTE 0x40 53 #define IBM_RTC_MASK_VOLKEY 0x80 54 55 #define IBM_NAME_GET_WIRELESS "GBDC" 56 #define IBM_NAME_SET_WIRELESS "SBDC" 57 #define IBM_NAME_INTERFACE_VERSION "MHKV" 58 #define IBM_NAME_AVAIL_MASK "MHKA" 59 #define IBM_NAME_CURRENT_MASK "MHKN" 60 #define IBM_NAME_MODIFY_MASK "MHKM" 61 #define IBM_NAME_GET_EVENT "MHKP" 62 #define IBM_NAME_ENABLE "MHKC" 63 #if 0 64 /* TPX31 Specific? */ 65 #define IBM_UCMS_VOLDN 0x0 66 #define IBM_UCMS_VOLUP 0x1 67 #define IBM_UCMS_MUTE 0x2 68 #define IBM_UCMS_BRIUP 0x4 69 #define IBM_UCMS_BRIDN 0x5 70 #define IBM_UCMS_KEYLIGHT 0xe 71 #endif 72 73 struct acpi_ibm_softc { 74 unsigned int ibm_version; 75 unsigned int ibm_availmask; 76 unsigned int ibm_initialmask; 77 int ibm_enable; 78 int device_flag; 79 #define IBM_MHKN_AVAIL 1 80 #define IBM_MHKM_AVAIL 2 81 struct sysctl_oid *oid_bluetooth; 82 struct sysctl_oid *oid_wlan; 83 }; 84 85 static int acpi_ibm_probe(device_t dev); 86 static int acpi_ibm_attach(device_t dev); 87 static int acpi_ibm_detach(device_t dev); 88 static void 89 acpi_ibm_notify_handler(ACPI_HANDLE h, UINT32 notify, 90 void *context); 91 static int sysctl_acpi_ibm_mask_handler(SYSCTL_HANDLER_ARGS); 92 static int sysctl_acpi_ibm_enable_handler(SYSCTL_HANDLER_ARGS); 93 static int sysctl_acpi_ibm_misckey_handler(SYSCTL_HANDLER_ARGS); 94 static int sysctl_acpi_ibm_volume_handler(SYSCTL_HANDLER_ARGS); 95 static int sysctl_acpi_ibm_mute_handler(SYSCTL_HANDLER_ARGS); 96 static int sysctl_acpi_ibm_brightness_handler(SYSCTL_HANDLER_ARGS); 97 static int sysctl_acpi_ibm_keylight_handler(SYSCTL_HANDLER_ARGS); 98 static int sysctl_acpi_ibm_wireless_handler(SYSCTL_HANDLER_ARGS); 99 static int acpi_ibm_enable_mask(device_t dev, int val); 100 101 static device_method_t acpi_ibm_methods[] = { 102 /* Device interface */ 103 DEVMETHOD(device_probe, acpi_ibm_probe), 104 DEVMETHOD(device_attach, acpi_ibm_attach), 105 DEVMETHOD(device_detach, acpi_ibm_detach), 106 107 {0, 0} 108 }; 109 110 static driver_t acpi_ibm_driver = { 111 "acpi_ibm", 112 acpi_ibm_methods, 113 sizeof(struct acpi_ibm_softc), 114 }; 115 116 static devclass_t acpi_ibm_devclass; 117 118 DRIVER_MODULE(acpi_ibm, acpi, acpi_ibm_driver, acpi_ibm_devclass, 119 0, 0); 120 MODULE_DEPEND(acpi_ibm, acpi, 1, 1, 1); 121 static char *ibm_id[] = {"IBM0068", NULL}; 122 123 static int 124 acpi_ibm_probe(device_t dev) 125 { 126 struct acpi_ibm_softc *sc; 127 int ret = ENXIO; 128 129 sc = device_get_softc(dev); 130 131 if (ACPI_ID_PROBE(device_get_parent(dev), dev, ibm_id)) { 132 device_set_desc(dev, "IBM ThinkPad Button"); 133 ret = 0; 134 } 135 return (ret); 136 } 137 138 static int 139 acpi_ibm_call_two_method(device_t dev, char *name, int val1, int val2) 140 { 141 ACPI_OBJECT arg [2]; 142 ACPI_OBJECT_LIST args = {.Count = 2,.Pointer = arg}; 143 arg[0].Type = ACPI_TYPE_INTEGER; 144 arg[0].Integer.Value = val1; 145 arg[1].Type = ACPI_TYPE_INTEGER; 146 arg[1].Integer.Value = val2; 147 return AcpiEvaluateObject(acpi_get_handle(dev), name, &args, NULL); 148 } 149 150 static int 151 acpi_ibm_attach(device_t dev) 152 { 153 struct acpi_ibm_softc *sc; 154 ACPI_STATUS status; 155 ACPI_HANDLE h; 156 int dummy; 157 struct sysctl_oid *oid; 158 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 159 160 sc = device_get_softc(dev); 161 sc->device_flag = 0; 162 if (ACPI_FAILURE 163 (acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_INTERFACE_VERSION, &sc->ibm_version))) { 164 sc->ibm_version = 0; 165 } 166 device_printf(dev, "Version %x\n", sc->ibm_version); 167 if (ACPI_FAILURE 168 (acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_AVAIL_MASK, &sc->ibm_availmask))) 169 sc->ibm_availmask = 0xffffffff; 170 171 if (ACPI_FAILURE 172 (acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_CURRENT_MASK, &sc->ibm_initialmask))) 173 sc->ibm_initialmask = 0xffffffff; 174 else 175 sc->device_flag |= IBM_MHKN_AVAIL; 176 177 if (ACPI_SUCCESS(status = AcpiGetHandle(acpi_get_handle(dev), IBM_NAME_MODIFY_MASK, &h))) 178 sc->device_flag |= IBM_MHKM_AVAIL; 179 else 180 printf("%s\n", AcpiFormatException(status)); 181 182 device_printf(dev, "Available Mask %x\n", sc->ibm_availmask); 183 device_printf(dev, "Initial Mask %x\n", sc->ibm_initialmask); 184 /* Install Specific Handler */ 185 status = AcpiInstallNotifyHandler(acpi_get_handle(dev), ACPI_DEVICE_NOTIFY, acpi_ibm_notify_handler, dev); 186 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 187 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 188 OID_AUTO, "key_mask", CTLTYPE_INT | CTLFLAG_RW, 189 dev, 0, 190 sysctl_acpi_ibm_mask_handler, "I", "Hot key mask"); 191 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 192 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 193 OID_AUTO, "version", CTLFLAG_RD, 194 &sc->ibm_version, 0, "Interface version"); 195 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 196 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 197 OID_AUTO, "avail_mask", CTLFLAG_RD, 198 &sc->ibm_availmask, 0, "Available Key mask"); 199 if (ACPI_FAILURE(acpi_SetInteger(acpi_get_handle(dev), IBM_NAME_ENABLE, 1))) 200 goto fail; 201 sc->ibm_enable = 1; 202 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 203 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 204 OID_AUTO, "enable", CTLTYPE_INT | CTLFLAG_RW, 205 dev, 0, 206 sysctl_acpi_ibm_enable_handler, "I", "Hot key enable"); 207 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 208 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 209 OID_AUTO, "misckey", CTLTYPE_INT | CTLFLAG_RD, 210 dev, 0, 211 sysctl_acpi_ibm_misckey_handler, "I", "Key Status: Poll me"); 212 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 213 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 214 OID_AUTO, "brightness", CTLTYPE_INT | CTLFLAG_RD, 215 dev, 0, 216 sysctl_acpi_ibm_brightness_handler, "I", "Brightness"); 217 218 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 219 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 220 OID_AUTO, "volume", CTLTYPE_INT | CTLFLAG_RD, 221 dev, 0, 222 sysctl_acpi_ibm_volume_handler, "I", "Volume"); 223 224 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 225 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 226 OID_AUTO, "mute", CTLTYPE_INT | CTLFLAG_RD, 227 dev, 0, 228 sysctl_acpi_ibm_mute_handler, "I", "Muting"); 229 230 231 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 232 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 233 OID_AUTO, "keylight", CTLTYPE_INT | CTLFLAG_RD, 234 dev, 0, 235 sysctl_acpi_ibm_keylight_handler, "I", "Key Light"); 236 if (ACPI_SUCCESS(acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_GET_WIRELESS, &dummy))) { 237 oid = SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 238 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 239 OID_AUTO, "bluetooth", CTLTYPE_INT | CTLFLAG_RW, dev, 0, 240 sysctl_acpi_ibm_wireless_handler, "I", "Bluetooth Enable"); 241 sc->oid_bluetooth = oid; 242 oid = SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 243 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 244 OID_AUTO, "wlan", CTLTYPE_INT | CTLFLAG_RW, dev, 0, 245 sysctl_acpi_ibm_wireless_handler, "I", "WLAN Enable"); 246 sc->oid_wlan = oid; 247 } 248 return_VALUE(0); 249 fail: 250 device_printf(dev, "FAILED\n"); 251 AcpiRemoveNotifyHandler(acpi_get_handle(dev), ACPI_DEVICE_NOTIFY, acpi_ibm_notify_handler); 252 return_VALUE(EINVAL); 253 } 254 255 static int 256 acpi_ibm_detach(device_t dev) 257 { 258 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 259 260 struct acpi_ibm_softc *sc = device_get_softc(dev); 261 acpi_SetInteger(acpi_get_handle(dev), IBM_NAME_ENABLE, 0); 262 acpi_ibm_enable_mask(dev, sc->ibm_initialmask); 263 264 AcpiRemoveNotifyHandler(acpi_get_handle(dev), ACPI_DEVICE_NOTIFY, acpi_ibm_notify_handler); 265 return_VALUE(0); 266 } 267 #if 0 268 static int 269 acpi_ibm_suspend(device_t dev) 270 { 271 struct acpi_ibm_softc *sc = device_get_softc(dev); 272 return_VALUE(0); 273 } 274 275 static int 276 acpi_ibm_resume(device_t dev) 277 { 278 return (0); 279 } 280 #endif 281 static void 282 acpi_ibm_notify_handler(ACPI_HANDLE h, UINT32 notify, 283 void *context) 284 { 285 int mhkp , arg, type; 286 device_t dev = context; 287 struct acpi_ibm_softc *sc = device_get_softc(dev); 288 289 printf("IBM:NOTIFY:%x\n", notify); 290 if (notify != 0x80) { 291 printf("Unknown notify\n"); 292 } 293 for (;;) { 294 295 acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_GET_EVENT, &mhkp); 296 297 if (mhkp == 0) { 298 break; 299 } 300 printf("notify:%x\n", mhkp); 301 302 type = (mhkp >> 12) & 0xf; 303 arg = mhkp & 0xfff; 304 switch (type) { 305 case 1: 306 if (!(sc->ibm_availmask & (1 << (arg - 1)))) { 307 printf("Unknown key %d\n", arg); 308 break; 309 } 310 acpi_UserNotify("IBM", h, (arg & 0xff)); 311 break; 312 default: 313 break; 314 } 315 } 316 } 317 318 static int 319 acpi_ibm_enable_mask(device_t dev, int val) 320 { 321 int i; 322 struct acpi_ibm_softc *sc = device_get_softc(dev); 323 324 if (!(sc->device_flag | IBM_MHKM_AVAIL)) { 325 return -1; 326 } 327 for (i = 0; i < 32; i++) { 328 acpi_ibm_call_two_method(dev, IBM_NAME_MODIFY_MASK, i + 1, 1); 329 if (!((1 << i) & val)) 330 acpi_ibm_call_two_method(dev, IBM_NAME_MODIFY_MASK, i + 1, 0); 331 } 332 return 0; 333 } 334 335 static int 336 sysctl_acpi_ibm_mask_handler(SYSCTL_HANDLER_ARGS) 337 { 338 device_t dev = arg1; 339 int val = 0xffffffff; 340 int error = 0; 341 342 struct acpi_ibm_softc *sc = device_get_softc(dev); 343 344 if (sc->device_flag & IBM_MHKN_AVAIL) 345 acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_CURRENT_MASK, &val); 346 347 error = sysctl_handle_int(oidp, &val, 0, req); 348 349 if (error || !req->newptr) 350 return error; 351 352 val &= sc->ibm_availmask; 353 val |= sc->ibm_initialmask; 354 355 acpi_ibm_enable_mask(dev, val); 356 357 return 0; 358 } 359 360 static int 361 sysctl_acpi_ibm_misckey_handler(SYSCTL_HANDLER_ARGS) 362 { 363 int val , error; 364 val = rtcin(IBM_RTC_MISCKEY); 365 error = sysctl_handle_int(oidp, &val, 0, req); 366 if (error || !req->newptr) 367 return error; 368 return 0; 369 } 370 371 372 static int 373 sysctl_acpi_ibm_brightness_handler(SYSCTL_HANDLER_ARGS) 374 { 375 int val , error; 376 val = rtcin(IBM_RTC_BRIGHTNESS); 377 val &= IBM_RTC_MASK_BRI; 378 error = sysctl_handle_int(oidp, &val, 0, req); 379 if (error || !req->newptr) 380 return error; 381 return 0; 382 } 383 384 static int 385 sysctl_acpi_ibm_mute_handler(SYSCTL_HANDLER_ARGS) 386 { 387 int val , error; 388 val = rtcin(IBM_RTC_VOLUME); 389 val = ((val & IBM_RTC_MASK_MUTE) == IBM_RTC_MASK_MUTE); 390 391 error = sysctl_handle_int(oidp, &val, 0, req); 392 if (error || !req->newptr) 393 return error; 394 return 0; 395 } 396 397 static int 398 sysctl_acpi_ibm_keylight_handler(SYSCTL_HANDLER_ARGS) 399 { 400 int val , error; 401 val = ((rtcin(IBM_RTC_KEYLIGHT) & IBM_RTC_MASK_KEYLIGHT) 402 == IBM_RTC_MASK_KEYLIGHT); 403 404 error = sysctl_handle_int(oidp, &val, 0, req); 405 if (error || !req->newptr) 406 return error; 407 return 0; 408 } 409 410 static int 411 sysctl_acpi_ibm_volume_handler(SYSCTL_HANDLER_ARGS) 412 { 413 int val , error; 414 val = rtcin(IBM_RTC_VOLUME); 415 val &= IBM_RTC_MASK_VOL; 416 error = sysctl_handle_int(oidp, &val, 0, req); 417 if (error || !req->newptr) 418 return error; 419 return 0; 420 } 421 422 static int 423 sysctl_acpi_ibm_enable_handler(SYSCTL_HANDLER_ARGS) 424 { 425 device_t dev = arg1; 426 struct acpi_ibm_softc *sc = device_get_softc(dev); 427 int error = 0; 428 429 error = sysctl_handle_int(oidp, &sc->ibm_enable, 0, req); 430 431 if (error || !req->newptr) 432 return error; 433 434 if (sc->ibm_enable) 435 sc->ibm_enable = 1; 436 else 437 sc->ibm_enable = 0; 438 acpi_SetInteger(acpi_get_handle(dev), IBM_NAME_ENABLE, sc->ibm_enable); 439 440 return 0; 441 } 442 443 static int 444 sysctl_acpi_ibm_wireless_handler(SYSCTL_HANDLER_ARGS) 445 { 446 device_t dev = arg1; 447 struct acpi_ibm_softc *sc = device_get_softc(dev); 448 int error = 0, val, oldval, mask; 449 if (sc->oid_bluetooth == oidp) { 450 mask = 2; 451 } else if (sc->oid_wlan == oidp) { 452 mask = 4; 453 } else { 454 printf("WARNING: wrong handler invoked\n"); 455 return ENOENT; 456 } 457 458 acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_GET_WIRELESS, &oldval); 459 val = !((oldval & mask) == 0); 460 error = sysctl_handle_int(oidp, &val, 0, req); 461 462 if (error || !req->newptr) 463 return error; 464 oldval &= (~mask); 465 if (val) 466 oldval |= mask; 467 acpi_SetInteger(acpi_get_handle(dev), IBM_NAME_SET_WIRELESS, oldval); 468 return 0; 469 470 471 } 472