5f7e80a834
NetBSD/emips port runs on Xilinx and Beecube FPGA systems and the Giano system simulator. eMIPS is a platform developed at Microsoft Research for researching reconfigurable computing. eMIPS allows dynamic loading and scheduling of application-specific circuits for the purpose of accelerating computations based on the current workload. NetBSD eMIPS support for NetBSD 4.x was written at Microsoft Research by Alessandro Forin and Neil Pittman. Microsoft Corporation has donated full copyright to The NetBSD Foundation. Platform support for eMIPS is the first part of Microsoft's contribution. The second part includes the hardware accelerator framework and will be proposed on tech-kern soon.
794 lines
16 KiB
C
794 lines
16 KiB
C
/* $NetBSD: dz_ebus.c,v 1.1 2011/01/26 01:18:50 pooka Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code was written by Alessandro Forin and Neil Pittman
|
|
* at Microsoft Research and contributed to The NetBSD Foundation
|
|
* by Microsoft Corporation.
|
|
*
|
|
* 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/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: dz_ebus.c,v 1.1 2011/01/26 01:18:50 pooka Exp $");
|
|
|
|
#include "opt_ddb.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/callout.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/tty.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/file.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/syslog.h>
|
|
#include <sys/device.h>
|
|
#include <sys/kauth.h>
|
|
|
|
#include <machine/bus.h>
|
|
#include <machine/emipsreg.h>
|
|
|
|
#include <dev/cons.h>
|
|
|
|
|
|
#include <emips/ebus/ebusvar.h>
|
|
#include <emips/emips/cons.h>
|
|
//#include <emips/emips/machdep.h>
|
|
|
|
#include "ioconf.h" /* for dz_cd */
|
|
|
|
#define DZ_C2I(c) ((c)<<3) /* convert controller # to index */
|
|
#define DZ_I2C(c) ((c)>>3) /* convert minor to controller # */
|
|
#define DZ_PORT(u) ((u)&07) /* extract the port # */
|
|
|
|
struct dz_softc {
|
|
struct device sc_dev; /* Autoconf blaha */
|
|
struct evcnt sc_rintrcnt; /* recevive interrupt counts */
|
|
struct evcnt sc_tintrcnt; /* transmit interrupt counts */
|
|
struct _Usart *sc_dr; /* reg pointers */
|
|
bus_space_tag_t sc_iot;
|
|
bus_space_handle_t sc_ioh;
|
|
int sc_consline; /* console line, or -1 */
|
|
int sc_rxint; /* Receive interrupt count XXX */
|
|
u_char sc_brk; /* Break asserted on some lines */
|
|
u_char sc_dsr; /* DSR set bits if no mdm ctrl */
|
|
struct dz_linestate {
|
|
struct dz_softc *dz_sc; /* backpointer to softc */
|
|
int dz_line; /* channel number */
|
|
struct tty * dz_tty; /* what we work on */
|
|
} sc_dz;
|
|
};
|
|
|
|
void dzrint(struct dz_softc *, uint32_t);
|
|
void dzxint(struct dz_softc *, uint32_t);
|
|
|
|
#ifndef TIOCM_BRK
|
|
#define TIOCM_BRK 0100000 /* no equivalent */
|
|
|
|
static void dzstart(struct tty *);
|
|
static int dzparam(struct tty *, struct termios *);
|
|
static unsigned dzmctl(struct dz_softc *sc, int line,
|
|
int bits, /* one of the TIOCM_xx */
|
|
int how); /* one of the DMSET/BIS.. */
|
|
|
|
#include <dev/dec/dzkbdvar.h>
|
|
#endif
|
|
|
|
dev_type_open(dzopen);
|
|
dev_type_close(dzclose);
|
|
dev_type_read(dzread);
|
|
dev_type_write(dzwrite);
|
|
dev_type_ioctl(dzioctl);
|
|
dev_type_stop(dzstop);
|
|
dev_type_tty(dztty);
|
|
dev_type_poll(dzpoll);
|
|
|
|
const struct cdevsw dz_cdevsw = {
|
|
dzopen, dzclose, dzread, dzwrite, dzioctl,
|
|
dzstop, dztty, dzpoll, nommap, ttykqfilter, D_TTY
|
|
};
|
|
|
|
int
|
|
dzopen(dev_t dev, int flag, int mode, struct lwp *l)
|
|
{
|
|
struct tty *tp;
|
|
int unit, line;
|
|
struct dz_softc *sc;
|
|
int s, error = 0;
|
|
|
|
unit = DZ_I2C(minor(dev));
|
|
line = DZ_PORT(minor(dev));
|
|
if (unit >= dz_cd.cd_ndevs || dz_cd.cd_devs[unit] == NULL)
|
|
return (ENXIO);
|
|
|
|
sc = (void *)dz_cd.cd_devs[unit];
|
|
|
|
if (line > 0) /* FIXME fo rmore than one line */
|
|
return ENXIO;
|
|
|
|
tp = sc->sc_dz.dz_tty;
|
|
if (tp == NULL)
|
|
return (ENODEV);
|
|
tp->t_oproc = dzstart;
|
|
tp->t_param = dzparam;
|
|
tp->t_dev = dev;
|
|
|
|
if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
|
|
return (EBUSY);
|
|
|
|
if ((tp->t_state & TS_ISOPEN) == 0) {
|
|
ttychars(tp);
|
|
if (tp->t_ispeed == 0) {
|
|
tp->t_iflag = TTYDEF_IFLAG;
|
|
tp->t_oflag = TTYDEF_OFLAG;
|
|
tp->t_cflag = TTYDEF_CFLAG;
|
|
tp->t_lflag = TTYDEF_LFLAG;
|
|
tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
|
|
}
|
|
(void) dzparam(tp, &tp->t_termios);
|
|
ttsetwater(tp);
|
|
}
|
|
/* we have no modem control but..*/
|
|
if (dzmctl(sc, line, TIOCM_DTR, DMBIS) & TIOCM_CD)
|
|
tp->t_state |= TS_CARR_ON;
|
|
s = spltty();
|
|
while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
|
|
!(tp->t_state & TS_CARR_ON)) {
|
|
tp->t_wopen++;
|
|
error = ttysleep(tp, &tp->t_rawcv, true, 0);
|
|
tp->t_wopen--;
|
|
if (error)
|
|
break;
|
|
}
|
|
(void) splx(s);
|
|
if (error)
|
|
return (error);
|
|
return ((*tp->t_linesw->l_open)(dev, tp));
|
|
}
|
|
int
|
|
dzclose(dev_t dev, int flag, int mode, struct lwp *l)
|
|
{
|
|
struct dz_softc *sc;
|
|
struct tty *tp;
|
|
int unit, line;
|
|
|
|
|
|
unit = DZ_I2C(minor(dev));
|
|
line = DZ_PORT(minor(dev));
|
|
sc = (void *)dz_cd.cd_devs[unit];
|
|
|
|
tp = sc->sc_dz.dz_tty;
|
|
|
|
(*tp->t_linesw->l_close)(tp, flag);
|
|
|
|
/* Make sure a BREAK state is not left enabled. */
|
|
(void) dzmctl(sc, line, TIOCM_BRK, DMBIC);
|
|
|
|
/* Do a hangup if so required. */
|
|
if ((tp->t_cflag & HUPCL) || tp->t_wopen || !(tp->t_state & TS_ISOPEN))
|
|
(void) dzmctl(sc, line, 0, DMSET);
|
|
|
|
return (ttyclose(tp));
|
|
}
|
|
int
|
|
dzread(dev_t dev, struct uio *uio, int flag)
|
|
{
|
|
struct tty *tp;
|
|
struct dz_softc *sc;
|
|
|
|
sc = (void *)dz_cd.cd_devs[DZ_I2C(minor(dev))];
|
|
|
|
tp = sc->sc_dz.dz_tty;
|
|
return ((*tp->t_linesw->l_read)(tp, uio, flag));
|
|
}
|
|
|
|
int
|
|
dzwrite(dev_t dev, struct uio *uio, int flag)
|
|
{
|
|
struct tty *tp;
|
|
struct dz_softc *sc;
|
|
|
|
sc = (void *)dz_cd.cd_devs[DZ_I2C(minor(dev))];
|
|
|
|
tp = sc->sc_dz.dz_tty;
|
|
return ((*tp->t_linesw->l_write)(tp, uio, flag));
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
dzioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
|
|
{
|
|
struct dz_softc *sc;
|
|
struct tty *tp;
|
|
int unit, line;
|
|
int error;
|
|
|
|
unit = DZ_I2C(minor(dev));
|
|
line = 0;
|
|
sc = (void *)dz_cd.cd_devs[unit];
|
|
tp = sc->sc_dz.dz_tty;
|
|
|
|
error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
|
|
if (error >= 0)
|
|
return (error);
|
|
|
|
error = ttioctl(tp, cmd, data, flag, l);
|
|
if (error >= 0)
|
|
return (error);
|
|
|
|
switch (cmd) {
|
|
|
|
case TIOCSBRK:
|
|
(void) dzmctl(sc, line, TIOCM_BRK, DMBIS);
|
|
break;
|
|
|
|
case TIOCCBRK:
|
|
(void) dzmctl(sc, line, TIOCM_BRK, DMBIC);
|
|
break;
|
|
|
|
case TIOCSDTR:
|
|
(void) dzmctl(sc, line, TIOCM_DTR, DMBIS);
|
|
break;
|
|
|
|
case TIOCCDTR:
|
|
(void) dzmctl(sc, line, TIOCM_DTR, DMBIC);
|
|
break;
|
|
|
|
case TIOCMSET:
|
|
(void) dzmctl(sc, line, *(int *)data, DMSET);
|
|
break;
|
|
|
|
case TIOCMBIS:
|
|
(void) dzmctl(sc, line, *(int *)data, DMBIS);
|
|
break;
|
|
|
|
case TIOCMBIC:
|
|
(void) dzmctl(sc, line, *(int *)data, DMBIC);
|
|
break;
|
|
|
|
case TIOCMGET:
|
|
*(int *)data = (dzmctl(sc, line, 0, DMGET) & ~TIOCM_BRK);
|
|
break;
|
|
|
|
default:
|
|
return (EPASSTHROUGH);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
dzstop(struct tty *tp, int flag)
|
|
{
|
|
if (tp->t_state & TS_BUSY)
|
|
if (!(tp->t_state & TS_TTSTOP))
|
|
tp->t_state |= TS_FLUSH;
|
|
}
|
|
|
|
struct tty *
|
|
dztty(dev_t dev)
|
|
{
|
|
struct dz_softc *sc = (void *)dz_cd.cd_devs[DZ_I2C(minor(dev))];
|
|
struct tty *tp = sc->sc_dz.dz_tty;
|
|
|
|
return (tp);
|
|
}
|
|
|
|
int
|
|
dzpoll( dev_t dev, int events, struct lwp *l)
|
|
{
|
|
struct tty *tp;
|
|
struct dz_softc *sc;
|
|
|
|
sc = (void *)dz_cd.cd_devs[DZ_I2C(minor(dev))];
|
|
|
|
tp = sc->sc_dz.dz_tty;
|
|
return ((*tp->t_linesw->l_poll)(tp, events, l));
|
|
}
|
|
|
|
void
|
|
dzstart(struct tty *tp)
|
|
{
|
|
struct dz_softc *sc;
|
|
struct clist *cl;
|
|
int unit, s;
|
|
|
|
unit = DZ_I2C(minor(tp->t_dev));
|
|
sc = (void *)dz_cd.cd_devs[unit];
|
|
|
|
s = spltty();
|
|
if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) {
|
|
splx(s);
|
|
return;
|
|
}
|
|
cl = &tp->t_outq;
|
|
ttypull(tp);
|
|
if (cl->c_cc == 0) {
|
|
splx(s);
|
|
return;
|
|
}
|
|
|
|
tp->t_state |= TS_BUSY;
|
|
|
|
/* was idle, get it started */
|
|
dzxint(sc,USI_TXRDY);
|
|
splx(s);
|
|
}
|
|
|
|
static int rclk = 25000000; /* BUGBUGBUGBUG */
|
|
|
|
static int
|
|
dzdivisor(int baudrate)
|
|
{
|
|
int act_baud, divisor, error;
|
|
|
|
if (baudrate <= 0)
|
|
return (0);
|
|
|
|
divisor = (rclk/8)/(baudrate);
|
|
divisor = (divisor/2) + (divisor&1);
|
|
|
|
if (divisor <= 0)
|
|
return (-1);
|
|
act_baud = rclk / (divisor * 16);
|
|
|
|
/* 10 times error in percent: */
|
|
error = ((act_baud - baudrate) * 2000 / baudrate + 1) >> 1;
|
|
|
|
/* 3.0% maximum error tolerance: */
|
|
if (error < -30 || error > 30)
|
|
return (-1);
|
|
|
|
return (divisor);
|
|
}
|
|
|
|
static int
|
|
dzparam(struct tty *tp, struct termios *t)
|
|
{
|
|
struct dz_softc *sc;
|
|
int cflag = t->c_cflag;
|
|
int unit, line;
|
|
int speed;
|
|
unsigned lpr;
|
|
int s;
|
|
struct _Usart *dzr;
|
|
|
|
unit = DZ_I2C(minor(tp->t_dev));
|
|
line = DZ_PORT(minor(tp->t_dev));
|
|
sc = (void *)dz_cd.cd_devs[unit];
|
|
|
|
/* check requested parameters */
|
|
if (t->c_ispeed != t->c_ospeed)
|
|
return (EINVAL);
|
|
speed = dzdivisor(t->c_ispeed);
|
|
if (speed < 0)
|
|
return (EINVAL);
|
|
|
|
tp->t_ispeed = t->c_ispeed;
|
|
tp->t_ospeed = t->c_ospeed;
|
|
tp->t_cflag = cflag;
|
|
|
|
{ static int didit=0;
|
|
if (!didit && t->c_ispeed != 38400)
|
|
printf("dzparam: c_ispeed %d ignored, keeping 38400\n",t->c_ispeed);
|
|
didit = 1;
|
|
}
|
|
speed = dzdivisor(38400);
|
|
|
|
if (speed == 0) {
|
|
(void) dzmctl(sc, line, 0, DMSET); /* hang up line */
|
|
return (0);
|
|
}
|
|
|
|
switch (cflag & CSIZE)
|
|
{
|
|
case CS5:
|
|
lpr = USC_BPC_5;
|
|
break;
|
|
case CS6:
|
|
lpr = USC_BPC_6;
|
|
break;
|
|
case CS7:
|
|
lpr = USC_BPC_7;
|
|
break;
|
|
default:
|
|
lpr = USC_BPC_8;
|
|
break;
|
|
}
|
|
if (cflag & CSTOPB)
|
|
lpr |= USC_2STOP;
|
|
|
|
if (cflag & PARENB) {
|
|
if (cflag & PARODD)
|
|
lpr |= USC_ODD;
|
|
else
|
|
lpr |= USC_EVEN;
|
|
} else
|
|
lpr |= USC_NONE;
|
|
|
|
s = spltty();
|
|
|
|
dzr = sc->sc_dr;
|
|
|
|
dzr->Baud = speed;
|
|
dzr->Control = USC_CLKDIV_4 | USC_TXEN | USC_RXEN | lpr;
|
|
#define USI_INTRS (USI_RXRDY|USI_RXBRK|USI_OVRE|USI_FRAME|USI_PARE)
|
|
dzr->IntrEnable = USI_INTRS;
|
|
|
|
(void) splx(s);
|
|
return (0);
|
|
}
|
|
|
|
static unsigned
|
|
dzmctl(struct dz_softc *sc, int line, int bits, int how)
|
|
{
|
|
unsigned mbits;
|
|
int s;
|
|
struct _Usart *dzr;
|
|
|
|
mbits = 0;
|
|
|
|
s = spltty();
|
|
|
|
dzr = sc->sc_dr;
|
|
|
|
/* we have no modem control bits (CD,RI,DTR,DSR,..) */
|
|
mbits |= TIOCM_CD;
|
|
mbits |= TIOCM_DTR;
|
|
|
|
if (dzr->ChannelStatus & USI_RXBRK)
|
|
mbits |= TIOCM_BRK;
|
|
|
|
switch (how)
|
|
{
|
|
case DMSET:
|
|
mbits = bits;
|
|
break;
|
|
|
|
case DMBIS:
|
|
mbits |= bits;
|
|
break;
|
|
|
|
case DMBIC:
|
|
mbits &= ~bits;
|
|
break;
|
|
|
|
case DMGET:
|
|
(void) splx(s);
|
|
return (mbits);
|
|
}
|
|
|
|
/* BUGBUG work in progress */
|
|
if (mbits & TIOCM_BRK) {
|
|
sc->sc_brk |= (1 << line);
|
|
dzr->Control |= USC_STTBRK;
|
|
} else {
|
|
sc->sc_brk &= ~(1 << line);
|
|
dzr->Control |= USC_STPBRK;
|
|
}
|
|
|
|
(void) splx(s);
|
|
return (mbits);
|
|
}
|
|
|
|
|
|
#if defined(DDB)
|
|
int dz_ddb = 0;
|
|
#endif
|
|
|
|
/* Receiver Interrupt */
|
|
|
|
void
|
|
dzrint(struct dz_softc *sc, uint32_t csr)
|
|
{
|
|
struct tty *tp;
|
|
int cc, mcc;
|
|
struct _Usart *dzr;
|
|
|
|
sc->sc_rxint++;
|
|
dzr = sc->sc_dr;
|
|
|
|
cc = dzr->RxData;
|
|
tp = sc->sc_dz.dz_tty;
|
|
|
|
if (csr & USI_RXBRK)
|
|
mcc = CNC_BREAK;
|
|
else
|
|
mcc = cc;
|
|
|
|
/* clear errors before we print or bail out */
|
|
if (csr & (USI_OVRE|USI_FRAME|USI_PARE))
|
|
dzr->Control = USC_RSTSTA;
|
|
|
|
if (!(tp->t_state & TS_ISOPEN)) {
|
|
wakeup(&tp->t_rawq);
|
|
return;
|
|
}
|
|
|
|
if (csr & USI_OVRE) {
|
|
log(LOG_WARNING, "%s: silo overflow, line %d\n",
|
|
sc->sc_dev.dv_xname, 0);
|
|
}
|
|
|
|
if (csr & USI_FRAME)
|
|
cc |= TTY_FE;
|
|
if (csr & USI_PARE)
|
|
cc |= TTY_PE;
|
|
|
|
#if defined(DDB)
|
|
/* ^P drops into DDB */
|
|
if (dz_ddb && (cc == 0x10))
|
|
Debugger();
|
|
#endif
|
|
(*tp->t_linesw->l_rint)(cc, tp);
|
|
|
|
}
|
|
|
|
/* Transmitter Interrupt */
|
|
|
|
void
|
|
dzxint(struct dz_softc *sc, uint32_t csr)
|
|
{
|
|
struct tty *tp;
|
|
struct clist *cl;
|
|
int ch;
|
|
struct _Usart *dzr;
|
|
|
|
dzr = sc->sc_dr;
|
|
|
|
tp = sc->sc_dz.dz_tty;
|
|
cl = &tp->t_outq;
|
|
tp->t_state &= ~TS_BUSY;
|
|
|
|
/* Just send out a char if we have one */
|
|
if (cl->c_cc) {
|
|
tp->t_state |= TS_BUSY;
|
|
ch = getc(cl);
|
|
dzr->TxData = ch;
|
|
dzr->IntrEnable = USI_TXRDY;
|
|
return;
|
|
}
|
|
|
|
/* Nothing to send; turn off intr */
|
|
dzr->IntrDisable = USI_TXRDY;
|
|
|
|
if (tp->t_state & TS_FLUSH)
|
|
tp->t_state &= ~TS_FLUSH;
|
|
else
|
|
ndflush (&tp->t_outq, cl->c_cc);
|
|
|
|
(*tp->t_linesw->l_start)(tp);
|
|
}
|
|
|
|
/* Machdep part of the driver
|
|
*/
|
|
int dz_ebus_match(struct device *, struct cfdata *, void *);
|
|
void dz_ebus_attach(struct device *, struct device *, void *);
|
|
int dz_ebus_intr(void *, void *);
|
|
|
|
void dz_ebus_cnsetup(paddr_t);
|
|
void dz_ebus_cninit(struct consdev*);
|
|
int dz_ebus_cngetc(dev_t);
|
|
void dz_ebus_cnputc(dev_t, int);
|
|
void dz_ebus_cnpollc(dev_t, int);
|
|
|
|
static int dz_ebus_getmajor(void);
|
|
|
|
CFATTACH_DECL(dz_ebus, sizeof(struct dz_softc),
|
|
dz_ebus_match, dz_ebus_attach, NULL, NULL);
|
|
|
|
struct consdev dz_ebus_consdev = {
|
|
NULL, dz_ebus_cninit, dz_ebus_cngetc, dz_ebus_cnputc,
|
|
dz_ebus_cnpollc, NULL, NULL, NULL, NODEV, CN_NORMAL,
|
|
};
|
|
|
|
/* Points to the console regs. Special mapping until VM is turned on.
|
|
*/
|
|
struct _Usart *dzcn;
|
|
|
|
int
|
|
dz_ebus_match(struct device *parent, struct cfdata *cf, void *aux)
|
|
{
|
|
struct ebus_attach_args *iba;
|
|
struct _Usart *us;
|
|
|
|
iba = aux;
|
|
|
|
if (strcmp(iba->ia_name, "dz") != 0)
|
|
return (0);
|
|
|
|
us = (struct _Usart *)iba->ia_vaddr;
|
|
if ((us == NULL) ||
|
|
(us->Tag != PMTTAG_USART))
|
|
return (0);
|
|
|
|
return (1);
|
|
}
|
|
|
|
void
|
|
dz_ebus_attach(struct device *parent, struct device *self, void *aux)
|
|
{
|
|
struct ebus_attach_args *iba;
|
|
struct dz_softc *sc;
|
|
|
|
iba = aux;
|
|
sc = (struct dz_softc *)self;
|
|
|
|
sc->sc_dr = (struct _Usart *)iba->ia_vaddr;
|
|
#if DEBUG
|
|
printf(" virt=%p ", (void *)sc->sc_dr);
|
|
#endif
|
|
|
|
printf(": neilsart 1 line");
|
|
ebus_intr_establish(parent, (void *)iba->ia_cookie, IPL_TTY,
|
|
dz_ebus_intr, sc);
|
|
|
|
sc->sc_rxint = sc->sc_brk = 0;
|
|
sc->sc_consline = 0;
|
|
|
|
/* Initialize our softc structure. Should be done in open? */
|
|
|
|
sc->sc_dz.dz_sc = sc;
|
|
sc->sc_dz.dz_line = 0;
|
|
sc->sc_dz.dz_tty = ttymalloc();
|
|
|
|
evcnt_attach_dynamic(&sc->sc_rintrcnt, EVCNT_TYPE_INTR, NULL,
|
|
sc->sc_dev.dv_xname, "rintr");
|
|
evcnt_attach_dynamic(&sc->sc_tintrcnt, EVCNT_TYPE_INTR, NULL,
|
|
sc->sc_dev.dv_xname, "tintr");
|
|
|
|
/* Initialize hw regs */
|
|
#if 0
|
|
DZ_WRITE_WORD(dr_csr, DZ_CSR_MSE | DZ_CSR_RXIE | DZ_CSR_TXIE);
|
|
DZ_WRITE_BYTE(dr_dtr, 0);
|
|
DZ_WRITE_BYTE(dr_break, 0);
|
|
#endif
|
|
|
|
/* Switch the console to virtual mode */
|
|
dzcn = sc->sc_dr;
|
|
/* And test it */
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
static int
|
|
dz_ebus_getmajor(void)
|
|
{
|
|
extern const struct cdevsw dz_cdevsw;
|
|
static int cache = -1;
|
|
|
|
if (cache != -1)
|
|
return (cache);
|
|
|
|
return (cache = cdevsw_lookup_major(&dz_cdevsw));
|
|
}
|
|
|
|
int
|
|
dz_ebus_intr(void *cookie, void *f)
|
|
{
|
|
struct dz_softc *sc;
|
|
struct _Usart *dzr;
|
|
uint32_t csr;
|
|
|
|
sc = cookie;
|
|
dzr = sc->sc_dr;
|
|
|
|
#define USI_INTERRUPTS (USI_INTRS|USI_TXRDY)
|
|
|
|
for (; ((csr = (dzr->ChannelStatus & dzr->IntrMask)) & USI_INTERRUPTS) != 0;) {
|
|
if ((csr & USI_INTRS) != 0)
|
|
dzrint(sc, csr);
|
|
if ((csr & USI_TXRDY) != 0)
|
|
dzxint(sc, csr);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
dz_ebus_cnsetup(paddr_t addr)
|
|
{
|
|
|
|
dzcn = (struct _Usart *)addr;
|
|
|
|
#if 0
|
|
/* Initialize enough to xmit/recv via polling.
|
|
* Bootloader might or might not have done it.
|
|
*/
|
|
dzcn->Control = USC_RXEN|USC_TXEN|USC_BPC_8|USC_NONE|USC_1STOP|USC_CLKDIV_4;
|
|
dzcn->Baud = 0x29; /* 38400 */
|
|
#endif
|
|
|
|
/*
|
|
* Point the console at us
|
|
*/
|
|
cn_tab = &dz_ebus_consdev;
|
|
cn_tab->cn_pri = CN_NORMAL;/*CN_REMOTE?*/
|
|
cn_tab->cn_dev = makedev(dz_ebus_getmajor(), 0);
|
|
}
|
|
|
|
void dz_ebus_cninit(struct consdev *cn)
|
|
{
|
|
}
|
|
|
|
int
|
|
dz_ebus_cngetc(dev_t dev)
|
|
{
|
|
int c, s;
|
|
|
|
c = 0;
|
|
s = spltty();
|
|
|
|
while ((dzcn->ChannelStatus & USI_RXRDY) == 0)
|
|
DELAY(10);
|
|
c = dzcn->RxData;
|
|
|
|
splx(s);
|
|
if (c == 13) /* map cr->ln */
|
|
c = 10;
|
|
return (c);
|
|
}
|
|
|
|
int dzflipped = 0;
|
|
void
|
|
dz_ebus_cnputc(dev_t dev, int ch)
|
|
{
|
|
int timeout, s;
|
|
|
|
/* Don't hang the machine! */
|
|
timeout = 1 << 15;
|
|
|
|
s = spltty();
|
|
|
|
#if 1
|
|
/* Keep wired to hunt for a bug */
|
|
if (dzcn && (dzcn != (struct _Usart *)0xfff90000)) {
|
|
dzcn = (struct _Usart *)0xfff90000;
|
|
dzflipped++;
|
|
}
|
|
#endif
|
|
|
|
/* Wait until ready */
|
|
while ((dzcn->ChannelStatus & USI_TXRDY) == 0)
|
|
if (--timeout < 0)
|
|
break;
|
|
|
|
/* Put the character */
|
|
dzcn->TxData = ch;
|
|
|
|
splx(s);
|
|
}
|
|
|
|
/* Called before/after going into poll mode
|
|
*/
|
|
void
|
|
dz_ebus_cnpollc(dev_t dev, int on)
|
|
{
|
|
}
|
|
|