xref: /netbsd/sys/arch/hppa/dev/power.c (revision e067edd4)
1*e067edd4Sskrll /*	$NetBSD: power.c,v 1.3 2019/04/15 20:40:37 skrll Exp $	*/
2fdfdea60Sskrll 
3fdfdea60Sskrll /*
4fdfdea60Sskrll  * Copyright (c) 2004 Jochen Kunz.
5fdfdea60Sskrll  * All rights reserved.
6fdfdea60Sskrll  *
7fdfdea60Sskrll  * Redistribution and use in source and binary forms, with or without
8fdfdea60Sskrll  * modification, are permitted provided that the following conditions
9fdfdea60Sskrll  * are met:
10fdfdea60Sskrll  * 1. Redistributions of source code must retain the above copyright
11fdfdea60Sskrll  *    notice, this list of conditions and the following disclaimer.
12fdfdea60Sskrll  * 2. Redistributions in binary form must reproduce the above copyright
13fdfdea60Sskrll  *    notice, this list of conditions and the following disclaimer in the
14fdfdea60Sskrll  *    documentation and/or other materials provided with the distribution.
15fdfdea60Sskrll  * 3. The name of Jochen Kunz may not be used to endorse or promote
16fdfdea60Sskrll  *    products derived from this software without specific prior
17fdfdea60Sskrll  *    written permission.
18fdfdea60Sskrll  *
19fdfdea60Sskrll  * THIS SOFTWARE IS PROVIDED BY JOCHEN KUNZ
20fdfdea60Sskrll  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21fdfdea60Sskrll  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22fdfdea60Sskrll  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL JOCHEN KUNZ
23fdfdea60Sskrll  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24fdfdea60Sskrll  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25fdfdea60Sskrll  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26fdfdea60Sskrll  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27fdfdea60Sskrll  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28fdfdea60Sskrll  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29fdfdea60Sskrll  * POSSIBILITY OF SUCH DAMAGE.
30fdfdea60Sskrll  */
31fdfdea60Sskrll 
32fdfdea60Sskrll /*	$OpenBSD: power.c,v 1.5 2004/06/11 12:53:09 mickey Exp $	*/
33fdfdea60Sskrll 
34fdfdea60Sskrll /*
35fdfdea60Sskrll  * Copyright (c) 2003 Michael Shalayeff
36fdfdea60Sskrll  * All rights reserved.
37fdfdea60Sskrll  *
38fdfdea60Sskrll  * Redistribution and use in source and binary forms, with or without
39fdfdea60Sskrll  * modification, are permitted provided that the following conditions
40fdfdea60Sskrll  * are met:
41fdfdea60Sskrll  * 1. Redistributions of source code must retain the above copyright
42fdfdea60Sskrll  *    notice, this list of conditions and the following disclaimer.
43fdfdea60Sskrll  * 2. Redistributions in binary form must reproduce the above copyright
44fdfdea60Sskrll  *    notice, this list of conditions and the following disclaimer in the
45fdfdea60Sskrll  *    documentation and/or other materials provided with the distribution.
46fdfdea60Sskrll  *
47fdfdea60Sskrll  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48fdfdea60Sskrll  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49fdfdea60Sskrll  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50fdfdea60Sskrll  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
51fdfdea60Sskrll  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
52fdfdea60Sskrll  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
53fdfdea60Sskrll  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54fdfdea60Sskrll  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
55fdfdea60Sskrll  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
56fdfdea60Sskrll  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
57fdfdea60Sskrll  * THE POSSIBILITY OF SUCH DAMAGE.
58fdfdea60Sskrll  */
59fdfdea60Sskrll 
60fdfdea60Sskrll #include <sys/param.h>
61fdfdea60Sskrll #include <sys/kernel.h>
62fdfdea60Sskrll #include <sys/systm.h>
63fdfdea60Sskrll #include <sys/reboot.h>
64fdfdea60Sskrll #include <sys/device.h>
65fdfdea60Sskrll #include <sys/sysctl.h>
66fdfdea60Sskrll #include <sys/kmem.h>
67fdfdea60Sskrll 
68fdfdea60Sskrll #include <machine/reg.h>
69fdfdea60Sskrll #include <machine/pdc.h>
70fdfdea60Sskrll #include <machine/autoconf.h>
71fdfdea60Sskrll 
72fdfdea60Sskrll #include <hppa/dev/cpudevs.h>
73fdfdea60Sskrll 
74fdfdea60Sskrll #include <dev/sysmon/sysmon_taskq.h>
75fdfdea60Sskrll #include <dev/sysmon/sysmonvar.h>
76fdfdea60Sskrll 
77fdfdea60Sskrll /* Enable / disable control over the power switch. */
78fdfdea60Sskrll #define	PWR_SW_CTRL_DISABLE	0
79fdfdea60Sskrll #define	PWR_SW_CTRL_ENABLE	1
80fdfdea60Sskrll #define	PWR_SW_CTRL_LOCK	2
81fdfdea60Sskrll #define	PWR_SW_CTRL_MAX		PWR_SW_CTRL_LOCK
82fdfdea60Sskrll 
83fdfdea60Sskrll struct power_softc {
84fdfdea60Sskrll 	device_t sc_dev;
85fdfdea60Sskrll 	bus_space_tag_t sc_bst;
86fdfdea60Sskrll 	bus_space_handle_t sc_bsh;
87fdfdea60Sskrll 
88fdfdea60Sskrll 	void (*sc_kicker)(void *);
89fdfdea60Sskrll 
90fdfdea60Sskrll 	struct callout sc_callout;
91fdfdea60Sskrll 	int sc_timeout;
92fdfdea60Sskrll 
93fdfdea60Sskrll 	int sc_dr_cnt;
94fdfdea60Sskrll };
95fdfdea60Sskrll 
96fdfdea60Sskrll int	powermatch(device_t, cfdata_t, void *);
97fdfdea60Sskrll void	powerattach(device_t, device_t, void *);
98fdfdea60Sskrll 
99fdfdea60Sskrll CFATTACH_DECL_NEW(power, sizeof(struct power_softc),
100fdfdea60Sskrll     powermatch, powerattach, NULL, NULL);
101fdfdea60Sskrll 
102fdfdea60Sskrll static struct pdc_power_info pdc_power_info;
103fdfdea60Sskrll static bool pswitch_on;			/* power switch */
104fdfdea60Sskrll static int pwr_sw_control;
105fdfdea60Sskrll static const char *pwr_sw_control_str[] = {"disabled", "enabled", "locked"};
106fdfdea60Sskrll static struct sysmon_pswitch *pwr_sw_sysmon;
107fdfdea60Sskrll 
108fdfdea60Sskrll static int pwr_sw_sysctl_state(SYSCTLFN_PROTO);
109fdfdea60Sskrll static int pwr_sw_sysctl_ctrl(SYSCTLFN_PROTO);
110fdfdea60Sskrll static void pwr_sw_sysmon_cb(void *);
111fdfdea60Sskrll static void pwr_sw_ctrl(int);
112fdfdea60Sskrll static int pwr_sw_init(struct power_softc *);
113fdfdea60Sskrll 
114fdfdea60Sskrll void power_thread_dr(void *v);
115fdfdea60Sskrll void power_thread_reg(void *v);
116fdfdea60Sskrll void power_cold_hook_reg(int);
117fdfdea60Sskrll 
118fdfdea60Sskrll int
powermatch(device_t parent,cfdata_t cf,void * aux)119fdfdea60Sskrll powermatch(device_t parent, cfdata_t cf, void *aux)
120fdfdea60Sskrll {
121fdfdea60Sskrll 	struct confargs *ca = aux;
122fdfdea60Sskrll 
123fdfdea60Sskrll 	if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "power"))
124fdfdea60Sskrll 		return (0);
125fdfdea60Sskrll 
126fdfdea60Sskrll 	return (1);
127fdfdea60Sskrll }
128fdfdea60Sskrll 
129fdfdea60Sskrll void
powerattach(device_t parent,device_t self,void * aux)130fdfdea60Sskrll powerattach(device_t parent, device_t self, void *aux)
131fdfdea60Sskrll {
132fdfdea60Sskrll 	struct power_softc *sc = device_private(self);
133fdfdea60Sskrll 	struct confargs *ca = aux;
134fdfdea60Sskrll 	int err;
135fdfdea60Sskrll 
136fdfdea60Sskrll 	sc->sc_dev = self;
137fdfdea60Sskrll 	sc->sc_kicker = NULL;
138fdfdea60Sskrll 
139fdfdea60Sskrll 	err = pdcproc_soft_power_info(&pdc_power_info);
140fdfdea60Sskrll 
141fdfdea60Sskrll 	if (!err)
142fdfdea60Sskrll 		ca->ca_hpa = pdc_power_info.addr;
143fdfdea60Sskrll 
144fdfdea60Sskrll 	switch (cpu_modelno) {
145fdfdea60Sskrll 	case HPPA_BOARD_HP712_60:
146fdfdea60Sskrll 	case HPPA_BOARD_HP712_80:
147fdfdea60Sskrll 	case HPPA_BOARD_HP712_100:
148fdfdea60Sskrll 	case HPPA_BOARD_HP712_120:
149fdfdea60Sskrll 		sc->sc_kicker = power_thread_dr;
150fdfdea60Sskrll 
151fdfdea60Sskrll 		/* Diag Reg. needs software dampening, poll at 0.2 Hz.*/
152fdfdea60Sskrll 		sc->sc_timeout = hz / 5;
153fdfdea60Sskrll 
154fdfdea60Sskrll 		aprint_normal(": DR25\n");
155fdfdea60Sskrll 		break;
156fdfdea60Sskrll 
157fdfdea60Sskrll 	default:
158fdfdea60Sskrll 		if (ca->ca_hpa) {
159fdfdea60Sskrll 			sc->sc_bst = ca->ca_iot;
160fdfdea60Sskrll 			if (bus_space_map(sc->sc_bst, ca->ca_hpa, 4, 0,
161fdfdea60Sskrll 			    &sc->sc_bsh) != 0)
162fdfdea60Sskrll 				aprint_error_dev(self,
163fdfdea60Sskrll 				    "Can't map power switch status reg.\n");
164fdfdea60Sskrll 
165fdfdea60Sskrll 			cold_hook = power_cold_hook_reg;
166fdfdea60Sskrll 			sc->sc_kicker = power_thread_reg;
167fdfdea60Sskrll 
168fdfdea60Sskrll 			/* Power Reg. is hardware dampened, poll at 1 Hz. */
169fdfdea60Sskrll 			sc->sc_timeout = hz;
170fdfdea60Sskrll 
171fdfdea60Sskrll 			aprint_normal("\n");
172fdfdea60Sskrll 		} else
173fdfdea60Sskrll 			aprint_normal(": not available\n");
174fdfdea60Sskrll 		break;
175fdfdea60Sskrll 	}
176fdfdea60Sskrll 
177fdfdea60Sskrll 	if (sc->sc_kicker) {
178fdfdea60Sskrll 		if (pwr_sw_init(sc))
179fdfdea60Sskrll 			return;
180fdfdea60Sskrll 
181fdfdea60Sskrll 		pswitch_on = true;
182fdfdea60Sskrll 		pwr_sw_control = PWR_SW_CTRL_ENABLE;
183fdfdea60Sskrll 	}
184fdfdea60Sskrll }
185fdfdea60Sskrll 
186fdfdea60Sskrll /*
187fdfdea60Sskrll  * If the power switch is turned off we schedule a sysmon task
188fdfdea60Sskrll  * to register that event for this power switch device.
189fdfdea60Sskrll  */
190fdfdea60Sskrll static void
check_pwr_state(struct power_softc * sc)191fdfdea60Sskrll check_pwr_state(struct power_softc *sc)
192fdfdea60Sskrll {
193fdfdea60Sskrll 	if (pswitch_on == false && pwr_sw_control != PWR_SW_CTRL_LOCK)
194fdfdea60Sskrll 		sysmon_task_queue_sched(0, pwr_sw_sysmon_cb, NULL);
195fdfdea60Sskrll 	else
196fdfdea60Sskrll 		callout_reset(&sc->sc_callout, sc->sc_timeout,
197fdfdea60Sskrll 		    sc->sc_kicker, sc);
198fdfdea60Sskrll }
199fdfdea60Sskrll 
200fdfdea60Sskrll void
power_thread_dr(void * v)201fdfdea60Sskrll power_thread_dr(void *v)
202fdfdea60Sskrll {
203fdfdea60Sskrll 	struct power_softc *sc = v;
204fdfdea60Sskrll 	uint32_t r;
205fdfdea60Sskrll 
206fdfdea60Sskrll 	/* Get Power Fail status from CPU Diagnose Register 25 */
207fdfdea60Sskrll 	mfcpu(25, r);
208fdfdea60Sskrll 
209fdfdea60Sskrll 	/*
210fdfdea60Sskrll 	 * On power failure, the hardware clears bit DR25_PCXL_POWFAIL
211fdfdea60Sskrll 	 * in CPU Diagnose Register 25.
212fdfdea60Sskrll 	 */
213fdfdea60Sskrll 	if (r & (1 << DR25_PCXL_POWFAIL))
214fdfdea60Sskrll 		sc->sc_dr_cnt = 0;
215fdfdea60Sskrll 	else
216fdfdea60Sskrll 		sc->sc_dr_cnt++;
217fdfdea60Sskrll 
218fdfdea60Sskrll 	/*
219fdfdea60Sskrll 	 * the bit is undampened straight wire from the power
220fdfdea60Sskrll 	 * switch and thus we have do dampen it ourselves.
221fdfdea60Sskrll 	 */
222fdfdea60Sskrll 	if (sc->sc_dr_cnt == sc->sc_timeout)
223fdfdea60Sskrll 		pswitch_on = false;
224fdfdea60Sskrll 	else
225fdfdea60Sskrll 		pswitch_on = true;
226fdfdea60Sskrll 
227fdfdea60Sskrll 	check_pwr_state(sc);
228fdfdea60Sskrll }
229fdfdea60Sskrll 
230fdfdea60Sskrll void
power_thread_reg(void * v)231fdfdea60Sskrll power_thread_reg(void *v)
232fdfdea60Sskrll {
233fdfdea60Sskrll 	struct power_softc *sc = v;
234fdfdea60Sskrll 	uint32_t r;
235fdfdea60Sskrll 
236fdfdea60Sskrll 	r = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 0);
237fdfdea60Sskrll 
238fdfdea60Sskrll 	if (!(r & 1))
239fdfdea60Sskrll 		pswitch_on = false;
240fdfdea60Sskrll 	else
241fdfdea60Sskrll 		pswitch_on = true;
242fdfdea60Sskrll 
243fdfdea60Sskrll 	check_pwr_state(sc);
244fdfdea60Sskrll }
245fdfdea60Sskrll 
246fdfdea60Sskrll void
power_cold_hook_reg(int on)247fdfdea60Sskrll power_cold_hook_reg(int on)
248fdfdea60Sskrll {
249fdfdea60Sskrll 	int error;
250fdfdea60Sskrll 
251fdfdea60Sskrll 	error = pdcproc_soft_power_enable(on == HPPA_COLD_HOT);
252fdfdea60Sskrll 	if (error)
253fdfdea60Sskrll 		aprint_error("PDC_SOFT_POWER_ENABLE failed (%d)\n", error);
254fdfdea60Sskrll }
255fdfdea60Sskrll 
256fdfdea60Sskrll static int
pwr_sw_init(struct power_softc * sc)257fdfdea60Sskrll pwr_sw_init(struct power_softc *sc)
258fdfdea60Sskrll {
259fdfdea60Sskrll 	struct sysctllog *sysctl_log = NULL;
260fdfdea60Sskrll 	const struct sysctlnode *pwr_sw_node;
261fdfdea60Sskrll 	const char *errmsg;
262fdfdea60Sskrll 	int error = EINVAL;
263fdfdea60Sskrll 
264fdfdea60Sskrll 	/*
265fdfdea60Sskrll 	 * Ensure that we are on a PCX-L / PA7100LC CPU if it is a
266fdfdea60Sskrll 	 * 712 style machine.
267fdfdea60Sskrll 	 */
268fdfdea60Sskrll 	if (pdc_power_info.addr == 0 && hppa_cpu_info->hci_cputype != hpcxl) {
269fdfdea60Sskrll 		aprint_error_dev(sc->sc_dev, "No soft power available.\n");
270fdfdea60Sskrll 		return error;
271fdfdea60Sskrll 	}
272fdfdea60Sskrll 
273fdfdea60Sskrll 	errmsg = "Can't create sysctl machdep.power_switch (or children)\n";
274fdfdea60Sskrll 	error = sysctl_createv(&sysctl_log, 0, NULL, NULL, 0,
275fdfdea60Sskrll 	    CTLTYPE_NODE, "machdep", NULL, NULL, 0, NULL, 0,
276fdfdea60Sskrll 	    CTL_MACHDEP, CTL_EOL);
277fdfdea60Sskrll 
278fdfdea60Sskrll 	if (error)
279fdfdea60Sskrll 		goto err_sysctl;
280fdfdea60Sskrll 
281fdfdea60Sskrll 	error = sysctl_createv(&sysctl_log, 0, NULL, &pwr_sw_node, 0,
282fdfdea60Sskrll 	    CTLTYPE_NODE, "power_switch", NULL, NULL, 0, NULL, 0,
283fdfdea60Sskrll 	    CTL_MACHDEP, CTL_CREATE, CTL_EOL);
284fdfdea60Sskrll 
285fdfdea60Sskrll 	if (error)
286fdfdea60Sskrll 		goto err_sysctl;
287fdfdea60Sskrll 
288fdfdea60Sskrll 	error = sysctl_createv(&sysctl_log, 0, NULL, NULL,
289fdfdea60Sskrll 	    CTLFLAG_READONLY, CTLTYPE_STRING, "state", NULL,
290fdfdea60Sskrll 	    pwr_sw_sysctl_state, 0, NULL, 16,
291fdfdea60Sskrll 	    CTL_MACHDEP, pwr_sw_node->sysctl_num, CTL_CREATE, CTL_EOL);
292fdfdea60Sskrll 
293fdfdea60Sskrll 	if (error)
294fdfdea60Sskrll 		goto err_sysctl;
295fdfdea60Sskrll 
296fdfdea60Sskrll 	error = sysctl_createv(&sysctl_log, 0, NULL, NULL,
297fdfdea60Sskrll 	    CTLFLAG_READWRITE, CTLTYPE_STRING, "control", NULL,
298fdfdea60Sskrll 	    pwr_sw_sysctl_ctrl, 0, NULL, 16,
299fdfdea60Sskrll 	    CTL_MACHDEP, pwr_sw_node->sysctl_num, CTL_CREATE, CTL_EOL);
300fdfdea60Sskrll 
301fdfdea60Sskrll 	if (error)
302fdfdea60Sskrll 		goto err_sysctl;
303fdfdea60Sskrll 
304fdfdea60Sskrll 	errmsg = "Can't alloc sysmon power switch.\n";
305fdfdea60Sskrll 	pwr_sw_sysmon = kmem_zalloc(sizeof(*pwr_sw_sysmon), KM_SLEEP);
306fdfdea60Sskrll 	errmsg = "Can't register power switch with sysmon.\n";
307fdfdea60Sskrll 	sysmon_task_queue_init();
308fdfdea60Sskrll 	pwr_sw_sysmon->smpsw_name = "power switch";
309fdfdea60Sskrll 	pwr_sw_sysmon->smpsw_type = PSWITCH_TYPE_POWER;
310fdfdea60Sskrll 	error = sysmon_pswitch_register(pwr_sw_sysmon);
311fdfdea60Sskrll 
312fdfdea60Sskrll 	if (error)
313fdfdea60Sskrll 		goto err_sysmon;
314fdfdea60Sskrll 
315fdfdea60Sskrll 	callout_init(&sc->sc_callout, 0);
316fdfdea60Sskrll 	callout_reset(&sc->sc_callout, sc->sc_timeout, sc->sc_kicker, sc);
317fdfdea60Sskrll 
318fdfdea60Sskrll 	return error;
319fdfdea60Sskrll 
320fdfdea60Sskrll err_sysmon:
321fdfdea60Sskrll 	kmem_free(pwr_sw_sysmon, sizeof(*pwr_sw_sysmon));
322fdfdea60Sskrll 
323fdfdea60Sskrll err_sysctl:
324fdfdea60Sskrll 	sysctl_teardown(&sysctl_log);
325fdfdea60Sskrll 
326fdfdea60Sskrll 	aprint_error_dev(sc->sc_dev, errmsg);
327fdfdea60Sskrll 
328fdfdea60Sskrll 	return error;
329fdfdea60Sskrll }
330fdfdea60Sskrll 
331fdfdea60Sskrll static void
pwr_sw_sysmon_cb(void * not_used)332fdfdea60Sskrll pwr_sw_sysmon_cb(void *not_used)
333fdfdea60Sskrll {
334fdfdea60Sskrll 	sysmon_pswitch_event(pwr_sw_sysmon, PSWITCH_EVENT_PRESSED);
335fdfdea60Sskrll }
336fdfdea60Sskrll 
337fdfdea60Sskrll static void
pwr_sw_ctrl(int enable)338fdfdea60Sskrll pwr_sw_ctrl(int enable)
339fdfdea60Sskrll {
340fdfdea60Sskrll 	int on;
341fdfdea60Sskrll 
342fdfdea60Sskrll #ifdef DEBUG
343fdfdea60Sskrll 	printf("pwr_sw_control=%d enable=%d\n", pwr_sw_control, enable);
344fdfdea60Sskrll #endif /* DEBUG */
345fdfdea60Sskrll 
346fdfdea60Sskrll 	if (cold_hook == NULL)
347fdfdea60Sskrll 		return;
348fdfdea60Sskrll 
349fdfdea60Sskrll 	switch(enable) {
350fdfdea60Sskrll 	case PWR_SW_CTRL_DISABLE:
351fdfdea60Sskrll 		on = HPPA_COLD_OFF;
352fdfdea60Sskrll 		break;
353fdfdea60Sskrll 	case PWR_SW_CTRL_ENABLE:
354fdfdea60Sskrll 	case PWR_SW_CTRL_LOCK:
355fdfdea60Sskrll 		on = HPPA_COLD_HOT;
356fdfdea60Sskrll 		break;
357fdfdea60Sskrll 	default:
358fdfdea60Sskrll 		panic("invalid power state in pwr_sw_control: %d", enable);
359fdfdea60Sskrll 	}
360fdfdea60Sskrll 
361fdfdea60Sskrll 	pwr_sw_control = enable;
362fdfdea60Sskrll 
363fdfdea60Sskrll 	if (cold_hook)
364fdfdea60Sskrll 		(*cold_hook)(on);
365fdfdea60Sskrll }
366fdfdea60Sskrll 
367fdfdea60Sskrll int
pwr_sw_sysctl_state(SYSCTLFN_ARGS)368fdfdea60Sskrll pwr_sw_sysctl_state(SYSCTLFN_ARGS)
369fdfdea60Sskrll {
370fdfdea60Sskrll 	struct sysctlnode node;
371fdfdea60Sskrll 	const char *status;
372fdfdea60Sskrll 
373fdfdea60Sskrll 	if (pswitch_on == true)
374fdfdea60Sskrll 		status = "on";
375fdfdea60Sskrll 	else
376fdfdea60Sskrll 		status = "off";
377fdfdea60Sskrll 
378fdfdea60Sskrll 	node = *rnode;
379fdfdea60Sskrll 	node.sysctl_data = __UNCONST(status);
380fdfdea60Sskrll 	return sysctl_lookup(SYSCTLFN_CALL(&node));
381fdfdea60Sskrll }
382fdfdea60Sskrll 
383fdfdea60Sskrll int
pwr_sw_sysctl_ctrl(SYSCTLFN_ARGS)384fdfdea60Sskrll pwr_sw_sysctl_ctrl(SYSCTLFN_ARGS)
385fdfdea60Sskrll {
386fdfdea60Sskrll 	struct sysctlnode node;
387fdfdea60Sskrll 	int i, error;
388fdfdea60Sskrll 	char val[16];
389fdfdea60Sskrll 
390fdfdea60Sskrll 	node = *rnode;
391fdfdea60Sskrll 	strcpy(val, pwr_sw_control_str[pwr_sw_control]);
392fdfdea60Sskrll 
393fdfdea60Sskrll 	node.sysctl_data = val;
394fdfdea60Sskrll 
395fdfdea60Sskrll 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
396fdfdea60Sskrll 
397fdfdea60Sskrll 	if (error || newp == NULL)
398fdfdea60Sskrll 		return error;
399fdfdea60Sskrll 
400fdfdea60Sskrll 	for (i = 0; i <= PWR_SW_CTRL_MAX; i++)
401fdfdea60Sskrll 		if (strcmp(val, pwr_sw_control_str[i]) == 0) {
402fdfdea60Sskrll 			pwr_sw_ctrl(i);
403fdfdea60Sskrll 			return 0;
404fdfdea60Sskrll 		}
405fdfdea60Sskrll 
406fdfdea60Sskrll 	return EINVAL;
407fdfdea60Sskrll }
408