u. is gone; new device calling conventions
[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 *
b28b3a13 7 * @(#)dca.c 7.8 (Berkeley) %G%
60f56dfc
KM
8 */
9
10#include "dca.h"
11#if NDCA > 0
12/*
13 * 98626/98644/internal serial interface
14 */
b28b3a13
KB
15#include "sys/param.h"
16#include "sys/systm.h"
17#include "sys/ioctl.h"
18#include "sys/tty.h"
19#include "sys/user.h"
20#include "sys/conf.h"
21#include "sys/file.h"
22#include "sys/uio.h"
23#include "sys/kernel.h"
24#include "sys/syslog.h"
60f56dfc
KM
25
26#include "device.h"
27#include "dcareg.h"
b28b3a13
KB
28#include "../include/cpu.h"
29#include "../hp300/isr.h"
60f56dfc
KM
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;
037e7e94 135 int error = 0;
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();
23166e33 160 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
60f56dfc
KM
161 (tp->t_state & TS_CARR_ON) == 0) {
162 tp->t_state |= TS_WOPEN;
23166e33
MH
163 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
164 ttopen, 0))
165 break;
60f56dfc
KM
166 }
167 (void) spl0();
23166e33
MH
168 if (error == 0)
169 error = (*linesw[tp->t_line].l_open)(dev, tp);
170 return (error);
60f56dfc
KM
171}
172
173/*ARGSUSED*/
174dcaclose(dev, flag)
175 dev_t dev;
176{
177 register struct tty *tp;
178 register struct dcadevice *dca;
179 register int unit;
180
181 unit = UNIT(dev);
182 dca = dca_addr[unit];
183 tp = &dca_tty[unit];
184 (*linesw[tp->t_line].l_close)(tp);
185 dca->dca_cfcr &= ~CFCR_SBREAK;
186#ifdef KGDB
187 /* do not disable interrupts if debugging */
188 if (kgdb_dev != makedev(1, unit))
189#endif
190 dca->dca_ier = 0;
191 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
192 (tp->t_state&TS_ISOPEN) == 0)
193 (void) dcamctl(dev, 0, DMSET);
194 ttyclose(tp);
195 return(0);
196}
197
198dcaread(dev, uio, flag)
199 dev_t dev;
200 struct uio *uio;
201{
202 register struct tty *tp = &dca_tty[UNIT(dev)];
203
204 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
205}
206
207dcawrite(dev, uio, flag)
208 dev_t dev;
209 struct uio *uio;
210{
211 int unit = UNIT(dev);
212 register struct tty *tp = &dca_tty[unit];
213
fdf2ec5d
KM
214 /*
215 * (XXX) We disallow virtual consoles if the physical console is
216 * a serial port. This is in case there is a display attached that
217 * is not the console. In that situation we don't need/want the X
218 * server taking over the console.
219 */
220 if (constty && unit == dcaconsole)
221 constty = NULL;
60f56dfc
KM
222 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
223}
224
225dcaintr(unit)
226 register int unit;
227{
228 register struct dcadevice *dca;
05a2e58f
MH
229 register u_char code;
230 register struct tty *tp;
60f56dfc
KM
231
232 dca = dca_addr[unit];
233 if ((dca->dca_ic & IC_IR) == 0)
234 return(0);
05a2e58f
MH
235 while (1) {
236 code = dca->dca_iir;
237 switch (code) {
238 case IIR_NOPEND:
239 return (1);
240 case IIR_RXRDY:
241 /* do time-critical read in-line */
242 tp = &dca_tty[unit];
243 code = dca->dca_data;
244 if ((tp->t_state & TS_ISOPEN) == 0) {
245#ifdef KGDB
246 if (kgdb_dev == makedev(1, unit) &&
247 code == '!') {
248 printf("kgdb trap from dca%d\n", unit);
249 /* trap into kgdb */
250 asm("trap #15;");
251 }
252#endif
253 } else
254 (*linesw[tp->t_line].l_rint)(code, tp);
255 break;
256 case IIR_TXRDY:
257 tp = &dca_tty[unit];
258 tp->t_state &=~ (TS_BUSY|TS_FLUSH);
259 if (tp->t_line)
260 (*linesw[tp->t_line].l_start)(tp);
261 else
262 dcastart(tp);
263 break;
264 case IIR_RLS:
60f56dfc 265 dcaeint(unit, dca);
05a2e58f
MH
266 break;
267 default:
268 if (code & IIR_NOPEND)
269 return (1);
270 log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
271 unit, code);
272 /* fall through */
273 case IIR_MLSC:
60f56dfc 274 dcamint(unit, dca);
05a2e58f
MH
275 break;
276 }
60f56dfc 277 }
60f56dfc
KM
278}
279
280dcaeint(unit, dca)
281 register int unit;
282 register struct dcadevice *dca;
283{
284 register struct tty *tp;
285 register int stat, c;
286
287 tp = &dca_tty[unit];
288 stat = dca->dca_lsr;
05a2e58f 289 c = dca->dca_data;
60f56dfc
KM
290 if ((tp->t_state & TS_ISOPEN) == 0) {
291#ifdef KGDB
292 /* we don't care about parity errors */
293 if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
294 kgdb_dev == makedev(1, unit) && c == '!') {
295 printf("kgdb trap from dca%d\n", unit);
296 /* trap into kgdb */
297 asm("trap #15;");
298 }
299#endif
300 return;
301 }
302 if (stat & (LSR_BI | LSR_FE))
303 c |= TTY_FE;
304 else if (stat & LSR_PE)
305 c |= TTY_PE;
306 else if (stat & LSR_OE)
307 log(LOG_WARNING, "dca%d: silo overflow\n", unit);
308 (*linesw[tp->t_line].l_rint)(c, tp);
309}
310
60f56dfc
KM
311dcamint(unit, dca)
312 register int unit;
313 register struct dcadevice *dca;
314{
315 register struct tty *tp;
316 register int stat;
317
318 tp = &dca_tty[unit];
319 stat = dca->dca_msr;
05a2e58f 320 if ((stat & MSR_DDCD) && (dcasoftCAR & (1 << unit)) == 0) {
60f56dfc 321 if (stat & MSR_DCD)
05a2e58f 322 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
60f56dfc
KM
323 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
324 dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
05a2e58f
MH
325 } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
326 (tp->t_flags & CRTSCTS)) {
327 /* the line is up and we want to do rts/cts flow control */
328 if (stat & MSR_CTS) {
329 tp->t_state &=~ TS_TTSTOP;
330 ttstart(tp);
331 } else
332 tp->t_state |= TS_TTSTOP;
60f56dfc
KM
333 }
334}
335
336dcaioctl(dev, cmd, data, flag)
337 dev_t dev;
338 caddr_t data;
339{
340 register struct tty *tp;
341 register int unit = UNIT(dev);
342 register struct dcadevice *dca;
343 register int error;
344
345 tp = &dca_tty[unit];
346 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
347 if (error >= 0)
348 return (error);
349 error = ttioctl(tp, cmd, data, flag);
350 if (error >= 0)
351 return (error);
352
353 dca = dca_addr[unit];
354 switch (cmd) {
355
356 case TIOCSBRK:
357 dca->dca_cfcr |= CFCR_SBREAK;
358 break;
359
360 case TIOCCBRK:
361 dca->dca_cfcr &= ~CFCR_SBREAK;
362 break;
363
364 case TIOCSDTR:
365 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
366 break;
367
368 case TIOCCDTR:
369 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
370 break;
371
372 case TIOCMSET:
373 (void) dcamctl(dev, *(int *)data, DMSET);
374 break;
375
376 case TIOCMBIS:
377 (void) dcamctl(dev, *(int *)data, DMBIS);
378 break;
379
380 case TIOCMBIC:
381 (void) dcamctl(dev, *(int *)data, DMBIC);
382 break;
383
384 case TIOCMGET:
385 *(int *)data = dcamctl(dev, 0, DMGET);
386 break;
387
388 default:
389 return (ENOTTY);
390 }
391 return (0);
392}
393
394dcaparam(tp, t)
395 register struct tty *tp;
396 register struct termios *t;
397{
398 register struct dcadevice *dca;
399 register int cfcr, cflag = t->c_cflag;
400 int unit = UNIT(tp->t_dev);
401 int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
402
403 /* check requested parameters */
404 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
405 return(EINVAL);
406 /* and copy to tty */
407 tp->t_ispeed = t->c_ispeed;
408 tp->t_ospeed = t->c_ospeed;
409 tp->t_cflag = cflag;
410
411 dca = dca_addr[unit];
412 dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
413 if (ospeed == 0) {
414 (void) dcamctl(unit, 0, DMSET); /* hang up line */
415 return(0);
416 }
417 dca->dca_cfcr |= CFCR_DLAB;
418 dca->dca_data = ospeed & 0xFF;
419 dca->dca_ier = ospeed >> 8;
420 switch (cflag&CSIZE) {
421 case CS5:
422 cfcr = CFCR_5BITS; break;
423 case CS6:
424 cfcr = CFCR_6BITS; break;
425 case CS7:
426 cfcr = CFCR_7BITS; break;
427 case CS8:
428 cfcr = CFCR_8BITS; break;
429 }
430 if (cflag&PARENB) {
431 cfcr |= CFCR_PENAB;
432 if ((cflag&PARODD) == 0)
433 cfcr |= CFCR_PEVEN;
434 }
435 if (cflag&CSTOPB)
436 cfcr |= CFCR_STOPB;
437 dca->dca_cfcr = cfcr;
438 return(0);
439}
440
441dcastart(tp)
442 register struct tty *tp;
443{
444 register struct dcadevice *dca;
445 int s, unit, c;
446
447 unit = UNIT(tp->t_dev);
448 dca = dca_addr[unit];
449 s = spltty();
05a2e58f 450 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
60f56dfc
KM
451 goto out;
452 if (tp->t_outq.c_cc <= tp->t_lowat) {
453 if (tp->t_state&TS_ASLEEP) {
454 tp->t_state &= ~TS_ASLEEP;
455 wakeup((caddr_t)&tp->t_outq);
456 }
457 if (tp->t_wsel) {
458 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
459 tp->t_wsel = 0;
460 tp->t_state &= ~TS_WCOLL;
461 }
462 }
463 if (tp->t_outq.c_cc == 0)
464 goto out;
05a2e58f
MH
465 if (dca->dca_lsr & LSR_TXRDY) {
466 c = getc(&tp->t_outq);
467 tp->t_state |= TS_BUSY;
468 dca->dca_data = c;
469 }
60f56dfc
KM
470out:
471 splx(s);
472}
473
474/*
475 * Stop output on a line.
476 */
477/*ARGSUSED*/
478dcastop(tp, flag)
479 register struct tty *tp;
480{
481 register int s;
482
483 s = spltty();
484 if (tp->t_state & TS_BUSY) {
485 if ((tp->t_state&TS_TTSTOP)==0)
486 tp->t_state |= TS_FLUSH;
487 }
488 splx(s);
489}
490
491dcamctl(dev, bits, how)
492 dev_t dev;
493 int bits, how;
494{
495 register struct dcadevice *dca;
496 register int unit;
497 int s;
498
499 unit = UNIT(dev);
500 dca = dca_addr[unit];
501 s = spltty();
502 switch (how) {
503
504 case DMSET:
505 dca->dca_mcr = bits;
506 break;
507
508 case DMBIS:
509 dca->dca_mcr |= bits;
510 break;
511
512 case DMBIC:
513 dca->dca_mcr &= ~bits;
514 break;
515
516 case DMGET:
517 bits = dca->dca_msr;
518 break;
519 }
520 (void) splx(s);
521 return(bits);
522}
523
524/*
525 * Following are all routines needed for DCA to act as console
526 */
b28b3a13 527#include "../hp300/cons.h"
60f56dfc
KM
528
529dcacnprobe(cp)
530 struct consdev *cp;
531{
532 int unit, i;
533 extern int dcaopen();
534
535 /* XXX: ick */
536 unit = CONUNIT;
537 dca_addr[CONUNIT] = CONADDR;
538
539 /* make sure hardware exists */
540 if (badaddr((short *)dca_addr[unit])) {
541 cp->cn_pri = CN_DEAD;
542 return;
543 }
544
545 /* locate the major number */
546 for (i = 0; i < nchrdev; i++)
547 if (cdevsw[i].d_open == dcaopen)
548 break;
549
550 /* initialize required fields */
551 cp->cn_dev = makedev(i, unit);
552 cp->cn_tp = &dca_tty[unit];
553 switch (dca_addr[unit]->dca_irid) {
554 case DCAID0:
555 case DCAID1:
556 cp->cn_pri = CN_NORMAL;
557 break;
558 case DCAREMID0:
559 case DCAREMID1:
560 cp->cn_pri = CN_REMOTE;
561 break;
562 default:
563 cp->cn_pri = CN_DEAD;
564 break;
565 }
566}
567
568dcacninit(cp)
569 struct consdev *cp;
570{
571 int unit = UNIT(cp->cn_dev);
572
573 dcainit(unit);
574 dcaconsole = unit;
575}
576
577dcainit(unit)
578 int unit;
579{
580 register struct dcadevice *dca;
581 int s, rate;
582 short stat;
583
584#ifdef lint
585 stat = unit; if (stat) return;
586#endif
587 dca = dca_addr[unit];
588 s = splhigh();
589 dca->dca_irid = 0xFF;
590 DELAY(100);
591 dca->dca_ic = IC_IE;
592 dca->dca_cfcr = CFCR_DLAB;
593 rate = ttspeedtab(dcadefaultrate, dcaspeedtab);
594 dca->dca_data = rate & 0xFF;
595 dca->dca_ier = rate >> 8;
596 dca->dca_cfcr = CFCR_8BITS;
597 dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
598 stat = dca->dca_iir;
599 splx(s);
600}
601
602dcacngetc(dev)
603{
604 register struct dcadevice *dca = dca_addr[UNIT(dev)];
605 short stat;
606 int c, s;
607
608#ifdef lint
609 stat = dev; if (stat) return(0);
610#endif
611 s = splhigh();
612 while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
613 ;
614 c = dca->dca_data;
615 stat = dca->dca_iir;
616 splx(s);
617 return(c);
618}
619
620/*
621 * Console kernel output character routine.
622 */
623dcacnputc(dev, c)
624 dev_t dev;
625 register int c;
626{
627 register struct dcadevice *dca = dca_addr[UNIT(dev)];
628 register int timo;
629 short stat;
630 int s = splhigh();
631
632#ifdef lint
633 stat = dev; if (stat) return;
634#endif
635 if (dcaconsole == -1) {
636 (void) dcainit(UNIT(dev));
637 dcaconsole = UNIT(dev);
638 }
639 /* wait for any pending transmission to finish */
640 timo = 50000;
641 while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
642 ;
643 dca->dca_data = c;
644 /* wait for this transmission to complete */
645 timo = 1500000;
646 while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
647 ;
648 /* clear any interrupts generated by this transmission */
649 stat = dca->dca_iir;
650 splx(s);
651}
652#endif