Module Name:    src
Committed By:   phx
Date:           Sat May 29 22:47:02 UTC 2010

Modified Files:
        src/sys/arch/sandpoint/conf: GENERIC.NAS KUROBOX files.sandpoint
        src/sys/arch/sandpoint/sandpoint: machdep.c
Added Files:
        src/sys/arch/sandpoint/sandpoint: satmgr.c

Log Message:
'satmgr' device for communicating with the satellite processor found on many
MPC824x-based systems. It registers the power button to sysmon and sets
a reboot/shutdown callback for cpu_reboot(). Other functions can be controlled
through /dev/satmgr.
Currently there is support for KuroBox and Synology, which will be extended
as soon more platforms have been reasearched.
This patch was submitted by Toru Nishimura.


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/sandpoint/conf/GENERIC.NAS
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/sandpoint/conf/KUROBOX
cvs rdiff -u -r1.25 -r1.26 src/sys/arch/sandpoint/conf/files.sandpoint
cvs rdiff -u -r1.50 -r1.51 src/sys/arch/sandpoint/sandpoint/machdep.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/sandpoint/sandpoint/satmgr.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/sandpoint/conf/GENERIC.NAS
diff -u src/sys/arch/sandpoint/conf/GENERIC.NAS:1.13 src/sys/arch/sandpoint/conf/GENERIC.NAS:1.14
--- src/sys/arch/sandpoint/conf/GENERIC.NAS:1.13	Mon May 17 22:52:17 2010
+++ src/sys/arch/sandpoint/conf/GENERIC.NAS	Sat May 29 22:47:02 2010
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC.NAS,v 1.13 2010/05/17 22:52:17 phx Exp $
+# $NetBSD: GENERIC.NAS,v 1.14 2010/05/29 22:47:02 phx Exp $
 #
 # machine description file for GENERIC.NAS
 # 
@@ -22,7 +22,7 @@
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"GENERIC.NAS-$Revision: 1.13 $"
+#ident 		"GENERIC.NAS-$Revision: 1.14 $"
 
 maxusers	32
 
@@ -160,7 +160,8 @@
 
 eumb*	at mainbus0
 com0	at eumb? unit 0			# console at 0x4500
-com1	at eumb? unit 1
+#com1	at eumb? unit 1
+satmgr0 at eumb? unit 1			# satmgr at 0x4600
 ociic*	at eumb?
 iic*	at ociic?
 rs5c372rtc* at iic? addr 0x32

Index: src/sys/arch/sandpoint/conf/KUROBOX
diff -u src/sys/arch/sandpoint/conf/KUROBOX:1.1 src/sys/arch/sandpoint/conf/KUROBOX:1.2
--- src/sys/arch/sandpoint/conf/KUROBOX:1.1	Mon May 17 22:52:17 2010
+++ src/sys/arch/sandpoint/conf/KUROBOX	Sat May 29 22:47:02 2010
@@ -1,4 +1,4 @@
-#	$NetBSD: KUROBOX,v 1.1 2010/05/17 22:52:17 phx Exp $
+#	$NetBSD: KUROBOX,v 1.2 2010/05/29 22:47:02 phx Exp $
 #
 # KuroBox/LinkStation support
 #
@@ -6,6 +6,7 @@
 include "arch/sandpoint/conf/GENERIC.NAS"
 
 no com0
-no com1
+no satmgr0
 com0	at eumb? unit 1			# console at 0x4600
-com1	at eumb? unit 0
+#com1	at eumb? unit 0
+satmgr0 at eumb? unit 0			# satmgr at 0x4500

Index: src/sys/arch/sandpoint/conf/files.sandpoint
diff -u src/sys/arch/sandpoint/conf/files.sandpoint:1.25 src/sys/arch/sandpoint/conf/files.sandpoint:1.26
--- src/sys/arch/sandpoint/conf/files.sandpoint:1.25	Wed Apr  9 01:56:19 2008
+++ src/sys/arch/sandpoint/conf/files.sandpoint	Sat May 29 22:47:02 2010
@@ -1,4 +1,4 @@
-#	$NetBSD: files.sandpoint,v 1.25 2008/04/09 01:56:19 nisimura Exp $
+#	$NetBSD: files.sandpoint,v 1.26 2010/05/29 22:47:02 phx Exp $
 #
 # Motorola's "SandPoint" evaluation board and multiplied descendents.
 #
@@ -94,14 +94,20 @@
 
 # Floppy disk controller
 device	fdc {drive = -1}: isadma
-file	dev/isa/fd.c			fdc needs-flag
+file	dev/isa/fd.c				fdc needs-flag
 
 attach	fdc at isa with fdc_isa
-file	dev/isa/fdc_isa.c		fdc_isa
+file	dev/isa/fdc_isa.c			fdc_isa
 
 device	fd: disk
 attach	fd at fdc
 
 include	"dev/usb/files.usb"
 
+device	satmgr: sysmon_power, sysmon_taskq
+attach	satmgr at eumb
+file	arch/sandpoint/sandpoint/satmgr.c	satmgr
+
 include "arch/powerpc/conf/majors.powerpc"
+
+device-major	satmgr		char 100	satmgr

Index: src/sys/arch/sandpoint/sandpoint/machdep.c
diff -u src/sys/arch/sandpoint/sandpoint/machdep.c:1.50 src/sys/arch/sandpoint/sandpoint/machdep.c:1.51
--- src/sys/arch/sandpoint/sandpoint/machdep.c:1.50	Thu May 20 19:27:25 2010
+++ src/sys/arch/sandpoint/sandpoint/machdep.c	Sat May 29 22:47:02 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: machdep.c,v 1.50 2010/05/20 19:27:25 phx Exp $	*/
+/*	$NetBSD: machdep.c,v 1.51 2010/05/29 22:47:02 phx Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.50 2010/05/20 19:27:25 phx Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.51 2010/05/29 22:47:02 phx Exp $");
 
 #include "opt_compat_netbsd.h"
 #include "opt_ddb.h"
@@ -98,14 +98,15 @@
 #include "ksyms.h"
 
 char bootinfo[BOOTINFO_MAXSIZE];
+void (*md_reboot)(int);
 
 void initppc(u_int, u_int, u_int, void *);
 void consinit(void);
 void sandpoint_bus_space_init(void);
 size_t mpc107memsize(void);
 
-#define	OFMEMREGIONS	32
-struct mem_region physmemr[OFMEMREGIONS], availmemr[OFMEMREGIONS];
+/* we support single chunk of memory */
+struct mem_region physmemr[2], availmemr[2];
 
 paddr_t avail_end;
 struct pic_ops *isa_pic = NULL;
@@ -142,8 +143,10 @@
 		memsize = mpc107memsize();
 	physmemr[0].start = 0;
 	physmemr[0].size = memsize;
+	physmemr[1].size = 0;
 	availmemr[0].start = (endkernel + PGOFSET) & ~PGOFSET;
 	availmemr[0].size = memsize - availmemr[0].start;
+	availmemr[1].size = 0;
 	avail_end = physmemr[0].start + physmemr[0].size; /* XXX */
 
 	clockinfo = lookup_bootinfo(BTINFO_CLOCK);
@@ -360,7 +363,7 @@
 	}	    
 	
 	/* Disable intr */
-	splhigh();	
+	/* splhigh(); */
 	
 	/* Do dump if requested */
 	if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
@@ -370,25 +373,21 @@
 
 	pmf_system_shutdown(boothowto);
 	 
-	if (howto & RB_HALT) {
+	if ((howto & RB_POWERDOWN) == RB_HALT) {
 		printf("\n");
 		printf("The operating system has halted.\n");
 		printf("Please press any key to reboot.\n\n");
 		cnpollc(1);	/* for proper keyboard command handling */
 		cngetc();  
 		cnpollc(0);
+		howto = RB_AUTOBOOT;
 	}
-    
-	printf("rebooting...\n\n");
 
-#if 1
-    {
-	/* XXX reboot scheme is target dependent XXX */
-	extern void jump_to_ppc_reset_entry(void);
-	jump_to_ppc_reset_entry();
-    }
-#endif
-	while (1);
+	if (md_reboot != NULL) {
+		(*md_reboot)(howto);
+		/* should not come here */
+	}
+	while (1) ; /* may practice PPC processor reset sequence here */
 }
 
 struct powerpc_bus_space sandpoint_io_space_tag = {

Added files:

Index: src/sys/arch/sandpoint/sandpoint/satmgr.c
diff -u /dev/null src/sys/arch/sandpoint/sandpoint/satmgr.c:1.1
--- /dev/null	Sat May 29 22:47:02 2010
+++ src/sys/arch/sandpoint/sandpoint/satmgr.c	Sat May 29 22:47:02 2010
@@ -0,0 +1,635 @@
+/* $NetBSD: satmgr.c,v 1.1 2010/05/29 22:47:02 phx Exp $ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>	
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/select.h>
+#include <sys/poll.h>
+#include <sys/callout.h>
+#include <sys/sysctl.h>
+#include <sys/reboot.h>
+#include <sys/intr.h>
+
+#include <dev/sysmon/sysmonvar.h>
+#include <dev/sysmon/sysmon_taskq.h>
+
+#include <dev/ic/comreg.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/bootinfo.h>
+
+#include <sandpoint/sandpoint/eumbvar.h>
+#include "locators.h"
+
+struct satmgr_softc {
+	device_t		sc_dev;
+	bus_space_tag_t		sc_iot;
+	bus_space_handle_t	sc_ioh;
+	kmutex_t		sc_lock;
+	struct selinfo		sc_rsel;
+	callout_t		sc_ch_wdog;
+	callout_t		sc_ch_pbutton;
+	struct sysmon_pswitch	sc_sm_pbutton;
+	int			sc_open;
+	void			*sc_si;
+	uint32_t		sc_ierror, sc_overr;
+	char sc_rd_buf[16], *sc_rd_lim, *sc_rd_cur, *sc_rd_ptr;
+	char sc_wr_buf[16], *sc_wr_lim, *sc_wr_cur, *sc_wr_ptr;
+	int sc_rd_cnt, sc_wr_cnt;
+};
+
+static int  satmgr_match(device_t, cfdata_t, void *);
+static void satmgr_attach(device_t, device_t, void *);
+
+CFATTACH_DECL_NEW(satmgr, sizeof(struct satmgr_softc),
+    satmgr_match, satmgr_attach, NULL, NULL);
+extern struct cfdriver satmgr_cd;
+
+static int found = 0;
+extern void (*md_reboot)(int);
+
+static dev_type_open(satopen);
+static dev_type_close(satclose);
+static dev_type_read(satread);
+static dev_type_write(satwrite);
+static dev_type_poll(satpoll);
+static dev_type_kqfilter(satkqfilter);
+
+const struct cdevsw satmgr_cdevsw = {
+	satopen, satclose, satread, satwrite, noioctl,
+	nostop, notty, satpoll, nommap, satkqfilter, D_OTHER
+};
+
+static void satmgr_reboot(int);
+static int satmgr_sysctl_wdogenable(SYSCTLFN_PROTO);
+static void wdog_tickle(void *);
+static void send_sat(struct satmgr_softc *, const char *);
+static int hwintr(void *);
+static void rxintr(struct satmgr_softc *);
+static void startoutput(struct satmgr_softc *);
+static void swintr(void *);
+static void kbutton(struct satmgr_softc *, int);
+static void sbutton(struct satmgr_softc *, int);
+static void qbutton(struct satmgr_softc *, int);
+static void guarded_pbutton(void *);
+static void sched_sysmon_pbutton(void *);
+
+struct satmsg {
+	const char *family;
+	const char *reboot, *poweroff;
+	void (*dispatch)(struct satmgr_softc *, int);
+};
+
+const struct satmsg satmodel[] = {
+    { "kurobox",  "CCGG", "EEGG", kbutton },
+    { "synology", "C",    "1",    sbutton },
+    { "qnap",     "f",    "A",    qbutton }
+} *satmgr_msg;
+
+/* single byte stride register layout */
+#define RBR		0
+#define THR		0
+#define DLB		0
+#define IER		1
+#define DMB		1
+#define IIR		2
+#define LCR		3
+#define LSR		5
+#define CSR_READ(t,r)	bus_space_read_1((t)->sc_iot, (t)->sc_ioh, (r))
+#define CSR_WRITE(t,r,v) bus_space_write_1((t)->sc_iot, (t)->sc_ioh, (r), (v))
+
+static int satmgr_wdog;
+
+static int
+satmgr_match(device_t parent, cfdata_t match, void *aux)
+{
+	struct eumb_attach_args *eaa = aux;
+	int unit = eaa->eumb_unit;
+
+	if (unit == EUMBCF_UNIT_DEFAULT && found == 0)
+		return (1);
+	if (unit == 0 || unit == 1)
+		return (1);
+	return (0);
+}
+
+static void
+satmgr_attach(device_t parent, device_t self, void *aux)
+{
+	struct eumb_attach_args *eaa = aux;
+	struct satmgr_softc *sc = device_private(self);
+	struct btinfo_prodfamily *pfam;
+	int i, sataddr, epicirq;
+
+	found = 1;
+	
+	if ((pfam = lookup_bootinfo(BTINFO_PRODFAMILY)) == NULL)
+		goto notavail;
+	satmgr_msg = NULL;
+	for (i = 0; i < (int)(sizeof(satmodel)/sizeof(satmodel[0])); i++) {
+		if (strcmp(pfam->name, satmodel[i].family) == 0) {
+			satmgr_msg = &satmodel[i];
+			break;
+		}
+	}
+	if (satmgr_msg == NULL)
+		goto notavail;
+	
+	aprint_normal(": button manager (%s)\n", satmgr_msg->family);
+
+	sc->sc_dev = self;
+	sataddr = (eaa->eumb_unit == 0) ? 0x4500 : 0x4600;
+	sc->sc_iot = eaa->eumb_bt;
+	bus_space_map(eaa->eumb_bt, sataddr, 0x20, 0, &sc->sc_ioh);
+	sc->sc_open = 0;
+	sc->sc_rd_cnt = 0;
+	sc->sc_rd_cur = sc->sc_rd_ptr = &sc->sc_rd_buf[0];
+	sc->sc_rd_lim = sc->sc_rd_cur + sizeof(sc->sc_rd_buf);
+	sc->sc_wr_cnt = 0;
+	sc->sc_wr_cur = sc->sc_wr_ptr = &sc->sc_wr_buf[0];
+	sc->sc_wr_lim = sc->sc_wr_cur + sizeof(sc->sc_wr_buf);
+	selinit(&sc->sc_rsel);
+	callout_init(&sc->sc_ch_wdog, 0);
+	callout_init(&sc->sc_ch_pbutton, 0);
+	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH);
+
+	epicirq = (eaa->eumb_unit == 0) ? 24 : 25;
+	intr_establish(epicirq + 16, IST_LEVEL, IPL_SERIAL, hwintr, sc);
+	sc->sc_si = softint_establish(SOFTINT_SERIAL, swintr, sc);
+
+	CSR_WRITE(sc, IER, 0x7f); /* all but MSR */
+
+	if (!pmf_device_register(sc->sc_dev, NULL, NULL))
+		aprint_error_dev(sc->sc_dev, "couldn't establish handler\n");
+
+	sysmon_task_queue_init();
+	memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch));
+	sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev);
+	sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
+	if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
+		aprint_error_dev(sc->sc_dev,
+		    "unable to register power button with sysmon\n");
+
+	if (strcmp(satmgr_msg->family, "kurobox") == 0) {
+		const struct sysctlnode *rnode;
+		struct sysctllog *clog;
+
+		/* create machdep.satmgr.* subtree */
+		clog = NULL;
+		sysctl_createv(&clog, 0, NULL, &rnode,
+			CTLFLAG_PERMANENT,
+			CTLTYPE_NODE, "machdep", NULL,
+			NULL, 0, NULL, 0,
+			CTL_MACHDEP, CTL_EOL);
+		sysctl_createv(&clog, 0, &rnode, &rnode,
+			CTLFLAG_PERMANENT,
+			CTLTYPE_NODE, "satmgr", NULL,
+			NULL, 0, NULL, 0,
+			CTL_CREATE, CTL_EOL);
+		sysctl_createv(&clog, 0, &rnode, NULL,
+			CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+			CTLTYPE_INT, "hwwdog_enable",
+			SYSCTL_DESCR("watchdog enable"),
+			satmgr_sysctl_wdogenable, 0, NULL, 0,
+			CTL_CREATE, CTL_EOL);
+	}
+
+	md_reboot = satmgr_reboot; /* cpu_reboot() hook */
+	return;
+
+  notavail:
+	aprint_normal(": button manager (not supported)\n");
+}
+
+static void
+satmgr_reboot(int howto)
+{
+	const char *msg;
+	struct satmgr_softc *sc = device_lookup_private(&satmgr_cd, 0);
+
+	if ((howto & RB_POWERDOWN) == RB_AUTOBOOT)
+		msg = satmgr_msg->reboot;	/* REBOOT */
+	else
+		msg = satmgr_msg->poweroff;	/* HALT or POWERDOWN */
+	send_sat(sc, msg);
+	tsleep(satmgr_reboot, PWAIT, "reboot", 0);
+	/*NOTREACHED*/
+}
+
+static int
+satmgr_sysctl_wdogenable(SYSCTLFN_ARGS)
+{
+	int error, t;
+	struct sysctlnode node;
+	struct satmgr_softc *sc;
+
+	node = *rnode;
+	t = satmgr_wdog;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	if (t < 0 || t > 1)
+		return EINVAL;
+
+	sc = device_lookup_private(&satmgr_cd, 0);
+	if (t == 1) {
+		callout_setfunc(&sc->sc_ch_wdog, wdog_tickle, sc);
+		callout_schedule(&sc->sc_ch_wdog, 90 * hz);
+		send_sat(sc, "JJ");
+	}
+	else {
+		callout_stop(&sc->sc_ch_wdog);
+		send_sat(sc, "KK");
+	}
+	return 0;
+}
+
+/* disarm watchdog timer periodically */
+static void
+wdog_tickle(void *arg)
+{
+	struct satmgr_softc *sc = arg;
+
+	send_sat(sc, "GG");
+	callout_schedule(&sc->sc_ch_wdog, 90 * hz);
+}
+
+static void
+send_sat(struct satmgr_softc *sc, const char *msg)
+{
+	unsigned lsr, ch, n;
+
+ again:
+	do {
+		lsr = CSR_READ(sc, LSR);
+	} while ((lsr & LSR_TXRDY) == 0);
+	n = 16; /* FIFO depth */
+	while ((ch = *msg++) != '\0' && n-- > 0) {
+		CSR_WRITE(sc, THR, ch);
+	}
+	if (ch != '\0')
+		goto again;
+}
+
+static int
+satopen(dev_t dev, int flags, int fmt, struct lwp *l)
+{
+	struct satmgr_softc *sc;
+
+	sc = device_lookup_private(&satmgr_cd, 0);
+	if (sc == NULL)
+		return ENXIO;
+	if (sc->sc_open > 0)
+		return EBUSY;
+	sc->sc_open = 1;
+	return 0;
+}
+
+static int
+satclose(dev_t dev, int flags, int fmt, struct lwp *l)
+{
+	struct satmgr_softc *sc;
+
+	sc = device_lookup_private(&satmgr_cd, 0);
+	if (sc == NULL)
+		return ENXIO;
+	KASSERT(sc->sc_open > 0);
+	sc->sc_open = 0;
+	return 0;
+}
+
+static int
+satread(dev_t dev, struct uio *uio, int flags)
+{
+	struct satmgr_softc *sc;
+	size_t n;
+	int error;
+
+	sc = device_lookup_private(&satmgr_cd, 0);
+	if (sc == NULL)
+		return ENXIO;
+
+	mutex_spin_enter(&sc->sc_lock);
+	if (sc->sc_rd_cnt == 0 && (flags & IO_NDELAY))
+		return EWOULDBLOCK;
+	error = 0;
+	while (sc->sc_rd_cnt == 0) {
+		error = tsleep(sc->sc_rd_buf, PZERO|PCATCH, "satrd", 0);
+		if (error)
+			goto out;
+	}
+	while (uio->uio_resid > 0 && sc->sc_rd_cnt > 0) {
+		n = min(sc->sc_rd_cnt, uio->uio_resid);
+		n = min(n, sc->sc_rd_lim - sc->sc_rd_ptr);
+		error = uiomove(sc->sc_rd_ptr, n, uio);
+		if (error)
+			goto out;
+		sc->sc_rd_cnt -= n;
+		sc->sc_rd_ptr += n;
+		if (sc->sc_rd_ptr == sc->sc_rd_lim)
+			sc->sc_rd_ptr = &sc->sc_rd_buf[0];
+	}
+ out:
+	mutex_spin_exit(&sc->sc_lock);
+	return error;
+}
+
+static int
+satwrite(dev_t dev, struct uio *uio, int flags)
+{
+	struct satmgr_softc *sc;
+	int error;
+	size_t n;
+
+	sc = device_lookup_private(&satmgr_cd, 0);
+	if (sc == NULL)
+		return ENXIO;
+
+	mutex_spin_enter(&sc->sc_lock);
+	if (sc->sc_wr_cnt == sizeof(sc->sc_wr_buf) && (flags & IO_NDELAY))
+		return EWOULDBLOCK;
+	error = 0;
+	while (sc->sc_wr_cnt == sizeof(sc->sc_wr_buf)) {
+		error = tsleep(sc->sc_wr_buf, PZERO|PCATCH, "satwr", 0);
+		if (error)
+			goto out;
+	}
+	while (uio->uio_resid > 0 && sc->sc_wr_cnt < sizeof(sc->sc_wr_buf)) {
+		n = min(uio->uio_resid, sizeof(sc->sc_wr_buf));
+		n = min(n, sc->sc_wr_lim - sc->sc_wr_cur);
+		error = uiomove(sc->sc_wr_cur, n, uio);
+		if (error)
+			goto out;
+		sc->sc_wr_cnt += n;
+		sc->sc_wr_cur += n;
+		if (sc->sc_wr_cur == sc->sc_wr_lim)
+			sc->sc_wr_cur = &sc->sc_wr_buf[0];
+	}
+	startoutput(sc); /* start xmit */
+ out:
+	mutex_spin_exit(&sc->sc_lock);
+	return error;
+}
+
+static int
+satpoll(dev_t dev, int events, struct lwp *l)
+{
+	struct satmgr_softc *sc;
+	int revents = 0;
+		
+	sc = device_lookup_private(&satmgr_cd, 0);
+	mutex_enter(&sc->sc_lock);
+	if (events & (POLLIN | POLLRDNORM)) {
+		if (sc->sc_rd_cnt)
+			revents |= events & (POLLIN | POLLRDNORM);
+		else
+			selrecord(l, &sc->sc_rsel);
+	}
+	mutex_exit(&sc->sc_lock);
+
+	return revents;
+}
+
+static void
+filt_rdetach(struct knote *kn)
+{
+	struct satmgr_softc *sc = kn->kn_hook;
+
+	mutex_enter(&sc->sc_lock);
+	SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
+	mutex_exit(&sc->sc_lock);
+}
+
+static int
+filt_read(struct knote *kn, long hint)
+{
+	struct satmgr_softc *sc = kn->kn_hook;
+
+	kn->kn_data = sc->sc_rd_cnt;
+	return (kn->kn_data > 0);
+}
+
+static const struct filterops read_filtops =
+	{ 1, NULL, filt_rdetach, filt_read };			
+
+int
+satkqfilter(dev_t dev, struct knote *kn)
+{
+	struct satmgr_softc *sc = device_lookup_private(&satmgr_cd, 0);
+	struct klist *klist;
+
+	switch (kn->kn_filter) {
+	case EVFILT_READ:
+		klist = &sc->sc_rsel.sel_klist;
+		kn->kn_fop = &read_filtops;
+		break;
+
+	default:
+		return (EINVAL);
+	}
+
+	kn->kn_hook = sc;
+
+	mutex_enter(&sc->sc_lock);
+	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+	mutex_exit(&sc->sc_lock);
+
+	return (0);
+}
+
+static int
+hwintr(void *arg)
+{
+	struct satmgr_softc *sc = arg;
+	int iir;
+
+	mutex_spin_enter(&sc->sc_lock);
+	iir = CSR_READ(sc, IIR) & IIR_IMASK;
+	if (iir == IIR_NOPEND) {
+		mutex_spin_exit(&sc->sc_lock);
+		return 0;
+	}
+	do {
+		switch (iir) {
+		case IIR_RLS:	/* LSR updated */
+		case IIR_RXRDY: /* RxFIFO has been accumulated */
+		case IIR_RXTOUT:/* receive timeout occurred */
+			rxintr(sc);
+			break;
+		case IIR_TXRDY: /* TxFIFO is ready to swallow data */
+			startoutput(sc);
+			break;
+		case IIR_MLSC:	/* MSR updated */
+			break;
+		}
+		iir = CSR_READ(sc, IIR) & IIR_IMASK;
+	} while (iir != IIR_NOPEND);
+	mutex_spin_exit(&sc->sc_lock);
+	return 1;
+}
+
+static void
+rxintr(struct satmgr_softc *sc)
+{
+	int lsr, ch;
+
+	lsr = CSR_READ(sc, LSR);
+	if (lsr & LSR_OE)
+		sc->sc_overr++;
+	ch = -1;
+	while (lsr & LSR_RXRDY) {
+		if (lsr & (LSR_BI | LSR_FE | LSR_PE)) {
+			(void) CSR_READ(sc, RBR);
+			sc->sc_ierror++;
+			lsr = CSR_READ(sc, LSR);
+			continue;
+		}
+		ch = CSR_READ(sc, RBR);
+		if (sc->sc_rd_cnt < sizeof(sc->sc_rd_buf)) {
+			*sc->sc_rd_cur = ch;
+			if (++sc->sc_rd_cur == sc->sc_rd_lim)
+				sc->sc_rd_cur = &sc->sc_rd_buf[0];
+			sc->sc_rd_cnt += 1;
+		}
+		lsr = CSR_READ(sc, LSR);
+	}
+	if (ch != -1)
+		softint_schedule(sc->sc_si);
+}
+
+static void
+startoutput(struct satmgr_softc *sc)
+{
+	int n, ch;
+
+	n = min(sc->sc_wr_cnt, 16);
+	while ((ch = *sc->sc_wr_ptr) && n-- > 0) {
+		CSR_WRITE(sc, THR, ch);
+		if (++sc->sc_wr_ptr == sc->sc_wr_lim)
+			sc->sc_wr_ptr = &sc->sc_wr_buf[0];
+		sc->sc_wr_cnt -= 1;
+	}
+}
+
+static void
+swintr(void *arg)
+{
+	struct satmgr_softc *sc = arg;
+	char *ptr;
+	int n;
+
+	/* we're now in softint(9) context */
+	ptr = sc->sc_rd_ptr;
+	for (n = 0; n < sc->sc_rd_cnt; n++) {
+		(*satmgr_msg->dispatch)(sc, *ptr);
+		if (++ptr == sc->sc_rd_lim)
+			ptr = &sc->sc_rd_buf[0];
+	}
+	if (sc->sc_open == 0) {
+		sc->sc_rd_cnt = 0;
+		sc->sc_rd_ptr = ptr;
+		return; /* drop characters down to floor */
+	}
+	wakeup(sc->sc_rd_buf);
+	selnotify(&sc->sc_rsel, 0, 0);
+}
+
+void
+kbutton(struct satmgr_softc *sc, int ch)
+{
+
+	switch (ch) {
+	case '!':
+		/* schedule 3 second poweroff guard time */
+		if (callout_pending(&sc->sc_ch_pbutton) == true)
+			callout_stop(&sc->sc_ch_pbutton);
+		callout_reset(&sc->sc_ch_pbutton,
+		     3 * hz, guarded_pbutton, sc);
+		break;
+	case ' ':
+		if (callout_expired(&sc->sc_ch_pbutton) == false)
+			callout_stop(&sc->sc_ch_pbutton);
+		else
+			/* should never come here */;
+		break;
+	case '#':
+	case '"':
+		break;
+	}
+}
+
+void
+sbutton(struct satmgr_softc *sc, int ch)
+{
+
+	switch (ch) {
+	case '0':
+		/* notified after 3 secord guard time */
+		sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
+		break;
+	case '?':
+	case '`':
+		break;
+	}
+}
+
+void
+qbutton(struct satmgr_softc *sc, int ch)
+{
+	/* research in progress */
+}
+
+static void
+guarded_pbutton(void *arg)
+{
+	struct satmgr_softc *sc = arg;
+
+	/* we're now in callout(9) context */
+	sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
+	send_sat(sc, "UU");
+}
+
+static void
+sched_sysmon_pbutton(void *arg)
+{
+	struct satmgr_softc *sc = arg;
+
+	/* we're now in kthread(9) context */
+	sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED);
+}

Reply via email to