msc.c revision 1.2 1 /* $NetBSD: msc.c,v 1.2 1995/10/07 18:18:26 chopps Exp $ */
2
3 /*
4 * Copyright (c) 1993 Zik.
5 * Copyright (c) 1995 Jukka Marin <jmarin (at) teeri.jmp.fi>.
6 * Copyright (c) 1995 Timo Rossi <trossi (at) jyu.fi>.
7 * Copyright (c) 1995 Rob Healey <rhealey (at) kas.helios.mn.org>.
8 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * - converted from NetBSD Amiga serial driver to A2232 serial driver
40 * by zik 931207
41 * - added ttyflags hooks rfh 940419
42 * - added new style config support rfh 940601
43 * - added code to halt board during memory load so board doesn't flip
44 * out. /dev/reload works now. Also created mschwiflow function so BSD can
45 * attempt to use board RTS flow control now. rfh 950108
46 * - Integrated work from Jukka Marin <jmarin (at) jmp.fi> and
47 * Timo Rossi <trossi (at) jyu.fi> The mscmint() code is Jukka's. 950916
48 * Integrated more bug fixes by Jukka Marin <jmarin (at) jmp.fi> 950918
49 * Also added Jukka's turbo board code. 950918
50 * - Reformatted to NetBSD style format.
51 */
52
53 #include "msc.h"
54
55 #if NMSC > 0
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/ioctl.h>
59 #include <sys/tty.h>
60 #include <sys/proc.h>
61 #include <sys/conf.h>
62 #include <sys/file.h>
63 #include <sys/malloc.h>
64 #include <sys/uio.h>
65 #include <sys/kernel.h>
66 #include <sys/syslog.h>
67 #include <sys/device.h>
68
69 #include <amiga/amiga/device.h>
70 #include <amiga/dev/zbusvar.h>
71 #include <amiga/dev/mscreg.h>
72 #include "machine/cpu.h"
73
74 #include <amiga/amiga/custom.h>
75 #include <amiga/amiga/cia.h>
76 #include <amiga/amiga/cc.h>
77
78 /* 6502 code for A2232 card */
79 #include "msc6502.h"
80
81 /*
82 * Note: These are Zik's original comments:
83 * There is a bit of a "gotcha" concerning the numbering
84 * of msc devices and the specification of the number of serial
85 * lines in the kernel.
86 *
87 * Each board has seven lines, but for programming convenience
88 * and compatibility with Amiga UNIX the boards' minor device
89 * numbers are allocated in groups of sixteen:
90 *
91 * minor device numbers
92 * First board 0 2 4 6 8 10 12
93 * Second board 16 18 20 22 24 26 28
94 * Third board 32 34 36 38 40 42 44
95 *
96 * The intermediate minor device numbers are dialin versions
97 * of the same devices. ie. 10 is dialout line 6 and 11 is
98 * the dialin version of line 6.
99 *
100 * On the other hand, I have made the NMSC config option refer
101 * to the total number of a2232 cards, not the maximum
102 * minor device number. So you might have NMSC=3, in which case
103 * you have three boards with minor device numbers from 0 to 45.
104 */
105
106 int mscparam();
107 int mscstart __P((struct tty *));
108 int mschwiflow __P((struct tty *, int));
109 int mscinitcard __P((struct zbus_args *));
110
111 int mscdefaultrate = TTYDEF_SPEED;
112
113 struct mscdevice mscdev[MSCSLOTS]; /* device structs for all lines */
114 struct tty *msc_tty[MSCTTYS]; /* ttys for all lines */
115
116 struct vbl_node msc_vbl_node[NMSC]; /* vbl interrupt node per board */
117
118 struct speedtab mscspeedtab_normal[] = {
119 0, 0,
120 50, MSCPARAM_B50,
121 75, MSCPARAM_B75,
122 110, MSCPARAM_B110,
123 134, MSCPARAM_B134,
124 150, MSCPARAM_B150,
125 300, MSCPARAM_B300,
126 600, MSCPARAM_B600,
127 1200, MSCPARAM_B1200,
128 1800, MSCPARAM_B1800,
129 2400, MSCPARAM_B2400,
130 3600, MSCPARAM_B3600,
131 4800, MSCPARAM_B4800,
132 7200, MSCPARAM_B7200,
133 9600, MSCPARAM_B9600,
134 19200, MSCPARAM_B19200,
135 115200, MSCPARAM_B115200,
136 -1, -1
137 };
138
139 struct speedtab mscspeedtab_turbo[] = {
140 0, 0,
141 100, MSCPARAM_B50,
142 150, MSCPARAM_B75,
143 220, MSCPARAM_B110,
144 269, MSCPARAM_B134,
145 300, MSCPARAM_B150,
146 600, MSCPARAM_B300,
147 1200, MSCPARAM_B600,
148 2400, MSCPARAM_B1200,
149 3600, MSCPARAM_B1800,
150 4800, MSCPARAM_B2400,
151 7200, MSCPARAM_B3600,
152 9600, MSCPARAM_B4800,
153 14400, MSCPARAM_B7200,
154 19200, MSCPARAM_B9600,
155 38400, MSCPARAM_B19200,
156 230400, MSCPARAM_B115200,
157 -1, -1
158 };
159
160 struct speedtab *mscspeedtab;
161
162 int mscmctl __P((dev_t dev, int bits, int howto));
163 void mscmint __P((register void *data));
164
165 int mscmatch __P((struct device *, struct cfdata *, void *));
166 void mscattach __P((struct device *, struct device *, void *));
167
168 #define SWFLAGS(dev) (msc->openflags | (MSCDIALIN(dev) ? 0 : TIOCFLAG_SOFTCAR))
169 #define DEBUG_MSC 0
170 #define DEBUG_CD 0
171
172 struct cfdriver msccd = {
173 NULL, "msc", (cfmatch_t) mscmatch, mscattach, DV_TTY,
174 sizeof(struct device), NULL, 0
175 };
176
177 #if DEBUG_MSC
178 void
179 bugi(msc, string)
180 struct mscdevice *msc;
181 char *string;
182 {
183 volatile struct mscstatus *ms;
184 volatile struct mscmemory *mscmem;
185
186 mscmem = msc->board;
187 ms = &mscmem->Status[msc->port];
188
189 printf("msc %s u%d f%08lx F%08lx\n", string, msc->port, msc->flags,
190 msc->openflags);
191 printf("msc h%d t%d H%d t%d p%02x c%02x CD%02x\n", ms->InHead,
192 ms->InTail, ms->OutHead, ms->OutTail, ms->Param, ms->Command,
193 ms->chCD);
194 printf("msc a%02x b%02x c%02x\n", ms->Pad_a, ms->Pad_b, ms->Padc);
195
196 return
197 }
198
199 #endif
200
201 int
202 mscmatch(pdp, cdp, auxp)
203 struct device *pdp;
204 struct cfdata *cdp;
205 void *auxp;
206 {
207 struct zbus_args *zap;
208
209 zap = auxp;
210 if (zap->manid == 514 && (zap->prodid == 70 || zap->prodid == 69))
211 return(1);
212
213 return (0);
214 }
215
216 void
217 mscattach(pdp, dp, auxp)
218 struct device *pdp, *dp;
219 void *auxp;
220 {
221 volatile struct mscmemory *mscmem;
222 struct mscdevice *msc;
223 struct zbus_args *zap;
224 int unit;
225 int Count;
226
227 zap = (struct zbus_args *)auxp;
228 unit = dp->dv_unit;
229
230 if (mscinitcard(zap) != 0) {
231 printf("\nmsc%d: Board initialize failed, bad download code.\n", unit);
232 return;
233 }
234
235 printf("\nmsc%d: Board successfully initialized.\n", unit);
236
237 mscmem = (struct mscmemory *) zap->va;
238
239 if (mscmem->Common.Crystal == MSC_UNKNOWN) {
240 printf("msc%d: Unable to detect crystal frequency.\n", unit);
241 return;
242 }
243
244 if (mscmem->Common.Crystal == MSC_TURBO) {
245 printf("msc%d: Turbo version detected (%02x%02x:%d)\n", unit,
246 mscmem->Common.TimerH, mscmem->Common.TimerL,
247 mscmem->Common.Pad_a);
248 mscspeedtab = mscspeedtab_turbo;
249 } else {
250 printf("msc%d: Normal version detected (%02x%02x:%d)\n", unit,
251 mscmem->Common.TimerH, mscmem->Common.TimerL,
252 mscmem->Common.Pad_a);
253 mscspeedtab = mscspeedtab_normal;
254 }
255
256 /* XXX 8 is a constant */
257 for (Count = 0; Count < 8 && MSCSLOTUL(unit, Count) < MSCSLOTS; Count++) {
258 msc = &mscdev[MSCSLOTUL(unit, Count)];
259 msc->board = mscmem;
260 msc->port = Count;
261 msc->flags = 0;
262 msc->openflags = 0;
263 msc->active = 1;
264 msc->closing = FALSE;
265 msc_tty[MSCTTYSLOT(MSCSLOTUL(unit, Count))] = NULL;
266 msc_tty[MSCTTYSLOT(MSCSLOTUL(unit, Count))+1] = NULL;
267
268 }
269
270 /* disable the non-existant eighth port */
271 if (MSCSLOTUL(unit, NUMLINES) < MSCSLOTS)
272 mscdev[MSCSLOTUL(unit, NUMLINES)].active = 0;
273
274 msc_vbl_node[unit].function = (void (*) (void *)) mscmint;
275 msc_vbl_node[unit].data = (void *) unit;
276
277 add_vbl_function (&msc_vbl_node[unit], MSC_VBL_PRIORITY, (void *)unit);
278
279 return;
280 }
281
282 /* ARGSUSED */
283 int
284 mscopen(dev, flag, mode, p)
285 dev_t dev;
286 int flag, mode;
287 struct proc *p;
288 {
289 register struct tty *tp;
290 int error = 0;
291 int s;
292 int slot;
293 int ttyn;
294 struct mscdevice *msc;
295 volatile struct mscstatus *ms;
296
297 /* get the device structure */
298 slot = MSCSLOT(dev);
299 ttyn = MSCTTY(dev);
300
301 if (slot >= MSCSLOTS)
302 return ENXIO;
303
304 if (MSCLINE(dev) >= NUMLINES)
305 return ENXIO;
306
307 msc = &mscdev[slot];
308 ms = &msc->board->Status[msc->port];
309
310 if (!msc->active)
311 return ENXIO;
312
313 /*
314 * RFH: WHY here? Put down by while like other serial drivers
315 * But if we do that it makes things bomb.
316 */
317 s = spltty();
318
319 if (!msc_tty[ttyn]) {
320
321 tp = ttymalloc();
322 msc_tty[ttyn] = tp;
323 msc_tty[ttyn+1] = (struct tty *)NULL;
324
325 #if 0
326 /* default values are not optimal for this device, increase buffers. */
327 clfree(&tp->t_rawq);
328 clfree(&tp->t_canq);
329 clfree(&tp->t_outq);
330 clalloc(&tp->t_rawq, 8192, 1);
331 clalloc(&tp->t_canq, 8192, 1);
332 clalloc(&tp->t_outq, 8192, 0);
333 #endif
334
335 }
336 else
337 tp = msc_tty[ttyn];
338
339 tp->t_oproc = (void (*) (struct tty *)) mscstart;
340 tp->t_param = mscparam;
341 tp->t_dev = dev;
342 tp->t_hwiflow = mschwiflow;
343
344 /* if port is still closing, just bitbucket remaining characters */
345 if (msc->closing) {
346
347 ms->OutFlush = TRUE;
348 msc->closing = FALSE;
349 }
350
351 /* initialize tty */
352 if ((tp->t_state & TS_ISOPEN) == 0) {
353
354 tp->t_state |= TS_WOPEN;
355 ttychars(tp);
356 if (tp->t_ispeed == 0) {
357
358 tp->t_iflag = TTYDEF_IFLAG;
359 tp->t_oflag = TTYDEF_OFLAG;
360 tp->t_cflag = TTYDEF_CFLAG;
361 tp->t_lflag = TTYDEF_LFLAG;
362 tp->t_ispeed = tp->t_ospeed = mscdefaultrate;
363 }
364
365 /* flags changed to be private to every unit by JM */
366 if (msc->openflags & TIOCFLAG_CLOCAL)
367 tp->t_cflag |= CLOCAL;
368 if (msc->openflags & TIOCFLAG_CRTSCTS)
369 tp->t_cflag |= CRTSCTS;
370 if (msc->openflags & TIOCFLAG_MDMBUF)
371 tp->t_cflag |= MDMBUF;
372
373 mscparam(tp, &tp->t_termios);
374 ttsetwater(tp);
375
376 (void) mscmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
377
378 if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) ||
379 (mscmctl(dev, 0, DMGET) & TIOCM_CD))
380 tp->t_state |= TS_CARR_ON;
381 else
382 tp->t_state &= ~TS_CARR_ON;
383
384 }
385 else {
386 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
387 splx(s);
388 return (EBUSY);
389 }
390 }
391
392 /*
393 * if NONBLOCK requested, ignore carrier
394 */
395 if (flag & O_NONBLOCK)
396 goto done;
397
398 /*
399 * s = spltty();
400 *
401 * This causes hangs when put here, like other TTY drivers do, rather than
402 * above, WHY? RFH
403 *
404 */
405
406 while ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) {
407
408 tp->t_state |= TS_WOPEN;
409
410 #if DEBUG_CD
411 printf("msc %ld waiting for CD\n", MSCLINE(dev));
412 #endif
413 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, ttopen, 0);
414
415 if (error) {
416 splx(s);
417 return(error);
418 }
419 }
420
421 done:
422 #if DEBUG_CD
423 printf("msc %ld waiting for CD\n", MSCLINE(dev));
424 #endif
425 /* This is a way to handle lost XON characters */
426 if ((flag & O_TRUNC) && (tp->t_state & TS_TTSTOP)) {
427 tp->t_state &= ~TS_TTSTOP;
428 ttstart (tp);
429 }
430
431 splx(s);
432
433 /*
434 * Reset the tty pointer, as there could have been a dialout
435 * use of the tty with a dialin open waiting.
436 */
437 tp->t_dev = dev;
438
439 return((*linesw[tp->t_line].l_open)(dev, tp));
440
441 }
442
443 int
444 mscclose(dev, flag, mode, p)
445 dev_t dev;
446 int flag, mode;
447 struct proc *p;
448 {
449 register struct tty *tp;
450 int slot;
451 volatile struct mscstatus *ms;
452 struct mscdevice *msc;
453
454 /* get the device structure */
455 slot = MSCSLOT(dev);
456
457 if (slot >= MSCSLOTS)
458 return ENXIO;
459
460 msc = &mscdev[slot];
461
462 if (!msc->active)
463 return ENXIO;
464
465 ms = &msc->board->Status[msc->port];
466
467 #if DEBUG_MSC
468 bugi(msc, "close1");
469 #endif
470
471 tp = msc_tty[MSCTTY(dev)];
472 (*linesw[tp->t_line].l_close)(tp, flag);
473
474 (void) mscmctl(dev, 0, DMSET);
475
476 ttyclose(tp);
477
478 if (msc->flags & TIOCM_DTR)
479 msc->closing = TRUE; /* flush remaining characters before dropping DTR */
480 else
481 ms->OutFlush = TRUE; /* just bitbucket remaining characters */
482
483 #if DEBUG_MSC
484 bugi(msc, "close2");
485 #endif
486
487 return (0);
488
489 }
490
491 int
492 mscread(dev, uio, flag)
493 dev_t dev;
494 struct uio *uio;
495 int flag;
496 {
497 register struct tty *tp;
498
499 tp = msc_tty[MSCTTY(dev)];
500
501 if (! tp)
502 return ENXIO;
503
504 return((*linesw[tp->t_line].l_read)(tp, uio, flag));
505 }
506
507 int
508 mscwrite(dev, uio, flag)
509 dev_t dev;
510 struct uio *uio;
511 int flag;
512 {
513 register struct tty *tp;
514
515 tp = msc_tty[MSCTTY(dev)];
516
517 if (! tp)
518 return ENXIO;
519
520 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
521 }
522
523 /*
524 * This interrupt is periodically invoked in the vertical blank
525 * interrupt. It's used to keep track of the modem control lines
526 * and (new with the fast_int code) to move accumulated data up in
527 * to the tty layer.
528 *
529 * NOTE: MSCCDHACK is an invention of mine for dubious purposes. If you
530 * want to activate it add
531 * options MSCCDHACK
532 * in the kernel conf file. Basically it forces CD->Low transitions
533 * to ALWAYS send a signal to the process, even if the device is in
534 * clocal mode or an outdial device. RFH
535 */
536 void
537 mscmint (data)
538 register void *data;
539 {
540 int unit;
541 register struct tty *tp;
542 int slot;
543 int maxslot;
544 struct mscdevice *msc;
545 volatile struct mscstatus *ms;
546 volatile u_char *ibuf, *cbuf;
547 unsigned char newhead; /* was int */
548 unsigned char bufpos; /* was int */
549 int s;
550
551 unit = (int) data;
552
553 /* check each line on this board */
554 maxslot = MSCSLOTUL(unit, NUMLINES);
555 if (maxslot > MSCSLOTS)
556 maxslot = MSCSLOTS;
557
558 for (slot = MSCSLOTUL(unit, 0); slot < maxslot; slot++)
559 {
560 msc = &mscdev[slot];
561
562 if (!msc->active)
563 continue;
564
565 tp = msc_tty[MSCTTYSLOT(slot)];
566 ms = &msc->board->Status[msc->port];
567
568 newhead = ms->InHead; /* 65c02 write pointer */
569
570 /* yoohoo, is the port open? */
571 if (tp && (tp->t_state & (TS_ISOPEN|TS_WOPEN))) {
572 /* port is open, handle all type of events */
573
574 /* set interrupt priority level */
575 s = spltty();
576
577 /* check for input for this port */
578 if (newhead != (bufpos = ms->InTail))
579 {
580 #if DEBUG_MSC
581 printf("iop%d\n",slot);
582 #endif
583 /* buffer for input chars/events */
584 ibuf = &msc->board->InBuf[msc->port][0];
585
586 /* data types of bytes in ibuf */
587 cbuf = &msc->board->InCtl[msc->port][0];
588
589 /* do for all chars, if room */
590 while (bufpos != newhead)
591 {
592 /* which type of input data? */
593 switch (cbuf[bufpos])
594 {
595 /* input event (CD, BREAK, etc.) */
596 case MSCINCTL_EVENT:
597 switch (ibuf[bufpos++])
598 {
599 /* carrier detect change OFF -> ON */
600 case MSCEVENT_CarrierOn:
601 #if DEBUG_CD
602 printf("msc CD ON %d\n", msc->port);
603 #endif
604 msc->flags |= TIOCM_CD;
605 if (MSCDIALIN(tp->t_dev))
606 (*linesw[tp->t_line].l_modem)(tp, 1);
607 break;
608
609 /* carrier detect change ON -> OFF */
610 case MSCEVENT_CarrierOff:
611 #if DEBUG_CD
612 printf("msc CD OFF %d\n", msc->port);
613 #endif
614 msc->flags &= ~TIOCM_CD;
615 #ifndef MSCCDHACK
616 if (MSCDIALIN(tp->t_dev))
617 #endif /* Note to format police: Don't merge the { below
618 in to the line above! */
619 {
620 if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
621 {
622 /* clear RTS and DTR, bitbucket output */
623 ms->Command = (ms->Command & ~MSCCMD_CMask) | MSCCMD_Close;
624 ms->Setup = TRUE;
625 msc->flags &= ~(TIOCM_DTR | TIOCM_RTS);
626 ms->OutFlush = TRUE;
627 }
628 }
629 break;
630
631 case MSCEVENT_Break:
632 #if DEBUG_MSC
633 printf("Break received on msc%d\n", slot);
634 #endif
635 (*linesw[tp->t_line].l_rint)(TTY_FE, tp);
636 break;
637
638 default:
639 printf("msc: unknown event type %d\n",
640 ibuf[(bufpos-1)&0xff]);
641
642 } /* event type switch */
643 break;
644
645 case MSCINCTL_CHAR:
646 if (tp->t_state & TS_TBLOCK) {
647 if (ms->chCD) {
648 /* Carrier detect ON -> OFF */
649 #if DEBUG_CD
650 printf("msc CD OFF blocked %d msc->flags %08lx\n",
651 msc->port, msc->flags);
652 #endif
653 msc->flags &= ~TIOCM_CD;
654
655 #ifndef MSCCDHACK
656 if (MSCDIALIN(tp->t_dev))
657 #endif
658 {
659 if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
660 /* Clear RTS and DTR, bitbucket output */
661 ms->Command = (ms->Command & ~MSCCMD_CMask) |
662 MSCCMD_Close;
663 ms->Setup = TRUE;
664 msc->flags &= ~(TIOCM_DTR | TIOCM_RTS);
665 ms->OutFlush = TRUE;
666 }
667 }
668 }
669 goto NoRoomForYa;
670 }
671 #if DEBUG_MSC
672 printf("'%c' ",ibuf[bufpos]);
673 #endif
674 (*linesw[tp->t_line].l_rint)((int)ibuf[bufpos++], tp);
675 break;
676
677 default:
678 printf("msc: unknown data type %d\n", cbuf[bufpos]);
679 bufpos++;
680
681 } /* switch on input data type */
682
683 } /* while there's something in the buffer */
684 NoRoomForYa:
685 ms->InTail = bufpos; /* tell 65C02 what we've read */
686
687 } /* if there was something in the buffer */
688
689 /* we get here only when the port is open */
690 /* send output */
691 if (tp->t_state & (TS_BUSY|TS_FLUSH))
692 {
693
694 bufpos = ms->OutHead - ms->OutTail;
695
696 /* busy and below low water mark? */
697 if (tp->t_state & TS_BUSY)
698 {
699 if (bufpos < IOBUFLOWWATER)
700 {
701 tp->t_state &= ~TS_BUSY; /* not busy any more */
702 if (tp->t_line)
703 (*linesw[tp->t_line].l_start)(tp);
704 else
705 mscstart(tp);
706 }
707 }
708
709 /* waiting for flush and buffer empty? */
710 if (tp->t_state & TS_FLUSH)
711 {
712 if (bufpos == 0)
713 tp->t_state &= ~TS_FLUSH; /* finished flushing */
714 }
715 } /* BUSY or FLUSH */
716
717 splx(s);
718
719 } else { /* End of port open */
720 /* port is closed, don't pass on the chars from it */
721
722 /* check for input for this port */
723 if (newhead != (bufpos = ms->InTail))
724 {
725 #if DEBUG_MSC
726 printf("icp%d\n",slot);
727 #endif
728 /* buffer for input chars/events */
729 ibuf = &msc->board->InBuf[msc->port][0];
730
731 /* data types of bytes in ibuf */
732 cbuf = &msc->board->InCtl[msc->port][0];
733
734 /* do for all chars, if room */
735 while (bufpos != newhead)
736 {
737 /* which type of input data? */
738 switch (cbuf[bufpos])
739 {
740 /* input event (CD, BREAK, etc.) */
741 case MSCINCTL_EVENT:
742 switch (ibuf[bufpos++])
743 {
744 /* carrier detect change OFF -> ON */
745 case MSCEVENT_CarrierOn:
746 #if DEBUG_CD
747 printf("msc CD ON %d (closed)\n", msc->port);
748 #endif
749 msc->flags |= TIOCM_CD;
750 break;
751
752 /* carrier detect change ON -> OFF */
753 case MSCEVENT_CarrierOff:
754 #if DEBUG_CD
755 printf("msc CD OFF %d (closed)\n", msc->port);
756 #endif
757 msc->flags &= ~TIOCM_CD;
758 #ifndef MSCCDHACK
759 if (tp && MSCDIALIN(tp->t_dev))
760 #else
761 if (tp )
762 #endif
763 {
764 if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
765 {
766 /* clear RTS and DTR, bitbucket output */
767 ms->Command = (ms->Command & ~MSCCMD_CMask) | MSCCMD_Close;
768 ms->Setup = TRUE;
769 msc->flags &= ~(TIOCM_DTR | TIOCM_RTS);
770 ms->OutFlush = TRUE;
771 }
772 }
773 break;
774
775 default:
776 printf("msc: unknown event type %d\n",
777 ibuf[(bufpos-1)&0xff]);
778
779 } /* event type switch */
780 break;
781
782 default:
783 bufpos++;
784
785 } /* switch on input data type */
786
787 } /* while there's something in the buffer */
788
789 ms->InTail = bufpos; /* tell 65C02 what we've read */
790
791 } /* if there was something in the buffer */
792 } /* End of port open/close */
793
794 /* is this port closing? */
795 if (msc->closing)
796 {
797 /* if DTR is off, just bitbucket remaining characters */
798 if ( (msc->flags & TIOCM_DTR) == 0)
799 {
800 ms->OutFlush = TRUE;
801 msc->closing = FALSE;
802 }
803 /* if output has drained, drop DTR */
804 else if (ms->OutHead == ms->OutTail)
805 {
806 (void) mscmctl(tp->t_dev, 0, DMSET);
807 msc->closing = FALSE;
808 }
809 }
810 } /* For all ports */
811
812 }
813
814 int
815 mscioctl(dev, cmd, data, flag, p)
816 dev_t dev;
817 int cmd;
818 caddr_t data;
819 int flag;
820 struct proc *p;
821 {
822 register struct tty *tp;
823 register int slot;
824 register int error;
825 struct mscdevice *msc;
826 volatile struct mscstatus *ms;
827 int s;
828
829 /* get the device structure */
830 slot = MSCSLOT(dev);
831
832 if (slot >= MSCSLOTS)
833 return ENXIO;
834
835 msc = &mscdev[slot];
836
837 if (!msc->active)
838 return ENXIO;
839
840 ms = &msc->board->Status[msc->port];
841 if (!(tp = msc_tty[MSCTTY(dev)]))
842 return ENXIO;
843
844 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
845
846 if (error >= 0)
847 return (error);
848
849 error = ttioctl(tp, cmd, data, flag, p);
850
851 if (error >= 0)
852 return (error);
853
854 switch (cmd) {
855
856 /* send break */
857 case TIOCSBRK:
858 s = spltty();
859 ms->Command = (ms->Command & (~MSCCMD_RTSMask)) | MSCCMD_Break;
860 ms->Setup = TRUE;
861 splx(s);
862 break;
863
864 /* clear break */
865 case TIOCCBRK:
866 s = spltty();
867 ms->Command = (ms->Command & (~MSCCMD_RTSMask)) | MSCCMD_RTSOn;
868 ms->Setup = TRUE;
869 splx(s);
870 break;
871
872 case TIOCSDTR:
873 (void) mscmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
874 break;
875
876 case TIOCCDTR:
877 if (!MSCDIALIN(dev)) /* don't let dialins drop DTR */
878 (void) mscmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
879 break;
880
881 case TIOCMSET:
882 (void) mscmctl(dev, *(int *)data, DMSET);
883 break;
884
885 case TIOCMBIS:
886 (void) mscmctl(dev, *(int *)data, DMBIS);
887 break;
888
889 case TIOCMBIC:
890 if (MSCDIALIN(dev)) /* don't let dialins drop DTR */
891 (void) mscmctl(dev, *(int *)data & TIOCM_DTR, DMBIC);
892 else
893 (void) mscmctl(dev, *(int *)data, DMBIC);
894 break;
895
896 case TIOCMGET:
897 *(int *)data = mscmctl(dev, 0, DMGET);
898 break;
899
900 case TIOCGFLAGS:
901 *(int *)data = SWFLAGS(dev);
902 break;
903
904 case TIOCSFLAGS:
905 error = suser(p->p_ucred, &p->p_acflag);
906 if (error != 0)
907 return(EPERM);
908
909 msc->openflags = *(int *)data;
910
911 /* only allow valid flags */
912 msc->openflags &= (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
913
914 break;
915
916 default:
917 return (ENOTTY);
918 }
919
920 return (0);
921 }
922
923
924 int
925 mscparam(tp, t)
926 register struct tty *tp;
927 register struct termios *t;
928 {
929 register int cfcr, cflag = t->c_cflag;
930 int slot;
931 struct mscdevice *msc;
932 volatile struct mscstatus *ms;
933 int s;
934 int ospeed = ttspeedtab(t->c_ospeed, mscspeedtab);
935
936 /* get the device structure */
937 slot = MSCSLOT(tp->t_dev);
938
939 if (slot >= MSCSLOTS)
940 return ENXIO;
941
942 msc = &mscdev[slot];
943
944 if (!msc->active)
945 return ENXIO;
946
947 ms = &msc->board->Status[msc->port];
948
949 #if DEBUG_MSC
950 bugi(msc, "param1");
951 #endif
952 /* check requested parameters */
953 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
954 return (EINVAL);
955
956 /* and copy to tty */
957 tp->t_ispeed = t->c_ispeed;
958 tp->t_ospeed = t->c_ospeed;
959 tp->t_cflag = cflag;
960
961 /* hang up if baud is zero */
962 if (t->c_ospeed == 0) {
963
964 if (!MSCDIALIN(tp->t_dev)) /* don't let dialins drop DTR */
965 (void) mscmctl(tp->t_dev, 0, DMSET);
966 }
967 else {
968
969 /* set the baud rate */
970 s = spltty();
971 ms->Param = (ms->Param & ~MSCPARAM_BaudMask) | ospeed | MSCPARAM_RcvBaud;
972
973 /* make sure any previous hangup is undone, ie. reenable DTR.
974 * also mscmctl will cause the speed to be set
975 */
976 (void) mscmctl (tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
977
978 splx(s);
979 }
980
981 #if DEBUG_MSC
982 bugi(msc, "param2");
983 #endif
984 return (0);
985
986 }
987
988
989 /*
990 * Jukka's code initializes alot of stuff that other drivers don't
991 * I'm including it here so that this code is a common set of work
992 * done by both of us. rfh
993 */
994 int
995 mschwiflow(tp, flag)
996 struct tty *tp;
997 int flag;
998 {
999
1000 /* Rob's version */
1001 #if 1
1002 #if DEBUG_MSC
1003 printf("mschwiflow %d\n", flag);
1004 #endif
1005
1006 if (flag)
1007 mscmctl( tp->t_dev, TIOCM_RTS, DMBIC); /* Clear/Lower RTS */
1008 else
1009 mscmctl( tp->t_dev, TIOCM_RTS, DMBIS); /* Set/Raise RTS */
1010
1011 #endif
1012
1013 /* Jukka's version */
1014 #if 0
1015 int slot;
1016 struct mscdevice *msc;
1017 volatile struct mscstatus *ms;
1018 int s;
1019
1020 /* get the device structure */
1021 slot = MSCSLOT(tp->t_dev);
1022 if (slot >= MSCSLOTS)
1023 return ENXIO;
1024 msc = &mscdev[slot];
1025 if (!msc->active)
1026 return ENXIO;
1027 ms = &msc->board->Status[msc->port];
1028
1029 #if DEBUG_MSC
1030 bugi(msc, "hwiflow");
1031 #endif
1032 /* Well, we should really _do_ something here, but the 65c02 code
1033 * manages the RTS signal on its own now, so... This will probably
1034 * change in the future.
1035 */
1036
1037 #endif
1038 return 1;
1039
1040 }
1041
1042 int
1043 mscstart(tp)
1044 register struct tty *tp;
1045 {
1046 register int cc;
1047 register char *cp;
1048 register int mhead;
1049 int s;
1050 int slot;
1051 struct mscdevice *msc;
1052 volatile struct mscstatus *ms;
1053 volatile char *mob;
1054 int hiwat = 0;
1055 int maxout;
1056
1057 if (! (tp->t_state & TS_ISOPEN))
1058 return;
1059
1060 slot = MSCSLOT(tp->t_dev);
1061
1062 #if 0
1063 printf("starting msc%d\n", slot);
1064 #endif
1065
1066 s = spltty();
1067
1068 /* don't start if explicitly stopped */
1069 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
1070 goto out;
1071
1072 /* wake up if below low water */
1073 cc = tp->t_outq.c_cc;
1074
1075 if (cc <= tp->t_lowat) {
1076 if (tp->t_state & TS_ASLEEP) {
1077
1078 tp->t_state &= ~TS_ASLEEP;
1079 wakeup((caddr_t)&tp->t_outq);
1080 }
1081
1082 selwakeup(&tp->t_wsel);
1083 }
1084
1085 /* don't bother if no characters or busy */
1086 if (cc == 0 || (tp->t_state & TS_BUSY))
1087 goto out;
1088
1089 /*
1090 * Limit the amount of output we do in one burst
1091 */
1092 msc = &mscdev[slot];
1093 ms = &msc->board->Status[msc->port];
1094 mhead = ms->OutHead;
1095 maxout = mhead - ms->OutTail;
1096
1097 if (maxout < 0)
1098 maxout += IOBUFLEN;
1099
1100 maxout = IOBUFLEN - 1 - maxout;
1101
1102 if (cc >= maxout) {
1103 hiwat++;
1104 cc = maxout;
1105 }
1106
1107 cc = q_to_b (&tp->t_outq, msc->tmpbuf, cc);
1108
1109 if (cc > 0) {
1110 tp->t_state |= TS_BUSY;
1111
1112 mob = &msc->board->OutBuf[msc->port][0];
1113 cp = &msc->tmpbuf[0];
1114
1115 /* enable output */
1116 ms->OutDisable = FALSE;
1117
1118 #if 0
1119 msc->tmpbuf[cc] = 0;
1120 printf("sending '%s'\n", msctmpbuf);
1121 #endif
1122
1123 /* send the first char across to reduce latency */
1124 mob[mhead++] = *cp++;
1125 mhead &= IOBUFLENMASK;
1126 ms->OutHead = mhead;
1127 cc--;
1128
1129 /* copy the rest of the chars across quickly */
1130 while (cc > 0) {
1131 mob[mhead++] = *cp++;
1132 mhead &= IOBUFLENMASK;
1133 cc--;
1134 }
1135 ms->OutHead = mhead;
1136
1137 /* leave the device busy if we've filled the buffer */
1138 if (!hiwat)
1139 tp->t_state &= ~TS_BUSY;
1140 }
1141
1142 out:
1143 splx(s);
1144
1145 }
1146
1147 /* XXX */
1148 /*
1149 * Stop output on a line.
1150 */
1151 /*ARGSUSED*/
1152 int
1153 mscstop(tp, flag)
1154 register struct tty *tp;
1155 int flag; /* defaulted to int anyway */
1156 {
1157 register int s;
1158 struct mscdevice *msc;
1159 volatile struct mscstatus *ms;
1160
1161 s = spltty();
1162 if (tp->t_state & TS_BUSY) {
1163 if (tp->t_state & TS_TTSTOP == 0) {
1164 tp->t_state |= TS_FLUSH;
1165 #if 0
1166 msc = &mscdev[MSCSLOT(tp->t_dev)];
1167 ms = &msc->board->Status[msc->port];
1168 printf("stopped output on msc%d\n", MSCSLOT(tp->t_dev));
1169 ms->OutDisable = TRUE;
1170 #endif
1171 }
1172 }
1173 splx(s);
1174 }
1175
1176 /*
1177 * bits can be: TIOCM_DTR, TIOCM_RTS, TIOCM_CTS, TIOCM_CD, TIOCM_RI, TIOCM_DSR
1178 */
1179 int
1180 mscmctl(dev, bits, how)
1181 dev_t dev;
1182 int bits, how;
1183 {
1184 struct mscdevice *msc;
1185 volatile struct mscstatus *ms;
1186 int slot;
1187 int s;
1188 u_char newcmd;
1189 int OldFlags;
1190
1191 /* get the device structure */
1192 slot = MSCSLOT(dev);
1193
1194 if (slot >= MSCSLOTS)
1195 return ENXIO;
1196
1197 msc = &mscdev[slot];
1198
1199 if (!msc->active)
1200 return ENXIO;
1201
1202 #if DEBUG_MSC
1203 bugi(msc, "mctl1");
1204 #endif
1205
1206 s = spltty(); /* Jukka wants spl6() here, WHY?!! RFH */
1207
1208 if (how != DMGET) {
1209 OldFlags = msc->flags;
1210 bits &= TIOCM_DTR | TIOCM_RTS; /* can only modify DTR and RTS */
1211
1212 switch (how) {
1213 case DMSET:
1214 msc->flags = (bits | (msc->flags & ~(TIOCM_DTR | TIOCM_RTS)));
1215 break;
1216
1217 case DMBIC:
1218 msc->flags &= ~bits;
1219 break;
1220
1221 case DMBIS:
1222 msc->flags |= bits;
1223 break;
1224 }
1225
1226 #if DEBUG_MSC
1227 bugi(msc, "mctl2");
1228 #endif
1229
1230 /* modify modem control state */
1231 ms = &msc->board->Status[msc->port];
1232
1233 if (msc->flags & TIOCM_RTS) /* was bits & */
1234 newcmd = MSCCMD_RTSOn;
1235 else /* this doesn't actually work now */
1236 newcmd = MSCCMD_RTSOff;
1237
1238 if (msc->flags & TIOCM_DTR) /* was bits & */
1239 newcmd |= MSCCMD_Enable;
1240
1241 ms->Command = (ms->Command & (~MSCCMD_RTSMask & ~MSCCMD_Enable)) | newcmd;
1242 ms->Setup = TRUE;
1243
1244 /* if we've dropped DTR, bitbucket any pending output */
1245 if ( (OldFlags & TIOCM_DTR) && ((bits & TIOCM_DTR) == 0))
1246 ms->OutFlush = TRUE;
1247 }
1248
1249 bits = msc->flags;
1250
1251 (void) splx(s);
1252
1253 #if DEBUG_MSC
1254 bugi(msc, "mctl3");
1255 #endif
1256
1257 return(bits);
1258
1259 }
1260
1261 struct tty *
1262 msctty(dev)
1263 dev_t dev;
1264 {
1265 return(msc_tty[MSCTTY(dev)]);
1266 }
1267
1268 /*
1269 * Load JM's freely redistributable A2232 6502c code. Let turbo detector
1270 * run for a while too.
1271 */
1272
1273 int
1274 mscinitcard(zap)
1275 struct zbus_args *zap;
1276 {
1277 int bcount;
1278 short start;
1279 u_char *from;
1280 volatile u_char *to;
1281 volatile struct mscmemory *mlm;
1282
1283 mlm = (volatile struct mscmemory *)zap->va;
1284 (void)mlm->Enable6502Reset;
1285
1286 /* copy the code across to the board */
1287 to = (u_char *)mlm;
1288 from = msc6502code; bcount = sizeof(msc6502code) - 2;
1289 start = *(short *)from; from += sizeof(start);
1290 to += start;
1291
1292 #if DEBUG_MSC
1293 printf("\n** copying %ld bytes from %08lx to %08lx (start=%04lx)\n",
1294 (unsigned long)bcount, (unsigned long)from, to, start);
1295 printf("First byte to copy is %02lx\n", *from);
1296 #endif
1297
1298 while(bcount--) *to++ = *from++;
1299
1300 mlm->Common.Crystal = MSC_UNKNOWN; /* use automatic speed check */
1301
1302 /* start 6502 running */
1303 (void)mlm->ResetBoard;
1304
1305 /* wait until speed detector has finished */
1306 for (bcount = 0; bcount < 200; bcount++) {
1307 delay(10000);
1308 if (mlm->Common.Crystal) break;
1309 }
1310
1311 return(0);
1312
1313 }
1314
1315 #endif /* NMSC > 0 */
1316