1 /* $OpenBSD: acpiasus.c,v 1.12 2011/06/06 06:13:46 deraadt Exp $ */ 2 /* $NetBSD: asus_acpi.c,v 1.2.2.2 2008/04/03 12:42:37 mjf Exp $ */ 3 /* 4 * Copyright (c) 2007, 2008 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Jared D. McNeill. 18 * 4. Neither the name of The NetBSD Foundation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * ASUS ACPI hotkeys driver. 37 */ 38 39 #include <sys/param.h> 40 #include <sys/device.h> 41 #include <sys/systm.h> 42 #include <sys/workq.h> 43 44 #include <dev/acpi/acpireg.h> 45 #include <dev/acpi/acpivar.h> 46 #include <dev/acpi/acpidev.h> 47 #include <dev/acpi/amltypes.h> 48 #include <dev/acpi/dsdt.h> 49 50 #include "audio.h" 51 #include "wskbd.h" 52 53 struct acpiasus_softc { 54 struct device sc_dev; 55 56 struct acpi_softc *sc_acpi; 57 struct aml_node *sc_devnode; 58 }; 59 60 #define ASUS_NOTIFY_WIRELESSON 0x10 61 #define ASUS_NOTIFY_WIRELESSOFF 0x11 62 #define ASUS_NOTIFY_TASKSWITCH 0x12 63 #define ASUS_NOTIFY_VOLUMEMUTE 0x13 64 #define ASUS_NOTIFY_VOLUMEDOWN 0x14 65 #define ASUS_NOTIFY_VOLUMEUP 0x15 66 #define ASUS_NOTIFY_LCDSWITCHOFF0 0x16 67 #define ASUS_NOTIFY_LCDSWITCHOFF1 0x1a 68 #define ASUS_NOTIFY_LCDCHANGERES 0x1b 69 #define ASUS_NOTIFY_USERDEF0 0x1c 70 #define ASUS_NOTIFY_USERDEF1 0x1d 71 #define ASUS_NOTIFY_BRIGHTNESSLOW 0x20 72 #define ASUS_NOTIFY_BRIGHTNESSHIGH 0x2f 73 #define ASUS_NOTIFY_DISPLAYCYCLEDOWN 0x30 74 #define ASUS_NOTIFY_DISPLAYCYCLEUP 0x32 75 76 #define ASUS_NOTIFY_POWERCONNECT 0x50 77 #define ASUS_NOTIFY_POWERDISCONNECT 0x51 78 79 #define ASUS_SDSP_LCD 0x01 80 #define ASUS_SDSP_CRT 0x02 81 #define ASUS_SDSP_TV 0x04 82 #define ASUS_SDSP_DVI 0x08 83 #define ASUS_SDSP_ALL \ 84 (ASUS_SDSP_LCD | ASUS_SDSP_CRT | ASUS_SDSP_TV | ASUS_SDSP_DVI) 85 86 int acpiasus_match(struct device *, void *, void *); 87 void acpiasus_attach(struct device *, struct device *, void *); 88 void acpiasus_init(struct device *); 89 int acpiasus_notify(struct aml_node *, int, void *); 90 int acpiasus_activate(struct device *, int); 91 92 #if NAUDIO > 0 && NWSKBD > 0 93 extern int wskbd_set_mixervolume(long dir, int out); 94 #endif 95 96 struct cfattach acpiasus_ca = { 97 sizeof(struct acpiasus_softc), acpiasus_match, acpiasus_attach, 98 acpiasus_activate 99 }; 100 101 struct cfdriver acpiasus_cd = { 102 NULL, "acpiasus", DV_DULL 103 }; 104 105 const char *acpiasus_hids[] = { ACPI_DEV_ASUS, 0 }; 106 107 int 108 acpiasus_match(struct device *parent, void *match, void *aux) 109 { 110 struct acpi_attach_args *aa = aux; 111 struct cfdata *cf = match; 112 113 return (acpi_matchhids(aa, acpiasus_hids, cf->cf_driver->cd_name)); 114 } 115 116 void 117 acpiasus_attach(struct device *parent, struct device *self, void *aux) 118 { 119 struct acpiasus_softc *sc = (struct acpiasus_softc *)self; 120 struct acpi_attach_args *aa = aux; 121 122 sc->sc_acpi = (struct acpi_softc *)parent; 123 sc->sc_devnode = aa->aaa_node; 124 125 printf("\n"); 126 127 acpiasus_init(self); 128 129 aml_register_notify(sc->sc_devnode, aa->aaa_dev, 130 acpiasus_notify, sc, ACPIDEV_NOPOLL); 131 } 132 133 void 134 acpiasus_init(struct device *self) 135 { 136 struct acpiasus_softc *sc = (struct acpiasus_softc *)self; 137 struct aml_value cmd; 138 struct aml_value ret; 139 140 bzero(&cmd, sizeof(cmd)); 141 cmd.type = AML_OBJTYPE_INTEGER; 142 cmd.v_integer = 0x40; /* Disable ASL display switching. */ 143 144 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "INIT", 1, &cmd, &ret)) 145 printf("%s: no INIT\n", DEVNAME(sc)); 146 else 147 aml_freevalue(&ret); 148 } 149 150 int 151 acpiasus_notify(struct aml_node *node, int notify, void *arg) 152 { 153 struct acpiasus_softc *sc = arg; 154 155 if (notify >= ASUS_NOTIFY_BRIGHTNESSLOW && 156 notify <= ASUS_NOTIFY_BRIGHTNESSHIGH) { 157 #ifdef ACPIASUS_DEBUG 158 printf("%s: brightness %d percent\n", DEVNAME(sc), 159 (notify & 0xf) * 100 / 0xf); 160 #endif 161 return 0; 162 } 163 164 switch (notify) { 165 case ASUS_NOTIFY_WIRELESSON: /* Handled by AML. */ 166 case ASUS_NOTIFY_WIRELESSOFF: /* Handled by AML. */ 167 break; 168 case ASUS_NOTIFY_TASKSWITCH: 169 break; 170 case ASUS_NOTIFY_DISPLAYCYCLEDOWN: 171 case ASUS_NOTIFY_DISPLAYCYCLEUP: 172 break; 173 #if NAUDIO > 0 && NWSKBD > 0 174 case ASUS_NOTIFY_VOLUMEMUTE: 175 workq_add_task(NULL, 0, (workq_fn)wskbd_set_mixervolume, 176 (void *)(long)0, (void *)(int)1); 177 break; 178 case ASUS_NOTIFY_VOLUMEDOWN: 179 workq_add_task(NULL, 0, (workq_fn)wskbd_set_mixervolume, 180 (void *)(long)-1, (void *)(int)1); 181 break; 182 case ASUS_NOTIFY_VOLUMEUP: 183 workq_add_task(NULL, 0, (workq_fn)wskbd_set_mixervolume, 184 (void *)(long)1, (void *)(int)1); 185 break; 186 #else 187 case ASUS_NOTIFY_VOLUMEMUTE: 188 case ASUS_NOTIFY_VOLUMEDOWN: 189 case ASUS_NOTIFY_VOLUMEUP: 190 break; 191 #endif 192 case ASUS_NOTIFY_POWERCONNECT: 193 case ASUS_NOTIFY_POWERDISCONNECT: 194 break; 195 196 case ASUS_NOTIFY_LCDSWITCHOFF0: 197 case ASUS_NOTIFY_LCDSWITCHOFF1: 198 break; 199 200 case ASUS_NOTIFY_LCDCHANGERES: 201 break; 202 203 case ASUS_NOTIFY_USERDEF0: 204 case ASUS_NOTIFY_USERDEF1: 205 break; 206 207 default: 208 printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify); 209 break; 210 } 211 212 return 0; 213 } 214 215 int 216 acpiasus_activate(struct device *self, int act) 217 { 218 struct acpiasus_softc *sc = (struct acpiasus_softc *)self; 219 struct aml_value cmd; 220 struct aml_value ret; 221 222 switch (act) { 223 case DVACT_SUSPEND: 224 break; 225 case DVACT_RESUME: 226 acpiasus_init(self); 227 228 bzero(&cmd, sizeof(cmd)); 229 cmd.type = AML_OBJTYPE_INTEGER; 230 cmd.v_integer = ASUS_SDSP_LCD; 231 232 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SDSP", 1, 233 &cmd, &ret)) 234 printf("%s: no SDSP\n", DEVNAME(sc)); 235 else 236 aml_freevalue(&ret); 237 break; 238 } 239 return (0); 240 } 241