set WOPEN on first open
[unix-history] / usr / src / sys / hp / dev / dca.c
CommitLineData
60f56dfc
KM
1/*
2 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
c98f3d99 7 * @(#)dca.c 7.4 (Berkeley) %G%
60f56dfc
KM
8 */
9
10#include "dca.h"
11#if NDCA > 0
12/*
13 * 98626/98644/internal serial interface
14 */
15#include "param.h"
16#include "systm.h"
17#include "ioctl.h"
18#include "tty.h"
19#include "user.h"
20#include "conf.h"
21#include "file.h"
22#include "uio.h"
23#include "kernel.h"
24#include "syslog.h"
25
26#include "device.h"
27#include "dcareg.h"
28#include "machine/cpu.h"
29#include "machine/isr.h"
30
31int dcaprobe();
32struct driver dcadriver = {
33 dcaprobe, "dca",
34};
35
36int dcastart(), dcaparam(), dcaintr();
37int dcasoftCAR;
38int dca_active;
39int ndca = NDCA;
40int dcaconsole = -1;
41int dcadefaultrate = TTYDEF_SPEED;
42struct dcadevice *dca_addr[NDCA];
43struct tty dca_tty[NDCA];
44struct isr dcaisr[NDCA];
45
46struct speedtab dcaspeedtab[] = {
47 0, 0,
48 50, DCABRD(50),
49 75, DCABRD(75),
50 110, DCABRD(110),
51 134, DCABRD(134),
52 150, DCABRD(150),
53 200, DCABRD(200),
54 300, DCABRD(300),
55 600, DCABRD(600),
56 1200, DCABRD(1200),
57 1800, DCABRD(1800),
58 2400, DCABRD(2400),
59 4800, DCABRD(4800),
60 9600, DCABRD(9600),
61 19200, DCABRD(19200),
62 38400, DCABRD(38400),
63 -1, -1
64};
65
66extern struct tty *constty;
67#ifdef KGDB
68extern int kgdb_dev;
69extern int kgdb_rate;
70extern int kgdb_debug_init;
71#endif
72
73#define UNIT(x) minor(x)
74
75dcaprobe(hd)
76 register struct hp_device *hd;
77{
78 register struct dcadevice *dca;
79 register int unit;
80
81 dca = (struct dcadevice *)hd->hp_addr;
82 if (dca->dca_irid != DCAID0 &&
83 dca->dca_irid != DCAREMID0 &&
84 dca->dca_irid != DCAID1 &&
85 dca->dca_irid != DCAREMID1)
86 return (0);
87 unit = hd->hp_unit;
88 if (unit == dcaconsole)
89 DELAY(100000);
90 dca->dca_irid = 0xFF;
91 DELAY(100);
92
93 hd->hp_ipl = DCAIPL(dca->dca_ic);
94 dcaisr[unit].isr_ipl = hd->hp_ipl;
95 dcaisr[unit].isr_arg = unit;
96 dcaisr[unit].isr_intr = dcaintr;
97 dca_addr[unit] = dca;
98 dca_active |= 1 << unit;
99 dcasoftCAR = hd->hp_flags;
100 isrlink(&dcaisr[unit]);
101#ifdef KGDB
102 if (kgdb_dev == makedev(1, unit)) {
103 if (dcaconsole == unit)
104 kgdb_dev = -1; /* can't debug over console port */
105 else {
106 (void) dcainit(unit);
107 dcaconsole = -2; /* XXX */
108 if (kgdb_debug_init) {
109 printf("dca%d: kgdb waiting...", unit);
110 /* trap into kgdb */
111 asm("trap #15;");
112 printf("connected.\n");
113 } else
114 printf("dca%d: kgdb enabled\n", unit);
115 }
116 }
117#endif
118 dca->dca_ic = IC_IE;
119 /*
120 * Need to reset baud rate, etc. of next print so reset dcaconsole.
121 * Also make sure console is always "hardwired"
122 */
123 if (unit == dcaconsole) {
124 dcaconsole = -1;
125 dcasoftCAR |= (1 << unit);
126 }
127 return (1);
128}
129
130dcaopen(dev, flag)
131 dev_t dev;
132{
133 register struct tty *tp;
134 register int unit;
fdf2ec5d 135 int error;
60f56dfc
KM
136
137 unit = UNIT(dev);
138 if (unit >= NDCA || (dca_active & (1 << unit)) == 0)
139 return (ENXIO);
140 tp = &dca_tty[unit];
141 tp->t_oproc = dcastart;
142 tp->t_param = dcaparam;
143 tp->t_dev = dev;
144 if ((tp->t_state & TS_ISOPEN) == 0) {
c98f3d99 145 tp->t_state |= TS_WOPEN;
60f56dfc
KM
146 ttychars(tp);
147 tp->t_iflag = TTYDEF_IFLAG;
148 tp->t_oflag = TTYDEF_OFLAG;
149 tp->t_cflag = TTYDEF_CFLAG;
150 tp->t_lflag = TTYDEF_LFLAG;
151 tp->t_ispeed = tp->t_ospeed = dcadefaultrate;
152 dcaparam(tp, &tp->t_termios);
153 ttsetwater(tp);
154 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
155 return (EBUSY);
156 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET);
157 if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD))
158 tp->t_state |= TS_CARR_ON;
159 (void) spltty();
160 while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
161 (tp->t_state & TS_CARR_ON) == 0) {
162 tp->t_state |= TS_WOPEN;
b886928d
MT
163 if ((error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
164 ttopen, 0)) ||
165 (error = ttclosed(tp))) {
fdf2ec5d
KM
166 tp->t_state &= ~TS_WOPEN;
167 (void) spl0();
168 return (error);
169 }
60f56dfc
KM
170 }
171 (void) spl0();
172 return ((*linesw[tp->t_line].l_open)(dev, tp));
173}
174
175/*ARGSUSED*/
176dcaclose(dev, flag)
177 dev_t dev;
178{
179 register struct tty *tp;
180 register struct dcadevice *dca;
181 register int unit;
182
183 unit = UNIT(dev);
184 dca = dca_addr[unit];
185 tp = &dca_tty[unit];
186 (*linesw[tp->t_line].l_close)(tp);
187 dca->dca_cfcr &= ~CFCR_SBREAK;
188#ifdef KGDB
189 /* do not disable interrupts if debugging */
190 if (kgdb_dev != makedev(1, unit))
191#endif
192 dca->dca_ier = 0;
193 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
194 (tp->t_state&TS_ISOPEN) == 0)
195 (void) dcamctl(dev, 0, DMSET);
196 ttyclose(tp);
197 return(0);
198}
199
200dcaread(dev, uio, flag)
201 dev_t dev;
202 struct uio *uio;
203{
204 register struct tty *tp = &dca_tty[UNIT(dev)];
205
206 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
207}
208
209dcawrite(dev, uio, flag)
210 dev_t dev;
211 struct uio *uio;
212{
213 int unit = UNIT(dev);
214 register struct tty *tp = &dca_tty[unit];
215
fdf2ec5d
KM
216 /*
217 * (XXX) We disallow virtual consoles if the physical console is
218 * a serial port. This is in case there is a display attached that
219 * is not the console. In that situation we don't need/want the X
220 * server taking over the console.
221 */
222 if (constty && unit == dcaconsole)
223 constty = NULL;
60f56dfc
KM
224 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
225}
226
227dcaintr(unit)
228 register int unit;
229{
230 register struct dcadevice *dca;
231 register int code;
232
233 dca = dca_addr[unit];
234 if ((dca->dca_ic & IC_IR) == 0)
235 return(0);
236 while (((code = dca->dca_iir) & IIR_NOPEND) == 0) {
237 code &= IIR_IMASK;
238 if (code == IIR_RLS)
239 dcaeint(unit, dca);
240 else if (code == IIR_RXRDY)
241 dcarint(unit, dca);
242 else if (code == IIR_TXRDY)
243 dcaxint(unit, dca);
244 else
245 dcamint(unit, dca);
246 }
247 return(1);
248}
249
250dcaeint(unit, dca)
251 register int unit;
252 register struct dcadevice *dca;
253{
254 register struct tty *tp;
255 register int stat, c;
256
257 tp = &dca_tty[unit];
258 stat = dca->dca_lsr;
259 c = dca->dca_data & 0xff;
260 if ((tp->t_state & TS_ISOPEN) == 0) {
261#ifdef KGDB
262 /* we don't care about parity errors */
263 if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
264 kgdb_dev == makedev(1, unit) && c == '!') {
265 printf("kgdb trap from dca%d\n", unit);
266 /* trap into kgdb */
267 asm("trap #15;");
268 }
269#endif
270 return;
271 }
272 if (stat & (LSR_BI | LSR_FE))
273 c |= TTY_FE;
274 else if (stat & LSR_PE)
275 c |= TTY_PE;
276 else if (stat & LSR_OE)
277 log(LOG_WARNING, "dca%d: silo overflow\n", unit);
278 (*linesw[tp->t_line].l_rint)(c, tp);
279}
280
281dcarint(unit, dca)
282 int unit;
283 register struct dcadevice *dca;
284{
285 register struct tty *tp;
286 register int c;
287
288 tp = &dca_tty[unit];
289 c = dca->dca_data;
290 if ((tp->t_state & TS_ISOPEN) == 0) {
291#ifdef KGDB
292 if (kgdb_dev == makedev(1, unit) && c == '!') {
293 printf("kgdb trap from dca%d\n", unit);
294 /* trap into kgdb */
295 asm("trap #15;");
296 }
297#endif
298 return;
299 }
300 (*linesw[tp->t_line].l_rint)(c, tp);
301}
302
303/*ARGSUSED*/
304dcaxint(unit, dca)
305 int unit;
306 struct dcadevice *dca;
307{
308 register struct tty *tp;
309
310 tp = &dca_tty[unit];
311 tp->t_state &= ~TS_BUSY;
312 if (tp->t_state & TS_FLUSH)
313 tp->t_state &= ~TS_FLUSH;
314 if (tp->t_line)
315 (*linesw[tp->t_line].l_start)(tp);
316 else
317 dcastart(tp);
318}
319
320dcamint(unit, dca)
321 register int unit;
322 register struct dcadevice *dca;
323{
324 register struct tty *tp;
325 register int stat;
326
327 tp = &dca_tty[unit];
328 stat = dca->dca_msr;
329 if ((stat & MSR_CCD) && (dcasoftCAR & (1 << unit)) == 0) {
330 if (stat & MSR_DCD)
331 (void) (*linesw[tp->t_line].l_modem)(tp, 1);
332 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
333 dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
334 }
335}
336
337dcaioctl(dev, cmd, data, flag)
338 dev_t dev;
339 caddr_t data;
340{
341 register struct tty *tp;
342 register int unit = UNIT(dev);
343 register struct dcadevice *dca;
344 register int error;
345
346 tp = &dca_tty[unit];
347 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
348 if (error >= 0)
349 return (error);
350 error = ttioctl(tp, cmd, data, flag);
351 if (error >= 0)
352 return (error);
353
354 dca = dca_addr[unit];
355 switch (cmd) {
356
357 case TIOCSBRK:
358 dca->dca_cfcr |= CFCR_SBREAK;
359 break;
360
361 case TIOCCBRK:
362 dca->dca_cfcr &= ~CFCR_SBREAK;
363 break;
364
365 case TIOCSDTR:
366 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
367 break;
368
369 case TIOCCDTR:
370 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
371 break;
372
373 case TIOCMSET:
374 (void) dcamctl(dev, *(int *)data, DMSET);
375 break;
376
377 case TIOCMBIS:
378 (void) dcamctl(dev, *(int *)data, DMBIS);
379 break;
380
381 case TIOCMBIC:
382 (void) dcamctl(dev, *(int *)data, DMBIC);
383 break;
384
385 case TIOCMGET:
386 *(int *)data = dcamctl(dev, 0, DMGET);
387 break;
388
389 default:
390 return (ENOTTY);
391 }
392 return (0);
393}
394
395dcaparam(tp, t)
396 register struct tty *tp;
397 register struct termios *t;
398{
399 register struct dcadevice *dca;
400 register int cfcr, cflag = t->c_cflag;
401 int unit = UNIT(tp->t_dev);
402 int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
403
404 /* check requested parameters */
405 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
406 return(EINVAL);
407 /* and copy to tty */
408 tp->t_ispeed = t->c_ispeed;
409 tp->t_ospeed = t->c_ospeed;
410 tp->t_cflag = cflag;
411
412 dca = dca_addr[unit];
413 dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
414 if (ospeed == 0) {
415 (void) dcamctl(unit, 0, DMSET); /* hang up line */
416 return(0);
417 }
418 dca->dca_cfcr |= CFCR_DLAB;
419 dca->dca_data = ospeed & 0xFF;
420 dca->dca_ier = ospeed >> 8;
421 switch (cflag&CSIZE) {
422 case CS5:
423 cfcr = CFCR_5BITS; break;
424 case CS6:
425 cfcr = CFCR_6BITS; break;
426 case CS7:
427 cfcr = CFCR_7BITS; break;
428 case CS8:
429 cfcr = CFCR_8BITS; break;
430 }
431 if (cflag&PARENB) {
432 cfcr |= CFCR_PENAB;
433 if ((cflag&PARODD) == 0)
434 cfcr |= CFCR_PEVEN;
435 }
436 if (cflag&CSTOPB)
437 cfcr |= CFCR_STOPB;
438 dca->dca_cfcr = cfcr;
439 return(0);
440}
441
442dcastart(tp)
443 register struct tty *tp;
444{
445 register struct dcadevice *dca;
446 int s, unit, c;
447
448 unit = UNIT(tp->t_dev);
449 dca = dca_addr[unit];
450 s = spltty();
451 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
452 goto out;
453 if (tp->t_outq.c_cc <= tp->t_lowat) {
454 if (tp->t_state&TS_ASLEEP) {
455 tp->t_state &= ~TS_ASLEEP;
456 wakeup((caddr_t)&tp->t_outq);
457 }
458 if (tp->t_wsel) {
459 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
460 tp->t_wsel = 0;
461 tp->t_state &= ~TS_WCOLL;
462 }
463 }
464 if (tp->t_outq.c_cc == 0)
465 goto out;
466 c = getc(&tp->t_outq);
467 tp->t_state |= TS_BUSY;
468 dca->dca_data = c;
469out:
470 splx(s);
471}
472
473/*
474 * Stop output on a line.
475 */
476/*ARGSUSED*/
477dcastop(tp, flag)
478 register struct tty *tp;
479{
480 register int s;
481
482 s = spltty();
483 if (tp->t_state & TS_BUSY) {
484 if ((tp->t_state&TS_TTSTOP)==0)
485 tp->t_state |= TS_FLUSH;
486 }
487 splx(s);
488}
489
490dcamctl(dev, bits, how)
491 dev_t dev;
492 int bits, how;
493{
494 register struct dcadevice *dca;
495 register int unit;
496 int s;
497
498 unit = UNIT(dev);
499 dca = dca_addr[unit];
500 s = spltty();
501 switch (how) {
502
503 case DMSET:
504 dca->dca_mcr = bits;
505 break;
506
507 case DMBIS:
508 dca->dca_mcr |= bits;
509 break;
510
511 case DMBIC:
512 dca->dca_mcr &= ~bits;
513 break;
514
515 case DMGET:
516 bits = dca->dca_msr;
517 break;
518 }
519 (void) splx(s);
520 return(bits);
521}
522
523/*
524 * Following are all routines needed for DCA to act as console
525 */
526#include "machine/cons.h"
527
528dcacnprobe(cp)
529 struct consdev *cp;
530{
531 int unit, i;
532 extern int dcaopen();
533
534 /* XXX: ick */
535 unit = CONUNIT;
536 dca_addr[CONUNIT] = CONADDR;
537
538 /* make sure hardware exists */
539 if (badaddr((short *)dca_addr[unit])) {
540 cp->cn_pri = CN_DEAD;
541 return;
542 }
543
544 /* locate the major number */
545 for (i = 0; i < nchrdev; i++)
546 if (cdevsw[i].d_open == dcaopen)
547 break;
548
549 /* initialize required fields */
550 cp->cn_dev = makedev(i, unit);
551 cp->cn_tp = &dca_tty[unit];
552 switch (dca_addr[unit]->dca_irid) {
553 case DCAID0:
554 case DCAID1:
555 cp->cn_pri = CN_NORMAL;
556 break;
557 case DCAREMID0:
558 case DCAREMID1:
559 cp->cn_pri = CN_REMOTE;
560 break;
561 default:
562 cp->cn_pri = CN_DEAD;
563 break;
564 }
565}
566
567dcacninit(cp)
568 struct consdev *cp;
569{
570 int unit = UNIT(cp->cn_dev);
571
572 dcainit(unit);
573 dcaconsole = unit;
574}
575
576dcainit(unit)
577 int unit;
578{
579 register struct dcadevice *dca;
580 int s, rate;
581 short stat;
582
583#ifdef lint
584 stat = unit; if (stat) return;
585#endif
586 dca = dca_addr[unit];
587 s = splhigh();
588 dca->dca_irid = 0xFF;
589 DELAY(100);
590 dca->dca_ic = IC_IE;
591 dca->dca_cfcr = CFCR_DLAB;
592 rate = ttspeedtab(dcadefaultrate, dcaspeedtab);
593 dca->dca_data = rate & 0xFF;
594 dca->dca_ier = rate >> 8;
595 dca->dca_cfcr = CFCR_8BITS;
596 dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
597 stat = dca->dca_iir;
598 splx(s);
599}
600
601dcacngetc(dev)
602{
603 register struct dcadevice *dca = dca_addr[UNIT(dev)];
604 short stat;
605 int c, s;
606
607#ifdef lint
608 stat = dev; if (stat) return(0);
609#endif
610 s = splhigh();
611 while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
612 ;
613 c = dca->dca_data;
614 stat = dca->dca_iir;
615 splx(s);
616 return(c);
617}
618
619/*
620 * Console kernel output character routine.
621 */
622dcacnputc(dev, c)
623 dev_t dev;
624 register int c;
625{
626 register struct dcadevice *dca = dca_addr[UNIT(dev)];
627 register int timo;
628 short stat;
629 int s = splhigh();
630
631#ifdef lint
632 stat = dev; if (stat) return;
633#endif
634 if (dcaconsole == -1) {
635 (void) dcainit(UNIT(dev));
636 dcaconsole = UNIT(dev);
637 }
638 /* wait for any pending transmission to finish */
639 timo = 50000;
640 while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
641 ;
642 dca->dca_data = c;
643 /* wait for this transmission to complete */
644 timo = 1500000;
645 while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
646 ;
647 /* clear any interrupts generated by this transmission */
648 stat = dca->dca_iir;
649 splx(s);
650}
651#endif