Commit | Line | Data |
---|---|---|
6c1a1c86 | 1 | /*- |
86090d31 KB |
2 | * Copyright (c) 1992, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
12d43ee5 KM |
4 | * |
5 | * This code is derived from software contributed to Berkeley by | |
6c1a1c86 | 6 | * Ralph Campbell and Rick Macklem. |
12d43ee5 KM |
7 | * |
8 | * %sccs.include.redist.c% | |
9 | * | |
86090d31 | 10 | * @(#)dc.c 8.1 (Berkeley) %G% |
6c1a1c86 RC |
11 | */ |
12 | ||
13 | /* | |
12d43ee5 KM |
14 | * devDC7085.c -- |
15 | * | |
16 | * This file contains machine-dependent routines that handle the | |
17 | * output queue for the serial lines. | |
18 | * | |
19 | * Copyright (C) 1989 Digital Equipment Corporation. | |
20 | * Permission to use, copy, modify, and distribute this software and | |
21 | * its documentation for any purpose and without fee is hereby granted, | |
22 | * provided that the above copyright notice appears in all copies. | |
23 | * Digital Equipment Corporation makes no representations about the | |
24 | * suitability of this software for any purpose. It is provided "as is" | |
25 | * without express or implied warranty. | |
26 | * | |
27 | * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devDC7085.c, | |
28 | * v 1.4 89/08/29 11:55:30 nelson Exp $ SPRITE (DECWRL)"; | |
29 | */ | |
30 | ||
6c1a1c86 | 31 | #include <dc.h> |
12d43ee5 KM |
32 | #if NDC > 0 |
33 | /* | |
34 | * DC7085 (DZ-11 look alike) Driver | |
35 | */ | |
38a01dbe KB |
36 | #include <sys/param.h> |
37 | #include <sys/systm.h> | |
38 | #include <sys/ioctl.h> | |
39 | #include <sys/tty.h> | |
40 | #include <sys/proc.h> | |
41 | #include <sys/map.h> | |
42 | #include <sys/buf.h> | |
43 | #include <sys/conf.h> | |
44 | #include <sys/file.h> | |
45 | #include <sys/uio.h> | |
46 | #include <sys/kernel.h> | |
47 | #include <sys/syslog.h> | |
12d43ee5 | 48 | |
38a01dbe | 49 | #include <machine/dc7085cons.h> |
6c1a1c86 RC |
50 | #include <machine/pmioctl.h> |
51 | ||
52 | #include <pmax/pmax/pmaxtype.h> | |
53 | #include <pmax/pmax/cons.h> | |
12d43ee5 | 54 | |
707603c0 KB |
55 | #include <pmax/dev/device.h> |
56 | #include <pmax/dev/pdma.h> | |
6c1a1c86 RC |
57 | #include <pmax/dev/fbreg.h> |
58 | ||
59 | extern int pmax_boardtype; | |
60 | extern struct consdev cn_tab; | |
12d43ee5 KM |
61 | |
62 | /* | |
63 | * Driver information for auto-configuration stuff. | |
64 | */ | |
65 | int dcprobe(); | |
84722262 | 66 | void dcintr(); |
12d43ee5 | 67 | struct driver dcdriver = { |
84722262 | 68 | "dc", dcprobe, 0, 0, dcintr, |
12d43ee5 KM |
69 | }; |
70 | ||
71 | #define NDCLINE (NDC*4) | |
72 | ||
6c1a1c86 RC |
73 | void dcstart __P((struct tty *)); |
74 | void dcxint __P((struct tty *)); | |
75 | void dcPutc __P((dev_t, int)); | |
76 | void dcscan __P((void *)); | |
2c940704 | 77 | extern void ttrstrt __P((void *)); |
6c1a1c86 RC |
78 | int dcGetc __P((dev_t)); |
79 | int dcparam __P((struct tty *, struct termios *)); | |
12d43ee5 KM |
80 | |
81 | struct tty dc_tty[NDCLINE]; | |
82 | int dc_cnt = NDCLINE; | |
60160479 RC |
83 | void (*dcDivertXInput)(); /* X windows keyboard input routine */ |
84 | void (*dcMouseEvent)(); /* X windows mouse motion event routine */ | |
85 | void (*dcMouseButtons)(); /* X windows mouse buttons event routine */ | |
12d43ee5 KM |
86 | #ifdef DEBUG |
87 | int debugChar; | |
88 | #endif | |
89 | ||
90 | /* | |
91 | * Software copy of brk register since it isn't readable | |
92 | */ | |
93 | int dc_brk[NDC]; | |
94 | char dcsoftCAR[NDC]; /* mask of dc's with carrier on (DSR) */ | |
95 | ||
96 | /* | |
97 | * The DC7085 doesn't interrupt on carrier transitions, so | |
98 | * we have to use a timer to watch it. | |
99 | */ | |
100 | int dc_timer; /* true if timer started */ | |
101 | ||
102 | /* | |
103 | * Pdma structures for fast output code | |
104 | */ | |
105 | struct pdma dcpdma[NDCLINE]; | |
106 | ||
107 | struct speedtab dcspeedtab[] = { | |
108 | 0, 0, | |
109 | 50, LPR_B50, | |
110 | 75, LPR_B75, | |
111 | 110, LPR_B110, | |
112 | 134, LPR_B134, | |
113 | 150, LPR_B150, | |
114 | 300, LPR_B300, | |
115 | 600, LPR_B600, | |
116 | 1200, LPR_B1200, | |
117 | 1800, LPR_B1800, | |
118 | 2400, LPR_B2400, | |
119 | 4800, LPR_B4800, | |
120 | 9600, LPR_B9600, | |
84722262 | 121 | 19200, LPR_B19200, |
12d43ee5 KM |
122 | -1, -1 |
123 | }; | |
124 | ||
125 | #ifndef PORTSELECTOR | |
126 | #define ISPEED TTYDEF_SPEED | |
127 | #define LFLAG TTYDEF_LFLAG | |
128 | #else | |
129 | #define ISPEED B4800 | |
130 | #define LFLAG (TTYDEF_LFLAG & ~ECHO) | |
131 | #endif | |
132 | ||
12d43ee5 KM |
133 | /* |
134 | * Test to see if device is present. | |
135 | * Return true if found and initialized ok. | |
136 | */ | |
137 | dcprobe(cp) | |
138 | register struct pmax_ctlr *cp; | |
139 | { | |
140 | register dcregs *dcaddr; | |
141 | register struct pdma *pdp; | |
142 | register struct tty *tp; | |
143 | register int cntr; | |
6c1a1c86 | 144 | int s; |
12d43ee5 KM |
145 | |
146 | if (cp->pmax_unit >= NDC) | |
147 | return (0); | |
148 | if (badaddr(cp->pmax_addr, 2)) | |
149 | return (0); | |
150 | ||
a7971d31 RC |
151 | /* |
152 | * For a remote console, wait a while for previous output to | |
153 | * complete. | |
154 | */ | |
155 | if (major(cn_tab.cn_dev) == DCDEV && cp->pmax_unit == 0 && | |
156 | cn_tab.cn_screen == 0) | |
157 | DELAY(10000); | |
158 | ||
12d43ee5 KM |
159 | /* reset chip */ |
160 | dcaddr = (dcregs *)cp->pmax_addr; | |
161 | dcaddr->dc_csr = CSR_CLR; | |
162 | MachEmptyWriteBuffer(); | |
163 | while (dcaddr->dc_csr & CSR_CLR) | |
164 | ; | |
165 | dcaddr->dc_csr = CSR_MSE | CSR_TIE | CSR_RIE; | |
166 | ||
167 | /* init pseudo DMA structures */ | |
168 | pdp = &dcpdma[cp->pmax_unit * 4]; | |
169 | tp = &dc_tty[cp->pmax_unit * 4]; | |
170 | for (cntr = 0; cntr < 4; cntr++) { | |
6c1a1c86 | 171 | pdp->p_addr = (void *)dcaddr; |
12d43ee5 KM |
172 | pdp->p_arg = (int)tp; |
173 | pdp->p_fcn = dcxint; | |
174 | tp->t_addr = (caddr_t)pdp; | |
175 | pdp++, tp++; | |
176 | } | |
177 | dcsoftCAR[cp->pmax_unit] = cp->pmax_flags | 0xB; | |
178 | ||
179 | if (dc_timer == 0) { | |
180 | dc_timer = 1; | |
57373dbf | 181 | timeout(dcscan, (void *)0, hz); |
12d43ee5 | 182 | } |
12d43ee5 | 183 | |
6c1a1c86 RC |
184 | /* |
185 | * Special handling for consoles. | |
186 | */ | |
187 | if (cp->pmax_unit == 0) { | |
188 | if (cn_tab.cn_screen) { | |
189 | s = spltty(); | |
190 | dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR | | |
191 | LPR_B4800 | DCKBD_PORT; | |
3c5e0ae7 | 192 | MachEmptyWriteBuffer(); |
6c1a1c86 RC |
193 | dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR | |
194 | LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT; | |
195 | MachEmptyWriteBuffer(); | |
a7971d31 | 196 | DELAY(1000); |
6c1a1c86 RC |
197 | KBDReset(makedev(DCDEV, DCKBD_PORT), dcPutc); |
198 | MouseInit(makedev(DCDEV, DCMOUSE_PORT), dcPutc, dcGetc); | |
199 | splx(s); | |
200 | } else if (major(cn_tab.cn_dev) == DCDEV) { | |
201 | s = spltty(); | |
202 | dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR | | |
203 | LPR_B9600 | minor(cn_tab.cn_dev); | |
204 | MachEmptyWriteBuffer(); | |
a7971d31 | 205 | DELAY(1000); |
6c1a1c86 RC |
206 | cn_tab.cn_disabled = 0; |
207 | splx(s); | |
208 | } | |
12d43ee5 | 209 | } |
a7971d31 RC |
210 | printf("dc%d at nexus0 csr 0x%x priority %d\n", |
211 | cp->pmax_unit, cp->pmax_addr, cp->pmax_pri); | |
12d43ee5 KM |
212 | return (1); |
213 | } | |
214 | ||
c74d1258 | 215 | dcopen(dev, flag, mode, p) |
12d43ee5 | 216 | dev_t dev; |
c74d1258 RC |
217 | int flag, mode; |
218 | struct proc *p; | |
12d43ee5 KM |
219 | { |
220 | register struct tty *tp; | |
221 | register int unit; | |
222 | int s, error = 0; | |
12d43ee5 KM |
223 | |
224 | unit = minor(dev); | |
6c1a1c86 | 225 | if (unit >= dc_cnt || dcpdma[unit].p_addr == (void *)0) |
12d43ee5 KM |
226 | return (ENXIO); |
227 | tp = &dc_tty[unit]; | |
228 | tp->t_addr = (caddr_t)&dcpdma[unit]; | |
229 | tp->t_oproc = dcstart; | |
230 | tp->t_param = dcparam; | |
231 | tp->t_dev = dev; | |
232 | if ((tp->t_state & TS_ISOPEN) == 0) { | |
233 | tp->t_state |= TS_WOPEN; | |
234 | ttychars(tp); | |
235 | #ifndef PORTSELECTOR | |
236 | if (tp->t_ispeed == 0) { | |
237 | #endif | |
238 | tp->t_iflag = TTYDEF_IFLAG; | |
239 | tp->t_oflag = TTYDEF_OFLAG; | |
240 | tp->t_cflag = TTYDEF_CFLAG; | |
241 | tp->t_lflag = LFLAG; | |
242 | tp->t_ispeed = tp->t_ospeed = ISPEED; | |
243 | #ifdef PORTSELECTOR | |
244 | tp->t_cflag |= HUPCL; | |
245 | #else | |
246 | } | |
247 | #endif | |
248 | (void) dcparam(tp, &tp->t_termios); | |
249 | ttsetwater(tp); | |
250 | } else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0) | |
251 | return (EBUSY); | |
252 | (void) dcmctl(dev, DML_DTR, DMSET); | |
253 | s = spltty(); | |
254 | while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) && | |
255 | !(tp->t_state & TS_CARR_ON)) { | |
256 | tp->t_state |= TS_WOPEN; | |
257 | if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, | |
258 | ttopen, 0)) | |
259 | break; | |
260 | } | |
261 | splx(s); | |
262 | if (error) | |
263 | return (error); | |
264 | return ((*linesw[tp->t_line].l_open)(dev, tp)); | |
265 | } | |
266 | ||
267 | /*ARGSUSED*/ | |
c74d1258 | 268 | dcclose(dev, flag, mode, p) |
12d43ee5 | 269 | dev_t dev; |
c74d1258 RC |
270 | int flag, mode; |
271 | struct proc *p; | |
12d43ee5 KM |
272 | { |
273 | register struct tty *tp; | |
274 | register int unit, bit; | |
275 | ||
276 | unit = minor(dev); | |
277 | tp = &dc_tty[unit]; | |
278 | bit = 1 << ((unit & 03) + 8); | |
279 | if (dc_brk[unit >> 2] & bit) { | |
280 | dc_brk[unit >> 2] &= ~bit; | |
281 | ttyoutput(0, tp); | |
282 | } | |
c74d1258 | 283 | (*linesw[tp->t_line].l_close)(tp, flag); |
12d43ee5 KM |
284 | if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) || |
285 | !(tp->t_state & TS_ISOPEN)) | |
286 | (void) dcmctl(dev, 0, DMSET); | |
287 | return (ttyclose(tp)); | |
288 | } | |
289 | ||
290 | dcread(dev, uio, flag) | |
291 | dev_t dev; | |
292 | struct uio *uio; | |
293 | { | |
294 | register struct tty *tp; | |
295 | ||
296 | tp = &dc_tty[minor(dev)]; | |
297 | return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); | |
298 | } | |
299 | ||
300 | dcwrite(dev, uio, flag) | |
301 | dev_t dev; | |
302 | struct uio *uio; | |
303 | { | |
304 | register struct tty *tp; | |
305 | ||
306 | tp = &dc_tty[minor(dev)]; | |
307 | return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); | |
308 | } | |
309 | ||
12d43ee5 | 310 | /*ARGSUSED*/ |
c74d1258 | 311 | dcioctl(dev, cmd, data, flag, p) |
12d43ee5 | 312 | dev_t dev; |
6c1a1c86 | 313 | int cmd; |
12d43ee5 | 314 | caddr_t data; |
c74d1258 RC |
315 | int flag; |
316 | struct proc *p; | |
12d43ee5 KM |
317 | { |
318 | register struct tty *tp; | |
319 | register int unit = minor(dev); | |
320 | register int dc = unit >> 2; | |
321 | int error; | |
322 | ||
323 | tp = &dc_tty[unit]; | |
c74d1258 | 324 | error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); |
12d43ee5 KM |
325 | if (error >= 0) |
326 | return (error); | |
327 | error = ttioctl(tp, cmd, data, flag); | |
328 | if (error >= 0) | |
329 | return (error); | |
330 | ||
331 | switch (cmd) { | |
332 | ||
333 | case TIOCSBRK: | |
334 | dc_brk[dc] |= 1 << ((unit & 03) + 8); | |
335 | ttyoutput(0, tp); | |
336 | break; | |
337 | ||
338 | case TIOCCBRK: | |
339 | dc_brk[dc] &= ~(1 << ((unit & 03) + 8)); | |
340 | ttyoutput(0, tp); | |
341 | break; | |
342 | ||
343 | case TIOCSDTR: | |
344 | (void) dcmctl(dev, DML_DTR|DML_RTS, DMBIS); | |
345 | break; | |
346 | ||
347 | case TIOCCDTR: | |
348 | (void) dcmctl(dev, DML_DTR|DML_RTS, DMBIC); | |
349 | break; | |
350 | ||
351 | case TIOCMSET: | |
352 | (void) dcmctl(dev, *(int *)data, DMSET); | |
353 | break; | |
354 | ||
355 | case TIOCMBIS: | |
356 | (void) dcmctl(dev, *(int *)data, DMBIS); | |
357 | break; | |
358 | ||
359 | case TIOCMBIC: | |
360 | (void) dcmctl(dev, *(int *)data, DMBIC); | |
361 | break; | |
362 | ||
363 | case TIOCMGET: | |
364 | *(int *)data = dcmctl(dev, 0, DMGET); | |
365 | break; | |
366 | ||
367 | default: | |
368 | return (ENOTTY); | |
369 | } | |
370 | return (0); | |
371 | } | |
372 | ||
373 | dcparam(tp, t) | |
374 | register struct tty *tp; | |
375 | register struct termios *t; | |
376 | { | |
377 | register dcregs *dcaddr; | |
378 | register int lpr; | |
379 | register int cflag = t->c_cflag; | |
380 | int unit = minor(tp->t_dev); | |
381 | int ospeed = ttspeedtab(t->c_ospeed, dcspeedtab); | |
382 | ||
383 | /* check requested parameters */ | |
384 | if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed) || | |
6c1a1c86 RC |
385 | (cflag & CSIZE) == CS5 || (cflag & CSIZE) == CS6 || |
386 | (pmax_boardtype == DS_PMAX && t->c_ospeed == 19200)) | |
12d43ee5 KM |
387 | return (EINVAL); |
388 | /* and copy to tty */ | |
389 | tp->t_ispeed = t->c_ispeed; | |
390 | tp->t_ospeed = t->c_ospeed; | |
391 | tp->t_cflag = cflag; | |
392 | ||
6c1a1c86 RC |
393 | dcaddr = (dcregs *)dcpdma[unit].p_addr; |
394 | ||
395 | /* | |
396 | * Handle console cases specially. | |
397 | */ | |
398 | if (cn_tab.cn_screen) { | |
399 | if (unit == DCKBD_PORT) { | |
400 | dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR | | |
401 | LPR_B4800 | DCKBD_PORT; | |
402 | MachEmptyWriteBuffer(); | |
403 | return (0); | |
404 | } else if (unit == DCMOUSE_PORT) { | |
405 | dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR | | |
406 | LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT; | |
407 | MachEmptyWriteBuffer(); | |
408 | return (0); | |
409 | } | |
410 | } else if (tp->t_dev == cn_tab.cn_dev) { | |
411 | dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR | | |
412 | LPR_B9600 | unit; | |
12d43ee5 KM |
413 | MachEmptyWriteBuffer(); |
414 | return (0); | |
415 | } | |
416 | if (ospeed == 0) { | |
417 | (void) dcmctl(unit, 0, DMSET); /* hang up line */ | |
418 | return (0); | |
419 | } | |
420 | lpr = LPR_RXENAB | ospeed | (unit & 03); | |
421 | if ((cflag & CSIZE) == CS7) | |
422 | lpr |= LPR_7_BIT_CHAR; | |
423 | else | |
424 | lpr |= LPR_8_BIT_CHAR; | |
425 | if (cflag & PARENB) | |
426 | lpr |= LPR_PARENB; | |
427 | if (cflag & PARODD) | |
428 | lpr |= LPR_OPAR; | |
429 | if (cflag & CSTOPB) | |
430 | lpr |= LPR_2_STOP; | |
431 | dcaddr->dc_lpr = lpr; | |
432 | MachEmptyWriteBuffer(); | |
3c5e0ae7 | 433 | DELAY(10); |
12d43ee5 KM |
434 | return (0); |
435 | } | |
436 | ||
84722262 RC |
437 | /* |
438 | * Check for interrupts from all devices. | |
439 | */ | |
440 | void | |
441 | dcintr(unit) | |
442 | register int unit; | |
443 | { | |
444 | register dcregs *dcaddr; | |
445 | register unsigned csr; | |
446 | ||
447 | unit <<= 2; | |
6c1a1c86 | 448 | dcaddr = (dcregs *)dcpdma[unit].p_addr; |
84722262 RC |
449 | while ((csr = dcaddr->dc_csr) & (CSR_RDONE | CSR_TRDY)) { |
450 | if (csr & CSR_RDONE) | |
451 | dcrint(unit); | |
452 | if (csr & CSR_TRDY) | |
453 | dcxint(&dc_tty[unit + ((csr >> 8) & 03)]); | |
454 | } | |
455 | } | |
456 | ||
457 | dcrint(unit) | |
458 | register int unit; | |
459 | { | |
460 | register dcregs *dcaddr; | |
461 | register struct tty *tp; | |
462 | register int c, cc; | |
463 | register struct tty *tp0; | |
464 | int overrun = 0; | |
465 | ||
6c1a1c86 | 466 | dcaddr = (dcregs *)dcpdma[unit].p_addr; |
84722262 RC |
467 | tp0 = &dc_tty[unit]; |
468 | while ((c = dcaddr->dc_rbuf) < 0) { /* char present */ | |
469 | cc = c & 0xff; | |
470 | tp = tp0 + ((c >> 8) & 03); | |
471 | if ((c & RBUF_OERR) && overrun == 0) { | |
472 | log(LOG_WARNING, "dc%d,%d: silo overflow\n", unit >> 2, | |
473 | (c >> 8) & 03); | |
474 | overrun = 1; | |
475 | } | |
476 | /* the keyboard requires special translation */ | |
6c1a1c86 | 477 | if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) { |
84722262 RC |
478 | #ifdef KADB |
479 | if (cc == LK_DO) { | |
480 | spl0(); | |
481 | kdbpanic(); | |
482 | return; | |
483 | } | |
484 | #endif | |
485 | #ifdef DEBUG | |
486 | debugChar = cc; | |
487 | #endif | |
488 | if (dcDivertXInput) { | |
60160479 | 489 | (*dcDivertXInput)(cc); |
84722262 RC |
490 | return; |
491 | } | |
6c1a1c86 | 492 | if ((cc = kbdMapChar(cc)) < 0) |
84722262 | 493 | return; |
6c1a1c86 | 494 | } else if (tp == &dc_tty[DCMOUSE_PORT] && dcMouseButtons) { |
60160479 | 495 | register MouseReport *mrp; |
84722262 RC |
496 | static MouseReport currentRep; |
497 | ||
60160479 RC |
498 | mrp = ¤tRep; |
499 | mrp->byteCount++; | |
84722262 RC |
500 | if (cc & MOUSE_START_FRAME) { |
501 | /* | |
502 | * The first mouse report byte (button state). | |
503 | */ | |
60160479 RC |
504 | mrp->state = cc; |
505 | if (mrp->byteCount > 1) | |
506 | mrp->byteCount = 1; | |
507 | } else if (mrp->byteCount == 2) { | |
84722262 RC |
508 | /* |
509 | * The second mouse report byte (delta x). | |
510 | */ | |
60160479 RC |
511 | mrp->dx = cc; |
512 | } else if (mrp->byteCount == 3) { | |
84722262 RC |
513 | /* |
514 | * The final mouse report byte (delta y). | |
515 | */ | |
60160479 RC |
516 | mrp->dy = cc; |
517 | mrp->byteCount = 0; | |
518 | if (mrp->dx != 0 || mrp->dy != 0) { | |
84722262 RC |
519 | /* |
520 | * If the mouse moved, | |
521 | * post a motion event. | |
522 | */ | |
60160479 | 523 | (*dcMouseEvent)(mrp); |
84722262 | 524 | } |
60160479 | 525 | (*dcMouseButtons)(mrp); |
84722262 RC |
526 | } |
527 | return; | |
528 | } | |
529 | if (!(tp->t_state & TS_ISOPEN)) { | |
530 | wakeup((caddr_t)&tp->t_rawq); | |
531 | #ifdef PORTSELECTOR | |
532 | if (!(tp->t_state & TS_WOPEN)) | |
533 | #endif | |
534 | return; | |
535 | } | |
536 | if (c & RBUF_FERR) | |
537 | cc |= TTY_FE; | |
538 | if (c & RBUF_PERR) | |
539 | cc |= TTY_PE; | |
540 | (*linesw[tp->t_line].l_rint)(cc, tp); | |
541 | } | |
542 | DELAY(10); | |
543 | } | |
544 | ||
024ed1ef | 545 | void |
12d43ee5 KM |
546 | dcxint(tp) |
547 | register struct tty *tp; | |
548 | { | |
549 | register struct pdma *dp; | |
550 | register dcregs *dcaddr; | |
551 | ||
552 | dp = (struct pdma *)tp->t_addr; | |
553 | if (dp->p_mem < dp->p_end) { | |
6c1a1c86 | 554 | dcaddr = (dcregs *)dp->p_addr; |
12d43ee5 KM |
555 | dcaddr->dc_tdr = dc_brk[(tp - dc_tty) >> 2] | *dp->p_mem++; |
556 | MachEmptyWriteBuffer(); | |
557 | DELAY(10); | |
558 | return; | |
559 | } | |
560 | tp->t_state &= ~TS_BUSY; | |
561 | if (tp->t_state & TS_FLUSH) | |
562 | tp->t_state &= ~TS_FLUSH; | |
563 | else { | |
564 | ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf); | |
565 | dp->p_end = dp->p_mem = tp->t_outq.c_cf; | |
566 | } | |
567 | if (tp->t_line) | |
568 | (*linesw[tp->t_line].l_start)(tp); | |
569 | else | |
570 | dcstart(tp); | |
571 | if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) { | |
3c5e0ae7 RC |
572 | dcaddr = (dcregs *)dp->p_addr; |
573 | dcaddr->dc_tcr &= ~(1 << (minor(tp->t_dev) & 03)); | |
12d43ee5 KM |
574 | MachEmptyWriteBuffer(); |
575 | DELAY(10); | |
576 | } | |
577 | } | |
578 | ||
024ed1ef | 579 | void |
12d43ee5 KM |
580 | dcstart(tp) |
581 | register struct tty *tp; | |
582 | { | |
583 | register struct pdma *dp; | |
584 | register dcregs *dcaddr; | |
585 | register int cc; | |
586 | int s; | |
587 | ||
588 | dp = (struct pdma *)tp->t_addr; | |
6c1a1c86 | 589 | dcaddr = (dcregs *)dp->p_addr; |
12d43ee5 KM |
590 | s = spltty(); |
591 | if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) | |
592 | goto out; | |
593 | if (tp->t_outq.c_cc <= tp->t_lowat) { | |
594 | if (tp->t_state & TS_ASLEEP) { | |
595 | tp->t_state &= ~TS_ASLEEP; | |
596 | wakeup((caddr_t)&tp->t_outq); | |
597 | } | |
86e31fc2 | 598 | selwakeup(&tp->t_wsel); |
12d43ee5 KM |
599 | } |
600 | if (tp->t_outq.c_cc == 0) | |
601 | goto out; | |
602 | /* handle console specially */ | |
6c1a1c86 | 603 | if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) { |
12d43ee5 KM |
604 | while (tp->t_outq.c_cc > 0) { |
605 | cc = getc(&tp->t_outq) & 0x7f; | |
60160479 | 606 | cnputc(cc); |
12d43ee5 KM |
607 | } |
608 | /* | |
609 | * After we flush the output queue we may need to wake | |
610 | * up the process that made the output. | |
611 | */ | |
612 | if (tp->t_outq.c_cc <= tp->t_lowat) { | |
613 | if (tp->t_state & TS_ASLEEP) { | |
614 | tp->t_state &= ~TS_ASLEEP; | |
615 | wakeup((caddr_t)&tp->t_outq); | |
616 | } | |
86e31fc2 | 617 | selwakeup(&tp->t_wsel); |
12d43ee5 KM |
618 | } |
619 | goto out; | |
620 | } | |
621 | if (tp->t_flags & (RAW|LITOUT)) | |
622 | cc = ndqb(&tp->t_outq, 0); | |
623 | else { | |
624 | cc = ndqb(&tp->t_outq, 0200); | |
625 | if (cc == 0) { | |
626 | cc = getc(&tp->t_outq); | |
57373dbf | 627 | timeout(ttrstrt, (void *)tp, (cc & 0x7f) + 6); |
12d43ee5 KM |
628 | tp->t_state |= TS_TIMEOUT; |
629 | goto out; | |
630 | } | |
631 | } | |
632 | tp->t_state |= TS_BUSY; | |
633 | dp->p_end = dp->p_mem = tp->t_outq.c_cf; | |
634 | dp->p_end += cc; | |
635 | dcaddr->dc_tcr |= 1 << (minor(tp->t_dev) & 03); | |
636 | MachEmptyWriteBuffer(); | |
637 | out: | |
638 | splx(s); | |
639 | } | |
640 | ||
641 | /* | |
642 | * Stop output on a line. | |
643 | */ | |
644 | /*ARGSUSED*/ | |
645 | dcstop(tp, flag) | |
646 | register struct tty *tp; | |
647 | { | |
648 | register struct pdma *dp; | |
649 | register int s; | |
650 | ||
651 | dp = (struct pdma *)tp->t_addr; | |
652 | s = spltty(); | |
653 | if (tp->t_state & TS_BUSY) { | |
654 | dp->p_end = dp->p_mem; | |
655 | if (!(tp->t_state & TS_TTSTOP)) | |
656 | tp->t_state |= TS_FLUSH; | |
657 | } | |
658 | splx(s); | |
659 | } | |
660 | ||
661 | dcmctl(dev, bits, how) | |
662 | dev_t dev; | |
663 | int bits, how; | |
664 | { | |
665 | register dcregs *dcaddr; | |
666 | register int unit, mbits; | |
667 | int b, s; | |
84722262 | 668 | register int msr; |
12d43ee5 KM |
669 | |
670 | unit = minor(dev); | |
671 | b = 1 << (unit & 03); | |
6c1a1c86 | 672 | dcaddr = (dcregs *)dcpdma[unit].p_addr; |
12d43ee5 KM |
673 | s = spltty(); |
674 | /* only channel 2 has modem control (what about line 3?) */ | |
6c1a1c86 | 675 | mbits = DML_DTR | DML_DSR | DML_CAR; |
84722262 RC |
676 | switch (unit & 03) { |
677 | case 2: | |
12d43ee5 KM |
678 | mbits = 0; |
679 | if (dcaddr->dc_tcr & TCR_DTR2) | |
680 | mbits |= DML_DTR; | |
84722262 RC |
681 | msr = dcaddr->dc_msr; |
682 | if (msr & MSR_CD2) | |
683 | mbits |= DML_CAR; | |
6c1a1c86 RC |
684 | if (msr & MSR_DSR2) { |
685 | if (pmax_boardtype == DS_PMAX) | |
686 | mbits |= DML_CAR | DML_DSR; | |
687 | else | |
688 | mbits |= DML_DSR; | |
689 | } | |
84722262 RC |
690 | break; |
691 | ||
84722262 | 692 | case 3: |
6c1a1c86 RC |
693 | if (pmax_boardtype != DS_PMAX) { |
694 | mbits = 0; | |
695 | if (dcaddr->dc_tcr & TCR_DTR3) | |
696 | mbits |= DML_DTR; | |
697 | msr = dcaddr->dc_msr; | |
698 | if (msr & MSR_CD3) | |
699 | mbits |= DML_CAR; | |
700 | if (msr & MSR_DSR3) | |
701 | mbits |= DML_DSR; | |
702 | } | |
84722262 | 703 | } |
12d43ee5 KM |
704 | switch (how) { |
705 | case DMSET: | |
706 | mbits = bits; | |
707 | break; | |
708 | ||
709 | case DMBIS: | |
710 | mbits |= bits; | |
711 | break; | |
712 | ||
713 | case DMBIC: | |
714 | mbits &= ~bits; | |
715 | break; | |
716 | ||
717 | case DMGET: | |
718 | (void) splx(s); | |
719 | return (mbits); | |
720 | } | |
84722262 RC |
721 | switch (unit & 03) { |
722 | case 2: | |
12d43ee5 KM |
723 | if (mbits & DML_DTR) |
724 | dcaddr->dc_tcr |= TCR_DTR2; | |
725 | else | |
726 | dcaddr->dc_tcr &= ~TCR_DTR2; | |
84722262 RC |
727 | break; |
728 | ||
84722262 | 729 | case 3: |
6c1a1c86 RC |
730 | if (pmax_boardtype != DS_PMAX) { |
731 | if (mbits & DML_DTR) | |
732 | dcaddr->dc_tcr |= TCR_DTR3; | |
733 | else | |
734 | dcaddr->dc_tcr &= ~TCR_DTR3; | |
735 | } | |
12d43ee5 KM |
736 | } |
737 | if ((mbits & DML_DTR) && (dcsoftCAR[unit >> 2] & b)) | |
738 | dc_tty[unit].t_state |= TS_CARR_ON; | |
739 | (void) splx(s); | |
740 | return (mbits); | |
741 | } | |
742 | ||
743 | /* | |
744 | * This is called by timeout() periodically. | |
745 | * Check to see if modem status bits have changed. | |
746 | */ | |
6c1a1c86 | 747 | void |
57373dbf RC |
748 | dcscan(arg) |
749 | void *arg; | |
12d43ee5 KM |
750 | { |
751 | register dcregs *dcaddr; | |
752 | register struct tty *tp; | |
753 | register int i, bit, car; | |
754 | int s; | |
755 | ||
756 | s = spltty(); | |
757 | /* only channel 2 has modem control (what about line 3?) */ | |
6c1a1c86 | 758 | dcaddr = (dcregs *)dcpdma[i = 2].p_addr; |
12d43ee5 KM |
759 | tp = &dc_tty[i]; |
760 | bit = TCR_DTR2; | |
761 | if (dcsoftCAR[i >> 2] & bit) | |
762 | car = 1; | |
763 | else | |
764 | car = dcaddr->dc_msr & MSR_DSR2; | |
765 | if (car) { | |
766 | /* carrier present */ | |
767 | if (!(tp->t_state & TS_CARR_ON)) | |
768 | (void)(*linesw[tp->t_line].l_modem)(tp, 1); | |
769 | } else if ((tp->t_state & TS_CARR_ON) && | |
770 | (*linesw[tp->t_line].l_modem)(tp, 0) == 0) | |
771 | dcaddr->dc_tcr &= ~bit; | |
772 | splx(s); | |
57373dbf | 773 | timeout(dcscan, (void *)0, hz); |
12d43ee5 KM |
774 | } |
775 | ||
776 | /* | |
777 | * ---------------------------------------------------------------------------- | |
778 | * | |
6c1a1c86 | 779 | * dcGetc -- |
12d43ee5 | 780 | * |
6c1a1c86 | 781 | * Read a character from a serial line. |
12d43ee5 KM |
782 | * |
783 | * Results: | |
6c1a1c86 | 784 | * A character read from the serial port. |
12d43ee5 KM |
785 | * |
786 | * Side effects: | |
787 | * None. | |
788 | * | |
789 | * ---------------------------------------------------------------------------- | |
790 | */ | |
791 | int | |
6c1a1c86 RC |
792 | dcGetc(dev) |
793 | dev_t dev; | |
12d43ee5 KM |
794 | { |
795 | register dcregs *dcaddr; | |
796 | register int c; | |
c74d1258 | 797 | int s; |
12d43ee5 | 798 | |
6c1a1c86 | 799 | dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr; |
12d43ee5 KM |
800 | if (!dcaddr) |
801 | return (0); | |
84722262 RC |
802 | s = spltty(); |
803 | for (;;) { | |
804 | if (!(dcaddr->dc_csr & CSR_RDONE)) | |
805 | continue; | |
806 | c = dcaddr->dc_rbuf; | |
807 | DELAY(10); | |
6c1a1c86 | 808 | if (((c >> 8) & 03) == (minor(dev) & 03)) |
84722262 RC |
809 | break; |
810 | } | |
811 | splx(s); | |
6c1a1c86 | 812 | return (c & 0xff); |
84722262 RC |
813 | } |
814 | ||
12d43ee5 | 815 | /* |
6c1a1c86 | 816 | * Send a char on a port, non interrupt driven. |
12d43ee5 KM |
817 | */ |
818 | void | |
6c1a1c86 RC |
819 | dcPutc(dev, c) |
820 | dev_t dev; | |
12d43ee5 KM |
821 | int c; |
822 | { | |
823 | register dcregs *dcaddr; | |
824 | register u_short tcr; | |
825 | register int timeout; | |
6c1a1c86 RC |
826 | int s, line; |
827 | ||
828 | s = spltty(); | |
12d43ee5 | 829 | |
6c1a1c86 | 830 | dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr; |
12d43ee5 | 831 | tcr = dcaddr->dc_tcr; |
6c1a1c86 | 832 | dcaddr->dc_tcr = tcr | (1 << minor(dev)); |
12d43ee5 KM |
833 | MachEmptyWriteBuffer(); |
834 | DELAY(10); | |
835 | while (1) { | |
836 | /* | |
837 | * Wait for transmitter to be not busy. | |
838 | */ | |
839 | timeout = 1000000; | |
840 | while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0) | |
841 | timeout--; | |
842 | if (timeout == 0) { | |
6c1a1c86 | 843 | printf("dcPutc: timeout waiting for CSR_TRDY\n"); |
12d43ee5 KM |
844 | break; |
845 | } | |
846 | line = (dcaddr->dc_csr >> 8) & 3; | |
847 | /* | |
848 | * Check to be sure its the right port. | |
849 | */ | |
6c1a1c86 | 850 | if (line != minor(dev)) { |
12d43ee5 KM |
851 | tcr |= 1 << line; |
852 | dcaddr->dc_tcr &= ~(1 << line); | |
853 | MachEmptyWriteBuffer(); | |
854 | DELAY(10); | |
855 | continue; | |
856 | } | |
857 | /* | |
858 | * Start sending the character. | |
859 | */ | |
860 | dcaddr->dc_tdr = dc_brk[0] | (c & 0xff); | |
861 | MachEmptyWriteBuffer(); | |
862 | DELAY(10); | |
863 | /* | |
864 | * Wait for character to be sent. | |
865 | */ | |
866 | while (1) { | |
867 | /* | |
868 | * cc -O bug: this code produces and infinite loop! | |
869 | * while (!(dcaddr->dc_csr & CSR_TRDY)) | |
870 | * ; | |
871 | */ | |
872 | timeout = 1000000; | |
873 | while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0) | |
874 | timeout--; | |
875 | line = (dcaddr->dc_csr >> 8) & 3; | |
6c1a1c86 | 876 | if (line != minor(dev)) { |
12d43ee5 KM |
877 | tcr |= 1 << line; |
878 | dcaddr->dc_tcr &= ~(1 << line); | |
879 | MachEmptyWriteBuffer(); | |
880 | DELAY(10); | |
881 | continue; | |
882 | } | |
6c1a1c86 | 883 | dcaddr->dc_tcr &= ~(1 << minor(dev)); |
12d43ee5 KM |
884 | MachEmptyWriteBuffer(); |
885 | DELAY(10); | |
886 | break; | |
887 | } | |
888 | break; | |
889 | } | |
890 | /* | |
891 | * Enable interrupts for other lines which became ready. | |
892 | */ | |
893 | if (tcr & 0xF) { | |
894 | dcaddr->dc_tcr = tcr; | |
895 | MachEmptyWriteBuffer(); | |
896 | DELAY(10); | |
897 | } | |
12d43ee5 | 898 | |
6c1a1c86 | 899 | splx(s); |
12d43ee5 KM |
900 | } |
901 | #endif /* NDC */ |