1 /* $OpenBSD: acpivideo.c,v 1.14 2022/04/06 18:59:27 naddy Exp $ */ 2 /* 3 * Copyright (c) 2008 Federico G. Schwindt <fgsch@openbsd.org> 4 * Copyright (c) 2009 Paul Irofti <paul@irofti.net> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 23 #include <machine/bus.h> 24 25 #include <dev/acpi/acpivar.h> 26 #include <dev/acpi/acpidev.h> 27 #include <dev/acpi/amltypes.h> 28 #include <dev/acpi/dsdt.h> 29 30 #ifdef ACPIVIDEO_DEBUG 31 #define DPRINTF(x) printf x 32 #else 33 #define DPRINTF(x) 34 #endif 35 36 /* _DOS Enable/Disable Output Switching */ 37 #define DOS_SWITCH_BY_OSPM 0 38 #define DOS_SWITCH_BY_BIOS 1 39 #define DOS_SWITCH_LOCKED 2 40 #define DOS_SWITCH_BY_OSPM_EXT 3 41 #define DOS_BRIGHTNESS_BY_OSPM 4 42 43 /* Notifications for Displays Devices */ 44 #define NOTIFY_OUTPUT_SWITCHED 0x80 45 #define NOTIFY_OUTPUT_CHANGED 0x81 46 #define NOTIFY_OUTPUT_CYCLE_KEY 0x82 47 #define NOTIFY_OUTPUT_NEXT_KEY 0x83 48 #define NOTIFY_OUTPUT_PREV_KEY 0x84 49 50 int acpivideo_match(struct device *, void *, void *); 51 void acpivideo_attach(struct device *, struct device *, void *); 52 int acpivideo_notify(struct aml_node *, int, void *); 53 54 void acpivideo_set_policy(struct acpivideo_softc *, int); 55 int acpi_foundvout(struct aml_node *, void *); 56 int acpivideo_print(void *, const char *); 57 58 int acpivideo_getpcibus(struct acpivideo_softc *, struct aml_node *); 59 60 const struct cfattach acpivideo_ca = { 61 sizeof(struct acpivideo_softc), acpivideo_match, acpivideo_attach 62 }; 63 64 struct cfdriver acpivideo_cd = { 65 NULL, "acpivideo", DV_DULL 66 }; 67 68 int 69 acpivideo_match(struct device *parent, void *match, void *aux) 70 { 71 struct acpi_attach_args *aaa = aux; 72 struct cfdata *cf = match; 73 74 if (aaa->aaa_name == NULL || strcmp(aaa->aaa_name, 75 cf->cf_driver->cd_name) != 0 || aaa->aaa_table != NULL) 76 return (0); 77 78 return (1); 79 } 80 81 void 82 acpivideo_attach(struct device *parent, struct device *self, void *aux) 83 { 84 struct acpivideo_softc *sc = (struct acpivideo_softc *)self; 85 struct acpi_attach_args *aaa = aux; 86 87 sc->sc_acpi = (struct acpi_softc *)parent; 88 sc->sc_devnode = aaa->aaa_node; 89 90 printf(": %s\n", sc->sc_devnode->name); 91 92 if (acpivideo_getpcibus(sc, sc->sc_devnode) == -1) 93 return; 94 95 aml_register_notify(sc->sc_devnode, aaa->aaa_dev, 96 acpivideo_notify, sc, ACPIDEV_NOPOLL); 97 98 acpivideo_set_policy(sc, 99 DOS_SWITCH_BY_OSPM | DOS_BRIGHTNESS_BY_OSPM); 100 101 aml_find_node(aaa->aaa_node, "_BCL", acpi_foundvout, sc); 102 } 103 104 int 105 acpivideo_notify(struct aml_node *node, int notify, void *arg) 106 { 107 struct acpivideo_softc *sc = arg; 108 109 switch (notify) { 110 case NOTIFY_OUTPUT_SWITCHED: 111 case NOTIFY_OUTPUT_CHANGED: 112 case NOTIFY_OUTPUT_CYCLE_KEY: 113 case NOTIFY_OUTPUT_NEXT_KEY: 114 case NOTIFY_OUTPUT_PREV_KEY: 115 DPRINTF(("%s: event 0x%02x\n", DEVNAME(sc), notify)); 116 break; 117 default: 118 printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify); 119 break; 120 } 121 122 return (0); 123 } 124 125 void 126 acpivideo_set_policy(struct acpivideo_softc *sc, int policy) 127 { 128 struct aml_value args, res; 129 130 memset(&args, 0, sizeof(args)); 131 args.v_integer = policy; 132 args.type = AML_OBJTYPE_INTEGER; 133 134 aml_evalname(sc->sc_acpi, sc->sc_devnode, "_DOS", 1, &args, &res); 135 DPRINTF(("%s: set policy to %lld\n", DEVNAME(sc), aml_val2int(&res))); 136 137 aml_freevalue(&res); 138 } 139 140 int 141 acpi_foundvout(struct aml_node *node, void *arg) 142 { 143 struct acpivideo_softc *sc = (struct acpivideo_softc *)arg; 144 struct device *self = (struct device *)arg; 145 struct acpi_attach_args aaa; 146 node = node->parent; 147 148 DPRINTF(("Inside acpi_foundvout()\n")); 149 if (node->parent != sc->sc_devnode) 150 return (0); 151 152 if (aml_searchname(node, "_BCM")) { 153 memset(&aaa, 0, sizeof(aaa)); 154 aaa.aaa_iot = sc->sc_acpi->sc_iot; 155 aaa.aaa_memt = sc->sc_acpi->sc_memt; 156 aaa.aaa_node = node; 157 aaa.aaa_name = "acpivout"; 158 159 config_found(self, &aaa, acpivideo_print); 160 } 161 162 return (0); 163 } 164 165 int 166 acpivideo_print(void *aux, const char *pnp) 167 { 168 struct acpi_attach_args *aa = aux; 169 170 if (pnp) { 171 if (aa->aaa_name) 172 printf("%s at %s", aa->aaa_name, pnp); 173 else 174 return (QUIET); 175 } 176 177 return (UNCONF); 178 } 179 180 int 181 acpivideo_getpcibus(struct acpivideo_softc *sc, struct aml_node *node) 182 { 183 /* Check if parent device has PCI mapping */ 184 return (node->parent && node->parent->pci) ? 185 node->parent->pci->sub : -1; 186 } 187