freebsd_amp_hwpstate/sys/gnu/isdn/iitty.c

551 lines
15 KiB
C
Raw Normal View History

static char _ittyid[] = "@(#)$Id: iitty.c,v 1.17 1995/12/08 23:19:42 phk Exp $";
/*******************************************************************************
* II - Version 0.1 $Revision: 1.17 $ $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.17 1995/12/08 23:19:42 phk
* Julian forgot to make the *devsw structures static.
*
* Revision 1.16 1995/12/08 11:12:56 julian
* Pass 3 of the great devsw changes
* most devsw referenced functions are now static, as they are
* in the same file as their devsw structure. I've also added DEVFS
* support for nearly every device in the system, however
* many of the devices have 'incorrect' names under DEVFS
* because I couldn't quickly work out the correct naming conventions.
* (but devfs won't be coming on line for a month or so anyhow so that doesn't
* matter)
*
* If you "OWN" a device which would normally have an entry in /dev
* then search for the devfs_add_devsw() entries and munge to make them right..
* check out similar devices to see what I might have done in them in you
* can't see what's going on..
* for a laugh compare conf.c conf.h defore and after... :)
* I have not doen DEVFS entries for any DISKSLICE devices yet as that will be
* a much more complicated job.. (pass 5 :)
*
* pass 4 will be to make the devsw tables of type (cdevsw * )
* rather than (cdevsw)
* seems to work here..
* complaints to the usual places.. :)
*
* Revision 1.15 1995/12/05 20:33:47 bde
* Fixed ity's d_stop entry. itystop() wasn't used. itystop() is inadequate
* but probably harmless. It's hard to tell because apparently no one runs
* ity.
*
* Fixed ity's d_reset entry. `nx' entries should never be used for existing
* devices.
*
* conf.c:
* Moved a prototype to a better place.
*
* Removed a stale #define.
*
* Revision 1.14 1995/11/29 14:39:12 julian
* If you're going to mechanically replicate something in 50 files
* it's best to not have a (compiles cleanly) typo in it! (sigh)
*
* Revision 1.13 1995/11/29 10:47:09 julian
* OK, that's it..
* That's EVERY SINGLE driver that has an entry in conf.c..
* my next trick will be to define cdevsw[] and bdevsw[]
* as empty arrays and remove all those DAMNED defines as well..
*
* Revision 1.12 1995/11/16 10:35:29 bde
* Fixed the type of ity_input(). A trailing arg was missing.
*
* Completed function declarations.
*
* Added prototypes.
*
* Removed some useless includes.
*
* Revision 1.11 1995/07/31 21:28:42 bde
* Use tsleep() instead of ttysleep() to wait for carrier since a generation
* change isn't an error.
*
* 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 <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/tty.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/kernel.h>
#include <sys/syslog.h>
#include <sys/types.h>
#ifdef DEVFS
#include <sys/devfsext.h>
#endif /*DEVFS*/
#include "gnu/isdn/isdn_ioctl.h"
static d_open_t ityopen;
static d_close_t ityclose;
static d_read_t ityread;
static d_write_t itywrite;
static d_ioctl_t ityioctl;
static d_stop_t itystop;
static d_devtotty_t itydevtotty;
#define CDEV_MAJOR 56
static struct cdevsw ity_cdevsw =
{ ityopen, ityclose, ityread, itywrite, /*56*/
ityioctl, itystop, noreset, itydevtotty,/* ity */
ttselect, nommap, NULL, "ity", NULL, -1 };
extern int ityparam __P((struct tty *tp, struct termios *t));
extern void itystart __P((struct tty *tp));
int nity = NITY;
int itydefaultrate = 64000;
short ity_addr[NITY];
struct tty ity_tty[NITY];
static int applnr[NITY];
static int next_if= 0;
#ifdef DEVFS
void *devfs_token[NITY];
void *devfs_token_out[NITY];
#endif
#define UNIT(x) (minor(x)&0x3f)
#define OUTBOUND(x) ((minor(x)&0x80)==0x80)
int
ityattach(int ap)
{
char name[32];
if(next_if >= NITY)
return(-1);
applnr[next_if]= ap;
#ifdef DEVFS
sprintf(name,"ity%d",next_if);
devfs_token[next_if] = devfs_add_devsw("/isdn",name,
&ity_cdevsw,next_if, DV_CHR, 0, 0, 0600);
sprintf(name,"Oity%d",next_if); /* XXX find out real name */
devfs_token[next_if] = devfs_add_devsw("/isdn",name,
&ity_cdevsw,(next_if | 0x80), DV_CHR, 0, 0, 0600);
#endif
return(next_if++);
}
/* ARGSUSED */
static 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 */
static 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);
}
static 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));
}
static 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, int dir)
{
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);
}
static 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 */
static 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);
}
static struct tty *
itydevtotty(dev_t dev)
{
register int unit = UNIT(dev);
if (unit >= next_if)
return (NULL);
return (&ity_tty[unit]);
}
static ity_devsw_installed = 0;
static void
ity_drvinit(void *unused)
{
dev_t dev;
if( ! ity_devsw_installed ) {
dev = makedev(CDEV_MAJOR, 0);
cdevsw_add(&dev,&ity_cdevsw, NULL);
ity_devsw_installed = 1;
}
}
SYSINIT(itydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ity_drvinit,NULL)
#endif