b42d2104dc
change isn't an error.
443 lines
12 KiB
C
443 lines
12 KiB
C
static char _ittyid[] = "@(#)$Id: iitty.c,v 1.10 1995/07/31 21:01:03 bde Exp $";
|
|
/*******************************************************************************
|
|
* II - Version 0.1 $Revision: 1.10 $ $State: Exp $
|
|
*
|
|
* Copyright 1994 Dietmar Friede
|
|
*******************************************************************************
|
|
* Bug reports, patches, comments, suggestions should be sent to:
|
|
*
|
|
* jkr@saarlink.de or jkrause@guug.de
|
|
*
|
|
*******************************************************************************
|
|
* $Log: iitty.c,v $
|
|
* Revision 1.10 1995/07/31 21:01:03 bde
|
|
* Obtained from: partly from ancient patches of mine via 1.1.5
|
|
*
|
|
* Introduce TS_CONNECTED and TS_ZOMBIE states. TS_CONNECTED is set
|
|
* while a connection is established. It is set while (TS_CARR_ON or
|
|
* CLOCAL is set) and TS_ZOMBIE is clear. TS_ZOMBIE is set for on to
|
|
* off transitions of TS_CARR_ON that occur when CLOCAL is clear and
|
|
* is cleared for off to on transitions of CLOCAL. I/o can only occur
|
|
* while TS_CONNECTED is set. TS_ZOMBIE prevents further i/o.
|
|
*
|
|
* Split the input-event sleep address TSA_CARR_ON(tp) into TSA_CARR_ON(tp)
|
|
* and TSA_HUP_OR_INPUT(tp). The former address is now used only for
|
|
* off to on carrier transitions and equivalent CLOCAL transitions.
|
|
* The latter is used for all input events, all carrier transitions
|
|
* and certain CLOCAL transitions. There are some harmless extra
|
|
* wakeups for rare connection- related events. Previously there were
|
|
* too many extra wakeups for non-rare input events.
|
|
*
|
|
* Drivers now call l_modem() instead of setting TS_CARR_ON directly
|
|
* to handle even the initial off to on transition of carrier. They
|
|
* should always have done this. l_modem() now handles TS_CONNECTED
|
|
* and TS_ZOMBIE as well as TS_CARR_ON.
|
|
*
|
|
* gnu/isdn/iitty.c:
|
|
* Set TS_CONNECTED for first open ourself to go with bogusly setting
|
|
* CLOCAL.
|
|
*
|
|
* i386/isa/syscons.c, i386/isa/pcvt/pcvt_drv.c:
|
|
* We fake carrier, so don't also fake CLOCAL.
|
|
*
|
|
* kern/tty.c:
|
|
* Testing TS_CONNECTED instead of TS_CARR_ON fixes TIOCCONS forgetting to
|
|
* test CLOCAL. TS_ISOPEN was tested instead, but that broke when we disabled
|
|
* the clearing of TS_ISOPEN for certain transitions of CLOCAL.
|
|
*
|
|
* Testing TS_CONNECTED fixes ttyselect() returning false success for output
|
|
* to devices in state !TS_CARR_ON && !CLOCAL.
|
|
*
|
|
* Optimize the other selwakeup() call (this is not related to the other
|
|
* changes).
|
|
*
|
|
* kern/tty_pty.c:
|
|
* ptcopen() can be declared in traditional C now that dev_t isn't short.
|
|
*
|
|
* Revision 1.9 1995/07/22 16:44:26 bde
|
|
* Obtained from: partly from ancient patches of mine via 1.1.5
|
|
*
|
|
* Give names to the magic tty i/o sleep addresses and use them. This makes
|
|
* it easier to remember what the addresses are for and to keep them unique.
|
|
*
|
|
* Revision 1.8 1995/07/22 01:29:28 bde
|
|
* Move the inline code for waking up writers to a new function
|
|
* ttwwakeup(). The conditions for doing the wakeup will soon become
|
|
* more complicated and I don't want them duplicated in all drivers.
|
|
*
|
|
* It's probably not worth making ttwwakeup() a macro or an inline
|
|
* function. The cost of the function call is relatively small when
|
|
* there is a process to wake up. There is usually a process to wake
|
|
* up for large writes and the system call overhead dwarfs the function
|
|
* call overhead for small writes.
|
|
*
|
|
* Revision 1.7 1995/07/21 20:52:21 bde
|
|
* Obtained from: partly from ancient patches by ache and me via 1.1.5
|
|
*
|
|
* Nuke `symbolic sleep message strings'. Use unique literal messages so that
|
|
* `ps l' shows unambiguously where processes are sleeping.
|
|
*
|
|
* Revision 1.6 1995/07/21 16:30:37 bde
|
|
* Obtained from: partly from an ancient patch of mine via 1.1.5
|
|
*
|
|
* Temporarily nuke TS_WOPEN. It was only used for the obscure MDMBUF
|
|
* flow control option in the kernel and for informational purposes
|
|
* in `pstat -t'. The latter worked properly only for ptys. In
|
|
* general there may be multiple processes sleeping in open() and
|
|
* multiple processes that successfully opened the tty by opening it
|
|
* in O_NONBLOCK mode or during a window when CLOCAL was set. tty.c
|
|
* doesn't have enough information to maintain the flag but always
|
|
* cleared it in ttyopen().
|
|
*
|
|
* TS_WOPEN should be restored someday just so that `pstat -t' can
|
|
* display it (MDMBUF is already fixed). Fixing it requires counting
|
|
* of processes sleeping in open() in too many serial drivers.
|
|
*
|
|
* Revision 1.5 1995/03/28 07:54:43 bde
|
|
* Add and move declarations to fix all of the warnings from `gcc -Wimplicit'
|
|
* (except in netccitt, netiso and netns) that I didn't notice when I fixed
|
|
* "all" such warnings before.
|
|
*
|
|
* Revision 1.4 1995/02/28 00:20:30 pst
|
|
* Incorporate bde's code-review comments.
|
|
*
|
|
* (a) bring back ttselect, now that we have xxxdevtotty() it isn't dangerous.
|
|
* (b) remove all of the wrappers that have been replaced by ttselect
|
|
* (c) fix formatting in syscons.c and definition in syscons.h
|
|
* (d) add cxdevtotty
|
|
*
|
|
* NOT DONE:
|
|
* (e) make pcvt work... it was already broken...when someone fixes pcvt to
|
|
* link properly, just rename get_pccons to xxxdevtotty and we're done
|
|
*
|
|
* Revision 1.3 1995/02/25 20:08:52 pst
|
|
* (a) remove the pointer to each driver's tty structure array from cdevsw
|
|
* (b) add a function callback vector to tty drivers that will return a pointer
|
|
* to a valid tty structure based upon a dev_t
|
|
* (c) make syscons structures the same size whether or not APM is enabled so
|
|
* utilities don't crash if NAPM changes (and make the damn kernel compile!)
|
|
* (d) rewrite /dev/snp ioctl interface so that it is device driver and i386
|
|
* independant
|
|
*
|
|
* Revision 1.2 1995/02/15 06:28:28 jkh
|
|
* Fix up include paths, nuke some warnings.
|
|
*
|
|
* Revision 1.1 1995/02/14 15:00:32 jkh
|
|
* An ISDN driver that supports the EDSS1 and the 1TR6 ISDN interfaces.
|
|
* EDSS1 is the "Euro-ISDN", 1TR6 is the soon obsolete german ISDN Interface.
|
|
* Obtained from: Dietmar Friede <dfriede@drnhh.neuhaus.de> and
|
|
* Juergen Krause <jkr@saarlink.de>
|
|
*
|
|
* This is only one part - the rest to follow in a couple of hours.
|
|
* This part is a benign import, since it doesn't affect anything else.
|
|
*
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include "ity.h"
|
|
#if NITY > 0
|
|
|
|
#include "param.h"
|
|
#include "systm.h"
|
|
#include "ioctl.h"
|
|
#include "select.h"
|
|
#include "tty.h"
|
|
#include "proc.h"
|
|
#include "user.h"
|
|
#include "conf.h"
|
|
#include "file.h"
|
|
#include "uio.h"
|
|
#include "kernel.h"
|
|
#include "syslog.h"
|
|
#include "types.h"
|
|
|
|
#include "gnu/isdn/isdn_ioctl.h"
|
|
|
|
int ityparam();
|
|
void itystart();
|
|
|
|
int nity = NITY;
|
|
int itydefaultrate = 64000;
|
|
short ity_addr[NITY];
|
|
struct tty ity_tty[NITY];
|
|
static int applnr[NITY];
|
|
static int next_if= 0;
|
|
|
|
#define UNIT(x) (minor(x)&0x3f)
|
|
#define OUTBOUND(x) ((minor(x)&0x80)==0x80)
|
|
|
|
int
|
|
ityattach(int ap)
|
|
{
|
|
if(next_if >= NITY)
|
|
return(-1);
|
|
|
|
applnr[next_if]= ap;
|
|
return(next_if++);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
int
|
|
ityopen(dev_t dev, int flag, int mode, struct proc * p)
|
|
{
|
|
register struct tty *tp;
|
|
register int unit;
|
|
int error = 0;
|
|
|
|
unit = UNIT(dev);
|
|
if (unit >= next_if)
|
|
return (ENXIO);
|
|
|
|
tp = &ity_tty[unit];
|
|
tp->t_oproc = itystart;
|
|
tp->t_param = ityparam;
|
|
tp->t_dev = dev;
|
|
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 = itydefaultrate;
|
|
}
|
|
ityparam(tp, &tp->t_termios);
|
|
ttsetwater(tp);
|
|
} else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
|
|
return (EBUSY);
|
|
(void) spltty();
|
|
|
|
if (OUTBOUND(dev)) {
|
|
/*
|
|
* XXX should call l_modem() here and not meddle with CLOCAL,
|
|
* but itystart() wants TS_CARR_ON to give the true carrier.
|
|
*/
|
|
tp->t_cflag |= CLOCAL;
|
|
tp->t_state |= TS_CONNECTED;
|
|
}
|
|
|
|
while ((flag & O_NONBLOCK) == 0 && (tp->t_cflag & CLOCAL) == 0 &&
|
|
(tp->t_state & TS_CARR_ON) == 0)
|
|
{
|
|
error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "iidcd", 0);
|
|
if (error)
|
|
break;
|
|
}
|
|
(void) spl0();
|
|
if (error == 0)
|
|
error = (*linesw[tp->t_line].l_open) (dev, tp);
|
|
return (error);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
int
|
|
ityclose(dev, flag, mode, p)
|
|
dev_t dev;
|
|
int flag, mode;
|
|
struct proc *p;
|
|
{
|
|
register struct tty *tp;
|
|
register ity;
|
|
register int unit;
|
|
|
|
unit = UNIT(dev);
|
|
ity = ity_addr[unit];
|
|
if(tp = &ity_tty[unit])
|
|
(*linesw[tp->t_line].l_close) (tp, flag);
|
|
ttyclose(tp);
|
|
isdn_disconnect(applnr[unit],0);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
ityread(dev, uio, flag)
|
|
dev_t dev;
|
|
struct uio *uio;
|
|
int flag;
|
|
{
|
|
register struct tty *tp = &ity_tty[UNIT(dev)];
|
|
|
|
return ((*linesw[tp->t_line].l_read) (tp, uio, flag));
|
|
}
|
|
|
|
int
|
|
itywrite(dev, uio, flag)
|
|
dev_t dev;
|
|
struct uio *uio;
|
|
int flag;
|
|
{
|
|
int unit = UNIT(dev);
|
|
register struct tty *tp = &ity_tty[unit];
|
|
|
|
return ((*linesw[tp->t_line].l_write) (tp, uio, flag));
|
|
}
|
|
|
|
int
|
|
ity_input(int no, int len, char *buf)
|
|
{
|
|
register struct tty *tp = &ity_tty[no];
|
|
int i;
|
|
|
|
if (tp->t_state & TS_ISOPEN)
|
|
for(i= 0; i<len; i++)
|
|
(*linesw[tp->t_line].l_rint)(buf[i], tp);
|
|
else len= 0;
|
|
return(len);
|
|
}
|
|
|
|
void
|
|
itystart(struct tty *tp)
|
|
{
|
|
int s, unit;
|
|
|
|
unit = UNIT(tp->t_dev);
|
|
|
|
s = splhigh();
|
|
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
|
|
{
|
|
splx(s);
|
|
return;
|
|
}
|
|
ttwwakeup(tp);
|
|
if (tp->t_outq.c_cc)
|
|
{
|
|
if(OUTBOUND(tp->t_dev) && (tp->t_cflag & CLOCAL) &&
|
|
((tp->t_state & TS_CARR_ON) == 0))
|
|
isdn_msg(applnr[unit]);
|
|
else isdn_output(applnr[unit]);
|
|
tp->t_state |= TS_BUSY;
|
|
}
|
|
splx(s);
|
|
}
|
|
|
|
int
|
|
ity_out(int no, char *buf, int len)
|
|
{
|
|
struct tty *tp = &ity_tty[no];
|
|
int i;
|
|
|
|
if(tp == NULL)
|
|
return(0);
|
|
if(tp->t_outq.c_cc)
|
|
{
|
|
for (i = 0; i < len && tp->t_outq.c_cc; ++i)
|
|
buf[i]= getc(&tp->t_outq);
|
|
return(i);
|
|
}
|
|
tp->t_state &=~ (TS_BUSY|TS_FLUSH);
|
|
if (tp->t_line)
|
|
(*linesw[tp->t_line].l_start)(tp);
|
|
else
|
|
itystart(tp);
|
|
return(0);
|
|
}
|
|
|
|
void
|
|
ity_connect(int no)
|
|
{
|
|
struct tty *tp = &ity_tty[no];
|
|
|
|
if(tp == NULL)
|
|
return;
|
|
if(OUTBOUND(tp->t_dev)) tp->t_cflag &= ~CLOCAL;
|
|
(*linesw[tp->t_line].l_modem) (tp, 1);
|
|
tp->t_state &=~ (TS_BUSY|TS_FLUSH);
|
|
if (tp->t_line)
|
|
(*linesw[tp->t_line].l_start)(tp);
|
|
else
|
|
itystart(tp);
|
|
}
|
|
|
|
void
|
|
ity_disconnect(int no)
|
|
{
|
|
struct tty *tp = &ity_tty[no];
|
|
if(tp) (*linesw[tp->t_line].l_modem) (tp, 0);
|
|
}
|
|
|
|
int
|
|
ityioctl(dev, cmd, data, flag,p)
|
|
dev_t dev;
|
|
int cmd;
|
|
caddr_t data;
|
|
int flag;
|
|
struct proc *p;
|
|
{
|
|
register struct tty *tp;
|
|
register int unit = UNIT(dev);
|
|
register int error;
|
|
|
|
tp = &ity_tty[unit];
|
|
error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag,p);
|
|
if (error >= 0)
|
|
return (error);
|
|
error = ttioctl(tp, cmd, data, flag);
|
|
if (error >= 0)
|
|
return (error);
|
|
|
|
switch (cmd)
|
|
{
|
|
default:
|
|
return (ENOTTY);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
ityparam(tp, t)
|
|
register struct tty *tp;
|
|
register struct termios *t;
|
|
{
|
|
register ity;
|
|
register int cfcr, cflag = t->c_cflag;
|
|
int unit = UNIT(tp->t_dev);
|
|
int ospeed = t->c_ospeed;
|
|
|
|
/* check requested parameters */
|
|
if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
|
|
return (EINVAL);
|
|
/* and copy to tty */
|
|
tp->t_ispeed = t->c_ispeed;
|
|
tp->t_ospeed = t->c_ospeed;
|
|
tp->t_cflag = cflag;
|
|
|
|
if (ospeed == 0)
|
|
{
|
|
isdn_disconnect(applnr[unit],0);
|
|
return (0);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Stop output on a line.
|
|
*/
|
|
/* ARGSUSED */
|
|
void
|
|
itystop(struct tty *tp, int flag)
|
|
{
|
|
register int s;
|
|
|
|
s = splhigh();
|
|
if (tp->t_state & TS_BUSY)
|
|
{
|
|
if ((tp->t_state & TS_TTSTOP) == 0)
|
|
tp->t_state |= TS_FLUSH;
|
|
}
|
|
splx(s);
|
|
}
|
|
|
|
struct tty *
|
|
itydevtotty(dev_t dev)
|
|
{
|
|
register int unit = UNIT(dev);
|
|
if (unit >= next_if)
|
|
return (NULL);
|
|
|
|
return (&ity_tty[unit]);
|
|
}
|
|
|
|
#endif
|