1 1.11 thorpej /* $NetBSD: hpqlb_acpi.c,v 1.11 2021/01/29 15:49:55 thorpej Exp $ */ 2 1.1 cegger 3 1.1 cegger /*- 4 1.1 cegger * Copyright (c) 2008 Christoph Egger <cegger (at) netbsd.org> 5 1.1 cegger * All rights reserved. 6 1.1 cegger * 7 1.1 cegger * Redistribution and use in source and binary forms, with or without 8 1.1 cegger * modification, are permitted provided that the following conditions 9 1.1 cegger * are met: 10 1.1 cegger * 1. Redistributions of source code must retain the above copyright 11 1.1 cegger * notice, this list of conditions and the following disclaimer. 12 1.1 cegger * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cegger * notice, this list of conditions and the following disclaimer in the 14 1.1 cegger * documentation and/or other materials provided with the distribution. 15 1.1 cegger * 16 1.1 cegger * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 cegger * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 cegger * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 cegger * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 cegger * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 cegger * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 cegger * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 cegger * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 cegger * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 cegger * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 cegger * POSSIBILITY OF SUCH DAMAGE. 27 1.1 cegger */ 28 1.1 cegger 29 1.1 cegger #include <sys/cdefs.h> 30 1.11 thorpej __KERNEL_RCSID(0, "$NetBSD: hpqlb_acpi.c,v 1.11 2021/01/29 15:49:55 thorpej Exp $"); 31 1.1 cegger 32 1.1 cegger #include <sys/param.h> 33 1.1 cegger #include <sys/device.h> 34 1.8 jruoho #include <sys/module.h> 35 1.7 jruoho #include <sys/systm.h> 36 1.7 jruoho 37 1.7 jruoho #include <machine/pio.h> 38 1.1 cegger 39 1.5 jruoho #include <dev/acpi/acpireg.h> 40 1.1 cegger #include <dev/acpi/acpivar.h> 41 1.1 cegger 42 1.7 jruoho #include <dev/isa/isareg.h> 43 1.7 jruoho 44 1.1 cegger #include <dev/wscons/wsconsio.h> 45 1.1 cegger #include <dev/wscons/wskbdvar.h> 46 1.1 cegger 47 1.5 jruoho #define _COMPONENT ACPI_RESOURCE_COMPONENT 48 1.5 jruoho ACPI_MODULE_NAME ("hpqlb_acpi") 49 1.5 jruoho 50 1.1 cegger struct hpqlb_softc { 51 1.1 cegger device_t sc_dev; 52 1.1 cegger struct acpi_devnode *sc_node; 53 1.1 cegger 54 1.1 cegger device_t sc_wskbddev; 55 1.1 cegger 56 1.1 cegger #define HP_PSW_DISPLAY_CYCLE 0 57 1.1 cegger #define HP_PSW_BRIGHTNESS_UP 1 58 1.1 cegger #define HP_PSW_BRIGHTNESS_DOWN 2 59 1.1 cegger #define HP_PSW_SLEEP 3 60 1.1 cegger #define HP_PSW_LAST 4 61 1.1 cegger struct sysmon_pswitch sc_smpsw[HP_PSW_LAST]; 62 1.1 cegger bool sc_smpsw_displaycycle_valid; 63 1.1 cegger bool sc_smpsw_sleep_valid; 64 1.1 cegger }; 65 1.1 cegger 66 1.1 cegger #define HP_QLB_Quick 0x88 67 1.1 cegger #define HP_QLB_DVD 0x8e 68 1.1 cegger #define HP_QLB_FullBackward 0x90 69 1.1 cegger #define HP_QLB_Play 0xa2 70 1.1 cegger #define HP_QLB_FullForward 0x99 71 1.1 cegger #define HP_QLB_Stop 0xa4 72 1.1 cegger #define HP_QLB_VolumeMute 0xa0 73 1.1 cegger #define HP_QLB_VolumeDown 0xae 74 1.1 cegger #define HP_QLB_VolumeUp 0xb0 75 1.1 cegger 76 1.1 cegger #define HP_QLB_Help 0xb1 77 1.1 cegger #define HP_QLB_WWW 0xb2 78 1.1 cegger #define HP_QLB_DisplayCycle /* ??? */ 79 1.1 cegger #define HP_QLB_Sleep 0xdf 80 1.1 cegger #define HP_QLB_Lock 0x8a 81 1.1 cegger #define HP_QLB_BrightnessDown /* ??? */ 82 1.1 cegger #define HP_QLB_BrightnessUp /* ??? */ 83 1.1 cegger #define HP_QLB_ChasisOpen 0xe3 84 1.1 cegger 85 1.1 cegger static int hpqlb_match(device_t, cfdata_t, void *); 86 1.1 cegger static void hpqlb_attach(device_t, device_t, void *); 87 1.8 jruoho static int hpqlb_detach(device_t, int); 88 1.1 cegger 89 1.1 cegger static int hpqlb_finalize(device_t); 90 1.1 cegger static int hpqlb_hotkey_handler(struct wskbd_softc *, void *, u_int, int); 91 1.1 cegger 92 1.1 cegger static void hpqlb_init(device_t); 93 1.6 dyoung static bool hpqlb_resume(device_t, const pmf_qual_t *); 94 1.1 cegger 95 1.1 cegger CFATTACH_DECL_NEW(hpqlb, sizeof(struct hpqlb_softc), 96 1.8 jruoho hpqlb_match, hpqlb_attach, hpqlb_detach, NULL); 97 1.1 cegger 98 1.11 thorpej static const struct device_compatible_entry compat_data[] = { 99 1.11 thorpej { .compat = "HPQ0006" }, 100 1.11 thorpej { .compat = "HPQ0007" }, 101 1.11 thorpej DEVICE_COMPAT_EOL 102 1.1 cegger }; 103 1.1 cegger 104 1.1 cegger static int 105 1.1 cegger hpqlb_match(device_t parent, cfdata_t match, void *opaque) 106 1.1 cegger { 107 1.1 cegger struct acpi_attach_args *aa = opaque; 108 1.1 cegger 109 1.11 thorpej return acpi_compatible_match(aa, compat_data); 110 1.1 cegger } 111 1.1 cegger 112 1.1 cegger static void 113 1.1 cegger hpqlb_attach(device_t parent, device_t self, void *opaque) 114 1.1 cegger { 115 1.1 cegger struct hpqlb_softc *sc = device_private(self); 116 1.1 cegger struct acpi_attach_args *aa = opaque; 117 1.1 cegger 118 1.1 cegger sc->sc_node = aa->aa_node; 119 1.1 cegger sc->sc_dev = self; 120 1.1 cegger 121 1.1 cegger aprint_naive("\n"); 122 1.1 cegger aprint_normal(": HP Quick Launch Buttons\n"); 123 1.1 cegger 124 1.1 cegger hpqlb_init(self); 125 1.1 cegger 126 1.1 cegger if (config_finalize_register(self, hpqlb_finalize) != 0) 127 1.8 jruoho aprint_error_dev(self, "unable to register hpqlb finalizer\n"); 128 1.1 cegger 129 1.1 cegger sc->sc_smpsw_displaycycle_valid = true; 130 1.8 jruoho 131 1.1 cegger sc->sc_smpsw[HP_PSW_DISPLAY_CYCLE].smpsw_name = 132 1.1 cegger PSWITCH_HK_DISPLAY_CYCLE; 133 1.8 jruoho 134 1.1 cegger sc->sc_smpsw[HP_PSW_DISPLAY_CYCLE].smpsw_type = 135 1.1 cegger PSWITCH_TYPE_HOTKEY; 136 1.8 jruoho 137 1.8 jruoho if (sysmon_pswitch_register(&sc->sc_smpsw[HP_PSW_DISPLAY_CYCLE]) != 0) 138 1.1 cegger sc->sc_smpsw_displaycycle_valid = false; 139 1.1 cegger 140 1.1 cegger sc->sc_smpsw_sleep_valid = true; 141 1.1 cegger sc->sc_smpsw[HP_PSW_SLEEP].smpsw_name = device_xname(self); 142 1.1 cegger sc->sc_smpsw[HP_PSW_SLEEP].smpsw_type = PSWITCH_TYPE_SLEEP; 143 1.8 jruoho 144 1.8 jruoho if (sysmon_pswitch_register(&sc->sc_smpsw[HP_PSW_SLEEP]) != 0) 145 1.1 cegger sc->sc_smpsw_sleep_valid = false; 146 1.1 cegger 147 1.8 jruoho (void)pmf_device_register(self, NULL, hpqlb_resume); 148 1.8 jruoho } 149 1.8 jruoho 150 1.8 jruoho static int 151 1.8 jruoho hpqlb_detach(device_t self, int flags) 152 1.8 jruoho { 153 1.8 jruoho struct hpqlb_softc *sc = device_private(self); 154 1.8 jruoho 155 1.8 jruoho pmf_device_deregister(self); 156 1.8 jruoho wskbd_hotkey_deregister(sc->sc_wskbddev); 157 1.8 jruoho 158 1.8 jruoho if (sc->sc_smpsw_sleep_valid != false) 159 1.8 jruoho sysmon_pswitch_unregister(&sc->sc_smpsw[HP_PSW_SLEEP]); 160 1.8 jruoho 161 1.8 jruoho if (sc->sc_smpsw_displaycycle_valid != false) 162 1.8 jruoho sysmon_pswitch_unregister(&sc->sc_smpsw[HP_PSW_DISPLAY_CYCLE]); 163 1.8 jruoho 164 1.8 jruoho return 0; 165 1.1 cegger } 166 1.1 cegger 167 1.1 cegger static int 168 1.1 cegger hpqlb_hotkey_handler(struct wskbd_softc *wskbd_sc, void *cookie, 169 1.1 cegger u_int type, int value) 170 1.1 cegger { 171 1.1 cegger struct hpqlb_softc *sc = cookie; 172 1.1 cegger int ret = 1; 173 1.1 cegger 174 1.1 cegger switch (value) { 175 1.1 cegger case HP_QLB_VolumeMute: 176 1.1 cegger if (type != WSCONS_EVENT_KEY_DOWN) 177 1.1 cegger break; 178 1.1 cegger pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_TOGGLE); 179 1.1 cegger break; 180 1.1 cegger case HP_QLB_VolumeDown: 181 1.1 cegger if (type != WSCONS_EVENT_KEY_DOWN) 182 1.1 cegger break; 183 1.1 cegger pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_DOWN); 184 1.1 cegger break; 185 1.1 cegger case HP_QLB_VolumeUp: 186 1.1 cegger if (type != WSCONS_EVENT_KEY_DOWN) 187 1.1 cegger break; 188 1.1 cegger pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_UP); 189 1.1 cegger break; 190 1.1 cegger 191 1.1 cegger #if 0 192 1.1 cegger case HP_QLB_DisplayCycle: /* ??? */ 193 1.1 cegger if (type != WSCONS_EVENT_KEY_DOWN) 194 1.1 cegger break; 195 1.1 cegger if (sc->sc_smpsw_displaycycle_valid == false) 196 1.1 cegger break; 197 1.1 cegger sysmon_pswitch_event(&sc->sc_smpsw[HP_PSW_DISPLAY_CYCLE], 198 1.1 cegger PSWITCH_EVENT_PRESSED); 199 1.1 cegger break; 200 1.1 cegger #endif 201 1.1 cegger case HP_QLB_Sleep: 202 1.1 cegger if (type != WSCONS_EVENT_KEY_DOWN) 203 1.1 cegger break; 204 1.8 jruoho if (sc->sc_smpsw_sleep_valid == false) 205 1.1 cegger break; 206 1.1 cegger sysmon_pswitch_event(&sc->sc_smpsw[HP_PSW_SLEEP], 207 1.1 cegger PSWITCH_EVENT_PRESSED); 208 1.1 cegger break; 209 1.1 cegger #if 0 210 1.1 cegger case HP_QLB_BrightnessDown: /* ??? */ 211 1.1 cegger if (type != WSCONS_EVENT_KEY_DOWN) 212 1.1 cegger break; 213 1.1 cegger pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_DOWN); 214 1.1 cegger break; 215 1.1 cegger case HP_QLB_BrightnessUp: /* ??? */ 216 1.1 cegger if (type != WSCONS_EVENT_KEY_DOWN) 217 1.1 cegger break; 218 1.1 cegger pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_UP); 219 1.1 cegger break; 220 1.1 cegger #endif 221 1.1 cegger case HP_QLB_ChasisOpen: 222 1.1 cegger if (type != WSCONS_EVENT_KEY_DOWN) 223 1.1 cegger break; 224 1.1 cegger pmf_event_inject(NULL, PMFE_CHASSIS_LID_OPEN); 225 1.1 cegger break; 226 1.1 cegger default: 227 1.8 jruoho 228 1.8 jruoho ACPI_DEBUG_PRINT((ACPI_DB_INFO, "unknown hotkey " 229 1.8 jruoho "0x%02x\n", value)); 230 1.1 cegger ret = 0; /* Assume, this is no hotkey */ 231 1.1 cegger break; 232 1.1 cegger } 233 1.1 cegger 234 1.1 cegger return ret; 235 1.1 cegger } 236 1.1 cegger 237 1.1 cegger static void 238 1.1 cegger hpqlb_init(device_t self) 239 1.1 cegger { 240 1.2 simonb 241 1.1 cegger /* HPQ0006: HP Quick Launch Buttons */ 242 1.1 cegger /* HPQ0007: HP Remote Device */ 243 1.1 cegger /* val 0, 1 or 7 == HPQ0006 */ 244 1.1 cegger /* val not 0, 1 or 7 == HPQ0007 */ 245 1.1 cegger 246 1.1 cegger /* Turn on Quick Launch Buttons */ 247 1.1 cegger outb(IO_RTC+2, 0xaf); 248 1.1 cegger outb(IO_RTC+3, 7 /* val */); 249 1.1 cegger } 250 1.1 cegger 251 1.1 cegger static int 252 1.1 cegger hpqlb_finalize(device_t self) 253 1.1 cegger { 254 1.1 cegger device_t dv; 255 1.3 dyoung deviter_t di; 256 1.1 cegger struct hpqlb_softc *sc = device_private(self); 257 1.1 cegger static int done_once = 0; 258 1.1 cegger 259 1.1 cegger /* Since we only handle real hardware, we only need to be 260 1.1 cegger * called once. 261 1.1 cegger */ 262 1.1 cegger if (done_once) 263 1.1 cegger return 0; 264 1.1 cegger done_once = 1; 265 1.1 cegger 266 1.3 dyoung for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL; 267 1.3 dyoung dv = deviter_next(&di)) { 268 1.1 cegger if (!device_is_a(dv, "wskbd")) 269 1.1 cegger continue; 270 1.1 cegger 271 1.1 cegger /* Make sure, we don't get a wskbd from a USB keyboard. 272 1.1 cegger * QLB only works on the wskbd attached on pckbd. */ 273 1.1 cegger if (!device_is_a(device_parent(dv), "pckbd")) 274 1.1 cegger continue; 275 1.1 cegger 276 1.1 cegger aprint_normal_dev(self, "registering on %s\n", 277 1.1 cegger device_xname(dv)); 278 1.1 cegger break; 279 1.1 cegger } 280 1.3 dyoung deviter_release(&di); 281 1.1 cegger 282 1.1 cegger if (dv == NULL) { 283 1.1 cegger aprint_error_dev(self, "WARNING: no matching wskbd found\n"); 284 1.1 cegger return 1; 285 1.1 cegger } 286 1.1 cegger 287 1.1 cegger sc->sc_wskbddev = dv; 288 1.1 cegger 289 1.1 cegger wskbd_hotkey_register(sc->sc_wskbddev, sc, hpqlb_hotkey_handler); 290 1.1 cegger 291 1.1 cegger return 0; 292 1.1 cegger } 293 1.1 cegger 294 1.1 cegger static bool 295 1.6 dyoung hpqlb_resume(device_t self, const pmf_qual_t *qual) 296 1.1 cegger { 297 1.2 simonb 298 1.1 cegger hpqlb_init(self); 299 1.1 cegger 300 1.1 cegger return true; 301 1.1 cegger } 302 1.8 jruoho 303 1.10 pgoyette MODULE(MODULE_CLASS_DRIVER, hpqlb, "sysmon_power"); 304 1.8 jruoho 305 1.9 jruoho #ifdef _MODULE 306 1.8 jruoho #include "ioconf.c" 307 1.9 jruoho #endif 308 1.8 jruoho 309 1.8 jruoho static int 310 1.9 jruoho hpqlb_modcmd(modcmd_t cmd, void *aux) 311 1.8 jruoho { 312 1.9 jruoho int rv = 0; 313 1.8 jruoho 314 1.8 jruoho switch (cmd) { 315 1.8 jruoho 316 1.8 jruoho case MODULE_CMD_INIT: 317 1.9 jruoho 318 1.9 jruoho #ifdef _MODULE 319 1.9 jruoho rv = config_init_component(cfdriver_ioconf_hpqlb, 320 1.8 jruoho cfattach_ioconf_hpqlb, cfdata_ioconf_hpqlb); 321 1.9 jruoho #endif 322 1.9 jruoho break; 323 1.8 jruoho 324 1.8 jruoho case MODULE_CMD_FINI: 325 1.9 jruoho 326 1.9 jruoho #ifdef _MODULE 327 1.9 jruoho rv = config_fini_component(cfdriver_ioconf_hpqlb, 328 1.8 jruoho cfattach_ioconf_hpqlb, cfdata_ioconf_hpqlb); 329 1.9 jruoho #endif 330 1.9 jruoho break; 331 1.8 jruoho 332 1.8 jruoho default: 333 1.9 jruoho rv = ENOTTY; 334 1.8 jruoho } 335 1.9 jruoho 336 1.9 jruoho return rv; 337 1.8 jruoho } 338