xref: /netbsd/sys/arch/sandpoint/sandpoint/satmgr.c (revision 6550d01e)
1 /* $NetBSD: satmgr.c,v 1.2 2010/06/03 10:44:21 phx Exp $ */
2 
3 /*-
4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Tohru Nishimura.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/device.h>
36 #include <sys/conf.h>
37 #include <sys/proc.h>
38 #include <sys/vnode.h>
39 #include <sys/select.h>
40 #include <sys/poll.h>
41 #include <sys/callout.h>
42 #include <sys/sysctl.h>
43 #include <sys/reboot.h>
44 #include <sys/intr.h>
45 
46 #include <dev/sysmon/sysmonvar.h>
47 #include <dev/sysmon/sysmon_taskq.h>
48 
49 #include <dev/ic/comreg.h>
50 
51 #include <machine/bus.h>
52 #include <machine/intr.h>
53 #include <machine/bootinfo.h>
54 
55 #include <sandpoint/sandpoint/eumbvar.h>
56 #include "locators.h"
57 
58 struct satmgr_softc {
59 	device_t		sc_dev;
60 	bus_space_tag_t		sc_iot;
61 	bus_space_handle_t	sc_ioh;
62 	struct selinfo		sc_rsel;
63 	callout_t		sc_ch_wdog;
64 	callout_t		sc_ch_pbutton;
65 	struct sysmon_pswitch	sc_sm_pbutton;
66 	int			sc_open;
67 	void			*sc_si;
68 	uint32_t		sc_ierror, sc_overr;
69 	kmutex_t		sc_lock;
70 	kcondvar_t		sc_rdcv, sc_wrcv;
71 	char sc_rd_buf[16], *sc_rd_lim, *sc_rd_cur, *sc_rd_ptr;
72 	char sc_wr_buf[16], *sc_wr_lim, *sc_wr_cur, *sc_wr_ptr;
73 	int sc_rd_cnt, sc_wr_cnt;
74 };
75 
76 static int  satmgr_match(device_t, cfdata_t, void *);
77 static void satmgr_attach(device_t, device_t, void *);
78 
79 CFATTACH_DECL_NEW(satmgr, sizeof(struct satmgr_softc),
80     satmgr_match, satmgr_attach, NULL, NULL);
81 extern struct cfdriver satmgr_cd;
82 
83 static int found = 0;
84 extern void (*md_reboot)(int);
85 
86 static dev_type_open(satopen);
87 static dev_type_close(satclose);
88 static dev_type_read(satread);
89 static dev_type_write(satwrite);
90 static dev_type_poll(satpoll);
91 static dev_type_kqfilter(satkqfilter);
92 
93 const struct cdevsw satmgr_cdevsw = {
94 	satopen, satclose, satread, satwrite, noioctl,
95 	nostop, notty, satpoll, nommap, satkqfilter, D_OTHER
96 };
97 
98 static void satmgr_reboot(int);
99 static int satmgr_sysctl_wdogenable(SYSCTLFN_PROTO);
100 static void wdog_tickle(void *);
101 static void send_sat(struct satmgr_softc *, const char *);
102 static int hwintr(void *);
103 static void rxintr(struct satmgr_softc *);
104 static void txintr(struct satmgr_softc *);
105 static void startoutput(struct satmgr_softc *);
106 static void swintr(void *);
107 static void kbutton(struct satmgr_softc *, int);
108 static void sbutton(struct satmgr_softc *, int);
109 static void qbutton(struct satmgr_softc *, int);
110 static void guarded_pbutton(void *);
111 static void sched_sysmon_pbutton(void *);
112 
113 struct satmsg {
114 	const char *family;
115 	const char *reboot, *poweroff;
116 	void (*dispatch)(struct satmgr_softc *, int);
117 };
118 
119 static const struct satmsg satmodel[] = {
120     { "kurobox",  "CCGG", "EEGG", kbutton },
121     { "synology", "C",    "1",    sbutton },
122     { "qnap",     "f",    "A",    qbutton }
123 };
124 static const struct satmsg *satmgr_msg;
125 
126 /* single byte stride register layout */
127 #define RBR		0
128 #define THR		0
129 #define DLB		0
130 #define IER		1
131 #define DMB		1
132 #define IIR		2
133 #define LCR		3
134 #define LSR		5
135 #define CSR_READ(t,r)	bus_space_read_1((t)->sc_iot, (t)->sc_ioh, (r))
136 #define CSR_WRITE(t,r,v) bus_space_write_1((t)->sc_iot, (t)->sc_ioh, (r), (v))
137 
138 static int satmgr_wdog;
139 
140 static int
141 satmgr_match(device_t parent, cfdata_t match, void *aux)
142 {
143 	struct eumb_attach_args *eaa = aux;
144 	int unit = eaa->eumb_unit;
145 
146 	if (unit == EUMBCF_UNIT_DEFAULT && found == 0)
147 		return (1);
148 	if (unit == 0 || unit == 1)
149 		return (1);
150 	return (0);
151 }
152 
153 static void
154 satmgr_attach(device_t parent, device_t self, void *aux)
155 {
156 	struct eumb_attach_args *eaa = aux;
157 	struct satmgr_softc *sc = device_private(self);
158 	struct btinfo_prodfamily *pfam;
159 	int i, sataddr, epicirq;
160 
161 	found = 1;
162 
163 	if ((pfam = lookup_bootinfo(BTINFO_PRODFAMILY)) == NULL)
164 		goto notavail;
165 	satmgr_msg = NULL;
166 	for (i = 0; i < (int)(sizeof(satmodel)/sizeof(satmodel[0])); i++) {
167 		if (strcmp(pfam->name, satmodel[i].family) == 0) {
168 			satmgr_msg = &satmodel[i];
169 			break;
170 		}
171 	}
172 	if (satmgr_msg == NULL)
173 		goto notavail;
174 
175 	aprint_normal(": button manager (%s)\n", satmgr_msg->family);
176 
177 	sc->sc_dev = self;
178 	sataddr = (eaa->eumb_unit == 0) ? 0x4500 : 0x4600;
179 	sc->sc_iot = eaa->eumb_bt;
180 	bus_space_map(eaa->eumb_bt, sataddr, 0x20, 0, &sc->sc_ioh);
181 	sc->sc_open = 0;
182 	sc->sc_rd_cnt = 0;
183 	sc->sc_rd_cur = sc->sc_rd_ptr = &sc->sc_rd_buf[0];
184 	sc->sc_rd_lim = sc->sc_rd_cur + sizeof(sc->sc_rd_buf);
185 	sc->sc_wr_cnt = 0;
186 	sc->sc_wr_cur = sc->sc_wr_ptr = &sc->sc_wr_buf[0];
187 	sc->sc_wr_lim = sc->sc_wr_cur + sizeof(sc->sc_wr_buf);
188 	sc->sc_ierror = sc->sc_overr = 0;
189 	selinit(&sc->sc_rsel);
190 	callout_init(&sc->sc_ch_wdog, 0);
191 	callout_init(&sc->sc_ch_pbutton, 0);
192 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH);
193 	cv_init(&sc->sc_rdcv, "satrd");
194 	cv_init(&sc->sc_wrcv, "satwr");
195 
196 	epicirq = (eaa->eumb_unit == 0) ? 24 : 25;
197 	intr_establish(epicirq + 16, IST_LEVEL, IPL_SERIAL, hwintr, sc);
198 	sc->sc_si = softint_establish(SOFTINT_SERIAL, swintr, sc);
199 
200 	CSR_WRITE(sc, IER, 0x7f); /* all but MSR */
201 
202 	if (!pmf_device_register(sc->sc_dev, NULL, NULL))
203 		aprint_error_dev(sc->sc_dev, "couldn't establish handler\n");
204 
205 	sysmon_task_queue_init();
206 	memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch));
207 	sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev);
208 	sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
209 	if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
210 		aprint_error_dev(sc->sc_dev,
211 		    "unable to register power button with sysmon\n");
212 
213 	if (strcmp(satmgr_msg->family, "kurobox") == 0) {
214 		const struct sysctlnode *rnode;
215 		struct sysctllog *clog;
216 
217 		/* create machdep.satmgr.* subtree */
218 		clog = NULL;
219 		sysctl_createv(&clog, 0, NULL, &rnode,
220 			CTLFLAG_PERMANENT,
221 			CTLTYPE_NODE, "machdep", NULL,
222 			NULL, 0, NULL, 0,
223 			CTL_MACHDEP, CTL_EOL);
224 		sysctl_createv(&clog, 0, &rnode, &rnode,
225 			CTLFLAG_PERMANENT,
226 			CTLTYPE_NODE, "satmgr", NULL,
227 			NULL, 0, NULL, 0,
228 			CTL_CREATE, CTL_EOL);
229 		sysctl_createv(&clog, 0, &rnode, NULL,
230 			CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
231 			CTLTYPE_INT, "hwwdog_enable",
232 			SYSCTL_DESCR("watchdog enable"),
233 			satmgr_sysctl_wdogenable, 0, NULL, 0,
234 			CTL_CREATE, CTL_EOL);
235 	}
236 
237 	md_reboot = satmgr_reboot; /* cpu_reboot() hook */
238 	return;
239 
240   notavail:
241 	aprint_normal(": button manager (not supported)\n");
242 }
243 
244 static void
245 satmgr_reboot(int howto)
246 {
247 	const char *msg;
248 	struct satmgr_softc *sc = device_lookup_private(&satmgr_cd, 0);
249 
250 	if ((howto & RB_POWERDOWN) == RB_AUTOBOOT)
251 		msg = satmgr_msg->reboot;	/* REBOOT */
252 	else
253 		msg = satmgr_msg->poweroff;	/* HALT or POWERDOWN */
254 	send_sat(sc, msg);
255 	tsleep(satmgr_reboot, PWAIT, "reboot", 0);
256 	/*NOTREACHED*/
257 }
258 
259 static int
260 satmgr_sysctl_wdogenable(SYSCTLFN_ARGS)
261 {
262 	int error, t;
263 	struct sysctlnode node;
264 	struct satmgr_softc *sc;
265 
266 	node = *rnode;
267 	t = satmgr_wdog;
268 	node.sysctl_data = &t;
269 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
270 	if (error || newp == NULL)
271 		return error;
272 
273 	if (t < 0 || t > 1)
274 		return EINVAL;
275 
276 	sc = device_lookup_private(&satmgr_cd, 0);
277 	if (t == 1) {
278 		callout_setfunc(&sc->sc_ch_wdog, wdog_tickle, sc);
279 		callout_schedule(&sc->sc_ch_wdog, 90 * hz);
280 		send_sat(sc, "JJ");
281 	}
282 	else {
283 		callout_stop(&sc->sc_ch_wdog);
284 		send_sat(sc, "KK");
285 	}
286 	return 0;
287 }
288 
289 /* disarm watchdog timer periodically */
290 static void
291 wdog_tickle(void *arg)
292 {
293 	struct satmgr_softc *sc = arg;
294 
295 	send_sat(sc, "GG");
296 	callout_schedule(&sc->sc_ch_wdog, 90 * hz);
297 }
298 
299 static void
300 send_sat(struct satmgr_softc *sc, const char *msg)
301 {
302 	unsigned lsr, ch, n;
303 
304  again:
305 	do {
306 		lsr = CSR_READ(sc, LSR);
307 	} while ((lsr & LSR_TXRDY) == 0);
308 	n = 16; /* FIFO depth */
309 	while ((ch = *msg++) != '\0' && n-- > 0) {
310 		CSR_WRITE(sc, THR, ch);
311 	}
312 	if (ch != '\0')
313 		goto again;
314 }
315 
316 static int
317 satopen(dev_t dev, int flags, int fmt, struct lwp *l)
318 {
319 	struct satmgr_softc *sc;
320 
321 	sc = device_lookup_private(&satmgr_cd, 0);
322 	if (sc == NULL)
323 		return ENXIO;
324 	if (sc->sc_open > 0)
325 		return EBUSY;
326 	sc->sc_open = 1;
327 	return 0;
328 }
329 
330 static int
331 satclose(dev_t dev, int flags, int fmt, struct lwp *l)
332 {
333 	struct satmgr_softc *sc;
334 
335 	sc = device_lookup_private(&satmgr_cd, 0);
336 	if (sc == NULL)
337 		return ENXIO;
338 	KASSERT(sc->sc_open > 0);
339 	sc->sc_open = 0;
340 	return 0;
341 }
342 
343 static int
344 satread(dev_t dev, struct uio *uio, int flags)
345 {
346 	struct satmgr_softc *sc;
347 	size_t n;
348 	int error;
349 
350 	sc = device_lookup_private(&satmgr_cd, 0);
351 	if (sc == NULL)
352 		return ENXIO;
353 
354 	mutex_enter(&sc->sc_lock);
355 	if (sc->sc_rd_cnt == 0 && (flags & IO_NDELAY)) {
356 		error = EWOULDBLOCK;
357 		goto out;
358 	}
359 	error = 0;
360 	while (sc->sc_rd_cnt == 0) {
361 		error = cv_wait_sig(&sc->sc_rdcv, &sc->sc_lock);
362 		if (error)
363 			goto out;
364 	}
365 	while (uio->uio_resid > 0 && sc->sc_rd_cnt > 0) {
366 		n = min(sc->sc_rd_cnt, uio->uio_resid);
367 		n = min(n, sc->sc_rd_lim - sc->sc_rd_ptr);
368 		error = uiomove(sc->sc_rd_ptr, n, uio);
369 		if (error)
370 			goto out;
371 		sc->sc_rd_cnt -= n;
372 		sc->sc_rd_ptr += n;
373 		if (sc->sc_rd_ptr == sc->sc_rd_lim)
374 			sc->sc_rd_ptr = &sc->sc_rd_buf[0];
375 	}
376  out:
377 	mutex_exit(&sc->sc_lock);
378 	return error;
379 }
380 
381 static int
382 satwrite(dev_t dev, struct uio *uio, int flags)
383 {
384 	struct satmgr_softc *sc;
385 	int error;
386 	size_t n;
387 
388 	sc = device_lookup_private(&satmgr_cd, 0);
389 	if (sc == NULL)
390 		return ENXIO;
391 
392 	mutex_enter(&sc->sc_lock);
393 	if (sc->sc_wr_cnt == sizeof(sc->sc_wr_buf) && (flags & IO_NDELAY)) {
394 		error = EWOULDBLOCK;
395 		goto out;
396 	}
397 	error = 0;
398 	while (sc->sc_wr_cnt == sizeof(sc->sc_wr_buf)) {
399 		error = cv_wait_sig(&sc->sc_wrcv, &sc->sc_lock);
400 		if (error)
401 			goto out;
402 	}
403 	while (uio->uio_resid > 0 && sc->sc_wr_cnt < sizeof(sc->sc_wr_buf)) {
404 		n = min(uio->uio_resid, sizeof(sc->sc_wr_buf));
405 		n = min(n, sc->sc_wr_lim - sc->sc_wr_cur);
406 		error = uiomove(sc->sc_wr_cur, n, uio);
407 		if (error)
408 			goto out;
409 		sc->sc_wr_cnt += n;
410 		sc->sc_wr_cur += n;
411 		if (sc->sc_wr_cur == sc->sc_wr_lim)
412 			sc->sc_wr_cur = &sc->sc_wr_buf[0];
413 	}
414 	startoutput(sc); /* start xmit */
415  out:
416 	mutex_exit(&sc->sc_lock);
417 	return error;
418 }
419 
420 static int
421 satpoll(dev_t dev, int events, struct lwp *l)
422 {
423 	struct satmgr_softc *sc;
424 	int revents = 0;
425 
426 	sc = device_lookup_private(&satmgr_cd, 0);
427 	mutex_enter(&sc->sc_lock);
428 	if (events & (POLLIN | POLLRDNORM)) {
429 		if (sc->sc_rd_cnt)
430 			revents |= events & (POLLIN | POLLRDNORM);
431 		else
432 			selrecord(l, &sc->sc_rsel);
433 	}
434 	mutex_exit(&sc->sc_lock);
435 
436 	return revents;
437 }
438 
439 static void
440 filt_rdetach(struct knote *kn)
441 {
442 	struct satmgr_softc *sc = kn->kn_hook;
443 
444 	mutex_enter(&sc->sc_lock);
445 	SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
446 	mutex_exit(&sc->sc_lock);
447 }
448 
449 static int
450 filt_read(struct knote *kn, long hint)
451 {
452 	struct satmgr_softc *sc = kn->kn_hook;
453 
454 	kn->kn_data = sc->sc_rd_cnt;
455 	return (kn->kn_data > 0);
456 }
457 
458 static const struct filterops read_filtops =
459 	{ 1, NULL, filt_rdetach, filt_read };
460 
461 static int
462 satkqfilter(dev_t dev, struct knote *kn)
463 {
464 	struct satmgr_softc *sc = device_lookup_private(&satmgr_cd, 0);
465 	struct klist *klist;
466 
467 	switch (kn->kn_filter) {
468 	case EVFILT_READ:
469 		klist = &sc->sc_rsel.sel_klist;
470 		kn->kn_fop = &read_filtops;
471 		break;
472 
473 	default:
474 		return (EINVAL);
475 	}
476 
477 	kn->kn_hook = sc;
478 
479 	mutex_enter(&sc->sc_lock);
480 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
481 	mutex_exit(&sc->sc_lock);
482 
483 	return (0);
484 }
485 
486 static int
487 hwintr(void *arg)
488 {
489 	struct satmgr_softc *sc = arg;
490 	int iir;
491 
492 	mutex_spin_enter(&sc->sc_lock);
493 	iir = CSR_READ(sc, IIR) & IIR_IMASK;
494 	if (iir == IIR_NOPEND) {
495 		mutex_spin_exit(&sc->sc_lock);
496 		return 0;
497 	}
498 	do {
499 		switch (iir) {
500 		case IIR_RLS:	/* LSR updated */
501 		case IIR_RXRDY: /* RxFIFO has been accumulated */
502 		case IIR_RXTOUT:/* receive timeout occurred */
503 			rxintr(sc);
504 			break;
505 		case IIR_TXRDY: /* TxFIFO is ready to swallow data */
506 			txintr(sc);
507 			break;
508 		case IIR_MLSC:	/* MSR updated */
509 			break;
510 		}
511 		iir = CSR_READ(sc, IIR) & IIR_IMASK;
512 	} while (iir != IIR_NOPEND);
513 	mutex_spin_exit(&sc->sc_lock);
514 	return 1;
515 }
516 
517 static void
518 rxintr(struct satmgr_softc *sc)
519 {
520 	int lsr, ch;
521 
522 	lsr = CSR_READ(sc, LSR);
523 	if (lsr & LSR_OE)
524 		sc->sc_overr++;
525 	ch = -1;
526 	while (lsr & LSR_RXRDY) {
527 		if (lsr & (LSR_BI | LSR_FE | LSR_PE)) {
528 			(void) CSR_READ(sc, RBR);
529 			sc->sc_ierror++;
530 			lsr = CSR_READ(sc, LSR);
531 			continue;
532 		}
533 		ch = CSR_READ(sc, RBR);
534 		if (sc->sc_rd_cnt < sizeof(sc->sc_rd_buf)) {
535 			*sc->sc_rd_cur = ch;
536 			if (++sc->sc_rd_cur == sc->sc_rd_lim)
537 				sc->sc_rd_cur = &sc->sc_rd_buf[0];
538 			sc->sc_rd_cnt += 1;
539 		}
540 		lsr = CSR_READ(sc, LSR);
541 	}
542 	if (ch != -1)
543 		softint_schedule(sc->sc_si);
544 }
545 
546 static void
547 txintr(struct satmgr_softc *sc)
548 {
549 
550 	cv_signal(&sc->sc_wrcv);
551 	startoutput(sc);
552 }
553 
554 static void
555 startoutput(struct satmgr_softc *sc)
556 {
557 	int n, ch;
558 
559 	n = min(sc->sc_wr_cnt, 16);
560 	while ((ch = *sc->sc_wr_ptr) && n-- > 0) {
561 		CSR_WRITE(sc, THR, ch);
562 		if (++sc->sc_wr_ptr == sc->sc_wr_lim)
563 			sc->sc_wr_ptr = &sc->sc_wr_buf[0];
564 		sc->sc_wr_cnt -= 1;
565 	}
566 }
567 
568 static void
569 swintr(void *arg)
570 {
571 	struct satmgr_softc *sc = arg;
572 	char *ptr;
573 	int n;
574 
575 	/* we're now in softint(9) context */
576 	mutex_spin_enter(&sc->sc_lock);
577 	ptr = sc->sc_rd_ptr;
578 	for (n = 0; n < sc->sc_rd_cnt; n++) {
579 		(*satmgr_msg->dispatch)(sc, *ptr);
580 		if (++ptr == sc->sc_rd_lim)
581 			ptr = &sc->sc_rd_buf[0];
582 	}
583 	if (sc->sc_open == 0) {
584 		sc->sc_rd_cnt = 0;
585 		sc->sc_rd_ptr = ptr;
586 		mutex_spin_exit(&sc->sc_lock);
587 		return; /* drop characters down to floor */
588 	}
589 	cv_signal(&sc->sc_rdcv);
590 	selnotify(&sc->sc_rsel, 0, 0);
591 	mutex_spin_exit(&sc->sc_lock);
592 }
593 
594 static void
595 kbutton(struct satmgr_softc *sc, int ch)
596 {
597 
598 	switch (ch) {
599 	case '!':
600 		/* schedule 3 second poweroff guard time */
601 		if (callout_pending(&sc->sc_ch_pbutton) == true)
602 			callout_stop(&sc->sc_ch_pbutton);
603 		callout_reset(&sc->sc_ch_pbutton,
604 		     3 * hz, guarded_pbutton, sc);
605 		break;
606 	case ' ':
607 		if (callout_expired(&sc->sc_ch_pbutton) == false)
608 			callout_stop(&sc->sc_ch_pbutton);
609 		else
610 			/* should never come here */;
611 		break;
612 	case '#':
613 	case '"':
614 		break;
615 	}
616 }
617 
618 static void
619 sbutton(struct satmgr_softc *sc, int ch)
620 {
621 
622 	switch (ch) {
623 	case '0':
624 		/* notified after 3 secord guard time */
625 		sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
626 		break;
627 	case 'a':
628 	case '`':
629 		break;
630 	}
631 }
632 
633 static void
634 qbutton(struct satmgr_softc *sc, int ch)
635 {
636 	/* research in progress */
637 }
638 
639 static void
640 guarded_pbutton(void *arg)
641 {
642 	struct satmgr_softc *sc = arg;
643 
644 	/* we're now in callout(9) context */
645 	sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
646 	send_sat(sc, "UU");
647 }
648 
649 static void
650 sched_sysmon_pbutton(void *arg)
651 {
652 	struct satmgr_softc *sc = arg;
653 
654 	/* we're now in kthread(9) context */
655 	sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED);
656 }
657