xref: /netbsd/sys/arch/sandpoint/sandpoint/satmgr.c (revision 984815da)
1 /* $NetBSD: satmgr.c,v 1.31 2021/09/26 01:16:08 thorpej 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 <sys/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 
59 struct satops;
60 
61 struct satmgr_softc {
62 	device_t		sc_dev;
63 	bus_space_tag_t		sc_iot;
64 	bus_space_handle_t	sc_ioh;
65 	struct selinfo		sc_rsel;
66 	callout_t		sc_ch_wdog;
67 	callout_t		sc_ch_pbutton;
68 	callout_t		sc_ch_sync;
69 	struct sysmon_pswitch	sc_sm_pbutton;
70 	int			sc_open;
71 	void			*sc_si;
72 	uint32_t		sc_ierror, sc_overr;
73 	kmutex_t		sc_lock;
74 	kcondvar_t		sc_rdcv, sc_wrcv;
75 	char			sc_rd_buf[16];
76 	char			*sc_rd_lim, *sc_rd_cur, *sc_rd_ptr;
77 	char			sc_wr_buf[16];
78 	char			*sc_wr_lim, *sc_wr_cur, *sc_wr_ptr;
79 	int			sc_rd_cnt, sc_wr_cnt;
80 	struct satops		*sc_ops;
81 	char			sc_btn_buf[8];
82 	int			sc_btn_cnt;
83 	char			sc_cmd_buf[8];
84 	kmutex_t		sc_replk;
85 	kcondvar_t		sc_repcv;
86 	int			sc_sysctl_wdog;
87 	int			sc_sysctl_fanlow;
88 	int			sc_sysctl_fanhigh;
89 };
90 
91 static int  satmgr_match(device_t, cfdata_t, void *);
92 static void satmgr_attach(device_t, device_t, void *);
93 
94 CFATTACH_DECL_NEW(satmgr, sizeof(struct satmgr_softc),
95     satmgr_match, satmgr_attach, NULL, NULL);
96 extern struct cfdriver satmgr_cd;
97 
98 static int found = 0;
99 extern void (*md_reboot)(int);
100 
101 static dev_type_open(satopen);
102 static dev_type_close(satclose);
103 static dev_type_read(satread);
104 static dev_type_write(satwrite);
105 static dev_type_poll(satpoll);
106 static dev_type_kqfilter(satkqfilter);
107 
108 const struct cdevsw satmgr_cdevsw = {
109 	.d_open = satopen,
110 	.d_close = satclose,
111 	.d_read = satread,
112 	.d_write = satwrite,
113 	.d_ioctl = noioctl,
114 	.d_stop = nostop,
115 	.d_tty = notty,
116 	.d_poll = satpoll,
117 	.d_mmap = nommap,
118 	.d_kqfilter = satkqfilter,
119 	.d_discard = nodiscard,
120 	.d_flag = D_OTHER
121 };
122 
123 static void satmgr_reboot(int);
124 static int satmgr_sysctl_wdogenable(SYSCTLFN_PROTO);
125 static int satmgr_sysctl_fanlow(SYSCTLFN_PROTO);
126 static int satmgr_sysctl_fanhigh(SYSCTLFN_PROTO);
127 static void wdog_tickle(void *);
128 static void send_sat(struct satmgr_softc *, const char *);
129 static void send_sat_len(struct satmgr_softc *, const char *, int);
130 static int hwintr(void *);
131 static void rxintr(struct satmgr_softc *);
132 static void txintr(struct satmgr_softc *);
133 static void startoutput(struct satmgr_softc *);
134 static void swintr(void *);
135 static void minit(device_t);
136 static void sinit(device_t);
137 static void qinit(device_t);
138 static void iinit(device_t);
139 static void kreboot(struct satmgr_softc *);
140 static void mreboot(struct satmgr_softc *);
141 static void sreboot(struct satmgr_softc *);
142 static void qreboot(struct satmgr_softc *);
143 static void ireboot(struct satmgr_softc *);
144 static void kpwroff(struct satmgr_softc *);
145 static void mpwroff(struct satmgr_softc *);
146 static void spwroff(struct satmgr_softc *);
147 static void qpwroff(struct satmgr_softc *);
148 static void dpwroff(struct satmgr_softc *);
149 static void ipwroff(struct satmgr_softc *);
150 static void kbutton(struct satmgr_softc *, int);
151 static void mbutton(struct satmgr_softc *, int);
152 static void sbutton(struct satmgr_softc *, int);
153 static void qbutton(struct satmgr_softc *, int);
154 static void dbutton(struct satmgr_softc *, int);
155 static void ibutton(struct satmgr_softc *, int);
156 static void msattalk(struct satmgr_softc *, const char *);
157 static void isattalk(struct satmgr_softc *, int, int, int, int, int, int);
158 static int  mbtnintr(void *);
159 static void guarded_pbutton(void *);
160 static void sched_sysmon_pbutton(void *);
161 
162 struct satops {
163 	const char *family;
164 	void (*init)(device_t);
165 	void (*reboot)(struct satmgr_softc *);
166 	void (*pwroff)(struct satmgr_softc *);
167 	void (*dispatch)(struct satmgr_softc *, int);
168 };
169 
170 static struct satops satmodel[] = {
171     { "dlink",    NULL,  NULL,    dpwroff, dbutton },
172     { "iomega",   iinit, ireboot, ipwroff, ibutton },
173     { "kurobox",  NULL,  kreboot, kpwroff, kbutton },
174     { "kurot4",   minit, mreboot, mpwroff, mbutton },
175     { "qnap",     qinit, qreboot, qpwroff, qbutton },
176     { "synology", sinit, sreboot, spwroff, sbutton }
177 };
178 
179 /* single byte stride register layout */
180 #define RBR		0
181 #define THR		0
182 #define DLB		0
183 #define IER		1
184 #define DMB		1
185 #define IIR		2
186 #define LCR		3
187 #define LSR		5
188 #define CSR_READ(t,r)	bus_space_read_1((t)->sc_iot, (t)->sc_ioh, (r))
189 #define CSR_WRITE(t,r,v) bus_space_write_1((t)->sc_iot, (t)->sc_ioh, (r), (v))
190 
191 static int
satmgr_match(device_t parent,cfdata_t match,void * aux)192 satmgr_match(device_t parent, cfdata_t match, void *aux)
193 {
194 	struct eumb_attach_args *eaa = aux;
195 	int unit = eaa->eumb_unit;
196 
197 	if (unit == EUMBCF_UNIT_DEFAULT && found == 0)
198 		return 1;
199 	if (unit == 0 || unit == 1)
200 		return 1;
201 	return 0;
202 }
203 
204 static void
satmgr_attach(device_t parent,device_t self,void * aux)205 satmgr_attach(device_t parent, device_t self, void *aux)
206 {
207 	struct eumb_attach_args *eaa = aux;
208 	struct satmgr_softc *sc = device_private(self);
209 	struct btinfo_prodfamily *pfam;
210 	struct satops *ops;
211 	int i, sataddr, epicirq;
212 	char intr_xname[INTRDEVNAMEBUF];
213 
214 	found = 1;
215 
216 	if ((pfam = lookup_bootinfo(BTINFO_PRODFAMILY)) == NULL)
217 		goto notavail;
218 	ops = NULL;
219 	for (i = 0; i < (int)(sizeof(satmodel)/sizeof(satmodel[0])); i++) {
220 		if (strcmp(pfam->name, satmodel[i].family) == 0) {
221 			ops = &satmodel[i];
222 			break;
223 		}
224 	}
225 	if (ops == NULL)
226 		goto notavail;
227 	aprint_naive(": button manager\n");
228 	aprint_normal(": button manager (%s)\n", ops->family);
229 	sc->sc_ops = ops;
230 
231 	sc->sc_dev = self;
232 	sataddr = (eaa->eumb_unit == 0) ? 0x4500 : 0x4600;
233 	sc->sc_iot = eaa->eumb_bt;
234 	bus_space_map(eaa->eumb_bt, sataddr, 0x20, 0, &sc->sc_ioh);
235 	sc->sc_open = 0;
236 	sc->sc_rd_cnt = 0;
237 	sc->sc_rd_cur = sc->sc_rd_ptr = &sc->sc_rd_buf[0];
238 	sc->sc_rd_lim = sc->sc_rd_cur + sizeof(sc->sc_rd_buf);
239 	sc->sc_wr_cnt = 0;
240 	sc->sc_wr_cur = sc->sc_wr_ptr = &sc->sc_wr_buf[0];
241 	sc->sc_wr_lim = sc->sc_wr_cur + sizeof(sc->sc_wr_buf);
242 	sc->sc_ierror = sc->sc_overr = 0;
243 	selinit(&sc->sc_rsel);
244 	callout_init(&sc->sc_ch_wdog, 0);
245 	callout_init(&sc->sc_ch_pbutton, 0);
246 	callout_init(&sc->sc_ch_sync, 0);
247 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH);
248 	cv_init(&sc->sc_rdcv, "satrd");
249 	cv_init(&sc->sc_wrcv, "satwr");
250 	sc->sc_btn_cnt = 0;
251 	mutex_init(&sc->sc_replk, MUTEX_DEFAULT, IPL_SERIAL);
252 	cv_init(&sc->sc_repcv, "stalk");
253 
254 	epicirq = (eaa->eumb_unit == 0) ? 24 : 25;
255 	intr_establish_xname(epicirq + I8259_ICU, IST_LEVEL, IPL_SERIAL,
256 	    hwintr, sc, device_xname(self));
257 	aprint_normal_dev(self, "interrupting at irq %d\n",
258 	    epicirq + I8259_ICU);
259 	sc->sc_si = softint_establish(SOFTINT_SERIAL, swintr, sc);
260 
261 	CSR_WRITE(sc, IER, 0x7f); /* all but MSR */
262 
263 	if (!pmf_device_register(sc->sc_dev, NULL, NULL))
264 		aprint_error_dev(sc->sc_dev, "couldn't establish handler\n");
265 
266 	sysmon_task_queue_init();
267 	memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch));
268 	sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev);
269 	sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
270 	if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
271 		aprint_error_dev(sc->sc_dev,
272 		    "unable to register power button with sysmon\n");
273 
274 	/* create machdep.satmgr subtree for those models which support it */
275 	if (strcmp(ops->family, "kurobox") == 0) {
276 		const struct sysctlnode *rnode;
277 		struct sysctllog *clog;
278 
279 		clog = NULL;
280 		sysctl_createv(&clog, 0, NULL, &rnode,
281 			CTLFLAG_PERMANENT,
282 			CTLTYPE_NODE, "machdep", NULL,
283 			NULL, 0, NULL, 0,
284 			CTL_MACHDEP, CTL_EOL);
285 		sysctl_createv(&clog, 0, &rnode, &rnode,
286 			CTLFLAG_PERMANENT,
287 			CTLTYPE_NODE, "satmgr", NULL,
288 			NULL, 0, NULL, 0,
289 			CTL_CREATE, CTL_EOL);
290 		sysctl_createv(&clog, 0, &rnode, NULL,
291 			CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
292 			CTLTYPE_INT, "hwwdog_enable",
293 			SYSCTL_DESCR("watchdog enable"),
294 			satmgr_sysctl_wdogenable, 0, NULL, 0,
295 			CTL_CREATE, CTL_EOL);
296 	}
297 	else if (strcmp(ops->family, "iomega") == 0) {
298 		const struct sysctlnode *rnode;
299 		struct sysctllog *clog;
300 
301 		clog = NULL;
302 		sysctl_createv(&clog, 0, NULL, &rnode,
303 			CTLFLAG_PERMANENT,
304 			CTLTYPE_NODE, "machdep", NULL,
305 			NULL, 0, NULL, 0,
306 			CTL_MACHDEP, CTL_EOL);
307 		sysctl_createv(&clog, 0, &rnode, &rnode,
308 			CTLFLAG_PERMANENT,
309 			CTLTYPE_NODE, "satmgr", NULL,
310 			NULL, 0, NULL, 0,
311 			CTL_CREATE, CTL_EOL);
312 		sysctl_createv(&clog, 0, &rnode, NULL,
313 			CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
314 			CTLTYPE_INT, "fan_low_temp",
315 			SYSCTL_DESCR("Turn off fan below this temperature"),
316 			satmgr_sysctl_fanlow, 0, NULL, 0,
317 			CTL_CREATE, CTL_EOL);
318 		sysctl_createv(&clog, 0, &rnode, NULL,
319 			CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
320 			CTLTYPE_INT, "fan_high_temp",
321 			SYSCTL_DESCR("Turn on fan above this temperature"),
322 			satmgr_sysctl_fanhigh, 0, NULL, 0,
323 			CTL_CREATE, CTL_EOL);
324 	}
325 	else if (strcmp(ops->family, "kurot4") == 0) {
326 		snprintf(intr_xname, sizeof(intr_xname), "%s mbtn",
327 		    device_xname(self));
328 		intr_establish_xname(2 + I8259_ICU,
329 			IST_LEVEL, IPL_SERIAL, mbtnintr, sc, intr_xname);
330 	}
331 
332 	md_reboot = satmgr_reboot;	/* cpu_reboot() hook */
333 	if (ops->init != NULL)		/* init sat.cpu, LEDs, etc. */
334 		config_interrupts(self, ops->init);
335 	return;
336 
337   notavail:
338 	aprint_normal(": button manager (not supported)\n");
339 }
340 
341 static void
satmgr_reboot(int howto)342 satmgr_reboot(int howto)
343 {
344 	struct satmgr_softc *sc = device_lookup_private(&satmgr_cd, 0);
345 
346 	if ((howto & RB_POWERDOWN) == RB_AUTOBOOT) {
347 		if (sc->sc_ops->reboot != NULL)
348 			(*sc->sc_ops->reboot)(sc);	/* REBOOT */
349 		else
350 			return;				/* default reboot */
351 	} else
352 		if (sc->sc_ops->pwroff != NULL)
353 			(*sc->sc_ops->pwroff)(sc);	/* HALT or POWERDOWN */
354 
355 	tsleep(satmgr_reboot, PWAIT, "reboot", 0);
356 	/*NOTREACHED*/
357 }
358 
359 static int
satmgr_sysctl_wdogenable(SYSCTLFN_ARGS)360 satmgr_sysctl_wdogenable(SYSCTLFN_ARGS)
361 {
362 	struct sysctlnode node;
363 	struct satmgr_softc *sc;
364 	int error, t;
365 
366 	sc = device_lookup_private(&satmgr_cd, 0);
367 	node = *rnode;
368 	t = sc->sc_sysctl_wdog;
369 	node.sysctl_data = &t;
370 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
371 	if (error || newp == NULL)
372 		return error;
373 	if (t < 0 || t > 1)
374 		return EINVAL;
375 
376 	sc->sc_sysctl_wdog = t;
377 	if (t == 1) {
378 		callout_setfunc(&sc->sc_ch_wdog, wdog_tickle, sc);
379 		callout_schedule(&sc->sc_ch_wdog, 90 * hz);
380 		send_sat(sc, "JJ");
381 	} else {
382 		callout_stop(&sc->sc_ch_wdog);
383 		send_sat(sc, "KK");
384 	}
385 	return 0;
386 }
387 
388 /* disarm watchdog timer periodically */
389 static void
wdog_tickle(void * arg)390 wdog_tickle(void *arg)
391 {
392 	struct satmgr_softc *sc = arg;
393 
394 	send_sat(sc, "GG");
395 	callout_schedule(&sc->sc_ch_wdog, 90 * hz);
396 }
397 
398 static int
satmgr_sysctl_fanlow(SYSCTLFN_ARGS)399 satmgr_sysctl_fanlow(SYSCTLFN_ARGS)
400 {
401 	struct sysctlnode node;
402 	struct satmgr_softc *sc;
403 	int error, t;
404 
405 	sc = device_lookup_private(&satmgr_cd, 0);
406 	node = *rnode;
407 	t = sc->sc_sysctl_fanlow;
408 	node.sysctl_data = &t;
409 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
410 	if (error || newp == NULL)
411 		return error;
412 	if (t < 0 || t > 99)
413 		return EINVAL;
414 	sc->sc_sysctl_fanlow = t;
415 	isattalk(sc, 'b', 'b', 10, 'a',
416 	    sc->sc_sysctl_fanhigh, sc->sc_sysctl_fanlow);
417 	return 0;
418 }
419 
420 static int
satmgr_sysctl_fanhigh(SYSCTLFN_ARGS)421 satmgr_sysctl_fanhigh(SYSCTLFN_ARGS)
422 {
423 	struct sysctlnode node;
424 	struct satmgr_softc *sc;
425 	int error, t;
426 
427 	sc = device_lookup_private(&satmgr_cd, 0);
428 	node = *rnode;
429 	t = sc->sc_sysctl_fanhigh;
430 	node.sysctl_data = &t;
431 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
432 	if (error || newp == NULL)
433 		return error;
434 	if (t < 0 || t > 99)
435 		return EINVAL;
436 	sc->sc_sysctl_fanhigh = t;
437 	isattalk(sc, 'b', 'b', 10, 'a',
438 	    sc->sc_sysctl_fanhigh, sc->sc_sysctl_fanlow);
439 	return 0;
440 }
441 
442 static void
send_sat(struct satmgr_softc * sc,const char * msg)443 send_sat(struct satmgr_softc *sc, const char *msg)
444 {
445 
446 	send_sat_len(sc, msg, strlen(msg));
447 }
448 
449 
450 static void
send_sat_len(struct satmgr_softc * sc,const char * msg,int len)451 send_sat_len(struct satmgr_softc *sc, const char *msg, int len)
452 {
453 	unsigned lsr;
454 	int n;
455 
456  again:
457 	do {
458 		lsr = CSR_READ(sc, LSR);
459 	} while ((lsr & LSR_TXRDY) == 0);
460 	n = 16; /* FIFO depth */
461 	while (len-- > 0 && n-- > 0)
462 		CSR_WRITE(sc, THR, *msg++);
463 	if (len > 0)
464 		goto again;
465 }
466 
467 static int
satopen(dev_t dev,int flags,int fmt,struct lwp * l)468 satopen(dev_t dev, int flags, int fmt, struct lwp *l)
469 {
470 	struct satmgr_softc *sc;
471 
472 	sc = device_lookup_private(&satmgr_cd, 0);
473 	if (sc == NULL)
474 		return ENXIO;
475 	if (sc->sc_open > 0)
476 		return EBUSY;
477 	sc->sc_open = 1;
478 	return 0;
479 }
480 
481 static int
satclose(dev_t dev,int flags,int fmt,struct lwp * l)482 satclose(dev_t dev, int flags, int fmt, struct lwp *l)
483 {
484 	struct satmgr_softc *sc;
485 
486 	sc = device_lookup_private(&satmgr_cd, 0);
487 	if (sc == NULL)
488 		return ENXIO;
489 	KASSERT(sc->sc_open > 0);
490 	sc->sc_open = 0;
491 	return 0;
492 }
493 
494 static int
satread(dev_t dev,struct uio * uio,int flags)495 satread(dev_t dev, struct uio *uio, int flags)
496 {
497 	struct satmgr_softc *sc;
498 	size_t n;
499 	int error;
500 
501 	sc = device_lookup_private(&satmgr_cd, 0);
502 	if (sc == NULL)
503 		return ENXIO;
504 
505 	mutex_enter(&sc->sc_lock);
506 	if (sc->sc_rd_cnt == 0 && (flags & IO_NDELAY)) {
507 		error = EWOULDBLOCK;
508 		goto out;
509 	}
510 	error = 0;
511 	while (sc->sc_rd_cnt == 0) {
512 		error = cv_wait_sig(&sc->sc_rdcv, &sc->sc_lock);
513 		if (error)
514 			goto out;
515 	}
516 	while (uio->uio_resid > 0 && sc->sc_rd_cnt > 0) {
517 		n = uimin(sc->sc_rd_cnt, uio->uio_resid);
518 		n = uimin(n, sc->sc_rd_lim - sc->sc_rd_ptr);
519 		error = uiomove(sc->sc_rd_ptr, n, uio);
520 		if (error)
521 			goto out;
522 		sc->sc_rd_cnt -= n;
523 		sc->sc_rd_ptr += n;
524 		if (sc->sc_rd_ptr == sc->sc_rd_lim)
525 			sc->sc_rd_ptr = &sc->sc_rd_buf[0];
526 	}
527  out:
528 	mutex_exit(&sc->sc_lock);
529 	return error;
530 }
531 
532 static int
satwrite(dev_t dev,struct uio * uio,int flags)533 satwrite(dev_t dev, struct uio *uio, int flags)
534 {
535 	struct satmgr_softc *sc;
536 	int error;
537 	size_t n;
538 
539 	sc = device_lookup_private(&satmgr_cd, 0);
540 	if (sc == NULL)
541 		return ENXIO;
542 
543 	mutex_enter(&sc->sc_lock);
544 	if (sc->sc_wr_cnt == sizeof(sc->sc_wr_buf) && (flags & IO_NDELAY)) {
545 		error = EWOULDBLOCK;
546 		goto out;
547 	}
548 	error = 0;
549 	while (sc->sc_wr_cnt == sizeof(sc->sc_wr_buf)) {
550 		error = cv_wait_sig(&sc->sc_wrcv, &sc->sc_lock);
551 		if (error)
552 			goto out;
553 	}
554 	while (uio->uio_resid > 0 && sc->sc_wr_cnt < sizeof(sc->sc_wr_buf)) {
555 		n = uimin(uio->uio_resid, sizeof(sc->sc_wr_buf));
556 		n = uimin(n, sc->sc_wr_lim - sc->sc_wr_cur);
557 		error = uiomove(sc->sc_wr_cur, n, uio);
558 		if (error)
559 			goto out;
560 		sc->sc_wr_cnt += n;
561 		sc->sc_wr_cur += n;
562 		if (sc->sc_wr_cur == sc->sc_wr_lim)
563 			sc->sc_wr_cur = &sc->sc_wr_buf[0];
564 	}
565 	startoutput(sc); /* start xmit */
566  out:
567 	mutex_exit(&sc->sc_lock);
568 	return error;
569 }
570 
571 static int
satpoll(dev_t dev,int events,struct lwp * l)572 satpoll(dev_t dev, int events, struct lwp *l)
573 {
574 	struct satmgr_softc *sc;
575 	int revents = 0;
576 
577 	sc = device_lookup_private(&satmgr_cd, 0);
578 	mutex_enter(&sc->sc_lock);
579 	if (events & (POLLIN | POLLRDNORM)) {
580 		if (sc->sc_rd_cnt)
581 			revents |= events & (POLLIN | POLLRDNORM);
582 		else
583 			selrecord(l, &sc->sc_rsel);
584 	}
585 	mutex_exit(&sc->sc_lock);
586 
587 	return revents;
588 }
589 
590 static void
filt_rdetach(struct knote * kn)591 filt_rdetach(struct knote *kn)
592 {
593 	struct satmgr_softc *sc = kn->kn_hook;
594 
595 	mutex_enter(&sc->sc_lock);
596 	selremove_knote(&sc->sc_rsel, kn);
597 	mutex_exit(&sc->sc_lock);
598 }
599 
600 static int
filt_read(struct knote * kn,long hint)601 filt_read(struct knote *kn, long hint)
602 {
603 	struct satmgr_softc *sc = kn->kn_hook;
604 
605 	kn->kn_data = sc->sc_rd_cnt;
606 	return (kn->kn_data > 0);
607 }
608 
609 static const struct filterops read_filtops ={
610 	.f_flags = FILTEROP_ISFD,
611 	.f_attach = NULL,
612 	.f_detach = filt_rdetach,
613 	.f_event = filt_read,
614 };
615 
616 static int
satkqfilter(dev_t dev,struct knote * kn)617 satkqfilter(dev_t dev, struct knote *kn)
618 {
619 	struct satmgr_softc *sc = device_lookup_private(&satmgr_cd, 0);
620 
621 	switch (kn->kn_filter) {
622 	case EVFILT_READ:
623 		kn->kn_fop = &read_filtops;
624 		break;
625 
626 	default:
627 		return EINVAL;
628 	}
629 
630 	kn->kn_hook = sc;
631 
632 	mutex_enter(&sc->sc_lock);
633 	selrecord_knote(&sc->sc_rsel, kn);
634 	mutex_exit(&sc->sc_lock);
635 
636 	return 0;
637 }
638 
639 static int
hwintr(void * arg)640 hwintr(void *arg)
641 {
642 	struct satmgr_softc *sc = arg;
643 	int iir;
644 
645 	mutex_spin_enter(&sc->sc_lock);
646 	iir = CSR_READ(sc, IIR) & IIR_IMASK;
647 	if (iir == IIR_NOPEND) {
648 		mutex_spin_exit(&sc->sc_lock);
649 		return 0;
650 	}
651 	do {
652 		switch (iir) {
653 		case IIR_RLS:	/* LSR updated */
654 		case IIR_RXRDY: /* RxFIFO has been accumulated */
655 		case IIR_RXTOUT:/* receive timeout occurred */
656 			rxintr(sc);
657 			break;
658 		case IIR_TXRDY: /* TxFIFO is ready to swallow data */
659 			txintr(sc);
660 			break;
661 		case IIR_MLSC:	/* MSR updated */
662 			break;
663 		}
664 		iir = CSR_READ(sc, IIR) & IIR_IMASK;
665 	} while (iir != IIR_NOPEND);
666 	mutex_spin_exit(&sc->sc_lock);
667 	return 1;
668 }
669 
670 static void
rxintr(struct satmgr_softc * sc)671 rxintr(struct satmgr_softc *sc)
672 {
673 	int lsr, ch;
674 
675 	lsr = CSR_READ(sc, LSR);
676 	if (lsr & LSR_OE)
677 		sc->sc_overr++;
678 	ch = -1;
679 	while (lsr & LSR_RXRDY) {
680 		if (lsr & (LSR_BI | LSR_FE | LSR_PE)) {
681 			(void) CSR_READ(sc, RBR);
682 			sc->sc_ierror++;
683 			lsr = CSR_READ(sc, LSR);
684 			continue;
685 		}
686 		ch = CSR_READ(sc, RBR);
687 		if (sc->sc_rd_cnt < sizeof(sc->sc_rd_buf)) {
688 			*sc->sc_rd_cur = ch;
689 			if (++sc->sc_rd_cur == sc->sc_rd_lim)
690 				sc->sc_rd_cur = &sc->sc_rd_buf[0];
691 			sc->sc_rd_cnt += 1;
692 		}
693 		lsr = CSR_READ(sc, LSR);
694 	}
695 	if (ch != -1)
696 		softint_schedule(sc->sc_si);
697 }
698 
699 static void
txintr(struct satmgr_softc * sc)700 txintr(struct satmgr_softc *sc)
701 {
702 
703 	cv_signal(&sc->sc_wrcv);
704 	startoutput(sc);
705 }
706 
707 static void
startoutput(struct satmgr_softc * sc)708 startoutput(struct satmgr_softc *sc)
709 {
710 	int n;
711 
712 	mutex_enter(&sc->sc_replk);
713 	n = uimin(sc->sc_wr_cnt, 16);
714 	while (n-- > 0) {
715 		CSR_WRITE(sc, THR, *sc->sc_wr_ptr);
716 		if (++sc->sc_wr_ptr == sc->sc_wr_lim)
717 			sc->sc_wr_ptr = &sc->sc_wr_buf[0];
718 		sc->sc_wr_cnt -= 1;
719 	}
720 	mutex_exit(&sc->sc_replk);
721 }
722 
723 static void
swintr(void * arg)724 swintr(void *arg)
725 {
726 	struct satmgr_softc *sc = arg;
727 	char *ptr;
728 	int n;
729 
730 	/* we're now in softint(9) context */
731 	mutex_spin_enter(&sc->sc_lock);
732 	ptr = sc->sc_rd_ptr;
733 	for (n = 0; n < sc->sc_rd_cnt; n++) {
734 		(*sc->sc_ops->dispatch)(sc, *ptr);
735 		if (++ptr == sc->sc_rd_lim)
736 			ptr = &sc->sc_rd_buf[0];
737 	}
738 	if (sc->sc_open == 0) {
739 		sc->sc_rd_cnt = 0;
740 		sc->sc_rd_ptr = ptr;
741 		mutex_spin_exit(&sc->sc_lock);
742 		return;		/* drop characters down to the floor */
743 	}
744 	cv_signal(&sc->sc_rdcv);
745 	selnotify(&sc->sc_rsel, 0, 0);
746 	mutex_spin_exit(&sc->sc_lock);
747 }
748 
749 static void
kreboot(struct satmgr_softc * sc)750 kreboot(struct satmgr_softc *sc)
751 {
752 
753 	send_sat(sc, "CCGG"); /* perform reboot */
754 }
755 
756 static void
kpwroff(struct satmgr_softc * sc)757 kpwroff(struct satmgr_softc *sc)
758 {
759 
760 	send_sat(sc, "EEGG"); /* force power off */
761 }
762 
763 static void
kbutton(struct satmgr_softc * sc,int ch)764 kbutton(struct satmgr_softc *sc, int ch)
765 {
766 
767 	switch (ch) {
768 	case '!':
769 		/* schedule 3 second poweroff guard time */
770 		if (callout_pending(&sc->sc_ch_pbutton) == true)
771 			callout_stop(&sc->sc_ch_pbutton);
772 		callout_reset(&sc->sc_ch_pbutton,
773 		     3 * hz, guarded_pbutton, sc);
774 		break;
775 	case ' ':
776 		if (callout_expired(&sc->sc_ch_pbutton) == false)
777 			callout_stop(&sc->sc_ch_pbutton);
778 		else
779 			/* should never come here */;
780 		break;
781 	case '#':
782 	case '"':
783 		break;
784 	}
785 }
786 
787 static void
sinit(device_t self)788 sinit(device_t self)
789 {
790 	struct satmgr_softc *sc = device_private(self);
791 
792 	send_sat(sc, "8");	/* status LED green */
793 }
794 
795 static void
sreboot(struct satmgr_softc * sc)796 sreboot(struct satmgr_softc *sc)
797 {
798 
799 	send_sat(sc, "C");
800 }
801 
802 static void
spwroff(struct satmgr_softc * sc)803 spwroff(struct satmgr_softc *sc)
804 {
805 
806 	send_sat(sc, "1");
807 }
808 
809 static void
sbutton(struct satmgr_softc * sc,int ch)810 sbutton(struct satmgr_softc *sc, int ch)
811 {
812 
813 	switch (ch) {
814 	case '0':
815 		/* notified after 5 seconds guard time */
816 		sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
817 		break;
818 	case 'a':
819 	case '`':
820 		break;
821 	}
822 }
823 
824 static void
qinit(device_t self)825 qinit(device_t self)
826 {
827 	struct satmgr_softc *sc = device_private(self);
828 
829 	send_sat(sc, "V");	/* status LED green */
830 }
831 
832 static void
qreboot(struct satmgr_softc * sc)833 qreboot(struct satmgr_softc *sc)
834 {
835 
836 	send_sat(sc, "Pf");	/* beep and reboot */
837 }
838 
839 static void
qpwroff(struct satmgr_softc * sc)840 qpwroff(struct satmgr_softc *sc)
841 {
842 
843 	send_sat(sc, "PA");	/* beep and power off */
844 }
845 
846 static void
qbutton(struct satmgr_softc * sc,int ch)847 qbutton(struct satmgr_softc *sc, int ch)
848 {
849 
850 	switch (ch) {
851 	case '@':
852 		/* power button, notified after 2 seconds guard time */
853 		sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
854 		break;
855 	case 'j':	/* reset to default button */
856 	case 'h':	/* USB copy button */
857 		break;
858 	}
859 }
860 
861 static void
dpwroff(struct satmgr_softc * sc)862 dpwroff(struct satmgr_softc *sc)
863 {
864 
865 	send_sat(sc, "ZWC\n");
866 
867 	/*
868 	 * When this line is reached, then this board revision doesn't
869 	 * support hardware-shutdown, so we flash the power LED
870 	 * to indicate that the device can be switched off.
871 	 */
872 	send_sat(sc, "SYN\nSYN\n");
873 
874 	/* drops into default power-off handling (looping forever) */
875 }
876 
877 static void
dbutton(struct satmgr_softc * sc,int ch)878 dbutton(struct satmgr_softc *sc, int ch)
879 {
880 
881 	if (sc->sc_btn_cnt < sizeof(sc->sc_btn_buf))
882 		sc->sc_btn_buf[sc->sc_btn_cnt++] = ch;
883 	if (ch == '\n' || ch == '\r') {
884 		if (memcmp(sc->sc_btn_buf, "PKO", 3) == 0) {
885 			/* notified after 5 seconds guard time */
886 			sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
887 		}
888 		sc->sc_btn_cnt = 0;
889 	}
890 }
891 
892 static void
iinit(device_t self)893 iinit(device_t self)
894 {
895 	struct satmgr_softc *sc = device_private(self);
896 
897 	/* LED blue, auto-fan, turn on at 50C, turn off at 45C */
898 	sc->sc_sysctl_fanhigh = 50;
899 	sc->sc_sysctl_fanlow = 45;
900 	isattalk(sc, 'b', 'b', 10, 'a',
901 	    sc->sc_sysctl_fanhigh, sc->sc_sysctl_fanlow);
902 }
903 
904 static void
ireboot(struct satmgr_softc * sc)905 ireboot(struct satmgr_softc *sc)
906 {
907 
908 	isattalk(sc, 'g', 0, 0, 0, 0, 0);
909 }
910 
911 static void
ipwroff(struct satmgr_softc * sc)912 ipwroff(struct satmgr_softc *sc)
913 {
914 
915 	isattalk(sc, 'c', 0, 0, 0, 0, 0);
916 }
917 
918 static void
ibutton(struct satmgr_softc * sc,int ch)919 ibutton(struct satmgr_softc *sc, int ch)
920 {
921 
922 	mutex_enter(&sc->sc_replk);
923 	if (++sc->sc_btn_cnt >= 8) {
924 		cv_signal(&sc->sc_repcv);
925 		sc->sc_btn_cnt = 0;
926 	}
927 	mutex_exit(&sc->sc_replk);
928 }
929 
930 static void
isattalk(struct satmgr_softc * sc,int pow,int led,int rat,int fan,int fhi,int flo)931 isattalk(struct satmgr_softc *sc, int pow, int led, int rat, int fan,
932     int fhi, int flo)
933 {
934 	char *p = sc->sc_cmd_buf;
935 	int i, cksum;
936 
937 	/*
938 	 * Construct the command packet. Values of -1 (0xff) will be
939 	 * replaced later by the current values from the last status.
940 	 */
941 	p[0] = pow;
942 	p[1] = led;
943 	p[2] = rat;
944 	p[3] = fan;
945 	p[4] = fhi;
946 	p[5] = flo;
947 	p[6] = 7; /* host id */
948 	for (i = 0, cksum = 0; i < 7; i++)
949 		cksum += p[i];
950 	p[7] = cksum & 0x7f;
951 	send_sat_len(sc, p, 8);
952 
953 	mutex_enter(&sc->sc_replk);
954 	sc->sc_btn_cnt = 0;
955 	cv_wait(&sc->sc_repcv, &sc->sc_replk);
956 	mutex_exit(&sc->sc_replk);
957 }
958 
959 
960 static void
minit(device_t self)961 minit(device_t self)
962 {
963 	struct satmgr_softc *sc = device_private(self);
964 #if 0
965 	static char msg[35] = "\x20\x92NetBSD/sandpoint";
966 	int m, n;
967 
968 	m = strlen(osrelease);
969 	n = (16 - m) / 2;
970 	memset(&msg[18], ' ', 16);
971 	memcpy(&msg[18 + n], osrelease, m);
972 
973 	msattalk(sc, "\x00\x03");	/* boot has completed */
974 	msattalk(sc, msg);		/* NB banner at disp2 */
975 	msattalk(sc, "\x01\x32\x80");	/* select disp2 */
976 	msattalk(sc, "\x00\x27");	/* show disp2 */
977 #else
978 	msattalk(sc, "\x00\x03");	/* boot has completed */
979 #endif
980 }
981 
982 static void
mreboot(struct satmgr_softc * sc)983 mreboot(struct satmgr_softc *sc)
984 {
985 
986 	msattalk(sc, "\x01\x35\x00");	/* stop watchdog timer */
987 	msattalk(sc, "\x00\x0c");	/* shutdown in progress */
988 	msattalk(sc, "\x00\x03");	/* boot has completed */
989 	msattalk(sc, "\x00\x0e");	/* perform reboot */
990 }
991 
992 static void
mpwroff(struct satmgr_softc * sc)993 mpwroff(struct satmgr_softc *sc)
994 {
995 
996 	msattalk(sc, "\x01\x35\x00");	/* stop watchdog timer */
997 	msattalk(sc, "\x00\x0c");	/* shutdown in progress */
998 	msattalk(sc, "\x00\x03");	/* boot has completed */
999 	msattalk(sc, "\x00\x06");	/* force power off */
1000 }
1001 
1002 static void
msattalk(struct satmgr_softc * sc,const char * cmd)1003 msattalk(struct satmgr_softc *sc, const char *cmd)
1004 {
1005 	int len, i;
1006 	uint8_t pa;
1007 
1008 	if (cmd[0] != 0x80)
1009 		len = 2 + cmd[0]; /* cmd[0] is data portion length */
1010 	else
1011 		len = 2; /* read report */
1012 
1013 	for (i = 0, pa = 0; i < len; i++)
1014 		pa += cmd[i];
1015 	pa = 0 - pa; /* parity formula */
1016 
1017 	send_sat_len(sc, cmd, len);
1018 	send_sat_len(sc, &pa, 1);
1019 
1020 	mutex_enter(&sc->sc_replk);
1021 	sc->sc_btn_cnt = 0;
1022 	cv_wait(&sc->sc_repcv, &sc->sc_replk);
1023 	mutex_exit(&sc->sc_replk);
1024 }
1025 
1026 static void
mbutton(struct satmgr_softc * sc,int ch)1027 mbutton(struct satmgr_softc *sc, int ch)
1028 {
1029 
1030 	mutex_enter(&sc->sc_replk);
1031 	if (sc->sc_btn_cnt < 4) /* record the first four */
1032 		sc->sc_btn_buf[sc->sc_btn_cnt] = ch;
1033 	sc->sc_btn_cnt++;
1034 	if (sc->sc_btn_cnt == sc->sc_btn_buf[0] + 3) {
1035 		if (sc->sc_btn_buf[1] == 0x36 && (sc->sc_btn_buf[2]&01) == 0) {
1036 			/* power button pressed */
1037 			sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
1038 		}
1039 		else {
1040 			/* unblock the talker */
1041 			cv_signal(&sc->sc_repcv);
1042 		}
1043 		sc->sc_btn_cnt = 0;
1044 	}
1045 	mutex_exit(&sc->sc_replk);
1046 }
1047 
1048 static int
mbtnintr(void * arg)1049 mbtnintr(void *arg)
1050 {
1051 	/* notified after 3 seconds guard time */
1052 	struct satmgr_softc *sc = arg;
1053 
1054 	send_sat(sc, "\x80\x36\x4a"); /* query button state with parity */
1055 	mutex_enter(&sc->sc_replk);
1056 	sc->sc_btn_cnt = 0;
1057 	mutex_exit(&sc->sc_replk);
1058 	return 1;
1059 }
1060 
1061 static void
guarded_pbutton(void * arg)1062 guarded_pbutton(void *arg)
1063 {
1064 	struct satmgr_softc *sc = arg;
1065 
1066 	/* we're now in callout(9) context */
1067 	sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
1068 	send_sat(sc, "UU"); /* make front panel LED flashing */
1069 }
1070 
1071 static void
sched_sysmon_pbutton(void * arg)1072 sched_sysmon_pbutton(void *arg)
1073 {
1074 	struct satmgr_softc *sc = arg;
1075 
1076 	/* we're now in kthread(9) context */
1077 	sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED);
1078 }
1079