1 /* $OpenBSD: acpisony.c,v 1.4 2011/01/02 04:56:57 jordan Exp $ */ 2 /* 3 * Copyright (c) 2010 Paul Irofti <pirofti@openbsd.org> 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/proc.h> 21 22 #include <dev/acpi/acpireg.h> 23 #include <dev/acpi/acpivar.h> 24 #include <dev/acpi/acpidev.h> 25 #include <dev/acpi/amltypes.h> 26 #include <dev/acpi/dsdt.h> 27 28 #include <machine/apmvar.h> 29 30 int acpisony_match(struct device *, void *, void *); 31 void acpisony_attach(struct device *, struct device *, void *); 32 int acpisony_activate(struct device *, int); 33 int acpisony_notify(struct aml_node *, int, void *); 34 35 #ifdef ACPISONY_DEBUG 36 #define DPRINTF(x) printf x 37 #else 38 #define DPRINTF(x) 39 #endif 40 41 /* Notifications */ 42 #define SONY_NOTIFY_FN_KEY 0x90 43 44 #define SONY_NOTIFY_BRIGHTNESS_DOWN_PRESSED 0x85 45 #define SONY_NOTIFY_BRIGHTNESS_DOWN_RELEASED 0x05 46 #define SONY_NOTIFY_BRIGHTNESS_UP_PRESSED 0x86 47 #define SONY_NOTIFY_BRIGHTNESS_UP_RELEASED 0x06 48 49 #define SONY_NOTIFY_DISPLAY_SWITCH_PRESSED 0x87 50 #define SONY_NOTIFY_DISPLAY_SWITCH_RELEASED 0x07 51 52 #define SONY_NOTIFY_ZOOM_OUT_PRESSED 0x89 53 #define SONY_NOTIFY_ZOOM_OUT_RELEASED 0x09 54 55 #define SONY_NOTIFY_ZOOM_IN_PRESSED 0x8a 56 #define SONY_NOTIFY_ZOOM_IN_RELEASED 0x0a 57 58 #define SONY_NOTIFY_SUSPEND_PRESSED 0x8c 59 #define SONY_NOTIFY_SUSPEND_RELEASED 0x0c 60 61 struct acpisony_softc { 62 struct device sc_dev; 63 64 bus_space_tag_t sc_iot; 65 bus_space_handle_t sc_ioh; 66 67 struct acpi_softc *sc_acpi; 68 struct aml_node *sc_devnode; 69 }; 70 71 struct cfattach acpisony_ca = { 72 sizeof(struct acpisony_softc), acpisony_match, acpisony_attach, 73 NULL, acpisony_activate 74 }; 75 76 struct cfdriver acpisony_cd = { 77 NULL, "acpisony", DV_DULL 78 }; 79 80 void acpisony_notify_setup(struct acpisony_softc *); 81 int acpisony_set_hotkey(struct acpisony_softc *, int, int); 82 int acpisony_find_offset(struct acpisony_softc *, int); 83 84 void acpisony_brightness_down(struct acpisony_softc *); 85 int acpisony_get_brightness(struct acpisony_softc *); 86 void acpisony_set_brightness(struct acpisony_softc *, int); 87 88 int 89 acpisony_match(struct device *parent, void *match, void *aux) 90 { 91 struct acpi_attach_args *aa = aux; 92 struct cfdata *cf = match; 93 94 if (aa->aaa_name == NULL || 95 strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 || 96 aa->aaa_table != NULL) 97 return (0); 98 99 return (1); 100 } 101 102 void 103 acpisony_attach(struct device *parent, struct device *self, void *aux) 104 { 105 struct acpisony_softc *sc = (struct acpisony_softc *)self; 106 struct acpi_attach_args *aa = aux; 107 108 sc->sc_acpi = (struct acpi_softc *)parent; 109 sc->sc_devnode = aa->aaa_node; 110 111 printf(": %s\n", sc->sc_devnode->name); 112 113 /* Setup the notification masks */ 114 acpisony_notify_setup(sc); 115 116 aml_register_notify(sc->sc_devnode, aa->aaa_dev, 117 acpisony_notify, sc, ACPIDEV_NOPOLL); 118 } 119 120 int 121 acpisony_activate(struct device *self, int act) 122 { 123 struct acpisony_softc *sc = (struct acpisony_softc *)self; 124 125 switch (act) { 126 case DVACT_RESUME: 127 acpisony_notify_setup(sc); 128 break; 129 } 130 return 0; 131 } 132 133 int 134 acpisony_notify(struct aml_node *node, int notify, void *arg) 135 { 136 struct acpisony_softc *sc = arg; 137 int val, key = 0; 138 139 if (notify == SONY_NOTIFY_FN_KEY) { 140 notify -= 0x90; 141 DPRINTF(("notify = %X", notify)); 142 143 if (notify == acpisony_find_offset(sc, 0x100)) { 144 DPRINTF(("key = 0x100\n")); 145 key = 0x100; 146 } 147 if (notify == acpisony_find_offset(sc, 0x127)) { 148 DPRINTF(("key = 0x127\n")); 149 key = 0x127; 150 } 151 152 if (key) { 153 val = acpisony_set_hotkey(sc, key, 0x200); 154 if (val < 0) { 155 printf("returned val = %X", val); 156 return 1; 157 } 158 notify = val & 0xff; 159 160 DPRINTF(("Treat %X events, notify %X\n", key, notify)); 161 } else 162 DPRINTF(("rfkill update, notify %X\n", notify)); 163 } 164 165 switch (notify) { 166 case SONY_NOTIFY_BRIGHTNESS_DOWN_PRESSED: 167 DPRINTF(("br-down-pressed\n")); 168 acpisony_brightness_down(sc); 169 break; 170 case SONY_NOTIFY_BRIGHTNESS_DOWN_RELEASED: 171 DPRINTF(("br-down-released\n")); 172 break; 173 case SONY_NOTIFY_BRIGHTNESS_UP_PRESSED: 174 DPRINTF(("br-up-pressed\n")); 175 break; 176 case SONY_NOTIFY_BRIGHTNESS_UP_RELEASED: 177 DPRINTF(("br-up-released\n")); 178 break; 179 case SONY_NOTIFY_DISPLAY_SWITCH_PRESSED: 180 DPRINTF(("display-pressed\n")); 181 break; 182 case SONY_NOTIFY_DISPLAY_SWITCH_RELEASED: 183 DPRINTF(("display-released\n")); 184 break; 185 case SONY_NOTIFY_ZOOM_IN_PRESSED: 186 DPRINTF(("zoom-in-pressed\n")); 187 break; 188 case SONY_NOTIFY_ZOOM_IN_RELEASED: 189 DPRINTF(("zoom-in-released\n")); 190 break; 191 case SONY_NOTIFY_ZOOM_OUT_PRESSED: 192 DPRINTF(("zoom-out-pressed\n")); 193 break; 194 case SONY_NOTIFY_ZOOM_OUT_RELEASED: 195 DPRINTF(("zoom-out-released\n")); 196 break; 197 case SONY_NOTIFY_SUSPEND_PRESSED: 198 DPRINTF(("suspend-pressed\n")); 199 #ifndef SMALL_KERNEL 200 if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) 201 acpi_addtask(sc->sc_acpi, acpi_sleep_task, 202 sc->sc_acpi, ACPI_STATE_S3); 203 #endif 204 break; 205 case SONY_NOTIFY_SUSPEND_RELEASED: 206 DPRINTF(("suspend-released\n")); 207 break; 208 default: 209 printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify); 210 break; 211 } 212 213 return 0; 214 } 215 216 void 217 acpisony_notify_setup(struct acpisony_softc *sc) 218 { 219 struct aml_value arg; 220 221 bzero(&arg, sizeof(arg)); 222 arg.type = AML_OBJTYPE_INTEGER; 223 224 arg.v_integer = 1; 225 aml_evalname(sc->sc_acpi, sc->sc_devnode, "ECON", 1, &arg, NULL); 226 227 /* Enable all events */ 228 arg.v_integer = 0xffff; 229 aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL); 230 231 /* Enable hotkeys */ 232 arg.v_integer = 0x04; 233 aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL); 234 arg.v_integer = 0x02; 235 aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL); 236 arg.v_integer = 0x10; 237 aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL); 238 arg.v_integer = 0x00; 239 aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL); 240 arg.v_integer = 0x02; 241 aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN03", 1, &arg, NULL); 242 arg.v_integer = 0x101; 243 aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL); 244 } 245 246 int 247 acpisony_find_offset(struct acpisony_softc *sc, int key) 248 { 249 struct aml_value arg, res; 250 int val; 251 252 bzero(&arg, sizeof(arg)); 253 arg.type = AML_OBJTYPE_INTEGER; 254 255 for (arg.v_integer = 0x20; arg.v_integer < 0x30; arg.v_integer++) { 256 aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN00", 1, &arg, &res); 257 val = aml_val2int(&res); 258 aml_freevalue(&res); 259 if (val == key) { 260 DPRINTF(("Matched key %X\n", val)); 261 return arg.v_integer - 0x20; 262 } 263 } 264 265 return -1; 266 } 267 268 int 269 acpisony_set_hotkey(struct acpisony_softc *sc, int key, int val) 270 { 271 int off, rc = -1; 272 struct aml_value res, arg; 273 274 bzero(&arg, sizeof(arg)); 275 arg.type = AML_OBJTYPE_INTEGER; 276 277 off = acpisony_find_offset(sc, key); 278 DPRINTF(("off = %X\n", off)); 279 if (off < 0) 280 return rc; 281 282 arg.v_integer = off | val; 283 aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, &res); 284 rc = aml_val2int(&res); 285 aml_freevalue(&res); 286 287 return rc; 288 } 289 290 void 291 acpisony_brightness_down(struct acpisony_softc *sc) 292 { 293 int val; 294 295 val = acpisony_get_brightness(sc); 296 DPRINTF(("current value = %X", val)); 297 if (val > 0) 298 val--; 299 else 300 val = 0; 301 DPRINTF(("next value = %X", val)); 302 acpisony_set_brightness(sc, val); 303 } 304 305 int 306 acpisony_get_brightness(struct acpisony_softc *sc) 307 { 308 struct aml_value res; 309 int val; 310 311 aml_evalname(sc->sc_acpi, sc->sc_devnode, "GBRT", 0, NULL, &res); 312 val = aml_val2int(&res); 313 aml_freevalue(&res); 314 315 return val; 316 } 317 318 void 319 acpisony_set_brightness(struct acpisony_softc *sc, int level) 320 { 321 struct aml_value arg; 322 323 bzero(&arg, sizeof(arg)); 324 arg.type = AML_OBJTYPE_INTEGER; 325 arg.v_integer = level; 326 aml_evalname(sc->sc_acpi, sc->sc_devnode, "SBRT", 1, &arg, NULL); 327 aml_freevalue(&arg); 328 } 329