1 /* $NetBSD: msc.c,v 1.40 2007/11/19 18:51:37 ad Exp $ */
4 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * - converted from NetBSD Amiga serial driver to A2232 serial driver
33 * - added ttyflags hooks rfh 940419
34 * - added new style config support rfh 940601
35 * - added code to halt board during memory load so board doesn't flip
36 * out. /dev/reload works now. Also created mschwiflow function so BSD can
37 * attempt to use board RTS flow control now. rfh 950108
38 * - Integrated work from Jukka Marin <jmarin@jmp.fi> and
39 * Timo Rossi <trossi@jyu.fi> The mscmint() code is Jukka's. 950916
40 * Integrated more bug fixes by Jukka Marin <jmarin@jmp.fi> 950918
41 * Also added Jukka's turbo board code. 950918
42 * - Reformatted to NetBSD style format.
43 * - Rewritten the carrier detect system to prevent lock-ups (jm 951029)
47 * Copyright (c) 1993 Zik.
48 * Copyright (c) 1995 Jukka Marin <jmarin@jmp.fi>.
49 * Copyright (c) 1995 Timo Rossi <trossi@jyu.fi>.
50 * Copyright (c) 1995 Rob Healey <rhealey@kas.helios.mn.org>.
52 * Redistribution and use in source and binary forms, with or without
53 * modification, are permitted provided that the following conditions
55 * 1. Redistributions of source code must retain the above copyright
56 * notice, this list of conditions and the following disclaimer.
57 * 2. Redistributions in binary form must reproduce the above copyright
58 * notice, this list of conditions and the following disclaimer in the
59 * documentation and/or other materials provided with the distribution.
60 * 3. All advertising materials mentioning features or use of this software
61 * must display the following acknowledgement:
62 * This product includes software developed by the University of
63 * California, Berkeley and its contributors.
64 * 4. Neither the name of the University nor the names of its contributors
65 * may be used to endorse or promote products derived from this software
66 * without specific prior written permission.
68 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
69 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
70 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
71 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
72 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
73 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
74 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
75 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
76 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
77 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
80 * - converted from NetBSD Amiga serial driver to A2232 serial driver
82 * - added ttyflags hooks rfh 940419
83 * - added new style config support rfh 940601
84 * - added code to halt board during memory load so board doesn't flip
85 * out. /dev/reload works now. Also created mschwiflow function so BSD can
86 * attempt to use board RTS flow control now. rfh 950108
87 * - Integrated work from Jukka Marin <jmarin@jmp.fi> and
88 * Timo Rossi <trossi@jyu.fi> The mscmint() code is Jukka's. 950916
89 * Integrated more bug fixes by Jukka Marin <jmarin@jmp.fi> 950918
90 * Also added Jukka's turbo board code. 950918
91 * - Reformatted to NetBSD style format.
92 * - Rewritten the carrier detect system to prevent lock-ups (jm 951029)
95 #include <sys/cdefs.h>
96 __KERNEL_RCSID(0, "$NetBSD: msc.c,v 1.40 2007/11/19 18:51:37 ad Exp $");
101 #include <sys/param.h>
102 #include <sys/systm.h>
103 #include <sys/ioctl.h>
105 #include <sys/proc.h>
106 #include <sys/file.h>
107 #include <sys/malloc.h>
109 #include <sys/kernel.h>
110 #include <sys/syslog.h>
111 #include <sys/device.h>
112 #include <sys/conf.h>
113 #include <sys/kauth.h>
115 #include <amiga/amiga/device.h>
116 #include <amiga/dev/zbusvar.h>
117 #include <amiga/dev/mscreg.h>
118 #include <machine/cpu.h>
120 #include <amiga/amiga/custom.h>
121 #include <amiga/amiga/cia.h>
122 #include <amiga/amiga/cc.h>
124 /* 6502 code for A2232 card */
128 * Note: These are Zik's original comments:
129 * There is a bit of a "gotcha" concerning the numbering
130 * of msc devices and the specification of the number of serial
131 * lines in the kernel.
133 * Each board has seven lines, but for programming convenience
134 * and compatibility with Amiga UNIX the boards' minor device
135 * numbers are allocated in groups of sixteen:
137 * minor device numbers
138 * First board 0 2 4 6 8 10 12
139 * Second board 16 18 20 22 24 26 28
140 * Third board 32 34 36 38 40 42 44
142 * The intermediate minor device numbers are dialin versions
143 * of the same devices. ie. 10 is dialout line 6 and 11 is
144 * the dialin version of line 6.
146 * On the other hand, I have made the NMSC config option refer
147 * to the total number of a2232 cards, not the maximum
148 * minor device number. So you might have NMSC=3, in which case
149 * you have three boards with minor device numbers from 0 to 45.
152 int mscparam(struct tty
*, struct termios
*);
153 void mscstart(struct tty
*);
154 int mschwiflow(struct tty
*, int);
155 int mscinitcard(struct zbus_args
*);
157 int mscdefaultrate
= TTYDEF_SPEED
;
159 struct mscdevice mscdev
[MSCSLOTS
]; /* device structs for all lines */
160 struct tty
*msc_tty
[MSCTTYS
]; /* ttys for all lines */
162 struct vbl_node msc_vbl_node
[NMSC
]; /* vbl interrupt node per board */
164 const struct speedtab mscspeedtab_normal
[] = {
166 { 50, MSCPARAM_B50
},
167 { 75, MSCPARAM_B75
},
168 { 110, MSCPARAM_B110
},
169 { 134, MSCPARAM_B134
},
170 { 150, MSCPARAM_B150
},
171 { 300, MSCPARAM_B300
},
172 { 600, MSCPARAM_B600
},
173 { 1200, MSCPARAM_B1200
},
174 { 1800, MSCPARAM_B1800
},
175 { 2400, MSCPARAM_B2400
},
176 { 3600, MSCPARAM_B3600
},
177 { 4800, MSCPARAM_B4800
},
178 { 7200, MSCPARAM_B7200
},
179 { 9600, MSCPARAM_B9600
},
180 { 19200, MSCPARAM_B19200
},
181 { 115200, MSCPARAM_B115200
},
185 const struct speedtab mscspeedtab_turbo
[] = {
187 { 100, MSCPARAM_B50
},
188 { 150, MSCPARAM_B75
},
189 { 220, MSCPARAM_B110
},
190 { 269, MSCPARAM_B134
},
191 { 300, MSCPARAM_B150
},
192 { 600, MSCPARAM_B300
},
193 { 1200, MSCPARAM_B600
},
194 { 2400, MSCPARAM_B1200
},
195 { 3600, MSCPARAM_B1800
},
196 { 4800, MSCPARAM_B2400
},
197 { 7200, MSCPARAM_B3600
},
198 { 9600, MSCPARAM_B4800
},
199 { 14400, MSCPARAM_B7200
},
200 { 19200, MSCPARAM_B9600
},
201 { 38400, MSCPARAM_B19200
},
202 { 230400, MSCPARAM_B115200
},
206 const struct speedtab
*mscspeedtab
;
208 int mscmctl(dev_t dev
, int bits
, int howto
);
209 void mscmint(register void *data
);
211 int mscmatch(struct device
*, struct cfdata
*, void *);
212 void mscattach(struct device
*, struct device
*, void *);
214 #define SWFLAGS(dev) (msc->openflags | (MSCDIALIN(dev) ? 0 : TIOCFLAG_SOFTCAR))
217 CFATTACH_DECL(msc
, sizeof(struct device
),
218 mscmatch
, mscattach
, NULL
, NULL
);
220 dev_type_open(mscopen
);
221 dev_type_close(mscclose
);
222 dev_type_read(mscread
);
223 dev_type_write(mscwrite
);
224 dev_type_ioctl(mscioctl
);
225 dev_type_stop(mscstop
);
226 dev_type_tty(msctty
);
227 dev_type_poll(mscpoll
);
229 const struct cdevsw msc_cdevsw
= {
230 mscopen
, mscclose
, mscread
, mscwrite
, mscioctl
,
231 mscstop
, msctty
, mscpoll
, nommap
, ttykqfilter
, D_TTY
235 mscmatch(struct device
*pdp
, struct cfdata
*cfp
, void *auxp
)
237 struct zbus_args
*zap
;
240 if (zap
->manid
== 514 && (zap
->prodid
== 70 || zap
->prodid
== 69))
247 mscattach(struct device
*pdp
, struct device
*dp
, void *auxp
)
249 volatile struct mscmemory
*mscmem
;
250 struct mscdevice
*msc
;
251 struct zbus_args
*zap
;
255 zap
= (struct zbus_args
*)auxp
;
256 unit
= device_unit(dp
);
259 * Make config msgs look nicer.
263 if (mscinitcard(zap
) != 0) {
264 printf("msc%d: Board initialize failed, bad download code.\n", unit
);
268 printf("msc%d: Board successfully initialized.\n", unit
);
270 mscmem
= (struct mscmemory
*) zap
->va
;
272 if (mscmem
->Common
.Crystal
== MSC_UNKNOWN
) {
273 printf("msc%d: Unable to detect crystal frequency.\n", unit
);
277 if (mscmem
->Common
.Crystal
== MSC_TURBO
) {
278 printf("msc%d: Turbo version detected (%02x%02x:%d)\n", unit
,
279 mscmem
->Common
.TimerH
, mscmem
->Common
.TimerL
,
280 mscmem
->Common
.Pad_a
);
281 mscspeedtab
= mscspeedtab_turbo
;
283 printf("msc%d: Normal version detected (%02x%02x:%d)\n", unit
,
284 mscmem
->Common
.TimerH
, mscmem
->Common
.TimerL
,
285 mscmem
->Common
.Pad_a
);
286 mscspeedtab
= mscspeedtab_normal
;
289 mscmem
->Common
.CDStatus
= 0; /* common status for all 7 ports */
291 /* XXX 8 is a constant */
292 for (Count
= 0; Count
< 8 && MSCSLOTUL(unit
, Count
) < MSCSLOTS
; Count
++) {
293 msc
= &mscdev
[MSCSLOTUL(unit
, Count
)];
300 msc
->closing
= false;
301 msc_tty
[MSCTTYSLOT(MSCSLOTUL(unit
, Count
))] = NULL
;
302 msc_tty
[MSCTTYSLOT(MSCSLOTUL(unit
, Count
)) + 1] = NULL
;
305 /* disable the non-existent eighth port */
306 if (MSCSLOTUL(unit
, NUMLINES
) < MSCSLOTS
)
307 mscdev
[MSCSLOTUL(unit
, NUMLINES
)].active
= 0;
309 msc_vbl_node
[unit
].function
= (void (*) (void *)) mscmint
;
310 msc_vbl_node
[unit
].data
= (void *) unit
;
312 add_vbl_function (&msc_vbl_node
[unit
], MSC_VBL_PRIORITY
, (void *)unit
);
319 mscopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
321 register struct tty
*tp
;
322 struct mscdevice
*msc
;
323 volatile struct mscstatus
*ms
;
327 /* get the device structure */
331 if (slot
>= MSCSLOTS
)
334 if (MSCLINE(dev
) >= NUMLINES
)
338 ms
= &msc
->board
->Status
[msc
->port
];
344 * RFH: WHY here? Put down by while like other serial drivers
345 * But if we do that it makes things bomb.
349 if (!msc_tty
[ttyn
]) {
354 msc_tty
[ttyn
+1] = (struct tty
*)NULL
;
357 /* default values are not optimal for this device, increase buffers. */
361 clalloc(&tp
->t_rawq
, 8192, 1);
362 clalloc(&tp
->t_canq
, 8192, 1);
363 clalloc(&tp
->t_outq
, 8192, 0);
369 tp
->t_oproc
= (void (*) (struct tty
*)) mscstart
;
370 tp
->t_param
= mscparam
;
372 tp
->t_hwiflow
= mschwiflow
;
374 /* if port is still closing, just bitbucket remaining characters */
377 msc
->closing
= false;
381 if (kauth_authorize_device_tty(l
->l_cred
, KAUTH_DEVICE_TTY_OPEN
, tp
))
384 mutex_spin_enter(&tty_lock
);
386 if ((tp
->t_state
& TS_ISOPEN
) == 0 && tp
->t_wopen
== 0) {
388 if (tp
->t_ispeed
== 0) {
389 tp
->t_iflag
= TTYDEF_IFLAG
;
390 tp
->t_oflag
= TTYDEF_OFLAG
;
391 tp
->t_cflag
= TTYDEF_CFLAG
;
392 tp
->t_lflag
= TTYDEF_LFLAG
;
393 tp
->t_ispeed
= tp
->t_ospeed
= mscdefaultrate
;
396 /* flags changed to be private to every unit by JM */
397 if (msc
->openflags
& TIOCFLAG_CLOCAL
)
398 tp
->t_cflag
|= CLOCAL
;
399 if (msc
->openflags
& TIOCFLAG_CRTSCTS
)
400 tp
->t_cflag
|= CRTSCTS
;
401 if (msc
->openflags
& TIOCFLAG_MDMBUF
)
402 tp
->t_cflag
|= MDMBUF
;
404 mscparam(tp
, &tp
->t_termios
);
407 (void) mscmctl(dev
, TIOCM_DTR
| TIOCM_RTS
, DMSET
);
409 if ((SWFLAGS(dev
) & TIOCFLAG_SOFTCAR
) ||
410 (mscmctl(dev
, 0, DMGET
) & TIOCM_CD
))
411 tp
->t_state
|= TS_CARR_ON
;
413 tp
->t_state
&= ~TS_CARR_ON
;
418 * if NONBLOCK requested, ignore carrier
420 if (flag
& O_NONBLOCK
) {
422 printf("msc%d: %d open nonblock\n", msc
->unit
, MSCLINE(dev
));
430 * This causes hangs when put here, like other TTY drivers do, rather than
435 while ((tp
->t_state
& TS_CARR_ON
) == 0 && (tp
->t_cflag
& CLOCAL
) == 0) {
439 printf("msc%d: %d waiting for CD\n", msc
->unit
, MSCLINE(dev
));
441 error
= ttysleep(tp
, &tp
->t_rawcv
, true, 0);
445 mutex_spin_exit(&tty_lock
);
451 printf("msc%d: %d got CD\n", msc
->unit
, MSCLINE(dev
));
455 /* This is a way to handle lost XON characters */
456 if ((flag
& O_TRUNC
) && (tp
->t_state
& TS_TTSTOP
)) {
457 tp
->t_state
&= ~TS_TTSTOP
;
462 * Reset the tty pointer, as there could have been a dialout
463 * use of the tty with a dialin open waiting.
466 mutex_spin_exit(&tty_lock
);
468 return tp
->t_linesw
->l_open(dev
, tp
);
473 mscclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
475 register struct tty
*tp
;
477 volatile struct mscstatus
*ms
;
478 struct mscdevice
*msc
;
480 /* get the device structure */
483 if (slot
>= MSCSLOTS
)
491 ms
= &msc
->board
->Status
[msc
->port
];
493 tp
= msc_tty
[MSCTTY(dev
)];
494 tp
->t_linesw
->l_close(tp
, flag
);
496 (void) mscmctl(dev
, 0, DMSET
);
500 if (msc
->flags
& TIOCM_DTR
)
501 msc
->closing
= true; /* flush remaining characters before dropping DTR */
503 ms
->OutFlush
= true; /* just bitbucket remaining characters */
510 mscread(dev_t dev
, struct uio
*uio
, int flag
)
512 register struct tty
*tp
;
514 tp
= msc_tty
[MSCTTY(dev
)];
519 return tp
->t_linesw
->l_read(tp
, uio
, flag
);
524 mscwrite(dev_t dev
, struct uio
*uio
, int flag
)
526 register struct tty
*tp
;
528 tp
= msc_tty
[MSCTTY(dev
)];
533 return tp
->t_linesw
->l_write(tp
, uio
, flag
);
537 mscpoll(dev_t dev
, int events
, struct lwp
*l
)
539 register struct tty
*tp
;
541 tp
= msc_tty
[MSCTTY(dev
)];
546 return ((*tp
->t_linesw
->l_poll
)(tp
, events
, l
));
550 * This interrupt is periodically invoked in the vertical blank
551 * interrupt. It's used to keep track of the modem control lines
552 * and (new with the fast_int code) to move accumulated data up in
555 * NOTE: MSCCDHACK is an invention of mine for dubious purposes. If you
556 * want to activate it add
558 * in the kernel conf file. Basically it forces CD->Low transitions
559 * to ALWAYS send a signal to the process, even if the device is in
560 * clocal mode or an outdial device. RFH
563 mscmint(register void *data
)
565 register struct tty
*tp
;
566 struct mscdevice
*msc
;
567 volatile struct mscstatus
*ms
;
568 volatile u_char
*ibuf
, *cbuf
;
569 unsigned char newhead
; /* was int */
570 unsigned char bufpos
; /* was int */
571 unsigned char ncd
, ocd
, ccd
;
572 int unit
, slot
, maxslot
;
577 /* check each line on this board */
578 maxslot
= MSCSLOTUL(unit
, NUMLINES
);
579 if (maxslot
> MSCSLOTS
)
582 msc
= &mscdev
[MSCSLOTUL(unit
, 0)];
584 newhead
= msc
->board
->Common
.CDHead
;
585 bufpos
= msc
->board
->Common
.CDTail
;
586 if (newhead
!= bufpos
) { /* CD events in queue */
587 /* set interrupt priority level */
589 ocd
= msc
->board
->Common
.CDStatus
; /* get old status bits */
590 while (newhead
!= bufpos
) { /* read all events */
591 ncd
= msc
->board
->CDBuf
[bufpos
++]; /* get one event */
592 ccd
= ncd
^ ocd
; /* mask of changed lines*/
593 ocd
= ncd
; /* save new status bits */
595 printf("ocd %02x ncd %02x ccd %02x\n", ocd
, ncd
, ccd
);
597 for(i
= 0; i
< NUMLINES
; i
++) { /* do for all lines */
598 if (ccd
& 1) { /* this one changed */
599 msc
= &mscdev
[MSCSLOTUL(unit
, i
)];
600 if (ncd
& 1) { /* CD is now OFF */
602 printf("msc%d: CD OFF %d\n", unit
, msc
->port
);
604 msc
->flags
&= ~TIOCM_CD
;
605 if ((tp
= msc_tty
[MSCTTYSLOT(MSCSLOTUL(unit
, i
))]) &&
606 (tp
->t_state
& TS_ISOPEN
) && tp
->t_wopen
== 0) {
609 if (MSCDIALIN(tp
->t_dev
))
612 if (tp
->t_linesw
->l_modem(tp
, 0) == 0) {
613 /* clear RTS and DTR, bitbucket output */
614 ms
= &msc
->board
->Status
[msc
->port
];
615 ms
->Command
= (ms
->Command
& ~MSCCMD_CMask
) |
618 msc
->flags
&= ~(TIOCM_DTR
| TIOCM_RTS
);
623 } else { /* CD is now ON */
625 printf("msc%d: CD ON %d\n", unit
, msc
->port
);
627 msc
->flags
|= TIOCM_CD
;
628 if ((tp
= msc_tty
[MSCTTYSLOT(MSCSLOTUL(unit
, i
))]) &&
629 (tp
->t_state
& TS_ISOPEN
) && tp
->t_wopen
== 0) {
630 if (MSCDIALIN(tp
->t_dev
))
631 tp
->t_linesw
->l_modem(tp
, 1);
632 } /* if tp valid and port open */
634 } /* if CD changed for this line */
635 ccd
>>= 1; ncd
>>= 1; /* bit for next line */
636 } /* for every line */
637 } /* while events in queue */
638 msc
->board
->Common
.CDStatus
= ocd
; /* save new status */
639 msc
->board
->Common
.CDTail
= bufpos
; /* remove events */
641 } /* if events in CD queue */
643 for (slot
= MSCSLOTUL(unit
, 0); slot
< maxslot
; slot
++) {
649 tp
= msc_tty
[MSCTTYSLOT(slot
)];
650 ms
= &msc
->board
->Status
[msc
->port
];
652 newhead
= ms
->InHead
; /* 65c02 write pointer */
654 /* yoohoo, is the port open? */
655 if (tp
&& (tp
->t_state
& TS_ISOPEN
) && tp
->t_wopen
== 0) {
656 /* port is open, handle all type of events */
658 /* set interrupt priority level */
661 /* check for input for this port */
662 if (newhead
!= (bufpos
= ms
->InTail
)) {
663 /* buffer for input chars/events */
664 ibuf
= &msc
->board
->InBuf
[msc
->port
][0];
666 /* data types of bytes in ibuf */
667 cbuf
= &msc
->board
->InCtl
[msc
->port
][0];
669 /* do for all chars, if room */
670 while (bufpos
!= newhead
) {
671 /* which type of input data? */
672 switch (cbuf
[bufpos
]) {
673 /* input event (CD, BREAK, etc.) */
675 switch (ibuf
[bufpos
++]) {
677 tp
->t_linesw
->l_rint(TTY_FE
, tp
);
681 printf("msc%d: unknown event type %d\n",
682 msc
->unit
, ibuf
[(bufpos
-1)&0xff]);
683 } /* event type switch */
687 if (tp
->t_state
& TS_TBLOCK
) {
690 tp
->t_linesw
->l_rint((int)ibuf
[bufpos
++], tp
);
694 printf("msc%d: unknown data type %d\n",
695 msc
->unit
, cbuf
[bufpos
]);
697 } /* switch on input data type */
698 } /* while there's something in the buffer */
700 ms
->InTail
= bufpos
; /* tell 65C02 what we've read */
701 } /* if there was something in the buffer */
703 /* we get here only when the port is open */
705 if (tp
->t_state
& (TS_BUSY
|TS_FLUSH
)) {
707 bufpos
= ms
->OutHead
- ms
->OutTail
;
709 /* busy and below low water mark? */
710 if (tp
->t_state
& TS_BUSY
) {
711 if (bufpos
< IOBUFLOWWATER
) {
712 tp
->t_state
&= ~TS_BUSY
; /* not busy any more */
714 tp
->t_linesw
->l_start(tp
);
720 /* waiting for flush and buffer empty? */
721 if (tp
->t_state
& TS_FLUSH
) {
723 tp
->t_state
&= ~TS_FLUSH
; /* finished flushing */
725 } /* BUSY or FLUSH */
729 } else { /* End of port open */
730 /* port is closed, don't pass on the chars from it */
732 /* check for input for this port */
733 if (newhead
!= (bufpos
= ms
->InTail
)) {
734 /* buffer for input chars/events */
735 ibuf
= &msc
->board
->InBuf
[msc
->port
][0];
737 /* data types of bytes in ibuf */
738 cbuf
= &msc
->board
->InCtl
[msc
->port
][0];
740 /* do for all chars, if room */
741 while (bufpos
!= newhead
) {
742 /* which type of input data? */
743 switch (cbuf
[bufpos
]) {
744 /* input event (BREAK, etc.) */
746 switch (ibuf
[bufpos
++]) {
748 printf("msc: unknown event type %d\n",
749 ibuf
[(bufpos
-1)&0xff]);
750 } /* event type switch */
755 } /* switch on input data type */
756 } /* while there's something in the buffer */
758 ms
->InTail
= bufpos
; /* tell 65C02 what we've read */
759 } /* if there was something in the buffer */
760 } /* End of port open/close */
762 /* is this port closing? */
764 /* if DTR is off, just bitbucket remaining characters */
765 if ( (msc
->flags
& TIOCM_DTR
) == 0) {
767 msc
->closing
= false;
769 /* if output has drained, drop DTR */
770 else if (ms
->OutHead
== ms
->OutTail
) {
771 (void) mscmctl(tp
->t_dev
, 0, DMSET
);
772 msc
->closing
= false;
775 } /* For all ports */
780 mscioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
782 register struct tty
*tp
;
785 struct mscdevice
*msc
;
786 volatile struct mscstatus
*ms
;
789 /* get the device structure */
792 if (slot
>= MSCSLOTS
)
800 ms
= &msc
->board
->Status
[msc
->port
];
801 if (!(tp
= msc_tty
[MSCTTY(dev
)]))
804 error
= tp
->t_linesw
->l_ioctl(tp
, cmd
, data
, flag
, l
);
805 if (error
!= EPASSTHROUGH
)
808 error
= ttioctl(tp
, cmd
, data
, flag
, l
);
809 if (error
!= EPASSTHROUGH
)
817 ms
->Command
= (ms
->Command
& (~MSCCMD_RTSMask
)) | MSCCMD_Break
;
825 ms
->Command
= (ms
->Command
& (~MSCCMD_RTSMask
)) | MSCCMD_RTSOn
;
831 (void) mscmctl(dev
, TIOCM_DTR
| TIOCM_RTS
, DMBIS
);
835 if (!MSCDIALIN(dev
)) /* don't let dialins drop DTR */
836 (void) mscmctl(dev
, TIOCM_DTR
| TIOCM_RTS
, DMBIC
);
840 (void) mscmctl(dev
, *(int *)data
, DMSET
);
844 (void) mscmctl(dev
, *(int *)data
, DMBIS
);
848 if (MSCDIALIN(dev
)) /* don't let dialins drop DTR */
849 (void) mscmctl(dev
, *(int *)data
& TIOCM_DTR
, DMBIC
);
851 (void) mscmctl(dev
, *(int *)data
, DMBIC
);
855 *(int *)data
= mscmctl(dev
, 0, DMGET
);
859 *(int *)data
= SWFLAGS(dev
);
863 error
= kauth_authorize_device_tty(l
->l_cred
,
864 KAUTH_DEVICE_TTY_PRIVSET
, tp
);
867 msc
->openflags
= *(int *)data
;
868 /* only allow valid flags */
870 (TIOCFLAG_SOFTCAR
| TIOCFLAG_CLOCAL
| TIOCFLAG_CRTSCTS
);
874 return (EPASSTHROUGH
);
882 mscparam(register struct tty
*tp
, register struct termios
*t
)
884 register int cflag
= t
->c_cflag
;
885 struct mscdevice
*msc
;
886 volatile struct mscstatus
*ms
;
888 int ospeed
= ttspeedtab(t
->c_ospeed
, mscspeedtab
);
890 /* get the device structure */
891 slot
= MSCSLOT(tp
->t_dev
);
893 if (slot
>= MSCSLOTS
)
901 ms
= &msc
->board
->Status
[msc
->port
];
903 /* check requested parameters */
904 if (ospeed
< 0 || (t
->c_ispeed
&& t
->c_ispeed
!= t
->c_ospeed
))
907 /* and copy to tty */
908 tp
->t_ispeed
= t
->c_ispeed
;
909 tp
->t_ospeed
= t
->c_ospeed
;
912 /* hang up if baud is zero */
913 if (t
->c_ospeed
== 0) {
914 if (!MSCDIALIN(tp
->t_dev
)) /* don't let dialins drop DTR */
915 (void) mscmctl(tp
->t_dev
, 0, DMSET
);
917 /* set the baud rate */
919 ms
->Param
= (ms
->Param
& ~MSCPARAM_BaudMask
) | ospeed
| MSCPARAM_RcvBaud
;
922 * Make sure any previous hangup is undone, ie. reenable DTR.
923 * also mscmctl will cause the speed to be set
925 (void) mscmctl (tp
->t_dev
, TIOCM_DTR
| TIOCM_RTS
, DMSET
);
935 * Jukka's code initializes alot of stuff that other drivers don't
936 * I'm including it here so that this code is a common set of work
937 * done by both of us. rfh
940 mschwiflow(struct tty
*tp
, int flag
)
946 mscmctl( tp
->t_dev
, TIOCM_RTS
, DMBIC
); /* Clear/Lower RTS */
948 mscmctl( tp
->t_dev
, TIOCM_RTS
, DMBIS
); /* Set/Raise RTS */
950 #else /* Jukka's version */
953 struct mscdevice
*msc
;
954 volatile struct mscstatus
*ms
;
956 /* get the device structure */
957 slot
= MSCSLOT(tp
->t_dev
);
958 if (slot
>= MSCSLOTS
)
963 ms
= &msc
->board
->Status
[msc
->port
];
965 /* Well, we should really _do_ something here, but the 65c02 code
966 * manages the RTS signal on its own now, so... This will probably
967 * change in the future.
975 mscstart(register struct tty
*tp
)
981 struct mscdevice
*msc
;
982 volatile struct mscstatus
*ms
;
987 if (! (tp
->t_state
& TS_ISOPEN
))
990 slot
= MSCSLOT(tp
->t_dev
);
993 printf("starting msc%d\n", slot
);
998 /* don't start if explicitly stopped */
999 if (tp
->t_state
& (TS_TIMEOUT
|TS_TTSTOP
))
1002 /* wake up if below low water */
1003 cc
= tp
->t_outq
.c_cc
;
1004 if (!ttypull(tp
) || (tp
->t_state
& TS_BUSY
))
1008 * Limit the amount of output we do in one burst
1010 msc
= &mscdev
[slot
];
1011 ms
= &msc
->board
->Status
[msc
->port
];
1012 mhead
= ms
->OutHead
;
1013 maxout
= mhead
- ms
->OutTail
;
1018 maxout
= IOBUFLEN
- 1 - maxout
;
1025 cc
= q_to_b (&tp
->t_outq
, msc
->tmpbuf
, cc
);
1028 tp
->t_state
|= TS_BUSY
;
1030 mob
= &msc
->board
->OutBuf
[msc
->port
][0];
1031 cp
= &msc
->tmpbuf
[0];
1034 ms
->OutDisable
= false;
1037 msc
->tmpbuf
[cc
] = 0;
1038 printf("sending '%s'\n", msctmpbuf
);
1041 /* send the first char across to reduce latency */
1042 mob
[mhead
++] = *cp
++;
1043 mhead
&= IOBUFLENMASK
;
1044 ms
->OutHead
= mhead
;
1047 /* copy the rest of the chars across quickly */
1049 mob
[mhead
++] = *cp
++;
1050 mhead
&= IOBUFLENMASK
;
1053 ms
->OutHead
= mhead
;
1055 /* leave the device busy if we've filled the buffer */
1057 tp
->t_state
&= ~TS_BUSY
;
1067 * Stop output on a line.
1071 mscstop(register struct tty
*tp
, int flag
)
1072 /* flag variable defaulted to int anyway */
1076 struct mscdevice
*msc
;
1077 volatile struct mscstatus
*ms
;
1081 if (tp
->t_state
& TS_BUSY
) {
1082 if ((tp
->t_state
& TS_TTSTOP
) == 0) {
1083 tp
->t_state
|= TS_FLUSH
;
1085 msc
= &mscdev
[MSCSLOT(tp
->t_dev
)];
1086 ms
= &msc
->board
->Status
[msc
->port
];
1087 printf("stopped output on msc%d\n", MSCSLOT(tp
->t_dev
));
1088 ms
->OutDisable
= true;
1097 * bits can be: TIOCM_DTR, TIOCM_RTS, TIOCM_CTS, TIOCM_CD, TIOCM_RI, TIOCM_DSR
1100 mscmctl(dev_t dev
, int bits
, int how
)
1102 struct mscdevice
*msc
;
1103 volatile struct mscstatus
*ms
;
1109 /* get the device structure */
1110 slot
= MSCSLOT(dev
);
1112 if (slot
>= MSCSLOTS
)
1115 msc
= &mscdev
[slot
];
1123 OldFlags
= msc
->flags
;
1124 bits
&= TIOCM_DTR
| TIOCM_RTS
; /* can only modify DTR and RTS */
1128 msc
->flags
= (bits
| (msc
->flags
& ~(TIOCM_DTR
| TIOCM_RTS
)));
1132 msc
->flags
&= ~bits
;
1140 /* modify modem control state */
1141 ms
= &msc
->board
->Status
[msc
->port
];
1143 if (msc
->flags
& TIOCM_RTS
) /* was bits & */
1144 newcmd
= MSCCMD_RTSOn
;
1145 else /* this doesn't actually work now */
1146 newcmd
= MSCCMD_RTSOff
;
1148 if (msc
->flags
& TIOCM_DTR
) /* was bits & */
1149 newcmd
|= MSCCMD_Enable
;
1151 ms
->Command
= (ms
->Command
& (~MSCCMD_RTSMask
& ~MSCCMD_Enable
)) | newcmd
;
1154 /* if we've dropped DTR, bitbucket any pending output */
1155 if ( (OldFlags
& TIOCM_DTR
) && ((bits
& TIOCM_DTR
) == 0))
1156 ms
->OutFlush
= true;
1170 return(msc_tty
[MSCTTY(dev
)]);
1175 * Load JM's freely redistributable A2232 6502c code. Let turbo detector
1176 * run for a while too.
1180 mscinitcard(struct zbus_args
*zap
)
1185 volatile u_char
*to
;
1186 volatile struct mscmemory
*mlm
;
1188 mlm
= (volatile struct mscmemory
*)zap
->va
;
1189 (void)mlm
->Enable6502Reset
;
1191 /* copy the code across to the board */
1192 to
= (volatile u_char
*)mlm
;
1193 from
= msc6502code
; bcount
= sizeof(msc6502code
) - 2;
1194 start
= *(short *)from
; from
+= sizeof(start
);
1197 while(bcount
--) *to
++ = *from
++;
1199 mlm
->Common
.Crystal
= MSC_UNKNOWN
; /* use automatic speed check */
1201 /* start 6502 running */
1202 (void)mlm
->ResetBoard
;
1204 /* wait until speed detector has finished */
1205 for (bcount
= 0; bcount
< 200; bcount
++) {
1207 if (mlm
->Common
.Crystal
)
1214 #endif /* NMSC > 0 */