#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 <sys/bus.h>
#include <machine/intr.h>
#include <machine/bootinfo.h>
#include <sandpoint/sandpoint/eumbvar.h>
#include "locators.h"
struct satops;
struct satmgr_softc {
device_t sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
struct selinfo sc_rsel;
callout_t sc_ch_wdog;
callout_t sc_ch_pbutton;
callout_t sc_ch_sync;
struct sysmon_pswitch sc_sm_pbutton;
int sc_open;
void *sc_si;
uint32_t sc_ierror, sc_overr;
kmutex_t sc_lock;
kcondvar_t sc_rdcv, sc_wrcv;
char sc_rd_buf[16];
char *sc_rd_lim, *sc_rd_cur, *sc_rd_ptr;
char sc_wr_buf[16];
char *sc_wr_lim, *sc_wr_cur, *sc_wr_ptr;
int sc_rd_cnt, sc_wr_cnt;
struct satops *sc_ops;
char sc_btn_buf[8];
int sc_btn_cnt;
char sc_cmd_buf[8];
kmutex_t sc_replk;
kcondvar_t sc_repcv;
int sc_sysctl_wdog;
int sc_sysctl_fanlow;
int sc_sysctl_fanhigh;
};
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 = {
.d_open = satopen,
.d_close = satclose,
.d_read = satread,
.d_write = satwrite,
.d_ioctl = noioctl,
.d_stop = nostop,
.d_tty = notty,
.d_poll = satpoll,
.d_mmap = nommap,
.d_kqfilter = satkqfilter,
.d_discard = nodiscard,
.d_flag = D_OTHER
};
static void satmgr_reboot(int);
static int satmgr_sysctl_wdogenable(SYSCTLFN_PROTO);
static int satmgr_sysctl_fanlow(SYSCTLFN_PROTO);
static int satmgr_sysctl_fanhigh(SYSCTLFN_PROTO);
static void wdog_tickle(void *);
static void send_sat(struct satmgr_softc *, const char *);
static void send_sat_len(struct satmgr_softc *, const char *, int);
static int hwintr(void *);
static void rxintr(struct satmgr_softc *);
static void txintr(struct satmgr_softc *);
static void startoutput(struct satmgr_softc *);
static void swintr(void *);
static void minit(device_t);
static void sinit(device_t);
static void qinit(device_t);
static void iinit(device_t);
static void kreboot(struct satmgr_softc *);
static void mreboot(struct satmgr_softc *);
static void sreboot(struct satmgr_softc *);
static void qreboot(struct satmgr_softc *);
static void ireboot(struct satmgr_softc *);
static void kpwroff(struct satmgr_softc *);
static void mpwroff(struct satmgr_softc *);
static void spwroff(struct satmgr_softc *);
static void qpwroff(struct satmgr_softc *);
static void dpwroff(struct satmgr_softc *);
static void ipwroff(struct satmgr_softc *);
static void kbutton(struct satmgr_softc *, int);
static void mbutton(struct satmgr_softc *, int);
static void sbutton(struct satmgr_softc *, int);
static void qbutton(struct satmgr_softc *, int);
static void dbutton(struct satmgr_softc *, int);
static void ibutton(struct satmgr_softc *, int);
static void msattalk(struct satmgr_softc *, const char *);
static void isattalk(struct satmgr_softc *, int, int, int, int, int, int);
static int mbtnintr(void *);
static void guarded_pbutton(void *);
static void sched_sysmon_pbutton(void *);
struct satops {
const char *family;
void (*init)(device_t);
void (*reboot)(struct satmgr_softc *);
void (*pwroff)(struct satmgr_softc *);
void (*dispatch)(struct satmgr_softc *, int);
};
static struct satops satmodel[] = {
{ "dlink", NULL, NULL, dpwroff, dbutton },
{ "iomega", iinit, ireboot, ipwroff, ibutton },
{ "kurobox", NULL, kreboot, kpwroff, kbutton },
{ "kurot4", minit, mreboot, mpwroff, mbutton },
{ "qnap", qinit, qreboot, qpwroff, qbutton },
{ "synology", sinit, sreboot, spwroff, sbutton }
};
#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_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;
struct satops *ops;
int i, sataddr, epicirq;
char intr_xname[INTRDEVNAMEBUF];
found = 1;
if ((pfam = lookup_bootinfo(BTINFO_PRODFAMILY)) == NULL)
goto notavail;
ops = NULL;
for (i = 0; i < (int)(sizeof(satmodel)/sizeof(satmodel[0])); i++) {
if (strcmp(pfam->name, satmodel[i].family) == 0) {
ops = &satmodel[i];
break;
}
}
if (ops == NULL)
goto notavail;
aprint_naive(": button manager\n");
aprint_normal(": button manager (%s)\n", ops->family);
sc->sc_ops = ops;
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);
sc->sc_ierror = sc->sc_overr = 0;
selinit(&sc->sc_rsel);
callout_init(&sc->sc_ch_wdog, 0);
callout_init(&sc->sc_ch_pbutton, 0);
callout_init(&sc->sc_ch_sync, 0);
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH);
cv_init(&sc->sc_rdcv, "satrd");
cv_init(&sc->sc_wrcv, "satwr");
sc->sc_btn_cnt = 0;
mutex_init(&sc->sc_replk, MUTEX_DEFAULT, IPL_SERIAL);
cv_init(&sc->sc_repcv, "stalk");
epicirq = (eaa->eumb_unit == 0) ? 24 : 25;
intr_establish_xname(epicirq + I8259_ICU, IST_LEVEL, IPL_SERIAL,
hwintr, sc, device_xname(self));
aprint_normal_dev(self, "interrupting at irq %d\n",
epicirq + I8259_ICU);
sc->sc_si = softint_establish(SOFTINT_SERIAL, swintr, sc);
CSR_WRITE(sc, IER, 0x7f);
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(ops->family, "kurobox") == 0) {
const struct sysctlnode *rnode;
struct sysctllog *clog;
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);
}
else if (strcmp(ops->family, "iomega") == 0) {
const struct sysctlnode *rnode;
struct sysctllog *clog;
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, "fan_low_temp",
SYSCTL_DESCR("Turn off fan below this temperature"),
satmgr_sysctl_fanlow, 0, NULL, 0,
CTL_CREATE, CTL_EOL);
sysctl_createv(&clog, 0, &rnode, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "fan_high_temp",
SYSCTL_DESCR("Turn on fan above this temperature"),
satmgr_sysctl_fanhigh, 0, NULL, 0,
CTL_CREATE, CTL_EOL);
}
else if (strcmp(ops->family, "kurot4") == 0) {
snprintf(intr_xname, sizeof(intr_xname), "%s mbtn",
device_xname(self));
intr_establish_xname(2 + I8259_ICU,
IST_LEVEL, IPL_SERIAL, mbtnintr, sc, intr_xname);
}
md_reboot = satmgr_reboot;
if (ops->init != NULL)
config_interrupts(self, ops->init);
return;
notavail:
aprint_normal(": button manager (not supported)\n");
}
static void
satmgr_reboot(int howto)
{
struct satmgr_softc *sc = device_lookup_private(&satmgr_cd, 0);
if ((howto & RB_POWERDOWN) == RB_AUTOBOOT) {
if (sc->sc_ops->reboot != NULL)
(*sc->sc_ops->reboot)(sc);
else
return;
} else
if (sc->sc_ops->pwroff != NULL)
(*sc->sc_ops->pwroff)(sc);
tsleep(satmgr_reboot, PWAIT, "reboot", 0);
}
static int
satmgr_sysctl_wdogenable(SYSCTLFN_ARGS)
{
struct sysctlnode node;
struct satmgr_softc *sc;
int error, t;
sc = device_lookup_private(&satmgr_cd, 0);
node = *rnode;
t = sc->sc_sysctl_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->sc_sysctl_wdog = t;
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;
}
static void
wdog_tickle(void *arg)
{
struct satmgr_softc *sc = arg;
send_sat(sc, "GG");
callout_schedule(&sc->sc_ch_wdog, 90 * hz);
}
static int
satmgr_sysctl_fanlow(SYSCTLFN_ARGS)
{
struct sysctlnode node;
struct satmgr_softc *sc;
int error, t;
sc = device_lookup_private(&satmgr_cd, 0);
node = *rnode;
t = sc->sc_sysctl_fanlow;
node.sysctl_data = &t;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
if (error || newp == NULL)
return error;
if (t < 0 || t > 99)
return EINVAL;
sc->sc_sysctl_fanlow = t;
isattalk(sc, 'b', 'b', 10, 'a',
sc->sc_sysctl_fanhigh, sc->sc_sysctl_fanlow);
return 0;
}
static int
satmgr_sysctl_fanhigh(SYSCTLFN_ARGS)
{
struct sysctlnode node;
struct satmgr_softc *sc;
int error, t;
sc = device_lookup_private(&satmgr_cd, 0);
node = *rnode;
t = sc->sc_sysctl_fanhigh;
node.sysctl_data = &t;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
if (error || newp == NULL)
return error;
if (t < 0 || t > 99)
return EINVAL;
sc->sc_sysctl_fanhigh = t;
isattalk(sc, 'b', 'b', 10, 'a',
sc->sc_sysctl_fanhigh, sc->sc_sysctl_fanlow);
return 0;
}
static void
send_sat(struct satmgr_softc *sc, const char *msg)
{
send_sat_len(sc, msg, strlen(msg));
}
static void
send_sat_len(struct satmgr_softc *sc, const char *msg, int len)
{
unsigned lsr;
int n;
again:
do {
lsr = CSR_READ(sc, LSR);
} while ((lsr & LSR_TXRDY) == 0);
n = 16;
while (len-- > 0 && n-- > 0)
CSR_WRITE(sc, THR, *msg++);
if (len > 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_enter(&sc->sc_lock);
if (sc->sc_rd_cnt == 0 && (flags & IO_NDELAY)) {
error = EWOULDBLOCK;
goto out;
}
error = 0;
while (sc->sc_rd_cnt == 0) {
error = cv_wait_sig(&sc->sc_rdcv, &sc->sc_lock);
if (error)
goto out;
}
while (uio->uio_resid > 0 && sc->sc_rd_cnt > 0) {
n = uimin(sc->sc_rd_cnt, uio->uio_resid);
n = uimin(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_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_enter(&sc->sc_lock);
if (sc->sc_wr_cnt == sizeof(sc->sc_wr_buf) && (flags & IO_NDELAY)) {
error = EWOULDBLOCK;
goto out;
}
error = 0;
while (sc->sc_wr_cnt == sizeof(sc->sc_wr_buf)) {
error = cv_wait_sig(&sc->sc_wrcv, &sc->sc_lock);
if (error)
goto out;
}
while (uio->uio_resid > 0 && sc->sc_wr_cnt < sizeof(sc->sc_wr_buf)) {
n = uimin(uio->uio_resid, sizeof(sc->sc_wr_buf));
n = uimin(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);
out:
mutex_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);
selremove_knote(&sc->sc_rsel, kn);
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 ={
.f_flags = FILTEROP_ISFD,
.f_attach = NULL,
.f_detach = filt_rdetach,
.f_event = filt_read,
};
static int
satkqfilter(dev_t dev, struct knote *kn)
{
struct satmgr_softc *sc = device_lookup_private(&satmgr_cd, 0);
switch (kn->kn_filter) {
case EVFILT_READ:
kn->kn_fop = &read_filtops;
break;
default:
return EINVAL;
}
kn->kn_hook = sc;
mutex_enter(&sc->sc_lock);
selrecord_knote(&sc->sc_rsel, kn);
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:
case IIR_RXRDY:
case IIR_RXTOUT:
rxintr(sc);
break;
case IIR_TXRDY:
txintr(sc);
break;
case IIR_MLSC:
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
txintr(struct satmgr_softc *sc)
{
cv_signal(&sc->sc_wrcv);
startoutput(sc);
}
static void
startoutput(struct satmgr_softc *sc)
{
int n;
mutex_enter(&sc->sc_replk);
n = uimin(sc->sc_wr_cnt, 16);
while (n-- > 0) {
CSR_WRITE(sc, THR, *sc->sc_wr_ptr);
if (++sc->sc_wr_ptr == sc->sc_wr_lim)
sc->sc_wr_ptr = &sc->sc_wr_buf[0];
sc->sc_wr_cnt -= 1;
}
mutex_exit(&sc->sc_replk);
}
static void
swintr(void *arg)
{
struct satmgr_softc *sc = arg;
char *ptr;
int n;
mutex_spin_enter(&sc->sc_lock);
ptr = sc->sc_rd_ptr;
for (n = 0; n < sc->sc_rd_cnt; n++) {
(*sc->sc_ops->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;
mutex_spin_exit(&sc->sc_lock);
return;
}
cv_signal(&sc->sc_rdcv);
selnotify(&sc->sc_rsel, 0, 0);
mutex_spin_exit(&sc->sc_lock);
}
static void
kreboot(struct satmgr_softc *sc)
{
send_sat(sc, "CCGG");
}
static void
kpwroff(struct satmgr_softc *sc)
{
send_sat(sc, "EEGG");
}
static void
kbutton(struct satmgr_softc *sc, int ch)
{
switch (ch) {
case '!':
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
;
break;
case '#':
case '"':
break;
}
}
static void
sinit(device_t self)
{
struct satmgr_softc *sc = device_private(self);
send_sat(sc, "8");
}
static void
sreboot(struct satmgr_softc *sc)
{
send_sat(sc, "C");
}
static void
spwroff(struct satmgr_softc *sc)
{
send_sat(sc, "1");
}
static void
sbutton(struct satmgr_softc *sc, int ch)
{
switch (ch) {
case '0':
sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
break;
case 'a':
case '`':
break;
}
}
static void
qinit(device_t self)
{
struct satmgr_softc *sc = device_private(self);
send_sat(sc, "V");
}
static void
qreboot(struct satmgr_softc *sc)
{
send_sat(sc, "Pf");
}
static void
qpwroff(struct satmgr_softc *sc)
{
send_sat(sc, "PA");
}
static void
qbutton(struct satmgr_softc *sc, int ch)
{
switch (ch) {
case '@':
sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
break;
case 'j':
case 'h':
break;
}
}
static void
dpwroff(struct satmgr_softc *sc)
{
send_sat(sc, "ZWC\n");
send_sat(sc, "SYN\nSYN\n");
}
static void
dbutton(struct satmgr_softc *sc, int ch)
{
if (sc->sc_btn_cnt < sizeof(sc->sc_btn_buf))
sc->sc_btn_buf[sc->sc_btn_cnt++] = ch;
if (ch == '\n' || ch == '\r') {
if (memcmp(sc->sc_btn_buf, "PKO", 3) == 0) {
sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
}
sc->sc_btn_cnt = 0;
}
}
static void
iinit(device_t self)
{
struct satmgr_softc *sc = device_private(self);
sc->sc_sysctl_fanhigh = 50;
sc->sc_sysctl_fanlow = 45;
isattalk(sc, 'b', 'b', 10, 'a',
sc->sc_sysctl_fanhigh, sc->sc_sysctl_fanlow);
}
static void
ireboot(struct satmgr_softc *sc)
{
isattalk(sc, 'g', 0, 0, 0, 0, 0);
}
static void
ipwroff(struct satmgr_softc *sc)
{
isattalk(sc, 'c', 0, 0, 0, 0, 0);
}
static void
ibutton(struct satmgr_softc *sc, int ch)
{
mutex_enter(&sc->sc_replk);
if (++sc->sc_btn_cnt >= 8) {
cv_signal(&sc->sc_repcv);
sc->sc_btn_cnt = 0;
}
mutex_exit(&sc->sc_replk);
}
static void
isattalk(struct satmgr_softc *sc, int pow, int led, int rat, int fan,
int fhi, int flo)
{
char *p = sc->sc_cmd_buf;
int i, cksum;
p[0] = pow;
p[1] = led;
p[2] = rat;
p[3] = fan;
p[4] = fhi;
p[5] = flo;
p[6] = 7;
for (i = 0, cksum = 0; i < 7; i++)
cksum += p[i];
p[7] = cksum & 0x7f;
send_sat_len(sc, p, 8);
mutex_enter(&sc->sc_replk);
sc->sc_btn_cnt = 0;
cv_wait(&sc->sc_repcv, &sc->sc_replk);
mutex_exit(&sc->sc_replk);
}
static void
minit(device_t self)
{
struct satmgr_softc *sc = device_private(self);
#if 0
static char msg[35] = "\x20\x92NetBSD/sandpoint";
int m, n;
m = strlen(osrelease);
n = (16 - m) / 2;
memset(&msg[18], ' ', 16);
memcpy(&msg[18 + n], osrelease, m);
msattalk(sc, "\x00\x03");
msattalk(sc, msg);
msattalk(sc, "\x01\x32\x80");
msattalk(sc, "\x00\x27");
#else
msattalk(sc, "\x00\x03");
#endif
}
static void
mreboot(struct satmgr_softc *sc)
{
msattalk(sc, "\x01\x35\x00");
msattalk(sc, "\x00\x0c");
msattalk(sc, "\x00\x03");
msattalk(sc, "\x00\x0e");
}
static void
mpwroff(struct satmgr_softc *sc)
{
msattalk(sc, "\x01\x35\x00");
msattalk(sc, "\x00\x0c");
msattalk(sc, "\x00\x03");
msattalk(sc, "\x00\x06");
}
static void
msattalk(struct satmgr_softc *sc, const char *cmd)
{
int len, i;
uint8_t pa;
if (cmd[0] != 0x80)
len = 2 + cmd[0];
else
len = 2;
for (i = 0, pa = 0; i < len; i++)
pa += cmd[i];
pa = 0 - pa;
send_sat_len(sc, cmd, len);
send_sat_len(sc, &pa, 1);
mutex_enter(&sc->sc_replk);
sc->sc_btn_cnt = 0;
cv_wait(&sc->sc_repcv, &sc->sc_replk);
mutex_exit(&sc->sc_replk);
}
static void
mbutton(struct satmgr_softc *sc, int ch)
{
mutex_enter(&sc->sc_replk);
if (sc->sc_btn_cnt < 4)
sc->sc_btn_buf[sc->sc_btn_cnt] = ch;
sc->sc_btn_cnt++;
if (sc->sc_btn_cnt == sc->sc_btn_buf[0] + 3) {
if (sc->sc_btn_buf[1] == 0x36 && (sc->sc_btn_buf[2]&01) == 0) {
sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
}
else {
cv_signal(&sc->sc_repcv);
}
sc->sc_btn_cnt = 0;
}
mutex_exit(&sc->sc_replk);
}
static int
mbtnintr(void *arg)
{
struct satmgr_softc *sc = arg;
send_sat(sc, "\x80\x36\x4a");
mutex_enter(&sc->sc_replk);
sc->sc_btn_cnt = 0;
mutex_exit(&sc->sc_replk);
return 1;
}
static void
guarded_pbutton(void *arg)
{
struct satmgr_softc *sc = arg;
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;
sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED);
}