[BACK]Return to acpidock.c CVS log [TXT][DIR] Up to [local] / sys / dev / acpi

File: [local] / sys / dev / acpi / acpidock.c (download)

Revision 1.1, Tue Mar 4 16:14:48 2008 UTC (16 years, 2 months ago) by nbrk
Branch point for: MAIN

Initial revision

/* $OpenBSD: acpidock.c,v 1.25 2007/04/23 19:29:03 mk Exp $ */
/*
 * Copyright (c) 2006,2007 Michael Knudsen <mk@openbsd.org>
 *
 * Permission to use, copy, modify, and 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 <sys/malloc.h>
#include <sys/sensors.h>

#include <machine/bus.h>

#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>
#include <dev/acpi/acpidev.h>
#include <dev/acpi/amltypes.h>
#include <dev/acpi/dsdt.h>

struct aml_nodelist {
	struct aml_node *node;
	TAILQ_ENTRY(aml_nodelist) entries;
};

int	acpidock_match(struct device *, void *, void *);
void	acpidock_attach(struct device *, struct device *, void *);

struct cfattach acpidock_ca = {
	sizeof(struct acpidock_softc), acpidock_match, acpidock_attach
};

struct cfdriver acpidock_cd = {
	NULL, "acpidock", DV_DULL
};


int	acpidock_docklock(struct acpidock_softc *, int);
int	acpidock_dockctl(struct acpidock_softc *, int);
int	acpidock_eject(struct acpidock_softc *, struct aml_node *);
int	acpidock_notify(struct aml_node *, int, void *);
int	acpidock_status(struct acpidock_softc *);

void	acpidock_foundejd(struct aml_node *, void *);

int
acpidock_match(struct device *parent, void *match, void *aux)
{
	struct acpi_attach_args	 *aaa = aux;
	struct cfdata		 *cf = match;

	/* sanity */
	if (aaa->aaa_name == NULL ||
	    strcmp(aaa->aaa_name, cf->cf_driver->cd_name) != 0 ||
	    aaa->aaa_table != NULL)
		return (0);

	return (1);
}

void
acpidock_attach(struct device *parent, struct device *self, void *aux)
{
	struct acpidock_softc	*sc = (struct acpidock_softc *)self;
	struct acpi_attach_args *aa = aux;
	extern struct aml_node	aml_root;

	sc->sc_acpi = (struct acpi_softc *)parent;
	sc->sc_devnode = aa->aaa_node->child;

	printf(": %s", sc->sc_devnode->parent->name);

	acpidock_status(sc);
	if (sc->sc_docked == ACPIDOCK_STATUS_DOCKED) {
		acpidock_docklock(sc, 1);
		acpidock_dockctl(sc, 1);
	} else {
		acpidock_dockctl(sc, 0);
		acpidock_docklock(sc, 0);
	}

	acpidock_status(sc);
	printf(":%s docked (%d)\n",
	    sc->sc_docked == ACPIDOCK_STATUS_DOCKED ? "" : " not",
	    sc->sc_sta);

	strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
	    sizeof(sc->sc_sensdev.xname));
	if (sc->sc_docked)
		strlcpy(sc->sc_sens.desc, "docked",
		    sizeof(sc->sc_sens.desc));
	else
		strlcpy(sc->sc_sens.desc, "not docked",
		    sizeof(sc->sc_sens.desc));

	sc->sc_sens.type = SENSOR_INDICATOR;
	sc->sc_sens.value = sc->sc_docked == ACPIDOCK_STATUS_DOCKED;
	sensor_attach(&sc->sc_sensdev, &sc->sc_sens);
	sensordev_install(&sc->sc_sensdev);

	TAILQ_INIT(&sc->sc_deps_h);
	aml_find_node(aml_root.child, "_EJD", acpidock_foundejd, sc);

	aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev, 
	    acpidock_notify, sc, ACPIDEV_NOPOLL);

}

int
acpidock_status(struct acpidock_softc *sc)
{
	struct aml_value	res;
	int			rv;

	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL,
	    &res) != 0)
		rv = 0;
	else
		rv = 1;
	
	sc->sc_sta = aml_val2int(&res);

	sc->sc_docked = sc->sc_sta & STA_PRESENT;

	aml_freevalue(&res);

	return (rv);
}

int
acpidock_docklock(struct acpidock_softc *sc, int lock)
{
	struct aml_value	cmd;
	struct aml_value	res;
	int rv;

	memset(&cmd, 0, sizeof cmd);
	cmd.v_integer = lock;
	cmd.type = AML_OBJTYPE_INTEGER;
	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_LCK", 1, &cmd,
	    &res) != 0) {
		dnprintf(20, "%s: _LCK %d failed\n", DEVNAME(sc), lock);

		rv = 0;
	} else {
		dnprintf(20, "%s: _LCK %d successful\n", DEVNAME(sc), lock);

		rv = 1;
	}

	aml_freevalue(&res);

	return rv;
}

int
acpidock_dockctl(struct acpidock_softc *sc, int dock)
{
	struct aml_value	cmd;
	struct aml_value	res;
	int rv;

	memset(&cmd, 0, sizeof cmd);
	cmd.v_integer = dock;
	cmd.type = AML_OBJTYPE_INTEGER;
	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_DCK", 1, &cmd,
	    &res) != 0) {
		/* XXX */
		dnprintf(15, "%s: _DCK %d failed\n", DEVNAME(sc), dock);

		rv = 0;
	} else {
		dnprintf(15, "%s: _DCK %d successful\n", DEVNAME(sc), dock);

		rv = 1;
	}

	aml_freevalue(&res);

	return rv;
}

int
acpidock_eject(struct acpidock_softc *sc, struct aml_node *node)
{
	struct aml_value	cmd;
	struct aml_value	res;
	int rv;

	memset(&cmd, 0, sizeof cmd);
	cmd.v_integer = 1;
	cmd.type = AML_OBJTYPE_INTEGER;
	if (aml_evalname(sc->sc_acpi, node, "_EJ0", 1, &cmd,
	    &res) != 0) {
		/* XXX */
		dnprintf(15, "%s: _EJ0 failed\n", DEVNAME(sc));

		rv = 0;
	} else {
		dnprintf(15, "%s: _EJ0 successful\n", DEVNAME(sc));

		rv = 1;
	}

	aml_freevalue(&res);

	return rv;
}

int
acpidock_notify(struct aml_node *node, int notify_type, void *arg)
{
	struct acpidock_softc	*sc = arg;

	dnprintf(5, "%s: acpidock_notify: notify %d\n", DEVNAME(sc),
	    notify_type);

	switch (notify_type) {
	case ACPIDOCK_EVENT_INSERT:
		printf("%s: dock", DEVNAME(sc));
		acpidock_docklock(sc, 1);
		acpidock_dockctl(sc, 1);

		break;
	case ACPIDOCK_EVENT_EJECT: {
		struct aml_nodelist *n;

		TAILQ_FOREACH(n, &sc->sc_deps_h, entries)
			acpidock_eject(sc, n->node);

		acpidock_dockctl(sc, 0);
		acpidock_docklock(sc, 0);

		/* now actually undock */
		acpidock_eject(sc, sc->sc_devnode);

		printf("%s: undock", DEVNAME(sc));
		
		break;
		}
	}

	acpidock_status(sc);
	sc->sc_sens.value = sc->sc_docked == ACPIDOCK_STATUS_DOCKED;
	if (sc->sc_docked)
		strlcpy(sc->sc_sens.desc, "docked",
		    sizeof(sc->sc_sens.desc));
	else
		strlcpy(sc->sc_sens.desc, "not docked",
		    sizeof(sc->sc_sens.desc));

	printf(": status %s\n",
	    sc->sc_docked == ACPIDOCK_STATUS_DOCKED ? "docked" : "undocked");

	return (0);
}

void
acpidock_foundejd(struct aml_node *node, void *arg)
{
	struct acpidock_softc *sc = (struct acpidock_softc *)arg;
	struct aml_value res;

	dnprintf(15, "%s: %s", DEVNAME(sc), node->parent->name);

	if (aml_evalnode(sc->sc_acpi, node, 0, NULL, &res) == -1) {
		printf(": error\n");
	} else {
		struct aml_nodelist *n;

		/* XXX debug */
		dnprintf(10, "%s: %s depends on %s\n", DEVNAME(sc),
		    node->parent->name, res.v_string);

		/* XXX more than one dock? */
		
		n = malloc(sizeof(struct aml_nodelist), M_DEVBUF, M_WAITOK);
		n->node = node->parent;

		TAILQ_INSERT_TAIL(&sc->sc_deps_h, n, entries);
	}

	aml_freevalue(&res);
}