Commit | Line | Data |
---|---|---|
eda39fa8 KM |
1 | /* |
2 | * Copyright (c) 1985 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
0b35cf68 | 6 | * @(#)dmz.c 6.6 (Berkeley) %G% |
eda39fa8 KM |
7 | */ |
8 | ||
9 | /* | |
10 | * DMZ-32 driver | |
11 | * HISTORY | |
12 | * 23-Apr-85 Joe Camaratta (jcc) at Siemens RTL | |
13 | * Driver for DEC's DMZ32 24-line asynchronous multiplexor. | |
14 | * Based on Chris Maloney's driver for DEC's DMF32 | |
eda39fa8 KM |
15 | * |
16 | * 9-Aug-85 Mike Meyer (mwm) at ucb | |
17 | * Mangled into shape for 4.3. | |
18 | */ | |
19 | ||
20 | #include "dmz.h" | |
21 | #if NDMZ > 0 | |
22 | ||
23 | ||
24 | #include "../machine/pte.h" | |
25 | ||
26 | ||
27 | #include "bk.h" | |
28 | #include "uba.h" | |
29 | #include "param.h" | |
30 | #include "conf.h" | |
31 | #include "dir.h" | |
32 | #include "user.h" | |
0b35cf68 | 33 | #include "proc.h" |
eda39fa8 KM |
34 | #include "ioctl.h" |
35 | #include "tty.h" | |
36 | #include "map.h" | |
37 | #include "buf.h" | |
38 | #include "vm.h" | |
39 | #include "bkmac.h" | |
40 | #include "clist.h" | |
41 | #include "file.h" | |
42 | #include "uio.h" | |
43 | #include "kernel.h" | |
9e8c0c88 | 44 | #include "syslog.h" |
eda39fa8 KM |
45 | |
46 | #include "ubareg.h" | |
47 | #include "ubavar.h" | |
48 | #include "dmzreg.h" | |
a7aacc6a | 49 | #include "dmreg.h" |
eda39fa8 KM |
50 | |
51 | int dmzprobe(), dmzattach(), dmzrint(), dmzxint(); | |
52 | struct uba_device *dmzinfo[NDMZ]; | |
53 | u_short dmzstd[] = {0, 0}; | |
54 | struct uba_driver dmzdriver = { | |
55 | dmzprobe, 0, dmzattach, 0, dmzstd, "dmz", dmzinfo | |
56 | }; | |
57 | ||
58 | #define NDMZLINES (NDMZ*24) | |
59 | ||
60 | int ttrstrt(); | |
61 | struct tty dmz_tty[NDMZLINES]; | |
62 | ||
63 | int dmzsoftCAR[NDMZ]; | |
64 | ||
65 | struct { | |
66 | char dmz_state; /* dmz state */ | |
67 | int dmz_count; /* dmz dma count */ | |
68 | } dmz_softc[NDMZ*24]; | |
69 | ||
70 | #define ST_TXOFF (0x01) /* transmission turned off (^S) */ | |
71 | #define ST_DMA (0x02) /* dma inprogress */ | |
72 | #define ST_INBUSY (0x04) /* stop transmission in busy */ | |
73 | ||
74 | char dmz_speeds[] = { | |
75 | 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 | |
76 | }; | |
77 | ||
74bfa0d5 MK |
78 | #ifndef PORTSELECTOR |
79 | #define ISPEED B9600 | |
80 | #define IFLAGS (EVENP|ODDP|ECHO) | |
81 | #else | |
82 | #define ISPEED B4800 | |
83 | #define IFLAGS (EVENP|ODDP) | |
84 | #endif | |
85 | ||
eda39fa8 KM |
86 | #ifndef lint |
87 | int ndmz = NDMZLINES; /* Used by pstat/iostat */ | |
88 | #endif | |
89 | ||
90 | short dmzact[NDMZ]; /* Mask of active octets on the dmz */ | |
91 | int dmzstart(); | |
92 | ||
93 | /* | |
94 | * SILO_TIMEOUT represents the number of milliseconds characters can sit | |
95 | * in the input silo without causing an interrupt. If data overruns or | |
96 | * slow XON/XOFF occur, set it lower but AT LEAST equal to 1. | |
97 | */ | |
98 | #define SILO_TIMEOUT (3) | |
99 | ||
100 | /* | |
101 | * DO_DMA_COUNT represents the threshold of the number of output | |
102 | * characters beyond which the driver uses DMA mode. | |
103 | */ | |
104 | #define DO_DMA_COUNT (10) | |
105 | ||
106 | #define TRUE (1) | |
107 | #define FALSE (0) | |
108 | ||
9e8c0c88 | 109 | int cbase[NUBA]; /* base address in unibus map */ |
eda39fa8 KM |
110 | int dmz_ubinfo[NUBA]; /* info about allocated unibus map */ |
111 | ||
112 | #define UBACVT(x, uban) (cbase[uban] + ((x) - (char *)cfree)) | |
113 | ||
114 | /* These flags are for debugging purposes only */ | |
115 | int dmz_dma_on = 1; | |
eda39fa8 KM |
116 | |
117 | dmzprobe(reg) | |
118 | caddr_t reg; | |
119 | { | |
120 | register int br, cvec; | |
121 | register struct dmzdevice *dmz_addr; | |
122 | register unsigned int a; | |
123 | ||
124 | dmz_addr = (struct dmzdevice *)reg; | |
125 | ||
126 | #ifdef lint | |
127 | br = 0; cvec = br; br = cvec; dmzxinta(0); dmzxintb(0); dmzxintc(0); | |
128 | dmzrinta(0); dmzrintb(0); dmzrintc(0); | |
129 | #endif | |
130 | ||
131 | br = 0x15; | |
132 | ||
133 | a = dmz_addr->dmz_config; | |
134 | if (((a>>12) & ~DMZ_INTERFACE) != 0) { | |
135 | printf(" Unknown interface type\n"); | |
136 | return (0); | |
137 | } | |
138 | if (((a>>8) & DMZ_NOC_MASK) != 3) { | |
139 | printf(" Not all octets are available\n"); | |
140 | return (0); | |
141 | } | |
142 | ||
143 | cvec = (uba_hd[numuba].uh_lastiv -= 4 * 6); | |
144 | dmz_addr->dmz_config = cvec >> 2; | |
145 | ||
146 | return (sizeof(struct dmzdevice)); | |
147 | } | |
148 | ||
149 | dmzattach(ui) | |
150 | struct uba_device *ui; | |
151 | { | |
152 | dmzsoftCAR[ui->ui_unit] = ui->ui_flags; | |
cdebba26 | 153 | cbase[ui->ui_ubanum] = -1; |
eda39fa8 KM |
154 | } |
155 | ||
156 | /* ARGSUSED */ | |
157 | dmzopen(device, flag) | |
158 | dev_t device; | |
159 | int flag; | |
160 | { | |
161 | register struct tty *tp; | |
162 | register int unit, controller; | |
163 | register struct dmzdevice *dmz_addr; | |
164 | register struct uba_device *ui; | |
165 | int priority; | |
eda39fa8 KM |
166 | int octet; |
167 | ||
168 | unit = minor(device); | |
169 | controller = DMZ(unit); | |
170 | octet = OCTET(unit); | |
171 | ||
172 | if (unit >= NDMZLINES || | |
173 | (ui = dmzinfo[controller]) == 0 || | |
174 | ui->ui_alive == 0) | |
175 | return (ENXIO); | |
176 | ||
177 | tp = &dmz_tty[unit]; | |
178 | ||
179 | if ((tp->t_state & TS_XCLUDE) && u.u_uid != 0) | |
180 | return (EBUSY); | |
181 | ||
182 | dmz_addr = (struct dmzdevice *)ui->ui_addr; | |
183 | tp->t_addr = (caddr_t)dmz_addr; | |
184 | tp->t_oproc = dmzstart; | |
eda39fa8 KM |
185 | |
186 | /* | |
187 | * Set up Unibus map registers. Block uba resets, which can | |
188 | * clear the state. | |
189 | */ | |
190 | priority = spl5(); | |
cdebba26 | 191 | if (cbase[ui->ui_ubanum] == -1) { |
eda39fa8 KM |
192 | dmz_ubinfo[ui->ui_ubanum] = |
193 | uballoc(ui->ui_ubanum, (caddr_t)cfree, | |
194 | nclist * sizeof(struct cblock), 0); | |
195 | if (dmz_ubinfo[ui->ui_ubanum] == 0) { | |
196 | splx(priority); | |
197 | printf("dmz: insufficient unibus map regs\n"); | |
9e8c0c88 | 198 | return (ENOMEM); |
eda39fa8 | 199 | } |
cdebba26 | 200 | cbase[ui->ui_ubanum] = UBAI_ADDR(dmz_ubinfo[ui->ui_ubanum]); |
eda39fa8 KM |
201 | } |
202 | ||
203 | if ((dmzact[controller] & (1 << octet)) == 0) { | |
204 | dmz_addr->octet[octet].octet_csr |= DMZ_IE; | |
205 | dmzact[controller] |= 1 << octet; | |
206 | dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT; | |
207 | } | |
208 | ||
209 | splx(priority); | |
210 | ||
211 | if ((tp->t_state & TS_ISOPEN) == 0) { | |
212 | ttychars(tp); | |
74bfa0d5 MK |
213 | tp->t_ispeed = tp->t_ospeed = ISPEED; |
214 | tp->t_flags = IFLAGS; | |
eda39fa8 KM |
215 | dmz_softc[unit].dmz_state = 0; |
216 | } | |
a7aacc6a | 217 | dmzparam(unit); |
eda39fa8 KM |
218 | |
219 | /* | |
220 | * Wait for carrier, then process line discipline specific open. | |
221 | */ | |
a7aacc6a | 222 | if ((dmzmctl(unit, DMZ_ON, DMSET) & DMZ_CAR) || |
eda39fa8 KM |
223 | (dmzsoftCAR[controller] & (1 << (unit % 24)))) |
224 | tp->t_state |= TS_CARR_ON; | |
225 | priority = spl5(); | |
226 | while ((tp->t_state & TS_CARR_ON) == 0) { | |
227 | tp->t_state |= TS_WOPEN; | |
228 | sleep((caddr_t) &tp->t_rawq, TTIPRI); | |
229 | } | |
230 | splx(priority); | |
231 | ||
9e8c0c88 | 232 | return ((*linesw[tp->t_line].l_open)(device, tp)); |
eda39fa8 KM |
233 | } |
234 | ||
235 | dmzparam(unit) | |
236 | register int unit; | |
237 | { | |
238 | register struct tty *tp; | |
239 | register struct dmzdevice *dmz_addr; | |
a7aacc6a | 240 | register int line_parameters; |
eda39fa8 KM |
241 | register int octet; |
242 | int priority; | |
243 | ||
244 | octet = OCTET(unit); | |
245 | ||
246 | tp = &dmz_tty[unit]; | |
247 | dmz_addr = (struct dmzdevice *)tp->t_addr; | |
248 | ||
249 | priority = spl5(); | |
250 | if ((tp->t_ispeed) == 0) { | |
251 | tp->t_state |= TS_HUPCLS; | |
252 | (void) dmzmctl(unit, DMZ_OFF, DMSET); | |
253 | splx(priority); | |
254 | return; | |
255 | } | |
256 | ||
257 | line_parameters = (dmz_speeds[tp->t_ospeed] << 12) | (dmz_speeds[tp->t_ispeed] << 8); | |
eda39fa8 KM |
258 | |
259 | if ((tp->t_ispeed) == B134) | |
260 | line_parameters |= DMZ_6BT | DMZ_PEN; | |
a7aacc6a | 261 | else if (tp->t_flags & (RAW | LITOUT | PASS8)) |
eda39fa8 KM |
262 | line_parameters |= DMZ_8BT; |
263 | else | |
264 | line_parameters |= DMZ_7BT | DMZ_PEN; | |
265 | ||
266 | if (tp->t_flags & EVENP) | |
267 | line_parameters |= DMZ_EPR; | |
268 | if ((tp->t_ospeed) == B110) | |
269 | line_parameters |= DMZ_SCD; | |
270 | ||
271 | line_parameters |= (unit & 07); | |
272 | ||
273 | dmz_addr->octet[octet].octet_lprm = line_parameters; | |
eda39fa8 | 274 | splx(priority); |
eda39fa8 KM |
275 | } |
276 | ||
277 | /* ARGSUSED */ | |
278 | dmzclose(device, flag) | |
279 | dev_t device; | |
280 | int flag; | |
281 | { | |
282 | register struct tty *tp; | |
283 | register int unit; | |
284 | ||
285 | unit = minor(device); | |
286 | tp = &dmz_tty[unit]; | |
a7aacc6a | 287 | (*linesw[tp->t_line].l_close)(tp); |
eda39fa8 KM |
288 | |
289 | /* | |
a7aacc6a | 290 | * Clear break, hang-up and close the modem. |
eda39fa8 KM |
291 | */ |
292 | (void) dmzmctl(unit, DMZ_BRK, DMBIC); | |
293 | if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0) | |
294 | (void) dmzmctl(unit, DMZ_OFF, DMSET); | |
295 | ttyclose(tp); | |
296 | return; | |
297 | } | |
298 | ||
299 | dmzreset(uban) | |
300 | int uban; | |
301 | { | |
302 | register int controller, unit; | |
303 | register struct tty *tp; | |
304 | register struct uba_device *ui; | |
305 | register struct dmzdevice *dmz_addr; | |
306 | int i; | |
307 | int octet; | |
308 | ||
eda39fa8 KM |
309 | for (controller = 0; controller < NDMZ; controller++) { |
310 | ui = dmzinfo[controller]; | |
311 | if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) | |
312 | continue; | |
313 | printf("dmz%d ", controller); | |
314 | dmz_addr = (struct dmzdevice *) ui->ui_addr; | |
315 | ||
cdebba26 | 316 | if (dmz_ubinfo[uban]) { |
9e8c0c88 MK |
317 | dmz_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, |
318 | nclist * sizeof(struct cblock), 0); | |
cdebba26 | 319 | cbase[uban] = UBAI_ADDR(dmz_ubinfo[uban]); |
9e8c0c88 MK |
320 | } |
321 | ||
eda39fa8 KM |
322 | for (octet = 0; octet < 3; octet++) |
323 | if ((dmzact[controller] & (1 << octet)) != 0) { | |
324 | dmz_addr->octet[octet].octet_csr |= DMZ_IE; | |
325 | dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT; | |
326 | } | |
327 | ||
328 | unit = controller * 24; | |
329 | ||
330 | /* | |
331 | * If a unit is open or waiting for open to complete, | |
332 | * reset it. | |
333 | */ | |
334 | for (i = 0; i < 24; i++) { | |
335 | dmz_softc[unit].dmz_state = 0; | |
336 | tp = &dmz_tty[unit]; | |
337 | if (tp->t_state & (TS_ISOPEN | TS_WOPEN)) { | |
338 | dmzparam(unit); | |
339 | (void) dmzmctl(unit, DMZ_ON, DMSET); | |
340 | tp->t_state &= ~TS_BUSY; | |
341 | dmzstart(tp); | |
342 | } | |
343 | unit++; | |
344 | } | |
345 | } | |
346 | return; | |
347 | } | |
348 | ||
349 | dmzread(device, uio) | |
350 | dev_t device; | |
351 | struct uio *uio; | |
352 | { | |
353 | register struct tty *tp; | |
354 | int xstatus; | |
355 | ||
356 | tp = &dmz_tty[minor(device)]; | |
357 | xstatus = (*linesw[tp->t_line].l_read)(tp, uio); | |
358 | return (xstatus); | |
359 | } | |
360 | ||
361 | dmzwrite(device, uio) | |
362 | dev_t device; | |
363 | struct uio *uio; | |
364 | { | |
365 | register struct tty *tp; | |
366 | int xstatus; | |
367 | ||
368 | tp = &dmz_tty[minor(device)]; | |
369 | xstatus = (*linesw[tp->t_line].l_write)(tp, uio); | |
370 | return (xstatus); | |
371 | } | |
372 | ||
373 | dmzrinta(controller) | |
374 | int controller; | |
375 | { | |
376 | dmzrint(controller, 0); | |
377 | } | |
378 | ||
379 | dmzrintb(controller) | |
380 | int controller; | |
381 | { | |
382 | dmzrint(controller, 1); | |
383 | } | |
384 | ||
385 | dmzrintc(controller) | |
386 | int controller; | |
387 | { | |
388 | dmzrint(controller, 2); | |
389 | } | |
390 | ||
391 | dmzrint(controller, octet) | |
392 | int controller; | |
393 | register int octet; | |
394 | { | |
395 | register struct tty *tp; | |
396 | register int character; | |
397 | register struct dmzdevice *dmz_addr; | |
398 | register struct tty *tp0; | |
399 | register int unit; | |
400 | register struct uba_device *ui; | |
74bfa0d5 | 401 | int overrun; |
eda39fa8 KM |
402 | |
403 | overrun = 0; | |
404 | ui = dmzinfo[controller]; | |
405 | if (ui == 0 || ui->ui_alive == 0) | |
406 | return; | |
407 | dmz_addr = (struct dmzdevice *) ui->ui_addr; | |
408 | tp0 = &dmz_tty[controller * 24]; | |
409 | ||
410 | while ((character = dmz_addr->octet[octet].octet_receive.octet_rb) < 0) { | |
411 | unit = (character >> 8) & 07; /* unit is bits 8-10 of rb */ | |
412 | tp = tp0 + (octet * 8 + unit); | |
413 | ||
cdebba26 | 414 | if (character & DMZ_DSC) { |
a7aacc6a MK |
415 | dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMSTSC | unit; |
416 | if (dmz_addr->octet[octet].octet_rmstsc & DMZ_CAR) | |
74bfa0d5 | 417 | (void)(*linesw[tp->t_line].l_modem)(tp, 1); |
cdebba26 MK |
418 | else if (dmzsoftCAR[controller] & |
419 | (1 << (octet * 8 + unit)) == 0 && | |
420 | (*linesw[tp->t_line].l_modem)(tp, 0) == 0) | |
a7aacc6a | 421 | (void)dmzmctl(tp - dmz_tty, DMZ_OFF, DMSET); |
eda39fa8 KM |
422 | continue; |
423 | } | |
424 | ||
74bfa0d5 MK |
425 | if ((tp->t_state&TS_ISOPEN)==0) { |
426 | wakeup((caddr_t)&tp->t_rawq); | |
427 | #ifdef PORTSELECTOR | |
428 | if ((tp->t_state&TS_WOPEN) == 0) | |
429 | #endif | |
430 | continue; | |
eda39fa8 KM |
431 | } |
432 | ||
433 | if (character & DMZ_PE) { | |
434 | if ((tp->t_flags & (EVENP | ODDP)) == EVENP || | |
435 | (tp->t_flags & (EVENP | ODDP)) == ODDP) | |
436 | continue; | |
437 | } | |
438 | ||
439 | if ((character & DMZ_DO) && overrun == 0) { | |
9e8c0c88 | 440 | log(LOG_WARNING, "dmz%d: silo overflow\n", controller); |
eda39fa8 KM |
441 | overrun = 1; |
442 | } | |
443 | ||
444 | if (character & DMZ_FE) { | |
445 | if (tp->t_flags & RAW) | |
446 | character = 0; | |
447 | else | |
448 | character = tp->t_intrc; | |
449 | } | |
450 | ||
451 | (*linesw[tp->t_line].l_rint)(character, tp); | |
452 | } | |
453 | ||
454 | return; | |
455 | } | |
456 | ||
457 | dmzxinta(controller) | |
458 | int controller; | |
459 | { | |
460 | dmzxint(controller, 0); | |
461 | } | |
462 | ||
463 | dmzxintb(controller) | |
464 | int controller; | |
465 | { | |
466 | dmzxint(controller, 1); | |
467 | } | |
468 | ||
469 | dmzxintc(controller) | |
470 | int controller; | |
471 | { | |
472 | dmzxint(controller, 2); | |
473 | } | |
474 | ||
475 | dmzxint(controller, octet) | |
476 | int controller; | |
477 | register int octet; | |
478 | { | |
479 | register struct tty *tp; | |
480 | register struct dmzdevice *dmz_addr; | |
481 | register struct uba_device *ui; | |
482 | register int unit, t; | |
483 | int priority; | |
484 | ||
485 | ui = dmzinfo[controller]; | |
486 | dmz_addr = (struct dmzdevice *)ui->ui_addr; | |
487 | ||
488 | priority = spl5(); | |
489 | ||
490 | while ((t = dmz_addr->octet[octet].octet_csr) & DMZ_TRDY) { | |
491 | unit = controller * 24 + (octet * 8 + ((t>>8) & 07)); | |
492 | tp = &dmz_tty[unit]; | |
493 | tp->t_state &= ~TS_BUSY; | |
494 | ||
495 | if (t & DMZ_NXM) | |
496 | printf("dmz%d: NXM line %d\n", controller, | |
497 | octet * 8 + (unit & 07)); | |
498 | ||
499 | if (tp->t_state & TS_FLUSH) { | |
500 | tp->t_state &= ~TS_FLUSH; | |
501 | dmz_addr->octet[octet].octet_csr = | |
502 | DMZ_IE | IR_LCTMR | (unit & 07); | |
503 | dmz_addr->octet[octet].octet_lctmr = | |
504 | (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); | |
505 | } else | |
506 | if (dmz_softc[unit].dmz_state & ST_DMA) | |
507 | ndflush(&tp->t_outq, dmz_softc[unit].dmz_count); | |
508 | dmz_softc[unit].dmz_state = 0; | |
509 | ||
510 | if (tp->t_line) | |
511 | (*linesw[tp->t_line].l_start)(tp); | |
512 | else | |
513 | dmzstart(tp); | |
514 | } | |
515 | ||
516 | splx(priority); | |
517 | return; | |
518 | } | |
519 | ||
520 | dmzstart(tp) | |
521 | register struct tty *tp; | |
522 | { | |
523 | register struct dmzdevice *dmz_addr; | |
524 | register int unit, nch, room; | |
525 | int controller, octet; | |
526 | int priority, car, use_dma; | |
527 | register int i; | |
528 | register char *cp; | |
529 | ||
530 | unit = minor(tp->t_dev); | |
531 | controller = DMZ(unit); | |
532 | octet = OCTET(unit); | |
533 | dmz_addr = (struct dmzdevice *)tp->t_addr; | |
534 | ||
535 | priority = spl5(); | |
536 | ||
537 | if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) | |
538 | goto out; | |
539 | ||
540 | /* | |
541 | * If the transmitter has been disabled, reenable it. | |
542 | * If the transmitter was disabled before the xint (the | |
543 | * ST_INBUSY was still on), then reset the BUSY state and | |
544 | * we will wait for the interrupt. If !TS_BUSY, we already | |
545 | * saw the interrupt so we can start another transmission. | |
546 | */ | |
547 | if (dmz_softc[unit].dmz_state & ST_TXOFF) { | |
548 | dmz_addr->octet[octet].octet_csr = | |
549 | DMZ_IE | IR_LCTMR | (unit & 07); | |
550 | dmz_addr->octet[octet].octet_lctmr = | |
551 | (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); | |
552 | dmz_softc[unit].dmz_state &= ~ST_TXOFF; | |
553 | if (dmz_softc[unit].dmz_state & ST_INBUSY) { | |
554 | dmz_softc[unit].dmz_state &= ~ST_INBUSY; | |
555 | tp->t_state |= TS_BUSY; | |
556 | goto out; | |
557 | } | |
558 | } | |
559 | ||
560 | if (tp->t_outq.c_cc <= TTLOWAT(tp)) { | |
561 | if (tp->t_state & TS_ASLEEP) { | |
562 | tp->t_state &= ~TS_ASLEEP; | |
563 | wakeup((caddr_t)&tp->t_outq); | |
564 | } | |
565 | if (tp->t_wsel) { | |
566 | selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); | |
567 | tp->t_wsel = 0; | |
568 | tp->t_state &= ~TS_WCOLL; | |
569 | } | |
570 | } | |
571 | ||
572 | if (tp->t_outq.c_cc == 0) | |
573 | goto out; | |
a7aacc6a | 574 | if (tp->t_flags & (RAW | LITOUT | PASS8)) |
eda39fa8 KM |
575 | nch = ndqb(&tp->t_outq, 0); |
576 | else { | |
577 | nch = ndqb(&tp->t_outq, 0200); | |
578 | if (nch == 0) { | |
579 | nch = getc(&tp->t_outq); | |
580 | timeout(ttrstrt, (caddr_t)tp, (nch & 0x7f)+6); | |
581 | tp->t_state |= TS_TIMEOUT; | |
582 | goto out; | |
583 | } | |
584 | } | |
585 | ||
586 | /* | |
587 | * Should we use DMA or SILO mode? | |
588 | * If nch is greater than DO_DMA_COUNT then DMA. | |
589 | */ | |
590 | if (nch) { | |
591 | dmz_addr->octet[octet].octet_csr = | |
592 | DMZ_IE | IR_LCTMR | (unit & 07); | |
593 | dmz_addr->octet[octet].octet_lctmr = | |
594 | (dmz_addr->octet[octet].octet_lctmr | DMZ_TE); | |
595 | tp->t_state |= TS_BUSY; | |
596 | ||
597 | use_dma = FALSE; | |
598 | room = DMZ_SIZ; | |
599 | ||
600 | if (nch > DO_DMA_COUNT) | |
601 | use_dma = TRUE; | |
602 | ||
603 | if (use_dma && dmz_dma_on) { | |
604 | car = UBACVT(tp->t_outq.c_cf, | |
605 | dmzinfo[controller]->ui_ubanum); | |
606 | dmz_softc[unit].dmz_count = nch; | |
607 | dmz_softc[unit].dmz_state |= ST_DMA; | |
608 | dmz_addr->octet[octet].octet_csr = | |
609 | DMZ_IE | IR_TBA | (unit & 07); | |
610 | dmz_addr->octet[octet].octet_tba = car; | |
611 | dmz_addr->octet[octet].octet_tcc = | |
612 | ((car >> 2) & 0xc000) | nch; | |
613 | } else { | |
614 | dmz_softc[unit].dmz_state &= ~ST_DMA; | |
615 | cp = tp->t_outq.c_cf; | |
616 | nch = MIN(nch, room); | |
617 | dmz_addr->octet[octet].octet_csr = | |
618 | DMZ_IE | IR_TBUF | (unit & 07); | |
619 | for (i = 0; i < nch; i++) | |
620 | dmz_addr->octet[octet].octet_tbf = *cp++ ; | |
621 | ndflush(&tp->t_outq, nch); | |
622 | } | |
623 | } | |
624 | ||
625 | out: | |
626 | splx(priority); | |
627 | return; | |
628 | } | |
629 | ||
630 | /* ARGSUSED */ | |
631 | dmzstop(tp, flag) | |
632 | register struct tty *tp; | |
633 | { | |
634 | register struct dmzdevice *dmz_addr; | |
635 | register int unit, priority, octet; | |
636 | ||
637 | priority = spl5(); | |
638 | dmz_addr = (struct dmzdevice *) tp->t_addr; | |
639 | unit = minor(tp->t_dev); | |
640 | octet = OCTET(unit); | |
641 | ||
642 | dmz_addr->octet[octet].octet_csr = IR_LCTMR | (unit & 07) | DMZ_IE; | |
643 | dmz_addr->octet[octet].octet_lctmr = | |
644 | (dmz_addr->octet[octet].octet_lctmr & ~DMZ_TE); | |
645 | dmz_softc[unit].dmz_state |= ST_TXOFF; | |
646 | if ((tp->t_state & TS_TTSTOP) == 0) { | |
647 | tp->t_state |= (TS_FLUSH | TS_BUSY); | |
648 | dmz_addr->octet[octet].octet_lctmr = | |
649 | (dmz_addr->octet[octet].octet_lctmr | DMZ_FLS); | |
650 | } else if (tp->t_state & TS_BUSY) { | |
651 | dmz_softc[unit].dmz_state |= ST_INBUSY; | |
652 | tp->t_state &= ~TS_BUSY; | |
653 | } | |
654 | ||
655 | splx(priority); | |
656 | return; | |
657 | } | |
658 | ||
659 | /* ARGSUSED */ | |
660 | dmzioctl(device, command, data, flag) | |
661 | dev_t device; | |
662 | caddr_t data; | |
663 | { | |
664 | register struct tty *tp; | |
665 | register int unit; | |
666 | int error; | |
667 | ||
668 | unit = minor(device); | |
669 | tp = &dmz_tty[unit]; | |
670 | ||
671 | error = (*linesw[tp->t_line].l_ioctl)(tp, command, data, flag); | |
672 | if (error >= 0) | |
673 | return (error); | |
674 | error = ttioctl(tp, command, data, flag); | |
675 | if (error >= 0) { | |
a7aacc6a MK |
676 | if (command == TIOCSETP || command == TIOCSETN || |
677 | command == TIOCLSET || command == TIOCLBIS || | |
678 | command == TIOCLBIC) | |
eda39fa8 KM |
679 | dmzparam(unit); |
680 | return (error); | |
681 | } | |
682 | ||
683 | switch (command) { | |
684 | case TIOCSBRK: | |
a7aacc6a | 685 | (void) dmzmctl(unit, DMZ_BRK, DMBIS); |
eda39fa8 KM |
686 | break; |
687 | case TIOCCBRK: | |
a7aacc6a | 688 | (void) dmzmctl(unit, DMZ_BRK, DMBIC); |
eda39fa8 KM |
689 | break; |
690 | case TIOCSDTR: | |
a7aacc6a | 691 | (void) dmzmctl(unit, DMZ_DTR | DMZ_RTS, DMBIS); |
eda39fa8 KM |
692 | break; |
693 | case TIOCCDTR: | |
a7aacc6a | 694 | (void) dmzmctl(unit, DMZ_DTR | DMZ_RTS, DMBIC); |
eda39fa8 KM |
695 | break; |
696 | case TIOCMSET: | |
a7aacc6a | 697 | (void) dmzmctl(unit, dmtodmz(*(int *)data), DMSET); |
eda39fa8 KM |
698 | break; |
699 | case TIOCMBIS: | |
a7aacc6a | 700 | (void) dmzmctl(unit, dmtodmz(*(int *)data), DMBIS); |
eda39fa8 KM |
701 | break; |
702 | case TIOCMBIC: | |
a7aacc6a | 703 | (void) dmzmctl(unit, dmtodmz(*(int *)data), DMBIC); |
eda39fa8 KM |
704 | break; |
705 | case TIOCMGET: | |
a7aacc6a | 706 | *(int *)data = dmzmctl(unit, 0, DMGET); |
eda39fa8 KM |
707 | break; |
708 | default: | |
709 | return (ENOTTY); | |
710 | } | |
711 | return (0); | |
712 | } | |
713 | ||
a7aacc6a MK |
714 | dmzmctl(unit, bits, how) |
715 | register int unit; | |
eda39fa8 KM |
716 | int bits, how; |
717 | { | |
718 | register struct dmzdevice *dmz_addr; | |
a7aacc6a | 719 | register int modem_status, line_control; |
eda39fa8 KM |
720 | int priority; |
721 | int octet; | |
722 | ||
eda39fa8 | 723 | octet = OCTET(unit); |
a7aacc6a | 724 | dmz_addr = (struct dmzdevice *) dmzinfo[DMZ(unit)]->ui_addr; |
eda39fa8 KM |
725 | |
726 | priority = spl5(); | |
a7aacc6a MK |
727 | dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMSTSC | (unit & 07); |
728 | modem_status = dmz_addr->octet[octet].octet_rmstsc & 0xff00; | |
eda39fa8 KM |
729 | |
730 | dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07); | |
a7aacc6a | 731 | line_control = dmz_addr->octet[octet].octet_lctmr; |
eda39fa8 | 732 | |
eda39fa8 KM |
733 | |
734 | switch (how) { | |
735 | case DMSET: | |
a7aacc6a | 736 | line_control = bits; |
eda39fa8 KM |
737 | break; |
738 | case DMBIS: | |
a7aacc6a | 739 | line_control |= bits; |
eda39fa8 KM |
740 | break; |
741 | case DMBIC: | |
a7aacc6a | 742 | line_control &= ~bits; |
eda39fa8 KM |
743 | break; |
744 | case DMGET: | |
745 | (void) splx(priority); | |
a7aacc6a | 746 | return (dmztodm(modem_status, line_control)); |
eda39fa8 KM |
747 | } |
748 | ||
eda39fa8 KM |
749 | dmz_addr->octet[octet].octet_csr = |
750 | DMZ_IE | IR_LCTMR | (unit & 07); | |
a7aacc6a | 751 | dmz_addr->octet[octet].octet_lctmr = line_control; |
eda39fa8 | 752 | |
a7aacc6a | 753 | splx(priority); |
eda39fa8 KM |
754 | return (modem_status); |
755 | } | |
756 | ||
757 | /* | |
a7aacc6a | 758 | * Routine to convert modem status from dm to dmz lctmr format. |
eda39fa8 KM |
759 | */ |
760 | dmtodmz(bits) | |
761 | register int bits; | |
762 | { | |
a7aacc6a MK |
763 | register int lcr = DMZ_LCE; |
764 | ||
765 | if (bits & DML_DTR) | |
766 | lcr |= DMZ_DTR; | |
767 | if (bits & DML_RTS) | |
768 | lcr |= DMZ_RTS; | |
769 | if (bits & DML_ST) | |
770 | lcr |= DMF_ST; | |
771 | if (bits & DML_USR) | |
772 | lcr |= DMZ_USRW; | |
773 | return (lcr); | |
eda39fa8 KM |
774 | } |
775 | ||
776 | /* | |
a7aacc6a MK |
777 | * Routine to convert modem status from dmz receive modem status |
778 | * and line control register to dm format. | |
779 | * If dmz user modem read bit set, set DML_USR. | |
eda39fa8 | 780 | */ |
a7aacc6a MK |
781 | dmztodm(rms, lcr) |
782 | register int rms, lcr; | |
eda39fa8 | 783 | { |
a7aacc6a MK |
784 | |
785 | rms = ((rms & (DMZ_DSR|DMZ_RNG|DMZ_CAR|DMZ_CTS|DMF_SR)) >> 7) | | |
786 | ((rms & DMZ_USRR) >> 1) | DML_LE; | |
787 | if (lcr & DMZ_DTR) | |
788 | rms |= DML_DTR; | |
789 | if (lcr & DMF_ST) | |
790 | rms |= DML_ST; | |
791 | if (lcr & DMZ_RTS) | |
792 | rms |= DML_RTS; | |
793 | return (rms); | |
eda39fa8 KM |
794 | } |
795 | #endif |