1c8fe38aeSMatthew Dillon /*-
2c8fe38aeSMatthew Dillon * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
3c8fe38aeSMatthew Dillon * Copyright (c) 2008 The DragonFly Project.
4c8fe38aeSMatthew Dillon * All rights reserved.
5c8fe38aeSMatthew Dillon *
6c8fe38aeSMatthew Dillon * Redistribution and use in source and binary forms, with or without
7c8fe38aeSMatthew Dillon * modification, are permitted provided that the following conditions
8c8fe38aeSMatthew Dillon * are met:
9c8fe38aeSMatthew Dillon * 1. Redistributions of source code must retain the above copyright
10c8fe38aeSMatthew Dillon * notice, this list of conditions and the following disclaimer.
11c8fe38aeSMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
12c8fe38aeSMatthew Dillon * notice, this list of conditions and the following disclaimer in the
13c8fe38aeSMatthew Dillon * documentation and/or other materials provided with the distribution.
14c8fe38aeSMatthew Dillon *
15c8fe38aeSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16c8fe38aeSMatthew Dillon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17c8fe38aeSMatthew Dillon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18c8fe38aeSMatthew Dillon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c8fe38aeSMatthew Dillon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c8fe38aeSMatthew Dillon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21c8fe38aeSMatthew Dillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c8fe38aeSMatthew Dillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c8fe38aeSMatthew Dillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c8fe38aeSMatthew Dillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c8fe38aeSMatthew Dillon * SUCH DAMAGE.
26c8fe38aeSMatthew Dillon */
27c8fe38aeSMatthew Dillon
28c8fe38aeSMatthew Dillon /*
29c8fe38aeSMatthew Dillon * Timer device driver for power management events.
30c8fe38aeSMatthew Dillon * The code for suspend/resume is derived from APM device driver.
31c8fe38aeSMatthew Dillon */
32c8fe38aeSMatthew Dillon
33c8fe38aeSMatthew Dillon #include <sys/param.h>
34c8fe38aeSMatthew Dillon #include <sys/systm.h>
35c8fe38aeSMatthew Dillon #include <sys/bus.h>
36c8fe38aeSMatthew Dillon #include <sys/kernel.h>
37c8fe38aeSMatthew Dillon #include <sys/syslog.h>
38c8fe38aeSMatthew Dillon #include <sys/thread2.h>
39c8fe38aeSMatthew Dillon #include <machine/clock.h>
40c8fe38aeSMatthew Dillon
41c8fe38aeSMatthew Dillon #include <bus/isa/isavar.h>
42c8fe38aeSMatthew Dillon
43c8fe38aeSMatthew Dillon static devclass_t pmtimer_devclass;
44c8fe38aeSMatthew Dillon
45c8fe38aeSMatthew Dillon /* reject any PnP devices for now */
46c8fe38aeSMatthew Dillon static struct isa_pnp_id pmtimer_ids[] = {
47c8fe38aeSMatthew Dillon {0}
48c8fe38aeSMatthew Dillon };
49c8fe38aeSMatthew Dillon
50c8fe38aeSMatthew Dillon static int
pmtimer_probe(device_t dev)51c8fe38aeSMatthew Dillon pmtimer_probe(device_t dev)
52c8fe38aeSMatthew Dillon {
53c8fe38aeSMatthew Dillon
54c8fe38aeSMatthew Dillon if (ISA_PNP_PROBE(device_get_parent(dev), dev, pmtimer_ids) == ENXIO) {
55c8fe38aeSMatthew Dillon return (ENXIO);
56c8fe38aeSMatthew Dillon }
57c8fe38aeSMatthew Dillon
58c8fe38aeSMatthew Dillon /* only one instance always */
59c8fe38aeSMatthew Dillon return (device_get_unit(dev));
60c8fe38aeSMatthew Dillon }
61c8fe38aeSMatthew Dillon
62c8fe38aeSMatthew Dillon static struct timeval suspend_time;
63c8fe38aeSMatthew Dillon static struct timeval diff_time;
64c8fe38aeSMatthew Dillon
65c8fe38aeSMatthew Dillon static int
pmtimer_suspend(device_t dev)66c8fe38aeSMatthew Dillon pmtimer_suspend(device_t dev)
67c8fe38aeSMatthew Dillon {
68c8fe38aeSMatthew Dillon crit_enter();
69c8fe38aeSMatthew Dillon microtime(&diff_time);
70c8fe38aeSMatthew Dillon inittodr(0);
71c8fe38aeSMatthew Dillon microtime(&suspend_time);
72c8fe38aeSMatthew Dillon timevalsub(&diff_time, &suspend_time);
73c8fe38aeSMatthew Dillon crit_exit();
74c8fe38aeSMatthew Dillon return (0);
75c8fe38aeSMatthew Dillon }
76c8fe38aeSMatthew Dillon
77c8fe38aeSMatthew Dillon static int
pmtimer_resume(device_t dev)78c8fe38aeSMatthew Dillon pmtimer_resume(device_t dev)
79c8fe38aeSMatthew Dillon {
80c8fe38aeSMatthew Dillon u_int second, minute, hour;
81c8fe38aeSMatthew Dillon struct timeval resume_time;
82c8fe38aeSMatthew Dillon
83c8fe38aeSMatthew Dillon /* modified for adjkerntz */
84c8fe38aeSMatthew Dillon crit_enter();
85c8fe38aeSMatthew Dillon timer_restore(); /* restore the all timers */
86c8fe38aeSMatthew Dillon inittodr(0); /* adjust time to RTC */
87c8fe38aeSMatthew Dillon microtime(&resume_time);
88c8fe38aeSMatthew Dillon
89c8fe38aeSMatthew Dillon crit_exit();
90c8fe38aeSMatthew Dillon second = resume_time.tv_sec - suspend_time.tv_sec;
91c8fe38aeSMatthew Dillon hour = second / 3600;
92c8fe38aeSMatthew Dillon second %= 3600;
93c8fe38aeSMatthew Dillon minute = second / 60;
94c8fe38aeSMatthew Dillon second %= 60;
95c8fe38aeSMatthew Dillon log(LOG_NOTICE, "wakeup from sleeping state (slept %02d:%02d:%02d)\n",
96c8fe38aeSMatthew Dillon hour, minute, second);
97c8fe38aeSMatthew Dillon return (0);
98c8fe38aeSMatthew Dillon }
99c8fe38aeSMatthew Dillon
100c8fe38aeSMatthew Dillon /*
101c8fe38aeSMatthew Dillon * Because pmtimer is a static device that always exists under any attached
102c8fe38aeSMatthew Dillon * isa device, and not scanned by the isa device, we need an identify
103c8fe38aeSMatthew Dillon * function to install the device.
104c8fe38aeSMatthew Dillon */
105c8fe38aeSMatthew Dillon static device_method_t pmtimer_methods[] = {
106c8fe38aeSMatthew Dillon /* Device interface */
107c8fe38aeSMatthew Dillon DEVMETHOD(device_identify, bus_generic_identify),
108c8fe38aeSMatthew Dillon DEVMETHOD(device_probe, pmtimer_probe),
109c8fe38aeSMatthew Dillon DEVMETHOD(device_attach, bus_generic_attach),
110c8fe38aeSMatthew Dillon DEVMETHOD(device_suspend, pmtimer_suspend),
111c8fe38aeSMatthew Dillon DEVMETHOD(device_resume, pmtimer_resume),
112*d3c9c58eSSascha Wildner DEVMETHOD_END
113c8fe38aeSMatthew Dillon };
114c8fe38aeSMatthew Dillon
115c8fe38aeSMatthew Dillon static driver_t pmtimer_driver = {
116c8fe38aeSMatthew Dillon "pmtimer",
117c8fe38aeSMatthew Dillon pmtimer_methods,
118c8fe38aeSMatthew Dillon 1, /* no softc */
119c8fe38aeSMatthew Dillon };
120c8fe38aeSMatthew Dillon
121aa2b9d05SSascha Wildner DRIVER_MODULE(pmtimer, isa, pmtimer_driver, pmtimer_devclass, NULL, NULL);
122