Home | History | Annotate | Line # | Download | only in sandpoint
      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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    700 txintr(struct satmgr_softc *sc)
    701 {
    702 
    703 	cv_signal(&sc->sc_wrcv);
    704 	startoutput(sc);
    705 }
    706 
    707 static void
    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
    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
    750 kreboot(struct satmgr_softc *sc)
    751 {
    752 
    753 	send_sat(sc, "CCGG"); /* perform reboot */
    754 }
    755 
    756 static void
    757 kpwroff(struct satmgr_softc *sc)
    758 {
    759 
    760 	send_sat(sc, "EEGG"); /* force power off */
    761 }
    762 
    763 static void
    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
    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
    796 sreboot(struct satmgr_softc *sc)
    797 {
    798 
    799 	send_sat(sc, "C");
    800 }
    801 
    802 static void
    803 spwroff(struct satmgr_softc *sc)
    804 {
    805 
    806 	send_sat(sc, "1");
    807 }
    808 
    809 static void
    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
    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
    833 qreboot(struct satmgr_softc *sc)
    834 {
    835 
    836 	send_sat(sc, "Pf");	/* beep and reboot */
    837 }
    838 
    839 static void
    840 qpwroff(struct satmgr_softc *sc)
    841 {
    842 
    843 	send_sat(sc, "PA");	/* beep and power off */
    844 }
    845 
    846 static void
    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
    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
    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
    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
    905 ireboot(struct satmgr_softc *sc)
    906 {
    907 
    908 	isattalk(sc, 'g', 0, 0, 0, 0, 0);
    909 }
    910 
    911 static void
    912 ipwroff(struct satmgr_softc *sc)
    913 {
    914 
    915 	isattalk(sc, 'c', 0, 0, 0, 0, 0);
    916 }
    917 
    918 static void
    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
    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
    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
    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
    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
   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
   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
   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
   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
   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