src/sys/dev/acpi/acpivideo.c

187 lines
4.8 KiB
C

/* $OpenBSD: acpivideo.c,v 1.14 2022/04/06 18:59:27 naddy Exp $ */
/*
* Copyright (c) 2008 Federico G. Schwindt <fgsch@openbsd.org>
* Copyright (c) 2009 Paul Irofti <paul@irofti.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <dev/acpi/acpivar.h>
#include <dev/acpi/acpidev.h>
#include <dev/acpi/amltypes.h>
#include <dev/acpi/dsdt.h>
#ifdef ACPIVIDEO_DEBUG
#define DPRINTF(x) printf x
#else
#define DPRINTF(x)
#endif
/* _DOS Enable/Disable Output Switching */
#define DOS_SWITCH_BY_OSPM 0
#define DOS_SWITCH_BY_BIOS 1
#define DOS_SWITCH_LOCKED 2
#define DOS_SWITCH_BY_OSPM_EXT 3
#define DOS_BRIGHTNESS_BY_OSPM 4
/* Notifications for Displays Devices */
#define NOTIFY_OUTPUT_SWITCHED 0x80
#define NOTIFY_OUTPUT_CHANGED 0x81
#define NOTIFY_OUTPUT_CYCLE_KEY 0x82
#define NOTIFY_OUTPUT_NEXT_KEY 0x83
#define NOTIFY_OUTPUT_PREV_KEY 0x84
int acpivideo_match(struct device *, void *, void *);
void acpivideo_attach(struct device *, struct device *, void *);
int acpivideo_notify(struct aml_node *, int, void *);
void acpivideo_set_policy(struct acpivideo_softc *, int);
int acpi_foundvout(struct aml_node *, void *);
int acpivideo_print(void *, const char *);
int acpivideo_getpcibus(struct acpivideo_softc *, struct aml_node *);
const struct cfattach acpivideo_ca = {
sizeof(struct acpivideo_softc), acpivideo_match, acpivideo_attach
};
struct cfdriver acpivideo_cd = {
NULL, "acpivideo", DV_DULL
};
int
acpivideo_match(struct device *parent, void *match, void *aux)
{
struct acpi_attach_args *aaa = aux;
struct cfdata *cf = match;
if (aaa->aaa_name == NULL || strcmp(aaa->aaa_name,
cf->cf_driver->cd_name) != 0 || aaa->aaa_table != NULL)
return (0);
return (1);
}
void
acpivideo_attach(struct device *parent, struct device *self, void *aux)
{
struct acpivideo_softc *sc = (struct acpivideo_softc *)self;
struct acpi_attach_args *aaa = aux;
sc->sc_acpi = (struct acpi_softc *)parent;
sc->sc_devnode = aaa->aaa_node;
printf(": %s\n", sc->sc_devnode->name);
if (acpivideo_getpcibus(sc, sc->sc_devnode) == -1)
return;
aml_register_notify(sc->sc_devnode, aaa->aaa_dev,
acpivideo_notify, sc, ACPIDEV_NOPOLL);
acpivideo_set_policy(sc,
DOS_SWITCH_BY_OSPM | DOS_BRIGHTNESS_BY_OSPM);
aml_find_node(aaa->aaa_node, "_BCL", acpi_foundvout, sc);
}
int
acpivideo_notify(struct aml_node *node, int notify, void *arg)
{
struct acpivideo_softc *sc = arg;
switch (notify) {
case NOTIFY_OUTPUT_SWITCHED:
case NOTIFY_OUTPUT_CHANGED:
case NOTIFY_OUTPUT_CYCLE_KEY:
case NOTIFY_OUTPUT_NEXT_KEY:
case NOTIFY_OUTPUT_PREV_KEY:
DPRINTF(("%s: event 0x%02x\n", DEVNAME(sc), notify));
break;
default:
printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify);
break;
}
return (0);
}
void
acpivideo_set_policy(struct acpivideo_softc *sc, int policy)
{
struct aml_value args, res;
memset(&args, 0, sizeof(args));
args.v_integer = policy;
args.type = AML_OBJTYPE_INTEGER;
aml_evalname(sc->sc_acpi, sc->sc_devnode, "_DOS", 1, &args, &res);
DPRINTF(("%s: set policy to %lld\n", DEVNAME(sc), aml_val2int(&res)));
aml_freevalue(&res);
}
int
acpi_foundvout(struct aml_node *node, void *arg)
{
struct acpivideo_softc *sc = (struct acpivideo_softc *)arg;
struct device *self = (struct device *)arg;
struct acpi_attach_args aaa;
node = node->parent;
DPRINTF(("Inside acpi_foundvout()\n"));
if (node->parent != sc->sc_devnode)
return (0);
if (aml_searchname(node, "_BCM")) {
memset(&aaa, 0, sizeof(aaa));
aaa.aaa_iot = sc->sc_acpi->sc_iot;
aaa.aaa_memt = sc->sc_acpi->sc_memt;
aaa.aaa_node = node;
aaa.aaa_name = "acpivout";
config_found(self, &aaa, acpivideo_print);
}
return (0);
}
int
acpivideo_print(void *aux, const char *pnp)
{
struct acpi_attach_args *aa = aux;
if (pnp) {
if (aa->aaa_name)
printf("%s at %s", aa->aaa_name, pnp);
else
return (QUIET);
}
return (UNCONF);
}
int
acpivideo_getpcibus(struct acpivideo_softc *sc, struct aml_node *node)
{
/* Check if parent device has PCI mapping */
return (node->parent && node->parent->pci) ?
node->parent->pci->sub : -1;
}