Use generic device/tty adaptation code.
New device names are "{tty|cua}A$(card)$(port)[.init|.lock]" Put a portname in the port structure if SI_DEBUG is defined to avoid need to inspect minor number to construct name.. Constify some strings. Remove duplicated DBG_ #defines.
This commit is contained in:
parent
24dcf06b45
commit
aefadae38e
630
sys/dev/si/si.c
630
sys/dev/si/si.c
@ -47,11 +47,7 @@ static const char si_copyright1[] = "@(#) Copyright (C) Specialix International
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#ifndef BURN_BRIDGES
|
||||
#if defined(COMPAT_43)
|
||||
#include <sys/ioctl_compat.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <sys/serial.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/fcntl.h>
|
||||
@ -92,37 +88,25 @@ static const char si_copyright1[] = "@(#) Copyright (C) Specialix International
|
||||
#define JET_INT_COUNT 100 /* max of 100 ints per second */
|
||||
#define RXINT_COUNT 1 /* one rxint per 10 milliseconds */
|
||||
|
||||
enum si_mctl { GET, SET, BIS, BIC };
|
||||
|
||||
static void si_command(struct si_port *, int, int);
|
||||
static int si_modem(struct si_port *, enum si_mctl, int);
|
||||
static void si_write_enable(struct si_port *, int);
|
||||
static int si_Sioctl(struct cdev *, u_long, caddr_t, int, struct thread *);
|
||||
static void si_start(struct tty *);
|
||||
static void si_stop(struct tty *, int);
|
||||
static timeout_t si_lstart;
|
||||
static void sihardclose(struct si_port *pp);
|
||||
|
||||
#ifdef SI_DEBUG
|
||||
static char *si_mctl2str(enum si_mctl cmd);
|
||||
#endif
|
||||
static t_break_t sibreak;
|
||||
static t_close_t siclose;
|
||||
static t_modem_t simodem;
|
||||
static t_open_t siopen;
|
||||
|
||||
static int siparam(struct tty *, struct termios *);
|
||||
|
||||
static void si_modem_state(struct si_port *pp, struct tty *tp, int hi_ip);
|
||||
static char * si_modulename(int host_type, int uart_type);
|
||||
|
||||
static d_open_t siopen;
|
||||
static d_close_t siclose;
|
||||
static d_write_t siwrite;
|
||||
static d_ioctl_t siioctl;
|
||||
|
||||
static struct cdevsw si_cdevsw = {
|
||||
static struct cdevsw si_Scdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_open = siopen,
|
||||
.d_close = siclose,
|
||||
.d_write = siwrite,
|
||||
.d_ioctl = siioctl,
|
||||
.d_ioctl = si_Sioctl,
|
||||
.d_name = "si",
|
||||
.d_flags = D_TTY | D_NEEDGIANT,
|
||||
};
|
||||
@ -197,7 +181,7 @@ static void si_poll(void *);
|
||||
* Array of adapter types and the corresponding RAM size. The order of
|
||||
* entries here MUST match the ordinal of the adapter type.
|
||||
*/
|
||||
static char *si_type[] = {
|
||||
static const char *si_type[] = {
|
||||
"EMPTY",
|
||||
"SIHOST",
|
||||
"SIMCA", /* FreeBSD does not support Microchannel */
|
||||
@ -255,6 +239,7 @@ siattach(device_t dev)
|
||||
int unit;
|
||||
struct si_softc *sc;
|
||||
struct si_port *pp;
|
||||
struct tty *tp;
|
||||
volatile struct si_channel *ccbp;
|
||||
volatile struct si_reg *regp;
|
||||
volatile caddr_t maddr;
|
||||
@ -553,17 +538,21 @@ try_next:
|
||||
|
||||
for (x = 0; x < nport; x++, pp++, ccbp++) {
|
||||
pp->sp_ccb = ccbp; /* save the address */
|
||||
pp->sp_tty = ttyalloc();
|
||||
pp->sp_pend = IDLE_CLOSE;
|
||||
pp->sp_state = 0; /* internal flag */
|
||||
pp->sp_iin.c_iflag = TTYDEF_IFLAG;
|
||||
pp->sp_iin.c_oflag = TTYDEF_OFLAG;
|
||||
pp->sp_iin.c_cflag = TTYDEF_CFLAG;
|
||||
pp->sp_iin.c_lflag = TTYDEF_LFLAG;
|
||||
termioschars(&pp->sp_iin);
|
||||
pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed =
|
||||
TTYDEF_SPEED;;
|
||||
pp->sp_iout = pp->sp_iin;
|
||||
#ifdef SI_DEBUG
|
||||
sprintf(pp->sp_name, "si%r%r", unit, x);
|
||||
#endif
|
||||
tp = pp->sp_tty = ttyalloc();
|
||||
tp->t_sc = pp;
|
||||
tp->t_break = sibreak;
|
||||
tp->t_close = siclose;
|
||||
tp->t_modem = simodem;
|
||||
tp->t_open = siopen;
|
||||
tp->t_oproc = si_start;
|
||||
tp->t_param = siparam;
|
||||
tp->t_stop = si_stop;
|
||||
ttycreate(tp, NULL, 0, MINOR_CALLOUT, "A%r%r", unit, x);
|
||||
}
|
||||
try_next2:
|
||||
if (modp->sm_next == 0) {
|
||||
@ -587,56 +576,13 @@ try_next2:
|
||||
done_chartimes = 1;
|
||||
}
|
||||
|
||||
/* path name devsw minor type uid gid perm*/
|
||||
for (x = 0; x < sc->sc_nport; x++) {
|
||||
/* sync with the manuals that start at 1 */
|
||||
y = x + 1 + unit * (1 << SI_CARDSHIFT);
|
||||
make_dev(&si_cdevsw, x, 0, 0, 0600, "ttyA%02d", y);
|
||||
make_dev(&si_cdevsw, x + 0x00080, 0, 0, 0600, "cuaA%02d", y);
|
||||
make_dev(&si_cdevsw, x + 0x10000, 0, 0, 0600, "ttyiA%02d", y);
|
||||
make_dev(&si_cdevsw, x + 0x10080, 0, 0, 0600, "cuaiA%02d", y);
|
||||
make_dev(&si_cdevsw, x + 0x20000, 0, 0, 0600, "ttylA%02d", y);
|
||||
make_dev(&si_cdevsw, x + 0x20080, 0, 0, 0600, "cualA%02d", y);
|
||||
}
|
||||
make_dev(&si_cdevsw, 0x40000, 0, 0, 0600, "si_control");
|
||||
make_dev(&si_Scdevsw, 0, 0, 0, 0600, "si_control");
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
siopen(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
siopen(struct tty *tp, struct cdev *dev)
|
||||
{
|
||||
int oldspl, error;
|
||||
int card, port;
|
||||
struct si_softc *sc;
|
||||
struct tty *tp;
|
||||
volatile struct si_channel *ccbp;
|
||||
struct si_port *pp;
|
||||
int mynor = minor(dev);
|
||||
|
||||
/* quickly let in /dev/si_control */
|
||||
if (IS_CONTROLDEV(mynor)) {
|
||||
if ((error = suser(td)))
|
||||
return(error);
|
||||
return(0);
|
||||
}
|
||||
|
||||
card = SI_CARD(mynor);
|
||||
sc = devclass_get_softc(si_devclass, card);
|
||||
if (sc == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
if (sc->sc_type == SIEMPTY) {
|
||||
DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n",
|
||||
card, sc->sc_typename));
|
||||
return(ENXIO);
|
||||
}
|
||||
|
||||
port = SI_PORT(mynor);
|
||||
if (port >= sc->sc_nport) {
|
||||
DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n",
|
||||
card, sc->sc_nport));
|
||||
return(ENXIO);
|
||||
}
|
||||
|
||||
#ifdef POLL
|
||||
/*
|
||||
@ -647,416 +593,33 @@ siopen(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
init_finished = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* initial/lock device */
|
||||
if (IS_STATE(mynor)) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
pp = sc->sc_ports + port;
|
||||
tp = pp->sp_tty; /* the "real" tty */
|
||||
dev->si_tty = tp;
|
||||
ccbp = pp->sp_ccb; /* Find control block */
|
||||
DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%s,%x,%x,%x)\n",
|
||||
devtoname(dev), flag, mode, td));
|
||||
|
||||
oldspl = spltty(); /* Keep others out */
|
||||
error = 0;
|
||||
|
||||
open_top:
|
||||
error = ttydtrwaitsleep(tp);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
|
||||
if (tp->t_state & TS_ISOPEN) {
|
||||
/*
|
||||
* The device is open, so everything has been initialised.
|
||||
* handle conflicts.
|
||||
*/
|
||||
if (IS_CALLOUT(mynor)) {
|
||||
if (!pp->sp_active_out) {
|
||||
error = EBUSY;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if (pp->sp_active_out) {
|
||||
if (flag & O_NONBLOCK) {
|
||||
error = EBUSY;
|
||||
goto out;
|
||||
}
|
||||
error = tsleep(&pp->sp_active_out,
|
||||
TTIPRI|PCATCH, "sibi", 0);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
goto open_top;
|
||||
}
|
||||
}
|
||||
if (tp->t_state & TS_XCLUDE &&
|
||||
suser(td)) {
|
||||
DPRINT((pp, DBG_OPEN|DBG_FAIL,
|
||||
"already open and EXCLUSIVE set\n"));
|
||||
error = EBUSY;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The device isn't open, so there are no conflicts.
|
||||
* Initialize it. Avoid sleep... :-)
|
||||
*/
|
||||
DPRINT((pp, DBG_OPEN, "first open\n"));
|
||||
tp->t_oproc = si_start;
|
||||
tp->t_stop = si_stop;
|
||||
tp->t_param = siparam;
|
||||
tp->t_dev = dev;
|
||||
tp->t_termios = mynor & SI_CALLOUT_MASK
|
||||
? pp->sp_iout : pp->sp_iin;
|
||||
|
||||
(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
|
||||
|
||||
++pp->sp_wopeners; /* in case of sleep in siparam */
|
||||
|
||||
error = siparam(tp, &tp->t_termios);
|
||||
|
||||
--pp->sp_wopeners;
|
||||
if (error != 0)
|
||||
goto out;
|
||||
/* XXX: we should goto_top if siparam slept */
|
||||
|
||||
/* set initial DCD state */
|
||||
pp->sp_last_hi_ip = ccbp->hi_ip;
|
||||
if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) {
|
||||
ttyld_modem(tp, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* whoops! we beat the close! */
|
||||
if (pp->sp_state & SS_CLOSING) {
|
||||
/* try and stop it from proceeding to bash the hardware */
|
||||
pp->sp_state &= ~SS_CLOSING;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for DCD if necessary
|
||||
*/
|
||||
if (!(tp->t_state & TS_CARR_ON) &&
|
||||
!IS_CALLOUT(mynor) &&
|
||||
!(tp->t_cflag & CLOCAL) &&
|
||||
!(flag & O_NONBLOCK)) {
|
||||
++pp->sp_wopeners;
|
||||
DPRINT((pp, DBG_OPEN, "sleeping for carrier\n"));
|
||||
error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0);
|
||||
--pp->sp_wopeners;
|
||||
if (error != 0)
|
||||
goto out;
|
||||
goto open_top;
|
||||
}
|
||||
|
||||
error = ttyld_open(tp, dev);
|
||||
ttyldoptim(tp);
|
||||
if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor))
|
||||
pp->sp_active_out = TRUE;
|
||||
|
||||
pp->sp_state |= SS_OPEN; /* made it! */
|
||||
|
||||
out:
|
||||
splx(oldspl);
|
||||
|
||||
DPRINT((pp, DBG_OPEN, "leaving siopen\n"));
|
||||
|
||||
if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0)
|
||||
sihardclose(pp);
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
static int
|
||||
siclose(struct cdev *dev, int flag, int mode, struct thread *td)
|
||||
{
|
||||
struct si_port *pp;
|
||||
struct tty *tp;
|
||||
int oldspl;
|
||||
int error = 0;
|
||||
int mynor = minor(dev);
|
||||
|
||||
if (IS_SPECIAL(mynor))
|
||||
return(0);
|
||||
|
||||
oldspl = spltty();
|
||||
|
||||
pp = MINOR2PP(mynor);
|
||||
tp = pp->sp_tty;
|
||||
|
||||
DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%s,%x,%x,%x) sp_state:%x\n",
|
||||
devtoname(dev), flag, mode, td, pp->sp_state));
|
||||
|
||||
/* did we sleep and loose a race? */
|
||||
if (pp->sp_state & SS_CLOSING) {
|
||||
/* error = ESOMETING? */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* begin race detection.. */
|
||||
pp->sp_state |= SS_CLOSING;
|
||||
|
||||
si_write_enable(pp, 0); /* block writes for ttywait() */
|
||||
|
||||
/* THIS MAY SLEEP IN TTYWAIT!!! */
|
||||
ttyld_close(tp, flag);
|
||||
|
||||
si_write_enable(pp, 1);
|
||||
|
||||
/* did we sleep and somebody started another open? */
|
||||
if (!(pp->sp_state & SS_CLOSING)) {
|
||||
/* error = ESOMETING? */
|
||||
goto out;
|
||||
}
|
||||
/* ok. we are now still on the right track.. nuke the hardware */
|
||||
|
||||
if (pp->sp_state & SS_LSTART) {
|
||||
untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch);
|
||||
pp->sp_state &= ~SS_LSTART;
|
||||
}
|
||||
|
||||
sihardclose(pp);
|
||||
tty_close(tp);
|
||||
pp->sp_state &= ~SS_OPEN;
|
||||
|
||||
out:
|
||||
DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n"));
|
||||
splx(oldspl);
|
||||
return(error);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void
|
||||
sihardclose(struct si_port *pp)
|
||||
{
|
||||
int oldspl;
|
||||
struct tty *tp;
|
||||
volatile struct si_channel *ccbp;
|
||||
|
||||
oldspl = spltty();
|
||||
|
||||
tp = pp->sp_tty;
|
||||
ccbp = pp->sp_ccb; /* Find control block */
|
||||
if (tp->t_cflag & HUPCL ||
|
||||
(!pp->sp_active_out &&
|
||||
!(ccbp->hi_ip & IP_DCD) &&
|
||||
!(pp->sp_iin.c_cflag && CLOCAL)) ||
|
||||
!(tp->t_state & TS_ISOPEN)) {
|
||||
|
||||
(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
|
||||
(void) si_command(pp, FCLOSE, SI_NOWAIT);
|
||||
|
||||
ttydtrwaitstart(tp);
|
||||
}
|
||||
pp->sp_active_out = FALSE;
|
||||
wakeup(&pp->sp_active_out);
|
||||
wakeup(TSA_CARR_ON(tp));
|
||||
|
||||
splx(oldspl);
|
||||
}
|
||||
|
||||
static int
|
||||
siwrite(struct cdev *dev, struct uio *uio, int flag)
|
||||
siclose(struct tty *tp)
|
||||
{
|
||||
struct si_port *pp;
|
||||
struct tty *tp;
|
||||
int error = 0;
|
||||
int mynor = minor(dev);
|
||||
int oldspl;
|
||||
|
||||
if (IS_SPECIAL(mynor)) {
|
||||
DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n"));
|
||||
return(ENODEV);
|
||||
}
|
||||
pp = MINOR2PP(mynor);
|
||||
tp = pp->sp_tty;
|
||||
DPRINT((pp, DBG_WRITE, "siwrite(%s,%x,%x)\n", devtoname(dev), uio, flag));
|
||||
|
||||
oldspl = spltty();
|
||||
/*
|
||||
* If writes are currently blocked, wait on the "real" tty
|
||||
*/
|
||||
while (pp->sp_state & SS_BLOCKWRITE) {
|
||||
pp->sp_state |= SS_WAITWRITE;
|
||||
DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n"));
|
||||
if ((error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH,
|
||||
"siwrite", tp->t_timeout))) {
|
||||
if (error == EWOULDBLOCK)
|
||||
error = EIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
error = ttyld_write(tp, uio, flag);
|
||||
out:
|
||||
splx(oldspl);
|
||||
return (error);
|
||||
pp = tp->t_sc;
|
||||
(void) si_command(pp, FCLOSE, SI_NOWAIT);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
siioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
static void
|
||||
sibreak(struct tty *tp, int sig)
|
||||
{
|
||||
struct si_port *pp;
|
||||
struct tty *tp;
|
||||
int error;
|
||||
int mynor = minor(dev);
|
||||
int oldspl;
|
||||
int blocked = 0;
|
||||
#ifndef BURN_BRIDGES
|
||||
#if defined(COMPAT_43)
|
||||
u_long oldcmd;
|
||||
struct termios term;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (IS_SI_IOCTL(cmd))
|
||||
return(si_Sioctl(dev, cmd, data, flag, td));
|
||||
|
||||
pp = MINOR2PP(mynor);
|
||||
tp = pp->sp_tty;
|
||||
|
||||
DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%s,%lx,%x,%x)\n",
|
||||
devtoname(dev), cmd, data, flag));
|
||||
if (IS_STATE(mynor)) {
|
||||
struct termios *ct;
|
||||
|
||||
switch (mynor & SI_STATE_MASK) {
|
||||
case SI_INIT_STATE_MASK:
|
||||
ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
|
||||
break;
|
||||
case SI_LOCK_STATE_MASK:
|
||||
ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin;
|
||||
break;
|
||||
default:
|
||||
return (ENODEV);
|
||||
}
|
||||
switch (cmd) {
|
||||
case TIOCSETA:
|
||||
error = suser(td);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
*ct = *(struct termios *)data;
|
||||
return (0);
|
||||
case TIOCGETA:
|
||||
*(struct termios *)data = *ct;
|
||||
return (0);
|
||||
case TIOCGETD:
|
||||
*(int *)data = TTYDISC;
|
||||
return (0);
|
||||
case TIOCGWINSZ:
|
||||
bzero(data, sizeof(struct winsize));
|
||||
return (0);
|
||||
default:
|
||||
return (ENOTTY);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Do the old-style ioctl compat routines...
|
||||
*/
|
||||
#ifndef BURN_BRIDGES
|
||||
#if defined(COMPAT_43)
|
||||
term = tp->t_termios;
|
||||
oldcmd = cmd;
|
||||
error = ttsetcompat(tp, &cmd, data, &term);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (cmd != oldcmd)
|
||||
data = (caddr_t)&term;
|
||||
#endif
|
||||
#endif
|
||||
/*
|
||||
* Do the initial / lock state business
|
||||
*/
|
||||
if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
|
||||
int cc;
|
||||
struct termios *dt = (struct termios *)data;
|
||||
struct termios *lt = mynor & SI_CALLOUT_MASK
|
||||
? &pp->sp_lout : &pp->sp_lin;
|
||||
|
||||
dt->c_iflag = (tp->t_iflag & lt->c_iflag) |
|
||||
(dt->c_iflag & ~lt->c_iflag);
|
||||
dt->c_oflag = (tp->t_oflag & lt->c_oflag) |
|
||||
(dt->c_oflag & ~lt->c_oflag);
|
||||
dt->c_cflag = (tp->t_cflag & lt->c_cflag) |
|
||||
(dt->c_cflag & ~lt->c_cflag);
|
||||
dt->c_lflag = (tp->t_lflag & lt->c_lflag) |
|
||||
(dt->c_lflag & ~lt->c_lflag);
|
||||
for (cc = 0; cc < NCCS; ++cc)
|
||||
if (lt->c_cc[cc] != 0)
|
||||
dt->c_cc[cc] = tp->t_cc[cc];
|
||||
if (lt->c_ispeed != 0)
|
||||
dt->c_ispeed = tp->t_ispeed;
|
||||
if (lt->c_ospeed != 0)
|
||||
dt->c_ospeed = tp->t_ospeed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Block user-level writes to give the ttywait()
|
||||
* a chance to completely drain for commands
|
||||
* that require the port to be in a quiescent state.
|
||||
*/
|
||||
switch (cmd) {
|
||||
case TIOCSETAW:
|
||||
case TIOCSETAF:
|
||||
case TIOCDRAIN:
|
||||
#ifndef BURN_BRIDGES
|
||||
#ifdef COMPAT_43
|
||||
case TIOCSETP:
|
||||
#endif
|
||||
#endif
|
||||
blocked++; /* block writes for ttywait() and siparam() */
|
||||
si_write_enable(pp, 0);
|
||||
}
|
||||
|
||||
error = ttyioctl(dev, cmd, data, flag, td);
|
||||
ttyldoptim(tp);
|
||||
if (error != ENOTTY)
|
||||
goto out;
|
||||
|
||||
oldspl = spltty();
|
||||
|
||||
error = 0;
|
||||
switch (cmd) {
|
||||
case TIOCSBRK:
|
||||
pp = tp->t_sc;
|
||||
if (sig)
|
||||
si_command(pp, SBREAK, SI_WAIT);
|
||||
break;
|
||||
case TIOCCBRK:
|
||||
else
|
||||
si_command(pp, EBREAK, SI_WAIT);
|
||||
break;
|
||||
case TIOCSDTR:
|
||||
(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
|
||||
break;
|
||||
case TIOCCDTR:
|
||||
(void) si_modem(pp, SET, 0);
|
||||
break;
|
||||
case TIOCMSET:
|
||||
(void) si_modem(pp, SET, *(int *)data);
|
||||
break;
|
||||
case TIOCMBIS:
|
||||
(void) si_modem(pp, BIS, *(int *)data);
|
||||
break;
|
||||
case TIOCMBIC:
|
||||
(void) si_modem(pp, BIC, *(int *)data);
|
||||
break;
|
||||
case TIOCMGET:
|
||||
*(int *)data = si_modem(pp, GET, 0);
|
||||
break;
|
||||
default:
|
||||
error = ENOTTY;
|
||||
}
|
||||
splx(oldspl);
|
||||
|
||||
out:
|
||||
DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error));
|
||||
if (blocked)
|
||||
si_write_enable(pp, 1);
|
||||
return(error);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handle the Specialix ioctls. All MUST be called via the CONTROL device
|
||||
* Handle the Specialix ioctls on the control dev.
|
||||
*/
|
||||
static int
|
||||
si_Sioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
@ -1069,7 +632,6 @@ si_Sioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t
|
||||
int *ip, error = 0;
|
||||
int oldspl;
|
||||
int card, port;
|
||||
int mynor = minor(dev);
|
||||
|
||||
DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%s,%lx,%x,%x)\n",
|
||||
devtoname(dev), cmd, data, flag));
|
||||
@ -1080,11 +642,6 @@ si_Sioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t
|
||||
DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));
|
||||
#endif
|
||||
|
||||
if (!IS_CONTROLDEV(mynor)) {
|
||||
DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n"));
|
||||
return(ENODEV);
|
||||
}
|
||||
|
||||
oldspl = spltty(); /* better safe than sorry */
|
||||
|
||||
ip = (int *)data;
|
||||
@ -1210,7 +767,7 @@ out:
|
||||
static int
|
||||
siparam(struct tty *tp, struct termios *t)
|
||||
{
|
||||
struct si_port *pp = TP2PP(tp);
|
||||
struct si_port *pp = tp->t_sc;
|
||||
volatile struct si_channel *ccbp;
|
||||
int oldspl, cflag, iflag, oflag, lflag;
|
||||
int error = 0; /* shutup gcc */
|
||||
@ -1356,13 +913,13 @@ siparam(struct tty *tp, struct termios *t)
|
||||
/* ========== set DTR etc ========== */
|
||||
/* Hangup if ospeed == 0 */
|
||||
if (t->c_ospeed == 0) {
|
||||
(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
|
||||
(void) simodem(tp, 0, SER_DTR | SER_RTS);
|
||||
} else {
|
||||
/*
|
||||
* If the previous speed was 0, may need to re-enable
|
||||
* the modem signals
|
||||
*/
|
||||
(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
|
||||
(void) simodem(tp, SER_DTR | SER_RTS, 0);
|
||||
}
|
||||
|
||||
DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n",
|
||||
@ -1372,31 +929,6 @@ siparam(struct tty *tp, struct termios *t)
|
||||
return(error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable or Disable the writes to this channel...
|
||||
* "state" -> enabled = 1; disabled = 0;
|
||||
*/
|
||||
static void
|
||||
si_write_enable(struct si_port *pp, int state)
|
||||
{
|
||||
int oldspl;
|
||||
|
||||
oldspl = spltty();
|
||||
|
||||
if (state) {
|
||||
pp->sp_state &= ~SS_BLOCKWRITE;
|
||||
if (pp->sp_state & SS_WAITWRITE) {
|
||||
pp->sp_state &= ~SS_WAITWRITE;
|
||||
/* thunder away! */
|
||||
wakeup(pp);
|
||||
}
|
||||
} else {
|
||||
pp->sp_state |= SS_BLOCKWRITE;
|
||||
}
|
||||
|
||||
splx(oldspl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set/Get state of modem control lines.
|
||||
* Due to DCE-like behaviour of the adapter, some signals need translation:
|
||||
@ -1404,39 +936,38 @@ si_write_enable(struct si_port *pp, int state)
|
||||
* TIOCM_RTS CTS
|
||||
*/
|
||||
static int
|
||||
si_modem(struct si_port *pp, enum si_mctl cmd, int bits)
|
||||
simodem(struct tty *tp, int sigon, int sigoff)
|
||||
{
|
||||
struct si_port *pp;
|
||||
volatile struct si_channel *ccbp;
|
||||
int x;
|
||||
|
||||
DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits));
|
||||
pp = tp->t_sc;
|
||||
DPRINT((pp, DBG_ENTRY|DBG_MODEM, "simodem(%x,%x)\n", sigon, sigoff));
|
||||
ccbp = pp->sp_ccb; /* Find channel address */
|
||||
switch (cmd) {
|
||||
case GET:
|
||||
if (sigon == 0 && sigoff == 0) {
|
||||
x = ccbp->hi_ip;
|
||||
bits = TIOCM_LE;
|
||||
if (x & IP_DCD) bits |= TIOCM_CAR;
|
||||
if (x & IP_DTR) bits |= TIOCM_DTR;
|
||||
if (x & IP_RTS) bits |= TIOCM_RTS;
|
||||
if (x & IP_RI) bits |= TIOCM_RI;
|
||||
return(bits);
|
||||
case SET:
|
||||
ccbp->hi_op &= ~(OP_DSR|OP_CTS);
|
||||
/* fall through */
|
||||
case BIS:
|
||||
x = 0;
|
||||
if (bits & TIOCM_DTR)
|
||||
x |= OP_DSR;
|
||||
if (bits & TIOCM_RTS)
|
||||
x |= OP_CTS;
|
||||
ccbp->hi_op |= x;
|
||||
break;
|
||||
case BIC:
|
||||
if (bits & TIOCM_DTR)
|
||||
ccbp->hi_op &= ~OP_DSR;
|
||||
if (bits & TIOCM_RTS)
|
||||
ccbp->hi_op &= ~OP_CTS;
|
||||
/*
|
||||
* XXX: not sure this is correct, should it be CTS&DSR ?
|
||||
* XXX: or do we (just) miss CTS & DSR ?
|
||||
*/
|
||||
if (x & IP_DCD) sigon |= SER_DCD;
|
||||
if (x & IP_DTR) sigon |= SER_DTR;
|
||||
if (x & IP_RTS) sigon |= SER_RTS;
|
||||
if (x & IP_RI) sigon |= SER_RI;
|
||||
return (sigon);
|
||||
}
|
||||
|
||||
x = ccbp->hi_op;
|
||||
if (sigon & SER_DTR)
|
||||
x |= OP_DSR;
|
||||
if (sigoff & SER_DTR)
|
||||
x &= ~OP_DSR;
|
||||
if (sigon & SER_RTS)
|
||||
x |= OP_CTS;
|
||||
if (sigoff & SER_RTS)
|
||||
x &= ~OP_CTS;
|
||||
ccbp->hi_op = x;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1457,7 +988,7 @@ si_modem_state(struct si_port *pp, struct tty *tp, int hi_ip)
|
||||
if (pp->sp_last_hi_ip & IP_DCD) {
|
||||
DPRINT((pp, DBG_INTR, "modem carr off\n"));
|
||||
if (ttyld_modem(tp, 0))
|
||||
(void) si_modem(pp, SET, 0);
|
||||
(void) simodem(tp, 0, SER_DTR | SER_RTS);
|
||||
}
|
||||
}
|
||||
pp->sp_last_hi_ip = hi_ip;
|
||||
@ -1838,7 +1369,7 @@ si_start(struct tty *tp)
|
||||
oldspl = spltty();
|
||||
|
||||
qp = &tp->t_outq;
|
||||
pp = TP2PP(tp);
|
||||
pp = tp->t_sc;
|
||||
|
||||
DPRINT((pp, DBG_ENTRY|DBG_START,
|
||||
"si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n",
|
||||
@ -1934,15 +1465,16 @@ si_lstart(void *arg)
|
||||
pp, pp->sp_state));
|
||||
|
||||
oldspl = spltty();
|
||||
tp = pp->sp_tty;
|
||||
|
||||
if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) {
|
||||
if ((tp->t_state & TS_ISOPEN) == 0 ||
|
||||
(pp->sp_state & SS_LSTART) == 0) {
|
||||
splx(oldspl);
|
||||
return;
|
||||
}
|
||||
pp->sp_state &= ~SS_LSTART;
|
||||
pp->sp_state |= SS_INLSTART;
|
||||
|
||||
tp = pp->sp_tty;
|
||||
|
||||
/* deal with the process exit case */
|
||||
ttwwakeup(tp);
|
||||
@ -1963,16 +1495,16 @@ si_stop(struct tty *tp, int rw)
|
||||
volatile struct si_channel *ccbp;
|
||||
struct si_port *pp;
|
||||
|
||||
pp = TP2PP(tp);
|
||||
pp = tp->t_sc;
|
||||
ccbp = pp->sp_ccb;
|
||||
|
||||
DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "si_stop(%x,%x)\n", tp, rw));
|
||||
DPRINT((pp, DBG_ENTRY|DBG_STOP, "si_stop(%x,%x)\n", tp, rw));
|
||||
|
||||
/* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
|
||||
if (rw & FWRITE) {
|
||||
/* what level are we meant to be flushing anyway? */
|
||||
if (tp->t_state & TS_BUSY) {
|
||||
si_command(TP2PP(tp), WFLUSH, SI_NOWAIT);
|
||||
si_command(pp, WFLUSH, SI_NOWAIT);
|
||||
tp->t_state &= ~TS_BUSY;
|
||||
ttwwakeup(tp); /* Bruce???? */
|
||||
}
|
||||
@ -2071,31 +1603,13 @@ si_dprintf(struct si_port *pp, int flags, const char *fmt, ...)
|
||||
if ((pp == NULL && (si_debug&flags)) ||
|
||||
(pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) {
|
||||
if (pp != NULL)
|
||||
printf("%ci%d(%d): ", 's',
|
||||
(int)SI_CARD(minor(pp->sp_tty->t_dev)),
|
||||
(int)SI_PORT(minor(pp->sp_tty->t_dev)));
|
||||
printf("%s: ", pp->sp_name);
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
si_mctl2str(enum si_mctl cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case GET:
|
||||
return("GET");
|
||||
case SET:
|
||||
return("SET");
|
||||
case BIS:
|
||||
return("BIS");
|
||||
case BIC:
|
||||
return("BIC");
|
||||
}
|
||||
return("BAD");
|
||||
}
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
static char *
|
||||
|
@ -36,61 +36,15 @@
|
||||
#include <sys/callout.h>
|
||||
|
||||
/*
|
||||
* Macro to turn a device number into various parameters, and test for
|
||||
* CONTROL device.
|
||||
* max of 4 controllers with up to 32 ports per controller.
|
||||
* minor device allocation is:
|
||||
* adapter port
|
||||
* 0 0-31
|
||||
* 1 32-63
|
||||
* 2 64-95
|
||||
* 3 96-127
|
||||
*/
|
||||
* We name devices with %r in make_dev() with a radix of 32.
|
||||
*/
|
||||
#define SI_MAXPORTPERCARD 32
|
||||
#define SI_MAXCONTROLLER 4
|
||||
|
||||
|
||||
/*
|
||||
* breakup of minor device number:
|
||||
* lowest 5 bits: port number on card 0x1f
|
||||
* next 2 bits: card number 0x60
|
||||
* top bit: callout 0x80
|
||||
* next 8 bits is the major number
|
||||
* next 2 bits select initial/lock states
|
||||
* next 1 bit selects the master control device
|
||||
*/
|
||||
|
||||
#define SI_PORT_MASK 0x1f
|
||||
#define SI_CARD_MASK 0x60
|
||||
#define SI_TTY_MASK 0x7f
|
||||
#define SI_CALLOUT_MASK 0x80
|
||||
#define SI_INIT_STATE_MASK 0x10000
|
||||
#define SI_LOCK_STATE_MASK 0x20000
|
||||
#define SI_STATE_MASK 0x30000
|
||||
#define SI_CONTROLDEV_MASK 0x40000
|
||||
#define SI_SPECIAL_MASK 0x70000
|
||||
|
||||
#define SI_CARDSHIFT 5
|
||||
#define SI_PORT(m) (m & SI_PORT_MASK)
|
||||
#define SI_CARD(m) ((m & SI_CARD_MASK) >> SI_CARDSHIFT)
|
||||
#define SI_TTY(m) (m & SI_TTY_MASK)
|
||||
|
||||
#define IS_CALLOUT(m) (m & SI_CALLOUT_MASK)
|
||||
#define IS_STATE(m) (m & SI_STATE_MASK)
|
||||
#define IS_CONTROLDEV(m) (m & SI_CONTROLDEV_MASK)
|
||||
#define IS_SPECIAL(m) (m & SI_SPECIAL_MASK)
|
||||
|
||||
#define MINOR2SC(m) ((struct si_softc *)devclass_get_softc(si_devclass, SI_CARD(m)))
|
||||
#define MINOR2PP(m) (MINOR2SC((m))->sc_ports + SI_PORT((m)))
|
||||
#define MINOR2TP(m) (MINOR2PP((m))->sp_tty)
|
||||
#define TP2PP(tp) (MINOR2PP(SI_TTY(minor((tp)->t_dev))))
|
||||
|
||||
/* Buffer parameters */
|
||||
#define SI_BUFFERSIZE 256
|
||||
|
||||
typedef unsigned char BYTE; /* Type cast for unsigned 8 bit */
|
||||
typedef unsigned short WORD; /* Type cast for unsigned 16 bit */
|
||||
|
||||
typedef uint8_t BYTE; /* Type cast for unsigned 8 bit */
|
||||
typedef uint16_t WORD; /* Type cast for unsigned 16 bit */
|
||||
|
||||
/*
|
||||
* Hardware `registers', stored in the shared memory.
|
||||
@ -330,24 +284,16 @@ struct si_port {
|
||||
int sp_pend; /* pending command */
|
||||
int sp_last_hi_ip; /* cached DCD */
|
||||
int sp_state;
|
||||
int sp_active_out; /* callout is open */
|
||||
int sp_delta_overflows;
|
||||
u_int sp_wopeners; /* # procs waiting DCD */
|
||||
/* Initial state. */
|
||||
struct termios sp_iin;
|
||||
struct termios sp_iout;
|
||||
/* Lock state. */
|
||||
struct termios sp_lin;
|
||||
struct termios sp_lout;
|
||||
struct callout_handle lstart_ch;/* For canceling our timeout */
|
||||
#ifdef SI_DEBUG
|
||||
int sp_debug; /* debug mask */
|
||||
char sp_name[5];
|
||||
#endif
|
||||
};
|
||||
|
||||
/* sp_state */
|
||||
#define SS_CLOSED 0x0000
|
||||
#define SS_OPEN 0x0001 /* Port is active */
|
||||
/* 0x0001 -- */
|
||||
/* 0x0002 -- */
|
||||
/* 0x0004 -- */
|
||||
/* 0x0008 -- */
|
||||
@ -357,10 +303,8 @@ struct si_port {
|
||||
/* 0x0080 -- */
|
||||
#define SS_LSTART 0x0100 /* lstart timeout pending */
|
||||
#define SS_INLSTART 0x0200 /* running an lstart induced t_oproc */
|
||||
#define SS_CLOSING 0x0400 /* in the middle of a siclose() */
|
||||
/* 0x0400 -- */
|
||||
/* 0x0800 -- */
|
||||
#define SS_WAITWRITE 0x1000
|
||||
#define SS_BLOCKWRITE 0x2000
|
||||
|
||||
/*
|
||||
* Command post flags
|
||||
@ -368,32 +312,6 @@ struct si_port {
|
||||
#define SI_NOWAIT 0x00 /* Don't wait for command */
|
||||
#define SI_WAIT 0x01 /* Wait for complete */
|
||||
|
||||
/*
|
||||
* Extensive debugging stuff - manipulated using siconfig(8)
|
||||
*/
|
||||
#define DBG_ENTRY 0x00000001
|
||||
#define DBG_DRAIN 0x00000002
|
||||
#define DBG_OPEN 0x00000004
|
||||
#define DBG_CLOSE 0x00000008
|
||||
#define DBG_READ 0x00000010
|
||||
#define DBG_WRITE 0x00000020
|
||||
#define DBG_PARAM 0x00000040
|
||||
#define DBG_INTR 0x00000080
|
||||
#define DBG_IOCTL 0x00000100
|
||||
/* 0x00000200 */
|
||||
#define DBG_SELECT 0x00000400
|
||||
#define DBG_OPTIM 0x00000800
|
||||
#define DBG_START 0x00001000
|
||||
#define DBG_EXIT 0x00002000
|
||||
#define DBG_FAIL 0x00004000
|
||||
#define DBG_STOP 0x00008000
|
||||
#define DBG_AUTOBOOT 0x00010000
|
||||
#define DBG_MODEM 0x00020000
|
||||
#define DBG_DOWNLOAD 0x00040000
|
||||
#define DBG_LSTART 0x00080000
|
||||
#define DBG_POLL 0x00100000
|
||||
#define DBG_ALL 0xffffffff
|
||||
|
||||
/*
|
||||
* SI ioctls
|
||||
*/
|
||||
|
@ -40,7 +40,7 @@ extern int si3_t225_bsize;
|
||||
|
||||
struct si_softc {
|
||||
int sc_type; /* adapter type */
|
||||
char *sc_typename; /* adapter type string */
|
||||
const char *sc_typename; /* adapter type string */
|
||||
|
||||
struct si_port *sc_ports; /* port structures for this card */
|
||||
|
||||
@ -67,6 +67,9 @@ void si_dprintf(struct si_port *pp, int flags, const char *fmt, ...);
|
||||
|
||||
#define DPRINT(x) si_dprintf x
|
||||
|
||||
/*
|
||||
* Extensive debugging stuff - manipulated using siconfig(8)
|
||||
*/
|
||||
#define DBG_ENTRY 0x00000001
|
||||
#define DBG_DRAIN 0x00000002
|
||||
#define DBG_OPEN 0x00000004
|
||||
|
Loading…
x
Reference in New Issue
Block a user