1*cbab9cadSchs /* $NetBSD: pwctl.c,v 1.20 2012/10/27 17:18:17 chs Exp $ */
2c732b455Stakemura
3c732b455Stakemura /*-
426b0905dStakemura * Copyright (c) 1999-2001
526b0905dStakemura * TAKEMURA Shin and PocketBSD Project. All rights reserved.
6c732b455Stakemura * Copyright (c) 2000,2001
7c732b455Stakemura * SATO Kazumi. All rights reserved.
8c732b455Stakemura *
9c732b455Stakemura * Redistribution and use in source and binary forms, with or without
10c732b455Stakemura * modification, are permitted provided that the following conditions
11c732b455Stakemura * are met:
12c732b455Stakemura * 1. Redistributions of source code must retain the above copyright
13c732b455Stakemura * notice, this list of conditions and the following disclaimer.
14c732b455Stakemura * 2. Redistributions in binary form must reproduce the above copyright
15c732b455Stakemura * notice, this list of conditions and the following disclaimer in the
16c732b455Stakemura * documentation and/or other materials provided with the distribution.
17c732b455Stakemura * 3. All advertising materials mentioning features or use of this software
18c732b455Stakemura * must display the following acknowledgement:
19c732b455Stakemura * This product includes software developed by the PocketBSD project
20c732b455Stakemura * and its contributors.
21c732b455Stakemura * 4. Neither the name of the project nor the names of its contributors
22c732b455Stakemura * may be used to endorse or promote products derived from this software
23c732b455Stakemura * without specific prior written permission.
24c732b455Stakemura *
25c732b455Stakemura * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26c732b455Stakemura * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27c732b455Stakemura * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28c732b455Stakemura * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29c732b455Stakemura * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30c732b455Stakemura * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31c732b455Stakemura * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32c732b455Stakemura * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33c732b455Stakemura * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34c732b455Stakemura * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35c732b455Stakemura * SUCH DAMAGE.
36c732b455Stakemura *
37c732b455Stakemura */
38c732b455Stakemura
39b84f53efSlukem #include <sys/cdefs.h>
40*cbab9cadSchs __KERNEL_RCSID(0, "$NetBSD: pwctl.c,v 1.20 2012/10/27 17:18:17 chs Exp $");
419eddf385Speter
429eddf385Speter #ifdef _KERNEL_OPT
439eddf385Speter #include "opt_pwctl.h"
449eddf385Speter #endif
45b84f53efSlukem
46c732b455Stakemura #include <sys/param.h>
47c732b455Stakemura #include <sys/systm.h>
48c732b455Stakemura #include <sys/device.h>
49387ddeb6Ssato #include <sys/reboot.h>
50c732b455Stakemura
51a2a38285Sad #include <sys/bus.h>
52c732b455Stakemura #include <machine/config_hook.h>
53c732b455Stakemura #include <machine/platid.h>
54c732b455Stakemura #include <machine/platid_mask.h>
55c732b455Stakemura
56c732b455Stakemura #include <dev/hpc/hpciovar.h>
57c732b455Stakemura
58c732b455Stakemura #include "locators.h"
59c732b455Stakemura
609eddf385Speter #ifdef PWCTLDEBUG
612746e887Ssato #ifndef PWCTLDEBUG_CONF
622746e887Ssato #define PWCTLDEBUG_CONF 0
632746e887Ssato #endif
642746e887Ssato int pwctl_debug = PWCTLDEBUG_CONF;
6526b0905dStakemura #define DPRINTF(arg) if (pwctl_debug) printf arg;
66387ddeb6Ssato #define VPRINTF(arg) if (bootverbose) printf arg;
67c732b455Stakemura #else
68c732b455Stakemura #define DPRINTF(arg)
69387ddeb6Ssato #define VPRINTF(arg) if (bootverbose) printf arg;
70c732b455Stakemura #endif
71c732b455Stakemura
7226b0905dStakemura struct pwctl_softc {
73c732b455Stakemura hpcio_chip_t sc_hc;
74c732b455Stakemura int sc_port;
75c732b455Stakemura long sc_id;
76c732b455Stakemura int sc_on, sc_off;
77c732b455Stakemura config_hook_tag sc_hook_tag;
78c732b455Stakemura config_hook_tag sc_hook_hardpower;
79c732b455Stakemura config_hook_tag sc_ghook_tag;
80c732b455Stakemura int sc_save;
81c732b455Stakemura int sc_initvalue;
82c732b455Stakemura };
83c732b455Stakemura
84529e91fcScegger static int pwctl_match(device_t, cfdata_t, void *);
85529e91fcScegger static void pwctl_attach(device_t, device_t, void *);
86859a6a49Such static int pwctl_hook(void *, int, long, void *);
87859a6a49Such static int pwctl_ghook(void *, int, long, void *);
88859a6a49Such int pwctl_hardpower(void *, int, long, void *);
89c732b455Stakemura
90*cbab9cadSchs CFATTACH_DECL_NEW(pwctl, sizeof(struct pwctl_softc),
91c9b3657cSthorpej pwctl_match, pwctl_attach, NULL, NULL);
92c732b455Stakemura
93c732b455Stakemura int
pwctl_match(device_t parent,cfdata_t match,void * aux)94529e91fcScegger pwctl_match(device_t parent, cfdata_t match, void *aux)
95c732b455Stakemura {
96a8304325Stakemura struct hpcio_attach_args *haa = aux;
97c732b455Stakemura platid_mask_t mask;
98c732b455Stakemura
99a8304325Stakemura if (strcmp(haa->haa_busname, HPCIO_BUSNAME))
100859a6a49Such return (0);
101c732b455Stakemura if (match->cf_loc[HPCIOIFCF_PLATFORM] == 0)
102859a6a49Such return (0);
103c732b455Stakemura mask = PLATID_DEREF(match->cf_loc[HPCIOIFCF_PLATFORM]);
104c732b455Stakemura if (!platid_match(&platid, &mask))
105859a6a49Such return (0);
106859a6a49Such return (1);
107c732b455Stakemura }
108c732b455Stakemura
109c732b455Stakemura void
pwctl_attach(device_t parent,device_t self,void * aux)110529e91fcScegger pwctl_attach(device_t parent, device_t self, void *aux)
111c732b455Stakemura {
112c732b455Stakemura struct hpcio_attach_args *haa = aux;
113c732b455Stakemura int *loc;
11492c7bba3Sthorpej struct pwctl_softc *sc = device_private(self);
115c732b455Stakemura
116*cbab9cadSchs loc = device_cfdata(self)->cf_loc;
11726b0905dStakemura sc->sc_hc = (*haa->haa_getchip)(haa->haa_sc, loc[HPCIOIFCF_IOCHIP]);
118c732b455Stakemura sc->sc_port = loc[HPCIOIFCF_PORT];
119c732b455Stakemura sc->sc_id = loc[HPCIOIFCF_ID];
120c732b455Stakemura sc->sc_on = loc[HPCIOIFCF_ACTIVE] ? 1 : 0;
121c732b455Stakemura sc->sc_off = loc[HPCIOIFCF_ACTIVE] ? 0 : 1;
122c732b455Stakemura sc->sc_initvalue = loc[HPCIOIFCF_INITVALUE];
123859a6a49Such
124c732b455Stakemura printf(" port=%d id=%ld on=%d%s",
125c732b455Stakemura sc->sc_port, sc->sc_id, sc->sc_on,
126c732b455Stakemura sc->sc_initvalue == -1 ? "" :
127c732b455Stakemura sc->sc_initvalue ? " init=on" : " init=off");
128c732b455Stakemura
129c732b455Stakemura if (sc->sc_port == HPCIOIFCF_PORT_DEFAULT ||
130c732b455Stakemura sc->sc_id == HPCIOIFCF_ID_DEFAULT) {
131c732b455Stakemura printf(" (ignored)");
132c732b455Stakemura } else {
133c732b455Stakemura sc->sc_hook_tag = config_hook(CONFIG_HOOK_POWERCONTROL,
134859a6a49Such sc->sc_id, CONFIG_HOOK_SHARE, pwctl_hook, sc);
135c732b455Stakemura sc->sc_ghook_tag = config_hook(CONFIG_HOOK_GET,
136859a6a49Such sc->sc_id, CONFIG_HOOK_SHARE, pwctl_ghook, sc);
137c732b455Stakemura sc->sc_hook_hardpower = config_hook(CONFIG_HOOK_PMEVENT,
138859a6a49Such CONFIG_HOOK_PMEVENT_HARDPOWER, CONFIG_HOOK_SHARE,
13926b0905dStakemura pwctl_hardpower, sc);
140c732b455Stakemura }
141859a6a49Such
142c732b455Stakemura if (sc->sc_initvalue != -1)
143c732b455Stakemura hpcio_portwrite(sc->sc_hc, sc->sc_port,
144c732b455Stakemura sc->sc_initvalue ? sc->sc_on : sc->sc_off);
145c732b455Stakemura printf("\n");
146c732b455Stakemura }
147c732b455Stakemura
148c732b455Stakemura int
pwctl_hook(void * ctx,int type,long id,void * msg)149859a6a49Such pwctl_hook(void *ctx, int type, long id, void *msg)
150c732b455Stakemura {
15126b0905dStakemura struct pwctl_softc *sc = ctx;
152c732b455Stakemura
153c732b455Stakemura DPRINTF(("pwctl hook: port %d %s(%d)", sc->sc_port,
154c732b455Stakemura msg ? "ON" : "OFF", msg ? sc->sc_on : sc->sc_off));
155c732b455Stakemura hpcio_portwrite(sc->sc_hc, sc->sc_port,
156c732b455Stakemura msg ? sc->sc_on : sc->sc_off);
157859a6a49Such
158c732b455Stakemura return (0);
159c732b455Stakemura }
160c732b455Stakemura
161c732b455Stakemura int
pwctl_ghook(void * ctx,int type,long id,void * msg)162859a6a49Such pwctl_ghook(void *ctx, int type, long id, void *msg)
163c732b455Stakemura {
16426b0905dStakemura struct pwctl_softc *sc = ctx;
165c732b455Stakemura
166c732b455Stakemura if (CONFIG_HOOK_VALUEP(msg))
167859a6a49Such return (1);
168c732b455Stakemura
169c732b455Stakemura *(int*)msg = hpcio_portread(sc->sc_hc, sc->sc_port) == sc->sc_on;
170c732b455Stakemura DPRINTF(("pwctl ghook: port %d %s(%d)", sc->sc_port,
171c732b455Stakemura *(int*)msg? "ON" : "OFF", *(int*)msg ? sc->sc_on : sc->sc_off));
172859a6a49Such
173859a6a49Such return (0);
174c732b455Stakemura }
175c732b455Stakemura
176c732b455Stakemura int
pwctl_hardpower(void * ctx,int type,long id,void * msg)177859a6a49Such pwctl_hardpower(void *ctx, int type, long id, void *msg)
178c732b455Stakemura {
17926b0905dStakemura struct pwctl_softc *sc = ctx;
180c732b455Stakemura int why =(int)msg;
181c732b455Stakemura
182387ddeb6Ssato VPRINTF(("pwctl hardpower: port %d %s: %s(%d)\n", sc->sc_port,
183c732b455Stakemura why == PWR_RESUME? "resume"
184c732b455Stakemura : why == PWR_SUSPEND? "suspend" : "standby",
185c732b455Stakemura sc->sc_save == sc->sc_on ? "on": "off", sc->sc_save));
186387ddeb6Ssato
187c732b455Stakemura switch (why) {
188c732b455Stakemura case PWR_STANDBY:
189c732b455Stakemura break;
190c732b455Stakemura case PWR_SUSPEND:
191c732b455Stakemura sc->sc_save = hpcio_portread(sc->sc_hc, sc->sc_port);
192c732b455Stakemura hpcio_portwrite(sc->sc_hc, sc->sc_port, sc->sc_off);
193c732b455Stakemura break;
194c732b455Stakemura case PWR_RESUME:
195c732b455Stakemura hpcio_portwrite(sc->sc_hc, sc->sc_port, sc->sc_save);
196c732b455Stakemura break;
197c732b455Stakemura }
198859a6a49Such
199c732b455Stakemura return (0);
200c732b455Stakemura }
201