freebsd-nq/sys/gnu/isdn/iitty.c

443 lines
12 KiB
C
Raw Normal View History

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.
*
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.
1995-07-31 21:02:00 +00:00
* 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();
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.
1995-07-31 21:02:00 +00:00
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