Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
0880b18e | 2 | * Copyright (c) 1985, 1986 Regents of the University of California. |
da7c5cc6 KM |
3 | * All rights reserved. The Berkeley software License Agreement |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
98567974 | 6 | * @(#)dhu.c 7.14 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
48952cf5 KM |
8 | |
9 | /* | |
10 | * based on dh.c 6.3 84/03/15 | |
11 | * and on dmf.c 6.2 84/02/16 | |
12 | * | |
13 | * Dave Johnson, Brown University Computer Science | |
14 | * ddj%brown@csnet-relay | |
15 | */ | |
16 | ||
17 | #include "dhu.h" | |
18 | #if NDHU > 0 | |
19 | /* | |
20 | * DHU-11 driver | |
21 | */ | |
b28b3a13 | 22 | #include "../include/pte.h" |
48952cf5 | 23 | |
b28b3a13 KB |
24 | #include "sys/param.h" |
25 | #include "sys/conf.h" | |
26 | #include "sys/user.h" | |
27 | #include "sys/proc.h" | |
28 | #include "sys/ioctl.h" | |
29 | #include "sys/tty.h" | |
30 | #include "sys/ttydefaults.h" | |
31 | #include "sys/map.h" | |
32 | #include "sys/buf.h" | |
33 | #include "sys/vm.h" | |
34 | #include "sys/kernel.h" | |
35 | #include "sys/syslog.h" | |
48952cf5 KM |
36 | |
37 | #include "uba.h" | |
38 | #include "ubareg.h" | |
39 | #include "ubavar.h" | |
40 | #include "dhureg.h" | |
41 | ||
b28b3a13 KB |
42 | #include "sys/bkmac.h" |
43 | #include "sys/clist.h" | |
44 | #include "sys/file.h" | |
45 | #include "sys/uio.h" | |
48952cf5 KM |
46 | |
47 | /* | |
48 | * Definition of the driver for the auto-configuration program. | |
49 | */ | |
50 | int dhuprobe(), dhuattach(), dhurint(), dhuxint(); | |
51 | struct uba_device *dhuinfo[NDHU]; | |
24db64ff | 52 | u_short dhustd[] = { 160440, 160500, 0 }; /* some common addresses */ |
48952cf5 KM |
53 | struct uba_driver dhudriver = |
54 | { dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo }; | |
55 | ||
56 | #define NDHULINE (NDHU*16) | |
57 | ||
58 | #define UNIT(x) (minor(x)) | |
59 | ||
60 | #ifndef PORTSELECTOR | |
f5f63131 MT |
61 | #define SPEED TTYDEF_SPEED |
62 | #define LFLAG TTYDEF_LFLAG | |
48952cf5 | 63 | #else |
f5f63131 MT |
64 | #define SPEED B4800 |
65 | #define LFLAG (TTYDEF_LFLAG & ~ECHO) | |
48952cf5 KM |
66 | #endif |
67 | ||
68 | /* | |
69 | * default receive silo timeout value -- valid values are 2..255 | |
70 | * number of ms. to delay between first char received and receive interrupt | |
71 | * | |
72 | * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0 | |
73 | */ | |
74 | #define DHU_DEF_TIMO 20 | |
75 | ||
76 | /* | |
77 | * Other values for silo timeout register defined here but not used: | |
78 | * receive interrupt only on modem control or silo alarm (3/4 full) | |
79 | */ | |
80 | #define DHU_POLL_TIMO 0 | |
81 | /* | |
82 | * receive interrupt immediately on receive character | |
83 | */ | |
84 | #define DHU_NO_TIMO 1 | |
85 | ||
86 | /* | |
87 | * Local variables for the driver | |
88 | */ | |
89 | /* | |
90 | * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B". | |
91 | * EXTA => 19200 baud | |
92 | * EXTB => 2000 baud | |
93 | */ | |
f5f63131 MT |
94 | struct speedtab dhuspeedtab[] = { |
95 | 19200, 14, | |
96 | 9600, 13, | |
97 | 4800, 11, | |
98 | 2400, 10, | |
99 | 2000, 9, | |
100 | 1800, 8, | |
101 | 1200, 7, | |
102 | 600, 6, | |
103 | 300, 5, | |
104 | 150, 4, | |
105 | 134, 3, | |
106 | 110, 2, | |
107 | 75, 1, | |
108 | 0, 0, | |
54766b65 MT |
109 | EXTA, 14, |
110 | EXTB, 9, | |
f5f63131 MT |
111 | -1, -1, |
112 | }; | |
48952cf5 KM |
113 | |
114 | short dhusoftCAR[NDHU]; | |
115 | ||
116 | struct tty dhu_tty[NDHULINE]; | |
117 | int ndhu = NDHULINE; | |
118 | int dhuact; /* mask of active dhu's */ | |
119 | int dhustart(), ttrstrt(); | |
120 | ||
121 | /* | |
e965c38b MK |
122 | * The clist space is mapped by one terminal driver onto each UNIBUS. |
123 | * The identity of the board which allocated resources is recorded, | |
124 | * so the process may be repeated after UNIBUS resets. | |
48952cf5 KM |
125 | * The UBACVT macro converts a clist space address for unibus uban |
126 | * into an i/o space address for the DMA routine. | |
127 | */ | |
e965c38b MK |
128 | int dhu_uballoc[NUBA]; /* which dhu (if any) allocated unibus map */ |
129 | int cbase[NUBA]; /* base address of clists in unibus map */ | |
48952cf5 KM |
130 | #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) |
131 | ||
132 | /* | |
133 | * Routine for configuration to force a dhu to interrupt. | |
134 | */ | |
135 | /*ARGSUSED*/ | |
136 | dhuprobe(reg) | |
137 | caddr_t reg; | |
138 | { | |
139 | register int br, cvec; /* these are ``value-result'' */ | |
140 | register struct dhudevice *dhuaddr = (struct dhudevice *)reg; | |
141 | int i; | |
142 | ||
143 | #ifdef lint | |
144 | br = 0; cvec = br; br = cvec; | |
145 | if (ndhu == 0) ndhu = 1; | |
146 | dhurint(0); dhuxint(0); | |
147 | #endif | |
148 | /* | |
149 | * The basic idea here is: | |
150 | * do a self-test by setting the Master-Reset bit | |
151 | * if this fails, then return | |
152 | * if successful, there will be 8 diagnostic codes in RX FIFO | |
153 | * therefore ask for a Received-Data-Available interrupt | |
154 | * wait for it... | |
155 | * reset the interrupt-enable bit and flush out the diag. codes | |
156 | */ | |
157 | dhuaddr->dhucsr = DHU_CS_MCLR; | |
158 | for (i = 0; i < 1000; i++) { | |
159 | DELAY(10000); | |
160 | if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0) | |
161 | break; | |
162 | } | |
163 | if (dhuaddr->dhucsr&DHU_CS_MCLR) | |
164 | return(0); | |
165 | if (dhuaddr->dhucsr&DHU_CS_DFAIL) | |
166 | return(0); | |
167 | dhuaddr->dhucsr = DHU_CS_RIE; | |
168 | DELAY(1000); | |
169 | dhuaddr->dhucsr = 0; | |
170 | while (dhuaddr->dhurbuf < 0) | |
171 | /* void */; | |
172 | return (sizeof(struct dhudevice)); | |
173 | } | |
174 | ||
175 | /* | |
176 | * Routine called to attach a dhu. | |
177 | */ | |
178 | dhuattach(ui) | |
179 | struct uba_device *ui; | |
180 | { | |
181 | ||
182 | dhusoftCAR[ui->ui_unit] = ui->ui_flags; | |
27f8c1d5 | 183 | cbase[ui->ui_ubanum] = -1; |
367868f3 | 184 | dhu_uballoc[ui->ui_ubanum] = -1; |
48952cf5 KM |
185 | } |
186 | ||
187 | /* | |
188 | * Open a DHU11 line, mapping the clist onto the uba if this | |
189 | * is the first dhu on this uba. Turn on this dhu if this is | |
190 | * the first use of it. | |
191 | */ | |
192 | /*ARGSUSED*/ | |
193 | dhuopen(dev, flag) | |
194 | dev_t dev; | |
195 | { | |
196 | register struct tty *tp; | |
197 | register int unit, dhu; | |
198 | register struct dhudevice *addr; | |
199 | register struct uba_device *ui; | |
c376c8e7 | 200 | int s, error = 0; |
f5f63131 | 201 | extern dhuparam(); |
48952cf5 KM |
202 | |
203 | unit = UNIT(dev); | |
204 | dhu = unit >> 4; | |
205 | if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0) | |
206 | return (ENXIO); | |
207 | tp = &dhu_tty[unit]; | |
208 | if (tp->t_state & TS_XCLUDE && u.u_uid != 0) | |
209 | return (EBUSY); | |
210 | addr = (struct dhudevice *)ui->ui_addr; | |
211 | tp->t_addr = (caddr_t)addr; | |
212 | tp->t_oproc = dhustart; | |
f5f63131 | 213 | tp->t_param = dhuparam; |
48952cf5 KM |
214 | /* |
215 | * While setting up state for this uba and this dhu, | |
216 | * block uba resets which can clear the state. | |
217 | */ | |
218 | s = spl5(); | |
27f8c1d5 | 219 | if (cbase[ui->ui_ubanum] == -1) { |
e965c38b MK |
220 | dhu_uballoc[ui->ui_ubanum] = dhu; |
221 | cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum, | |
222 | (caddr_t)cfree, nclist*sizeof(struct cblock), 0)); | |
48952cf5 KM |
223 | } |
224 | if ((dhuact&(1<<dhu)) == 0) { | |
225 | addr->dhucsr = DHU_SELECT(0) | DHU_IE; | |
226 | addr->dhutimo = DHU_DEF_TIMO; | |
227 | dhuact |= (1<<dhu); | |
228 | /* anything else to configure whole board */ | |
229 | } | |
230 | (void) splx(s); | |
231 | /* | |
232 | * If this is first open, initialize tty state to default. | |
233 | */ | |
234 | if ((tp->t_state&TS_ISOPEN) == 0) { | |
764619a6 | 235 | tp->t_state |= TS_WOPEN; |
48952cf5 KM |
236 | ttychars(tp); |
237 | #ifndef PORTSELECTOR | |
f5f63131 MT |
238 | if (tp->t_ospeed == 0) { |
239 | #endif | |
240 | tp->t_ispeed = SPEED; | |
241 | tp->t_ospeed = SPEED; | |
242 | ttsetwater(tp); | |
243 | tp->t_iflag = TTYDEF_IFLAG; | |
244 | tp->t_oflag = TTYDEF_OFLAG; | |
245 | tp->t_lflag = LFLAG; | |
246 | tp->t_cflag = TTYDEF_CFLAG; | |
247 | #ifdef PORTSELECTOR | |
248 | tp->t_cflag |= HUPCL; | |
249 | #else | |
48952cf5 | 250 | } |
f5f63131 | 251 | #endif |
48952cf5 | 252 | tp->t_dev = dev; |
f5f63131 | 253 | dhuparam(tp, &tp->t_termios); |
48952cf5 KM |
254 | } |
255 | /* | |
256 | * Wait for carrier, then process line discipline specific open. | |
257 | */ | |
f5f63131 | 258 | s = spltty(); |
48952cf5 KM |
259 | if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) || |
260 | (dhusoftCAR[dhu] & (1<<(unit&0xf)))) | |
261 | tp->t_state |= TS_CARR_ON; | |
c376c8e7 MK |
262 | while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && |
263 | (tp->t_state & TS_CARR_ON) == 0) { | |
48952cf5 | 264 | tp->t_state |= TS_WOPEN; |
764619a6 MT |
265 | if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, |
266 | ttopen, 0)) | |
c376c8e7 | 267 | break; |
48952cf5 KM |
268 | } |
269 | (void) splx(s); | |
c376c8e7 MK |
270 | if (error) |
271 | return (error); | |
48952cf5 KM |
272 | return ((*linesw[tp->t_line].l_open)(dev, tp)); |
273 | } | |
274 | ||
275 | /* | |
276 | * Close a DHU11 line, turning off the modem control. | |
277 | */ | |
278 | /*ARGSUSED*/ | |
279 | dhuclose(dev, flag) | |
280 | dev_t dev; | |
281 | int flag; | |
282 | { | |
283 | register struct tty *tp; | |
284 | register unit; | |
285 | ||
286 | unit = UNIT(dev); | |
287 | tp = &dhu_tty[unit]; | |
288 | (*linesw[tp->t_line].l_close)(tp); | |
289 | (void) dhumctl(unit, DHU_BRK, DMBIC); | |
f5f63131 | 290 | if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) || |
c376c8e7 | 291 | (tp->t_state&TS_ISOPEN) == 0) { |
48952cf5 | 292 | #ifdef PORTSELECTOR |
48952cf5 KM |
293 | (void) dhumctl(unit, DHU_OFF, DMSET); |
294 | /* Hold DTR low for 0.5 seconds */ | |
c376c8e7 | 295 | (void) tsleep((caddr_t) &tp->t_dev, PZERO, ttclos, hz/2); |
48952cf5 KM |
296 | #else |
297 | (void) dhumctl(unit, DHU_OFF, DMSET); | |
298 | #endif PORTSELECTOR | |
c376c8e7 MK |
299 | } |
300 | return (ttyclose(tp)); | |
48952cf5 KM |
301 | } |
302 | ||
54766b65 | 303 | dhuread(dev, uio, flag) |
48952cf5 KM |
304 | dev_t dev; |
305 | struct uio *uio; | |
306 | { | |
307 | register struct tty *tp = &dhu_tty[UNIT(dev)]; | |
308 | ||
54766b65 | 309 | return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); |
48952cf5 KM |
310 | } |
311 | ||
54766b65 | 312 | dhuwrite(dev, uio, flag) |
48952cf5 KM |
313 | dev_t dev; |
314 | struct uio *uio; | |
315 | { | |
316 | register struct tty *tp = &dhu_tty[UNIT(dev)]; | |
317 | ||
54766b65 | 318 | return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); |
48952cf5 KM |
319 | } |
320 | ||
321 | /* | |
322 | * DHU11 receiver interrupt. | |
323 | */ | |
324 | dhurint(dhu) | |
325 | int dhu; | |
326 | { | |
327 | register struct tty *tp; | |
f5f63131 | 328 | register creg, c; |
48952cf5 KM |
329 | register struct dhudevice *addr; |
330 | register struct tty *tp0; | |
331 | register struct uba_device *ui; | |
332 | register line; | |
333 | int overrun = 0; | |
334 | ||
f6322301 | 335 | #ifdef QBA |
f5f63131 | 336 | (void) spltty(); |
9d2503c6 | 337 | #endif |
48952cf5 KM |
338 | ui = dhuinfo[dhu]; |
339 | if (ui == 0 || ui->ui_alive == 0) | |
340 | return; | |
341 | addr = (struct dhudevice *)ui->ui_addr; | |
342 | tp0 = &dhu_tty[dhu<<4]; | |
343 | /* | |
344 | * Loop fetching characters from the silo for this | |
345 | * dhu until there are no more in the silo. | |
346 | */ | |
f5f63131 MT |
347 | while ((creg = addr->dhurbuf) < 0) { /* (c & DHU_RB_VALID) == on */ |
348 | line = DHU_RX_LINE(creg); | |
48952cf5 | 349 | tp = tp0 + line; |
f5f63131 MT |
350 | c = creg & 0xff; |
351 | if ((creg & DHU_RB_STAT) == DHU_RB_STAT) { | |
48952cf5 KM |
352 | /* |
353 | * modem changed or diag info | |
354 | */ | |
f5f63131 | 355 | if (creg & DHU_RB_DIAG) { |
48952cf5 KM |
356 | /* decode diagnostic messages */ |
357 | continue; | |
358 | } | |
f5f63131 | 359 | if (creg & DHU_ST_DCD) |
74bfa0d5 MK |
360 | (void)(*linesw[tp->t_line].l_modem)(tp, 1); |
361 | else if ((dhusoftCAR[dhu] & (1<<line)) == 0 && | |
362 | (*linesw[tp->t_line].l_modem)(tp, 0) == 0) | |
363 | (void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET); | |
48952cf5 KM |
364 | continue; |
365 | } | |
366 | if ((tp->t_state&TS_ISOPEN) == 0) { | |
367 | wakeup((caddr_t)&tp->t_rawq); | |
368 | #ifdef PORTSELECTOR | |
369 | if ((tp->t_state&TS_WOPEN) == 0) | |
370 | #endif | |
74bfa0d5 | 371 | continue; |
48952cf5 | 372 | } |
54766b65 MT |
373 | if (creg & DHU_RB_PE) |
374 | c |= TTY_PE; | |
375 | if (creg & DHU_RB_DO && overrun == 0) { | |
376 | log(LOG_WARNING, "dhu%d: silo overflow\n", dhu); | |
377 | overrun = 1; | |
48952cf5 | 378 | } |
54766b65 MT |
379 | if (creg & DHU_RB_FE) |
380 | c |= TTY_FE; | |
f5f63131 | 381 | |
54766b65 | 382 | (*linesw[tp->t_line].l_rint)(c, tp); |
48952cf5 KM |
383 | } |
384 | } | |
385 | ||
386 | /* | |
387 | * Ioctl for DHU11. | |
388 | */ | |
389 | /*ARGSUSED*/ | |
390 | dhuioctl(dev, cmd, data, flag) | |
391 | caddr_t data; | |
392 | { | |
393 | register struct tty *tp; | |
394 | register int unit = UNIT(dev); | |
48952cf5 KM |
395 | int error; |
396 | ||
397 | tp = &dhu_tty[unit]; | |
398 | error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); | |
399 | if (error >= 0) | |
400 | return (error); | |
401 | error = ttioctl(tp, cmd, data, flag); | |
f5f63131 | 402 | if (error >= 0) |
48952cf5 | 403 | return (error); |
48952cf5 KM |
404 | |
405 | switch (cmd) { | |
406 | case TIOCSBRK: | |
407 | (void) dhumctl(unit, DHU_BRK, DMBIS); | |
408 | break; | |
409 | ||
410 | case TIOCCBRK: | |
411 | (void) dhumctl(unit, DHU_BRK, DMBIC); | |
412 | break; | |
413 | ||
414 | case TIOCSDTR: | |
415 | (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS); | |
416 | break; | |
417 | ||
418 | case TIOCCDTR: | |
419 | (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC); | |
420 | break; | |
421 | ||
422 | case TIOCMSET: | |
423 | (void) dhumctl(dev, dmtodhu(*(int *)data), DMSET); | |
424 | break; | |
425 | ||
426 | case TIOCMBIS: | |
427 | (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS); | |
428 | break; | |
429 | ||
430 | case TIOCMBIC: | |
431 | (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC); | |
432 | break; | |
433 | ||
434 | case TIOCMGET: | |
435 | *(int *)data = dhutodm(dhumctl(dev, 0, DMGET)); | |
436 | break; | |
437 | default: | |
438 | return (ENOTTY); | |
439 | } | |
440 | return (0); | |
441 | } | |
442 | ||
443 | dmtodhu(bits) | |
444 | register int bits; | |
445 | { | |
446 | register int b = 0; | |
447 | ||
448 | if (bits & DML_RTS) b |= DHU_RTS; | |
449 | if (bits & DML_DTR) b |= DHU_DTR; | |
450 | if (bits & DML_LE) b |= DHU_LE; | |
451 | return(b); | |
452 | } | |
453 | ||
454 | dhutodm(bits) | |
455 | register int bits; | |
456 | { | |
457 | register int b = 0; | |
458 | ||
459 | if (bits & DHU_DSR) b |= DML_DSR; | |
460 | if (bits & DHU_RNG) b |= DML_RNG; | |
461 | if (bits & DHU_CAR) b |= DML_CAR; | |
462 | if (bits & DHU_CTS) b |= DML_CTS; | |
463 | if (bits & DHU_RTS) b |= DML_RTS; | |
464 | if (bits & DHU_DTR) b |= DML_DTR; | |
465 | if (bits & DHU_LE) b |= DML_LE; | |
466 | return(b); | |
467 | } | |
468 | ||
469 | ||
470 | /* | |
471 | * Set parameters from open or stty into the DHU hardware | |
f5f63131 MT |
472 | * registers. Impossible values for speed or character |
473 | * size are ignored and not copied back into tp. | |
48952cf5 | 474 | */ |
f5f63131 | 475 | dhuparam(tp, want) |
48952cf5 | 476 | register struct tty *tp; |
f5f63131 MT |
477 | register struct termios *want; |
478 | { | |
479 | register int unit = UNIT(tp->t_dev); | |
480 | register struct dhudevice *addr = (struct dhudevice *)tp->t_addr; | |
48952cf5 | 481 | register int lpar; |
f5f63131 MT |
482 | register long cflag; |
483 | register int incode, outcode; | |
48952cf5 | 484 | int s; |
f5f63131 | 485 | |
48952cf5 KM |
486 | /* |
487 | * Block interrupts so parameters will be set | |
488 | * before the line interrupts. | |
489 | */ | |
f5f63131 MT |
490 | s = spltty(); |
491 | ||
492 | if (want->c_ospeed == 0) { | |
493 | tp->t_ospeed = 0; | |
494 | tp->t_cflag |= HUPCL; | |
48952cf5 KM |
495 | (void)dhumctl(unit, DHU_OFF, DMSET); |
496 | splx(s); | |
98567974 | 497 | return (0); |
48952cf5 | 498 | } |
f5f63131 MT |
499 | |
500 | if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0) | |
501 | tp->t_ospeed = want->c_ospeed; | |
48952cf5 | 502 | else |
f5f63131 MT |
503 | outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab); |
504 | ||
505 | if (want->c_ispeed == 0) { | |
506 | tp->t_ispeed = 0; | |
507 | incode = outcode; | |
508 | } else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0) | |
509 | tp->t_ispeed = want->c_ispeed; | |
510 | else | |
511 | incode = ttspeedtab(tp->t_ispeed, dhuspeedtab); | |
512 | ||
513 | lpar = ((char)outcode<<12) | ((char)incode<<8); | |
514 | ||
515 | switch (want->c_cflag&CSIZE) { | |
516 | case CS6: case CS7: case CS8: | |
517 | tp->t_cflag = want->c_cflag; | |
518 | break; | |
519 | default: | |
520 | tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE); | |
521 | } | |
522 | cflag = tp->t_cflag; | |
523 | ||
524 | switch(cflag&CSIZE) { | |
525 | case CS6: | |
526 | lpar |= DHU_LP_BITS6; | |
527 | break; | |
528 | case CS7: | |
529 | lpar |= DHU_LP_BITS7; | |
530 | break; | |
531 | case CS8: | |
532 | lpar |= DHU_LP_BITS8; | |
533 | break; | |
534 | } | |
535 | if (cflag&PARENB) { | |
536 | lpar |= DHU_LP_PENABLE; | |
537 | if ((cflag&PARODD) == 0) | |
538 | lpar |= DHU_LP_EPAR; | |
539 | } | |
540 | if (cflag&CSTOPB) | |
48952cf5 | 541 | lpar |= DHU_LP_TWOSB; |
f5f63131 | 542 | |
54766b65 | 543 | addr->dhucsr = DHU_SELECT(unit) | DHU_IE; |
48952cf5 KM |
544 | addr->dhulpr = lpar; |
545 | splx(s); | |
98567974 | 546 | return (0); |
48952cf5 KM |
547 | } |
548 | ||
549 | /* | |
550 | * DHU11 transmitter interrupt. | |
551 | * Restart each line which used to be active but has | |
552 | * terminated transmission since the last interrupt. | |
553 | */ | |
554 | dhuxint(dhu) | |
555 | int dhu; | |
556 | { | |
557 | register struct tty *tp; | |
558 | register struct dhudevice *addr; | |
559 | register struct tty *tp0; | |
560 | register struct uba_device *ui; | |
561 | register int line, t; | |
562 | u_short cntr; | |
563 | ||
f6322301 | 564 | #ifdef QBA |
9d2503c6 BK |
565 | (void) spl5(); |
566 | #endif | |
48952cf5 KM |
567 | ui = dhuinfo[dhu]; |
568 | tp0 = &dhu_tty[dhu<<4]; | |
569 | addr = (struct dhudevice *)ui->ui_addr; | |
570 | while ((t = addr->dhucsrh) & DHU_CSH_TI) { | |
571 | line = DHU_TX_LINE(t); | |
572 | tp = tp0 + line; | |
573 | tp->t_state &= ~TS_BUSY; | |
574 | if (t & DHU_CSH_NXM) { | |
575 | printf("dhu(%d,%d): NXM fault\n", dhu, line); | |
576 | /* SHOULD RESTART OR SOMETHING... */ | |
577 | } | |
578 | if (tp->t_state&TS_FLUSH) | |
579 | tp->t_state &= ~TS_FLUSH; | |
580 | else { | |
581 | addr->dhucsrl = DHU_SELECT(line) | DHU_IE; | |
582 | /* | |
583 | * Do arithmetic in a short to make up | |
584 | * for lost 16&17 bits. | |
585 | */ | |
586 | cntr = addr->dhubar1 - | |
587 | UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); | |
588 | ndflush(&tp->t_outq, (int)cntr); | |
589 | } | |
590 | if (tp->t_line) | |
591 | (*linesw[tp->t_line].l_start)(tp); | |
592 | else | |
593 | dhustart(tp); | |
594 | } | |
595 | } | |
596 | ||
597 | /* | |
598 | * Start (restart) transmission on the given DHU11 line. | |
599 | */ | |
600 | dhustart(tp) | |
601 | register struct tty *tp; | |
602 | { | |
603 | register struct dhudevice *addr; | |
604 | register int car, dhu, unit, nch; | |
605 | int s; | |
606 | ||
607 | unit = minor(tp->t_dev); | |
608 | dhu = unit >> 4; | |
609 | unit &= 0xf; | |
610 | addr = (struct dhudevice *)tp->t_addr; | |
611 | ||
612 | /* | |
613 | * Must hold interrupts in following code to prevent | |
614 | * state of the tp from changing. | |
615 | */ | |
616 | s = spl5(); | |
617 | /* | |
618 | * If it's currently active, or delaying, no need to do anything. | |
619 | */ | |
620 | if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) | |
621 | goto out; | |
622 | /* | |
623 | * If there are sleepers, and output has drained below low | |
624 | * water mark, wake up the sleepers.. | |
625 | */ | |
f5f63131 | 626 | if (tp->t_outq.c_cc <= tp->t_lowat) { |
48952cf5 KM |
627 | if (tp->t_state&TS_ASLEEP) { |
628 | tp->t_state &= ~TS_ASLEEP; | |
629 | wakeup((caddr_t)&tp->t_outq); | |
630 | } | |
631 | if (tp->t_wsel) { | |
632 | selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); | |
633 | tp->t_wsel = 0; | |
634 | tp->t_state &= ~TS_WCOLL; | |
635 | } | |
636 | } | |
637 | /* | |
638 | * Now restart transmission unless the output queue is | |
639 | * empty. | |
640 | */ | |
641 | if (tp->t_outq.c_cc == 0) | |
642 | goto out; | |
54766b65 | 643 | if (1 || !(tp->t_oflag & OPOST)) /*XXX*/ |
48952cf5 KM |
644 | nch = ndqb(&tp->t_outq, 0); |
645 | else { | |
646 | nch = ndqb(&tp->t_outq, 0200); | |
647 | /* | |
648 | * If first thing on queue is a delay process it. | |
649 | */ | |
650 | if (nch == 0) { | |
651 | nch = getc(&tp->t_outq); | |
652 | timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); | |
653 | tp->t_state |= TS_TIMEOUT; | |
654 | goto out; | |
655 | } | |
656 | } | |
657 | /* | |
658 | * If characters to transmit, restart transmission. | |
659 | */ | |
660 | if (nch) { | |
661 | car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum); | |
662 | addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; | |
663 | addr->dhulcr &= ~DHU_LC_TXABORT; | |
664 | addr->dhubcr = nch; | |
665 | addr->dhubar1 = car; | |
666 | addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) | | |
667 | DHU_BA2_DMAGO; | |
668 | tp->t_state |= TS_BUSY; | |
669 | } | |
670 | out: | |
671 | splx(s); | |
672 | } | |
673 | ||
674 | /* | |
675 | * Stop output on a line, e.g. for ^S/^Q or output flush. | |
676 | */ | |
677 | /*ARGSUSED*/ | |
678 | dhustop(tp, flag) | |
679 | register struct tty *tp; | |
680 | { | |
681 | register struct dhudevice *addr; | |
682 | register int unit, s; | |
683 | ||
684 | addr = (struct dhudevice *)tp->t_addr; | |
685 | /* | |
686 | * Block input/output interrupts while messing with state. | |
687 | */ | |
688 | s = spl5(); | |
689 | if (tp->t_state & TS_BUSY) { | |
690 | /* | |
691 | * Device is transmitting; stop output | |
692 | * by selecting the line and setting the | |
693 | * abort xmit bit. We will get an xmit interrupt, | |
694 | * where we will figure out where to continue the | |
695 | * next time the transmitter is enabled. If | |
696 | * TS_FLUSH is set, the outq will be flushed. | |
697 | * In either case, dhustart will clear the TXABORT bit. | |
698 | */ | |
699 | unit = minor(tp->t_dev); | |
700 | addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; | |
701 | addr->dhulcr |= DHU_LC_TXABORT; | |
702 | if ((tp->t_state&TS_TTSTOP)==0) | |
703 | tp->t_state |= TS_FLUSH; | |
704 | } | |
705 | (void) splx(s); | |
706 | } | |
707 | ||
708 | /* | |
709 | * DHU11 modem control | |
710 | */ | |
711 | dhumctl(dev, bits, how) | |
712 | dev_t dev; | |
713 | int bits, how; | |
714 | { | |
715 | register struct dhudevice *dhuaddr; | |
9418508d | 716 | register int unit, mbits; |
48952cf5 KM |
717 | int s; |
718 | ||
719 | unit = UNIT(dev); | |
720 | dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr); | |
721 | unit &= 0xf; | |
722 | s = spl5(); | |
723 | dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE; | |
724 | /* | |
725 | * combine byte from stat register (read only, bits 16..23) | |
726 | * with lcr register (read write, bits 0..15). | |
727 | */ | |
728 | mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16); | |
729 | switch (how) { | |
730 | case DMSET: | |
731 | mbits = (mbits & 0xff0000) | bits; | |
732 | break; | |
733 | ||
734 | case DMBIS: | |
735 | mbits |= bits; | |
736 | break; | |
737 | ||
738 | case DMBIC: | |
739 | mbits &= ~bits; | |
740 | break; | |
741 | ||
742 | case DMGET: | |
743 | (void) splx(s); | |
744 | return(mbits); | |
745 | } | |
746 | dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN; | |
747 | dhuaddr->dhulcr2 = DHU_LC2_TXEN; | |
748 | (void) splx(s); | |
749 | return(mbits); | |
750 | } | |
751 | ||
752 | /* | |
753 | * Reset state of driver if UBA reset was necessary. | |
754 | * Reset the line and modem control registers. | |
755 | * restart transmitters. | |
756 | */ | |
757 | dhureset(uban) | |
758 | int uban; | |
759 | { | |
760 | register int dhu, unit; | |
761 | register struct tty *tp; | |
762 | register struct uba_device *ui; | |
763 | register struct dhudevice *addr; | |
764 | int i; | |
48952cf5 | 765 | |
48952cf5 KM |
766 | for (dhu = 0; dhu < NDHU; dhu++) { |
767 | ui = dhuinfo[dhu]; | |
768 | if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) | |
769 | continue; | |
770 | printf(" dhu%d", dhu); | |
e965c38b MK |
771 | if (dhu_uballoc[uban] == dhu) { |
772 | int info; | |
773 | ||
774 | info = uballoc(uban, (caddr_t)cfree, | |
775 | nclist * sizeof(struct cblock), UBA_CANTWAIT); | |
776 | if (info) | |
777 | cbase[uban] = UBAI_ADDR(info); | |
778 | else { | |
779 | printf(" [can't get uba map]"); | |
780 | cbase[uban] = -1; | |
781 | } | |
c18c7ccc | 782 | } |
48952cf5 KM |
783 | addr = (struct dhudevice *)ui->ui_addr; |
784 | addr->dhucsr = DHU_SELECT(0) | DHU_IE; | |
785 | addr->dhutimo = DHU_DEF_TIMO; | |
786 | unit = dhu * 16; | |
787 | for (i = 0; i < 16; i++) { | |
788 | tp = &dhu_tty[unit]; | |
789 | if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { | |
f5f63131 | 790 | dhuparam(tp, &tp->t_termios); |
48952cf5 KM |
791 | (void)dhumctl(unit, DHU_ON, DMSET); |
792 | tp->t_state &= ~TS_BUSY; | |
793 | dhustart(tp); | |
794 | } | |
795 | unit++; | |
796 | } | |
797 | } | |
798 | } | |
799 | #endif |