jcs's openbsd hax
openbsd
at jcs 230 lines 5.6 kB view raw
1/* $OpenBSD: abl.c,v 1.6 2025/01/23 11:24:34 kettenis Exp $ */ 2 3/* 4 * Copyright (c) 2020 Marcus Glocker <mglocker@openbsd.org> 5 * 6 * Permission to use, copy, modify, and 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/* 20 * Driver for controlling the screen backlight brightness on Apple machines. 21 */ 22#include <sys/param.h> 23#include <sys/systm.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#include <dev/pci/pcidevs.h> 31 32#include <dev/wscons/wsconsio.h> 33#include <dev/wscons/wsdisplayvar.h> 34 35#ifdef ABL_DEBUG 36#define DPRINTF(x) printf x 37#else 38#define DPRINTF(x) 39#endif 40 41#define ABL_IO_BASE_INTEL 0xb2 42#define ABL_IO_BASE_NVIDIA 0x52e 43#define ABL_IO_SIZE 2 44#define ABL_IO_LO 0x00 45#define ABL_IO_HI 0x01 46#define ABL_BRIGHTNESS_MIN 0 47#define ABL_BRIGHTNESS_MAX 15 48 49struct abl_softc { 50 struct device sc_dev; 51 52 struct acpi_softc *sc_acpi; 53 struct aml_node *sc_devnode; 54 55 bus_space_tag_t sc_bt; 56 bus_space_handle_t sc_bh; 57 58 bus_addr_t sc_io_base; 59 uint8_t sc_brightness; 60}; 61 62int abl_match(struct device *, void *, void *); 63void abl_attach(struct device *, struct device *, void *); 64 65int abl_get_brightness(struct abl_softc *); 66int abl_set_brightness(struct abl_softc *, uint8_t); 67 68/* Hooks for wsconsole brightness control. */ 69int abl_get_param(struct wsdisplay_param *); 70int abl_set_param(struct wsdisplay_param *); 71 72const struct cfattach abl_ca = { 73 sizeof(struct abl_softc), abl_match, abl_attach, NULL, NULL 74}; 75 76struct cfdriver abl_cd = { 77 NULL, "abl", DV_DULL 78}; 79 80const char *abl_hids[] = { 81 "APP0002", NULL 82}; 83 84int 85abl_match(struct device *parent, void *match, void *aux) 86{ 87 struct acpi_attach_args *aa = aux; 88 struct cfdata *cf = match; 89 90 return acpi_matchhids(aa, abl_hids, cf->cf_driver->cd_name); 91} 92 93void 94abl_attach(struct device *parent, struct device *self, void *aux) 95{ 96 struct abl_softc *sc = (struct abl_softc *)self; 97 struct acpi_attach_args *aaa = aux; 98 struct aml_value res; 99 int64_t sta; 100 int reg; 101 pci_chipset_tag_t pc; 102 pcitag_t tag; 103 104 sc->sc_acpi = (struct acpi_softc *)parent; 105 sc->sc_devnode = aaa->aaa_node; 106 107 printf(": %s", sc->sc_devnode->name); 108 109 sta = acpi_getsta(sc->sc_acpi, sc->sc_devnode); 110 if ((sta & (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) != 111 (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) { 112 printf(": not enabled\n"); 113 return; 114 } 115 116 if (!(aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CID", 0, NULL, &res))) 117 printf(" (%s)", res.v_string); 118 119 /* Backlight on non-iMacs is already handled differently. */ 120 if (strncmp(hw_prod, "iMac", 4)) { 121 printf("\n"); 122 return; 123 } 124 125 /* 126 * We need to check on what type of PCI controller we're running on to 127 * access the right I/O space. 128 */ 129 pc = pci_lookup_segment(0, 0); 130 tag = pci_make_tag(pc, 0, 0, 0); 131 reg = pci_conf_read(pc, tag, PCI_ID_REG); 132 133 switch (PCI_VENDOR(reg)) { 134 case PCI_VENDOR_INTEL: 135 sc->sc_io_base = ABL_IO_BASE_INTEL; 136 break; 137 case PCI_VENDOR_NVIDIA: 138 sc->sc_io_base = ABL_IO_BASE_NVIDIA; 139 break; 140 default: 141 printf(": pci controller not supported\n"); 142 return; 143 } 144 145 /* 146 * Map I/O space. This driver uses the ACPI SMI command port. 147 * This port has already been claimed by the generic ACPI code 148 * so we need to work around that here by calling _bus_space_map(). 149 */ 150 sc->sc_bt = aaa->aaa_iot; 151 if (_bus_space_map(sc->sc_bt, sc->sc_io_base, ABL_IO_SIZE, 0, 152 &sc->sc_bh)) { 153 printf(": can't map register\n"); 154 return; 155 } 156 157 /* Read the current brightness value initially. */ 158 sc->sc_brightness = abl_get_brightness(sc); 159 160 /* Map wsconsole hook functions. */ 161 ws_get_param = abl_get_param; 162 ws_set_param = abl_set_param; 163 164 printf("\n"); 165} 166 167int 168abl_get_brightness(struct abl_softc *sc) 169{ 170 uint8_t val; 171 172 bus_space_write_1(sc->sc_bt, sc->sc_bh, ABL_IO_HI, 0x03); 173 bus_space_write_1(sc->sc_bt, sc->sc_bh, ABL_IO_LO, 0xbf); 174 val = bus_space_read_1(sc->sc_bt, sc->sc_bh, ABL_IO_HI); 175 176 return (val >> 4); 177} 178 179int 180abl_set_brightness(struct abl_softc *sc, uint8_t val) 181{ 182 bus_space_write_1(sc->sc_bt, sc->sc_bh, ABL_IO_HI, 0x04 | (val << 4)); 183 bus_space_write_1(sc->sc_bt, sc->sc_bh, ABL_IO_LO, 0xbf); 184 185 return 0; 186} 187 188int 189abl_get_param(struct wsdisplay_param *dp) 190{ 191 struct abl_softc *sc = abl_cd.cd_devs[0]; 192 193 if (sc == NULL) 194 return -1; 195 196 switch (dp->param) { 197 case WSDISPLAYIO_PARAM_BRIGHTNESS: 198 DPRINTF(("abl_get_param: sc->sc_brightness = %d\n", 199 sc->sc_brightness)); 200 dp->min = ABL_BRIGHTNESS_MIN; 201 dp->max = ABL_BRIGHTNESS_MAX; 202 dp->curval = sc->sc_brightness; 203 return 0; 204 default: 205 return -1; 206 } 207} 208 209int 210abl_set_param(struct wsdisplay_param *dp) 211{ 212 struct abl_softc *sc = abl_cd.cd_devs[0]; 213 214 if (sc == NULL) 215 return -1; 216 217 switch (dp->param) { 218 case WSDISPLAYIO_PARAM_BRIGHTNESS: 219 DPRINTF(("abl_set_param: curval = %d\n", dp->curval)); 220 if (dp->curval < ABL_BRIGHTNESS_MIN) 221 dp->curval = 0; 222 if (dp->curval > ABL_BRIGHTNESS_MAX) 223 dp->curval = ABL_BRIGHTNESS_MAX; 224 abl_set_brightness(sc, dp->curval); 225 sc->sc_brightness = dp->curval; 226 return 0; 227 default: 228 return -1; 229 } 230}