aboutsummaryrefslogtreecommitdiff
path: root/sys/gnu/isdn/iitty.c
blob: 488203b6592960d89aa5bfc428938a42b033a5b9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
static char     _ittyid[] = "@(#)$Id: iitty.c,v 1.5.4.1 1995/09/14 07:08:54 davidg Exp $";
/*******************************************************************************
 *  II - Version 0.1 $Revision: 1.5.4.1 $   $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.5.4.1  1995/09/14  07:08:54  davidg
 * Brought in changes from main branch:
 * 1) Bruce and Andrey's tty fixes
 * 2) many of Bruce's prototype and function argument fixes/corrections
 * 3) Bruce's version of the Cyclades driver
 * 4) Improvements to the RISCom/8 driver
 *
 * 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.
 *
 * 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