#include <sys/param.h>
#include <sys/systm.h>
#include <sys/fcntl.h>
#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>
#include <dev/acpi/acpidev.h>
#include <dev/acpi/dsdt.h>
#include <machine/conf.h>
#include <machine/cpufunc.h>
#ifdef HIBERNATE
#include <sys/hibernate.h>
#endif
#include <machine/apmvar.h>
#define APMUNIT(dev) (minor(dev)&0xf0)
#define APMDEV(dev) (minor(dev)&0x0f)
#define APMDEV_NORMAL 0
#define APMDEV_CTL 8
#ifndef SMALL_KERNEL
int
acpiopen(dev_t dev, int flag, int mode, struct proc *p)
{
int error = 0;
struct acpi_softc *sc = acpi_softc;
int s;
if (sc == NULL)
return (ENXIO);
s = splbio();
switch (APMDEV(dev)) {
case APMDEV_CTL:
if (!(flag & FWRITE)) {
error = EINVAL;
break;
}
if (sc->sc_flags & SCFLAG_OWRITE) {
error = EBUSY;
break;
}
sc->sc_flags |= SCFLAG_OWRITE;
break;
case APMDEV_NORMAL:
if (!(flag & FREAD) || (flag & FWRITE)) {
error = EINVAL;
break;
}
sc->sc_flags |= SCFLAG_OREAD;
break;
default:
error = ENXIO;
break;
}
splx(s);
return (error);
}
int
acpiclose(dev_t dev, int flag, int mode, struct proc *p)
{
int error = 0;
struct acpi_softc *sc = acpi_softc;
int s;
if (sc == NULL)
return (ENXIO);
s = splbio();
switch (APMDEV(dev)) {
case APMDEV_CTL:
sc->sc_flags &= ~SCFLAG_OWRITE;
break;
case APMDEV_NORMAL:
sc->sc_flags &= ~SCFLAG_OREAD;
break;
default:
error = ENXIO;
break;
}
splx(s);
return (error);
}
int
acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
int error = 0;
struct acpi_softc *sc = acpi_softc;
struct apm_power_info *pi = (struct apm_power_info *)data;
int s;
if (sc == NULL)
return (ENXIO);
s = splbio();
switch (cmd) {
#ifdef SUSPEND
case APM_IOC_SUSPEND:
case APM_IOC_STANDBY:
if ((flag & FWRITE) == 0) {
error = EBADF;
break;
}
error = request_sleep(SLEEP_SUSPEND);
if (error)
break;
acpi_wakeup(sc);
break;
#ifdef HIBERNATE
case APM_IOC_HIBERNATE:
if ((error = suser(p)) != 0)
break;
if ((flag & FWRITE) == 0) {
error = EBADF;
break;
}
if (get_hibernate_io_function(swdevt[0]) == NULL) {
error = EOPNOTSUPP;
break;
}
error = request_sleep(SLEEP_HIBERNATE);
if (error)
break;
acpi_wakeup(sc);
break;
#endif
#endif
case APM_IOC_GETPOWER:
error = acpi_apminfo(pi);
break;
default:
error = ENOTTY;
}
splx(s);
return (error);
}
void acpi_filtdetach(struct knote *);
int acpi_filtread(struct knote *, long);
const struct filterops acpiread_filtops = {
.f_flags = FILTEROP_ISFD,
.f_attach = NULL,
.f_detach = acpi_filtdetach,
.f_event = acpi_filtread,
};
int
acpikqfilter(dev_t dev, struct knote *kn)
{
struct acpi_softc *sc = acpi_softc;
int s;
if (sc == NULL)
return (ENXIO);
switch (kn->kn_filter) {
case EVFILT_READ:
kn->kn_fop = &acpiread_filtops;
break;
default:
return (EINVAL);
}
kn->kn_hook = sc;
s = splbio();
klist_insert_locked(&sc->sc_note, kn);
splx(s);
return (0);
}
void
acpi_filtdetach(struct knote *kn)
{
struct acpi_softc *sc = kn->kn_hook;
int s;
s = splbio();
klist_remove_locked(&sc->sc_note, kn);
splx(s);
}
int
acpi_filtread(struct knote *kn, long hint)
{
if (hint && !kn->kn_data)
kn->kn_data = hint;
return (1);
}
#ifdef SUSPEND
int
request_sleep(int sleepmode)
{
struct acpi_softc *sc = acpi_softc;
#ifdef HIBERNATE
if (sleepmode == SLEEP_HIBERNATE) {
if (get_hibernate_io_function(swdevt[0]) == NULL)
return EOPNOTSUPP;
}
#endif
acpi_addtask(sc, acpi_sleep_task, sc, sleepmode);
return 0;
}
#endif
#else
int
acpiopen(dev_t dev, int flag, int mode, struct proc *p)
{
return (ENXIO);
}
int
acpiclose(dev_t dev, int flag, int mode, struct proc *p)
{
return (ENXIO);
}
int
acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
return (ENXIO);
}
int
acpikqfilter(dev_t dev, struct knote *kn)
{
return (EOPNOTSUPP);
}
#endif