1 /* $NetBSD: scn.c,v 1.1 2009/02/10 06:04:56 rumble Exp $ */
4 * Resurrected from the old pc532 port 1/18/2009.
6 * XXX- The locking in this is probably totally broken. I haven't attempted
7 * to get it right, but it seems to work okay anyhow.
11 * Copyright (c) 1991, 1992, 1993
12 * The Regents of the University of California. All rights reserved.
14 * Portions of this software were developed by the Computer Systems
15 * Engineering group at Lawrence Berkeley Laboratory under DARPA
16 * contract BG 91-66 and contributed to Berkeley.
18 * All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Lawrence Berkeley Laboratory.
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 3. Neither the name of the University nor the names of its contributors
32 * may be used to endorse or promote products derived from this software
33 * without specific prior written permission.
35 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * from: @(#)com.c 7.5 (Berkeley) 5/16/91
51 * Copyright (c) 1996, 1997 Philip L. Budne.
52 * Copyright (c) 1993 Philip A. Nelson.
54 * Portions of this software were developed by the Computer Systems
55 * Engineering group at Lawrence Berkeley Laboratory under DARPA
56 * contract BG 91-66 and contributed to Berkeley.
58 * All advertising materials mentioning features or use of this software
59 * must display the following acknowledgement:
60 * This product includes software developed by the University of
61 * California, Lawrence Berkeley Laboratory.
63 * Redistribution and use in source and binary forms, with or without
64 * modification, are permitted provided that the following conditions
66 * 1. Redistributions of source code must retain the above copyright
67 * notice, this list of conditions and the following disclaimer.
68 * 2. Redistributions in binary form must reproduce the above copyright
69 * notice, this list of conditions and the following disclaimer in the
70 * documentation and/or other materials provided with the distribution.
71 * 3. All advertising materials mentioning features or use of this software
72 * must display the following acknowledgement:
73 * This product includes software developed by the University of
74 * California, Berkeley and its contributors.
75 * 4. Neither the name of the University nor the names of its contributors
76 * may be used to endorse or promote products derived from this software
77 * without specific prior written permission.
79 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
80 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
81 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
82 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
83 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
84 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
85 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
86 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
87 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
88 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
91 * from: @(#)com.c 7.5 (Berkeley) 5/16/91
94 #include <sys/cdefs.h>
95 __KERNEL_RCSID(0, "$NetBSD: scn.c,v 1.1 2009/02/10 06:04:56 rumble Exp $");
101 #include <sys/param.h>
102 #include <sys/systm.h>
103 #include <sys/ioctl.h>
104 #include <sys/select.h>
106 #include <sys/proc.h>
107 #include <sys/file.h>
109 #include <sys/kernel.h>
110 #include <sys/syslog.h>
111 #include <sys/types.h>
112 #include <sys/device.h>
113 #include <sys/malloc.h>
114 #include <sys/conf.h>
115 #include <sys/intr.h>
117 #include <sys/kgdb.h>
119 #include <sys/kauth.h>
121 #include <dev/cons.h>
123 #include <machine/autoconf.h>
124 #include <machine/machtype.h>
126 #include <sgimips/dev/scnreg.h>
127 #include <sgimips/dev/scnvar.h>
129 int scn_match(device_t
, struct cfdata
*, void *);
130 void scn_attach(device_t
, device_t
, void *);
131 int scnparam(struct tty
*, struct termios
*);
132 void scnstart(struct tty
*);
133 int scnhwiflow(struct tty
*, int);
135 void scncnprobe(struct consdev
*);
136 void scncninit(struct consdev
*);
137 int scncngetc(dev_t
);
138 void scncnputc(dev_t
, int);
139 void scncnpollc(dev_t
, int);
140 int scninit(dev_t
, int);
141 void scncnreinit(void *);
143 CFATTACH_DECL(scn
, sizeof(struct scn_softc
),
144 scn_match
, scn_attach
, NULL
, NULL
);
146 extern struct cfdriver scn_cd
;
148 dev_type_open(scnopen
);
149 dev_type_close(scnclose
);
150 dev_type_read(scnread
);
151 dev_type_write(scnwrite
);
152 dev_type_ioctl(scnioctl
);
153 dev_type_stop(scnstop
);
154 dev_type_tty(scntty
);
155 dev_type_poll(scnpoll
);
157 const struct cdevsw scn_cdevsw
= {
158 scnopen
, scnclose
, scnread
, scnwrite
, scnioctl
,
159 scnstop
, scntty
, scnpoll
, nommap
, ttykqfilter
, D_TTY
162 struct consdev scn_cn
= {
175 #ifndef CONSOLE_SPEED
176 #define CONSOLE_SPEED TTYDEF_SPEED
180 #define SCNDEF_CFLAG TTYDEF_CFLAG
184 #define RECOVER() __asm volatile("bispsrw 0x800" : : : "cc")
189 int scndefaultrate
= TTYDEF_SPEED
;
190 int scnconsrate
= CONSOLE_SPEED
;
192 static inline struct scn_softc
*
195 if (unit
< 0 || unit
>= scn_cd
.cd_ndevs
)
197 return ((struct scn_softc
*)scn_cd
.cd_devs
[unit
]);
200 static int scnintr(void *);
201 static void scnrxintr(void *);
202 static int scn_rxintr(struct scn_softc
*);
203 static void scnsoft(void *);
204 static void scn_setchip(struct scn_softc
*sc
);
205 static int scniter(int *, int, int*, int*, struct chan
*, int);
206 static int scn_config(int, int, int, int, u_char
, u_char
);
207 static void scn_rxenable(struct scn_softc
*);
208 static void scn_rxdisable(struct scn_softc
*);
209 static void dcd_int(struct scn_softc
*, struct tty
*, u_char
);
210 static void scnoverrun(int, long *, const char *);
211 static u_char
opbits(struct scn_softc
*, int);
213 static void *scnsir
= NULL
; /* s/w intr cookie */
214 #define setsoftscn() softint_schedule(scnsir)
218 * Keep timing info on latency of software interrupt used by
219 * the ringbuf code to empty ring buffer.
220 * "getinfo" program reads data from /dev/kmem.
222 static struct timeval tstart
;
224 int scn_njitter
= NJITTER
;
225 int scn_jitter
[NJITTER
];
228 #define SCN_CLOCK 3686400 /* input clock */
230 /* speed table groups ACR[7] */
232 #define GRP_B ACR_BRG
234 /* combo of MR0[2:0] and ACR[7] */
235 #define MODE0A MR0_MODE_0
236 #define MODE0B (MR0_MODE_0|ACR_BRG)
237 #define MODE1A MR0_MODE_1
238 #define MODE1B (MR0_MODE_1|ACR_BRG)
239 #define MODE2A MR0_MODE_2
240 #define MODE2B (MR0_MODE_2|ACR_BRG)
243 #define DEFMODE(C92) MODE0A /* use MODE4A if 26c92? */
245 /* speed code for Counter/Timer (all modes, groups) */
249 * Rate table, ordered by speed, then mode.
250 * NOTE: ordering of modes must be done carefully!
259 { 110, 0x1, MODE0A
},
260 { 110, 0x1, MODE0B
},
261 { 110, 0x1, MODE1A
},
262 { 110, 0x1, MODE1B
},
263 { 134, 0x2, MODE0A
}, /* 134.5 */
264 { 134, 0x2, MODE0B
}, /* 134.5 */
265 { 134, 0x2, MODE1A
}, /* 134.5 */
266 { 134, 0x2, MODE1B
}, /* 134.5 */
267 { 150, 0x3, MODE0A
},
268 { 150, 0x3, MODE0A
},
269 { 200, 0x3, MODE0A
},
270 { 300, 0x4, MODE0A
},
271 { 300, 0x4, MODE0B
},
272 { 300, 0x0, MODE1A
},
273 { 450, 0x0, MODE1B
},
274 { 600, 0x5, MODE0A
},
275 { 600, 0x5, MODE0B
},
276 { 880, 0x1, MODE2A
},
277 { 880, 0x1, MODE2B
},
278 { 900, 0x3, MODE1B
},
279 { 1050, 0x7, MODE0A
},
280 { 1050, 0x7, MODE1A
},
281 { 1076, 0x2, MODE2A
},
282 { 1076, 0x2, MODE2B
},
283 { 1200, 0x6, MODE0A
},
284 { 1200, 0x6, MODE0B
},
285 { 1200, 0x3, MODE1A
},
286 { 1800, 0xa, MODE0B
},
287 { 1800, 0x4, MODE1A
},
288 { 1800, 0x4, MODE1B
},
289 { 2000, 0x7, MODE0B
},
290 { 2000, 0x7, MODE1B
},
291 { 2400, 0x8, MODE0A
},
292 { 2400, 0x8, MODE0B
},
293 { 3600, 0x5, MODE1A
},
294 { 3600, 0x5, MODE1B
},
295 { 4800, 0x9, MODE2A
},
296 { 4800, 0x9, MODE2B
},
297 { 4800, 0x9, MODE0A
},
298 { 4800, 0x9, MODE0B
},
299 { 7200, 0xa, MODE0A
},
300 { 7200, 0x0, MODE2B
},
301 { 7200, 0x6, MODE1A
},
302 { 7200, 0x6, MODE1B
},
303 { 9600, 0xb, MODE2A
},
304 { 9600, 0xb, MODE2B
},
305 { 9600, 0xb, MODE0A
},
306 { 9600, 0xb, MODE0B
},
307 { 9600, 0xd, MODE1A
}, /* use C/T as entre' to mode1 */
308 { 9600, 0xd, MODE1B
}, /* use C/T as entre' to mode1 */
309 { 14400, 0x3, MODE2B
},
310 { 14400, 0x8, MODE1A
},
311 { 14400, 0x8, MODE1B
},
312 { 19200, 0x3, MODE2A
},
313 { 19200, 0xc, MODE2B
},
314 { 19200, 0xc, MODE0B
},
315 { 19200, 0xd, MODE1A
}, /* use C/T as entre' to mode1 */
316 { 19200, 0xd, MODE1B
}, /* use C/T as entre' to mode1 */
317 { 28800, 0x4, MODE2A
},
318 { 28800, 0x4, MODE2B
},
319 { 28800, 0x9, MODE1A
},
320 { 28800, 0x9, MODE1B
},
321 { 38400, 0xc, MODE2A
},
322 { 38400, 0xc, MODE0A
},
323 { 57600, 0x5, MODE2A
},
324 { 57600, 0x5, MODE2B
},
325 { 57600, 0xb, MODE1A
},
326 { 57600, 0xb, MODE1B
},
327 { 115200, 0x6, MODE2A
},
328 { 115200, 0x6, MODE2B
},
329 { 115200, 0xc, MODE1B
},
330 { 230400, 0xc, MODE1A
}
332 #define TABENTRIES (sizeof(table)/sizeof(table[0]))
335 * boolean for speed codes which are identical in both A/B BRG groups
338 static u_char bothgroups
[16] = {
339 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1
343 * Manually constructed divisors table
344 * for minimum error (from some of Dave Rand's code)
350 { 50, 2303 }, /* 2304 is exact?? */
351 { 110, 1047 }, /* Should be 1047.27 */
352 { 134, 857 }, /* Should be 856.505576 */
353 { 1050, 110 }, /* Should be 109.7142857 */
354 { 2000, 57 } /* Should be 57.6 */
356 #define DIVS (sizeof(divs)/sizeof(divs[0]))
359 * minor unit bit decode:
363 * 0 - delay open until carrier high
364 * 1 - allow open with carrier low
368 #define DEV_UNIT(x) (minor(x) & 0x7)
369 #define DEV_DIALOUT(x) (minor(x) & 0x80)
371 extern struct tty
*constty
;
373 #define SCN_MAXDUART 4
374 static struct duart scn_duart
[SCN_MAXDUART
];
378 extern int kgdb_rate
;
379 extern int kgdb_debug_init
;
382 /* XXXXX - fix this */
383 #define splrtty() spltty()
385 /* RS-232 configuration routines */
388 * set chip parameters, or mark for delayed change.
389 * called at spltty() or on TxEMPTY interrupt.
391 * Reads current values to avoid glitches from redundant sets.
392 * Perhaps should save last value set to avoid read/write? NOTE:
393 * Would still need to do read if write not needed to advance MR
400 scn_setchip(struct scn_softc
*sc
)
403 u_char acr
, csr
, mr1
, mr2
;
406 if (sc
->sc_tty
&& (sc
->sc_tty
->t_state
& TS_BUSY
)) {
407 sc
->sc_heldchanges
= 1;
411 chan
= sc
->sc_channel
;
413 if (dp
->type
== SC26C92
) {
416 /* input rate high enough so 64 bit time watchdog not
418 if (dp
->chan
[chan
].ispeed
>= 1200) {
419 /* set FIFO threshold at 6 for other
420 * thresholds we could have to set MR1_FFULL
422 dp
->chan
[chan
].mr0
|= MR0_RXWD
| MR0_RXINT
;
424 dp
->chan
[chan
].mr0
&= ~(MR0_RXWD
| MR0_RXINT
);
427 /* select BRG mode (MR0A only) */
428 nmr0a
= dp
->chan
[0].mr0
| (dp
->mode
& MR0_MODE
);
430 dp
->base
[CH_CR
] = CR_CMD_MR0
;
433 mr0a
= dp
->base
[CH_MR
];
435 dp
->base
[CH_CR
] = CR_CMD_MR0
;
437 dp
->base
[CH_MR
] = nmr0a
;
440 if (chan
) { /* channel B? */
443 sc
->sc_chbase
[CH_CR
] = CR_CMD_MR0
;
445 mr0b
= dp
->base
[CH_MR
];
447 if (dp
->chan
[chan
].mr0
!= mr0b
) {
448 sc
->sc_chbase
[CH_CR
] = CR_CMD_MR0
;
450 sc
->sc_chbase
[CH_MR
] = dp
->chan
[chan
].mr0
;
454 sc
->sc_chbase
[CH_CR
] = CR_CMD_MR1
;
458 mr1
= sc
->sc_chbase
[CH_MR
];
459 mr2
= sc
->sc_chbase
[CH_MR
];
460 if (mr1
!= dp
->chan
[chan
].new_mr1
||
461 mr2
!= dp
->chan
[chan
].new_mr2
) {
462 sc
->sc_chbase
[CH_CR
] = CR_CMD_MR1
;
464 sc
->sc_chbase
[CH_MR
] = dp
->chan
[chan
].new_mr1
;
465 sc
->sc_chbase
[CH_MR
] = dp
->chan
[chan
].new_mr2
;
468 acr
= dp
->acr
| (dp
->mode
& ACR_BRG
);
469 dp
->base
[DU_ACR
] = acr
; /* write-only reg! */
471 /* set speed codes */
472 csr
= (dp
->chan
[chan
].icode
<<4) | dp
->chan
[chan
].ocode
;
473 if (sc
->sc_chbase
[CH_CSR
] != csr
) {
474 sc
->sc_chbase
[CH_CSR
] = csr
;
477 /* see if counter/timer in use */
479 (dp
->chan
[0].icode
== USE_CT
|| dp
->chan
[0].ocode
== USE_CT
||
480 dp
->chan
[1].icode
== USE_CT
|| dp
->chan
[1].ocode
== USE_CT
)) {
482 /* program counter/timer only if necessary */
483 if (dp
->counter
!= dp
->ocounter
) {
488 /* look for precalculated rate, for minimum error */
489 for (i
= 0; i
< DIVS
&& divs
[i
].speed
<= dp
->counter
; i
++) {
490 if (divs
[i
].speed
== dp
->counter
) {
497 /* not found in table; calculate a value (rounding up) */
498 div
= ((long)SCN_CLOCK
/16/2 + dp
->counter
/2) / dp
->counter
;
501 /* halt before loading? may ALWAYS glitch?
502 * reload race may only sometimes glitch??
504 dp
->base
[DU_CTUR
] = div
>> 8;
505 dp
->base
[DU_CTLR
] = div
& 255;
506 if (dp
->ocounter
== 0) {
507 /* not previously used? */
509 /* start C/T running */
510 temp
= dp
->base
[DU_CSTRT
];
512 dp
->ocounter
= dp
->counter
;
515 /* counter not in use; mark as free */
518 sc
->sc_heldchanges
= 0;
521 * delay a tiny bit to try and avoid tx glitching.
522 * I know we're at spltty(), but this is much better than the
523 * old version used DELAY((96000 / out_speed) * 10000)
530 * iterator function for speeds.
531 * (could be called "findnextcode")
532 * Returns sequence of possible speed codes for a given rate.
533 * should set index to zero before first call.
535 * Could be implemented as a "checkspeed()" function called
536 * to evaluate table entries, BUT this allows more variety in
537 * use of C/T with fewer table entries.
541 scniter(int *index
, int wanted
, int *counter
, int *mode
, struct chan
*other
,
545 while (*index
< TABENTRIES
) {
548 tp
= table
+ (*index
)++;
549 if (tp
->speed
!= wanted
)
552 /* if not a 26C92 only look at MODE0 entries */
553 if (!c92
&& (tp
->mode
& MR0_MODE
) != MR0_MODE_0
)
558 * OK if this table entry for current mode, or mode not
559 * yet set, or other channel's rates are available in both
563 if (tp
->mode
== *mode
|| *mode
== ANYMODE
||
564 (other
!= NULL
&& (tp
->mode
& MR0_MODE
) == (*mode
& MR0_MODE
) &&
565 bothgroups
[other
->icode
] && bothgroups
[other
->ocode
])) {
567 * for future table entries specifying
568 * use of counter/timer
570 if (tp
->code
== USE_CT
) {
571 if (*counter
!= wanted
&& *counter
!= 0)
572 continue; /* counter busy */
580 /* here after returning all applicable table entries */
581 /* XXX return sequence of USE_CT with all possible modes?? */
582 if ((*index
)++ == TABENTRIES
) {
583 /* Max C/T rate (even on 26C92?) is 57600 */
584 if (wanted
<= 57600 && (*counter
== wanted
|| *counter
== 0)) {
590 return -1; /* FAIL */
594 * calculate configuration
595 * rewritten 2/97 -plb
598 scn_config(int unit
, int chan
, int ispeed
, int ospeed
, u_char mr1
, u_char mr2
)
600 struct scn_softc
*sc
;
602 int other
; /* opposite of chan */
605 int i
, o
; /* input, output iterator indexes */
606 int ic
, oc
; /* input, output codes */
607 struct chan
*ocp
; /* other duart channel */
608 struct tty
*otp
; /* other channel tty struct */
609 int c92
; /* true if duart is sc26c92 */
612 /* Set up softc pointer. */
613 if (unit
>= scn_cd
.cd_ndevs
)
616 chan
= sc
->sc_channel
;
619 ocp
= &dp
->chan
[other
];
621 c92
= (dp
->type
== SC26C92
);
624 * Right now the first combination that works is used.
625 * Perhaps it should search entire solution space for "best"
626 * combination. For example, use heuristic weighting of mode
627 * preferences, and use of counter timer?
629 * For example right now with 2681/2692 when default rate is
630 * 9600 and other channel is closed setting 19200 will pick
631 * mode 0a and use counter/timer. Better solution might be
632 * mode 0b, leaving counter/timer free!
634 * When other channel is open might want to prefer
635 * leaving counter timer free, or not flipping A/B group?
637 if (otp
&& (otp
->t_state
& TS_ISOPEN
)) {
640 * Other channel open;
641 * Find speed codes compatible with current mode/counter.
647 counter
= dp
->counter
;
649 /* NOTE: pass other chan pointer to allow group flipping */
650 ic
= scniter(&i
, ispeed
, &counter
, &mode
, ocp
, c92
);
655 if ((oc
= scniter(&o
, ospeed
, &counter
,
656 &mode
, NULL
, c92
)) != -1) {
660 * Perhaps calculate heuristic "score",
661 * save score,codes,mode,counter if score
662 * better than previous best?
667 /* XXX try looping for ospeed? */
669 /* other channel closed */
670 int oo
, oi
; /* other input, output iterators */
671 int oic
, ooc
; /* other input, output codes */
674 * Here when other channel closed. Finds first
675 * combination that will allow other channel to be opened
676 * (with defaults) and fits our needs.
683 oic
= scniter(&oi
, ocp
->ispeed
, &counter
, &mode
, NULL
, c92
);
688 while ((ooc
= scniter(&oo
, ocp
->ospeed
, &counter
,
689 &mode
, NULL
, c92
)) != -1) {
691 while ((ic
= scniter(&i
, ispeed
, &counter
,
692 &mode
, NULL
, c92
)) != -1) {
694 if ((oc
= scniter(&o
, ospeed
, &counter
,
695 &mode
, NULL
, c92
)) != -1) {
699 * Perhaps calculate heuristic
701 * score,codes,mode,counter
702 * if score better than
706 dp
->chan
[other
].icode
= oic
;
707 dp
->chan
[other
].ocode
= ooc
;
719 dp
->chan
[chan
].new_mr1
= mr1
;
720 dp
->chan
[chan
].new_mr2
= mr2
;
721 dp
->chan
[chan
].ispeed
= ispeed
;
722 dp
->chan
[chan
].ospeed
= ospeed
;
723 dp
->chan
[chan
].icode
= ic
;
724 dp
->chan
[chan
].ocode
= oc
;
725 if (mode
== ANYMODE
) /* no mode selected?? */
728 dp
->counter
= counter
;
730 scn_setchip(sc
); /* set chip now, if possible */
736 scn_match(device_t parent
, struct cfdata
*cf
, void *aux
)
738 struct mainbus_attach_args
*ma
= aux
;
740 if ((mach_type
== MACH_SGI_IP6
|| mach_type
== MACH_SGI_IP10
) &&
741 ma
->ma_addr
== 0x1fb80004)
748 * No need to make scn_rx{en,dis}able too efficient,
749 * they're only called on setup, open & close!
752 scn_rxenable(struct scn_softc
*sc
)
758 channel
= sc
->sc_channel
;
760 /* Outputs wire-ored and connected to ICU input for fast rx interrupt. */
762 dp
->opcr
|= OPCR_OP4_RXRDYA
;
764 dp
->opcr
|= OPCR_OP5_RXRDYB
;
765 dp
->base
[DU_OPCR
] = dp
->opcr
;
766 dp
->imr
|= sc
->sc_rx_int
;
767 dp
->base
[DU_IMR
] = dp
->imr
;
771 scn_rxdisable(struct scn_softc
*sc
)
777 channel
= sc
->sc_channel
;
779 /* Outputs wire-ored and connected to ICU input for fast rx interrupt. */
781 dp
->opcr
&= ~OPCR_OP4_RXRDYA
;
783 dp
->opcr
&= ~OPCR_OP5_RXRDYB
;
784 dp
->base
[DU_OPCR
] = dp
->opcr
;
785 dp
->imr
&= ~sc
->sc_rx_int
;
786 dp
->base
[DU_IMR
] = dp
->imr
;
790 scn_attach(device_t parent
, device_t self
, void *aux
)
792 struct mainbus_attach_args
*ma
= aux
;
793 struct scn_softc
*sc
;
795 volatile u_char
*ch_base
;
796 volatile u_char
*duart_base
;
805 enum scntype scntype
= SCNUNK
;
806 const char *duart_type
= "Unknown";
813 sc
= device_private(self
);
814 unit
= device_unit(self
);
816 /* XXX - hard-coded */
817 if (ma
->ma_addr
== 0x1fb80004)
824 duart
= sc
->sc_duart
= &scn_duart
[duartno
];
825 duart
->chan
[channel
].sc
= sc
;
826 first
= (duart
->base
== NULL
);
829 sc
->sc_isconsole
= 1;
830 sc
->sc_swflags
|= SCN_SW_SOFTCAR
; /* ignore carrier */
833 duart_base
= (volatile u_char
*)MIPS_PHYS_TO_KSEG1(ma
->ma_addr
);
834 ch_base
= duart_base
; /* XXX */
837 /* Probe DUART type */
840 ch_base
[CH_CR
] = CR_DIS_TX
;
843 ch_base
[CH_CR
] = CR_CMD_MR1
;
845 mr1
= ch_base
[CH_MR
];
846 mr2
= ch_base
[CH_MR
];
847 ch_base
[CH_CR
] = CR_CMD_MR1
;
851 ch_base
[CH_CR
] = CR_CMD_MR1
;
853 if (ch_base
[CH_MR
] == 1) {
855 ch_base
[CH_CR
] = CR_CMD_MR0
;
857 /* if 2681, MR2 still selected */
859 ch_base
[CH_CR
] = CR_CMD_MR1
;
861 ch_base
[CH_MR
] = 0; /* MR1 */
862 ch_base
[CH_MR
] = 0; /* MR2 */
863 ch_base
[CH_CR
] = CR_CMD_MR0
;
865 /* if 2681, MR2 still selected */
866 if((ch_base
[CH_MR
] & 1) == 1) {
867 duart_type
= "sc26c92";
870 /* 2681 treats as MR1 Select */
871 ch_base
[CH_CR
] = CR_CMD_RTS_OFF
;
875 ch_base
[CH_CR
] = CR_CMD_RTS_OFF
;
877 if (ch_base
[CH_MR
] == 1) {
878 duart_type
= "scn2681";
881 duart_type
= "scn2692";
887 /* If a 2681, the CR_CMD_MR0 is interpreted as a TX_RESET */
889 ch_base
[CH_CR
] = CR_ENA_TX
;
892 ch_base
[CH_CR
] = CR_CMD_MR1
;
894 ch_base
[CH_MR
] = mr1
;
895 ch_base
[CH_MR
] = mr2
;
898 intrname
= malloc(sizeof("scnXX"), M_DEVBUF
, M_NOWAIT
);
899 snprintf(intrname
, sizeof("scnXX"), "scn%d", unit
);
902 * On IP6 the console chip is duart1. The keyboard/mouse
903 * is duart0. Each chip has two channels and the channels
904 * share an interrupt. Duart0 is interrupt 0, duart1 is
907 if (duartno
!= 0 && duartno
!= 1)
908 panic("scn_attach: bad duartno: %d", duartno
);
909 cpu_intr_establish(duartno
, IPL_TTY
, scnintr
, duart
);
911 printf("%c %s", delim
, duart_type
);
914 duart
->base
= duart_base
;
915 duart
->type
= scntype
;
917 /* Record channel, uart */
918 sc
->sc_channel
= channel
;
919 sc
->sc_chbase
= ch_base
;
921 /* Initialize modem/interrupt bit masks */
923 sc
->sc_op_rts
= OP_RTSA
;
924 sc
->sc_op_dtr
= OP_DTRA
;
925 sc
->sc_ip_cts
= IP_CTSA
;
926 sc
->sc_ip_dcd
= IP_DCDA
;
928 sc
->sc_tx_int
= INT_TXA
;
929 sc
->sc_rx_int
= INT_RXA
;
931 sc
->sc_op_rts
= OP_RTSB
;
932 sc
->sc_op_dtr
= OP_DTRB
;
933 sc
->sc_ip_cts
= IP_CTSB
;
934 sc
->sc_ip_dcd
= IP_DCDB
;
936 sc
->sc_tx_int
= INT_TXB
;
937 sc
->sc_rx_int
= INT_RXB
;
940 /* Initialize counters */
941 sc
->sc_framing_errors
= 0;
942 sc
->sc_fifo_overruns
= 0;
943 sc
->sc_parity_errors
= 0;
947 DELAY(5 * 10000); /* Let the output go out.... */
951 * Set up the hardware to a base state, in particular:
952 * o reset transmitter and receiver
953 * o set speeds and configurations
954 * o receiver interrupts only (RxRDY and BREAK)
959 SCN_OP_BIC(sc
, sc
->sc_op_rts
); /* "istop" */
961 ch_base
[CH_CR
] = CR_DIS_RX
| CR_DIS_TX
;
963 ch_base
[CH_CR
] = CR_CMD_RESET_RX
;
965 ch_base
[CH_CR
] = CR_CMD_RESET_TX
;
967 ch_base
[CH_CR
] = CR_CMD_RESET_ERR
;
969 ch_base
[CH_CR
] = CR_CMD_RESET_BRK
;
971 ch_base
[CH_CR
] = CR_CMD_MR1
;
974 /* No receiver control of RTS. */
978 /* Initialize the uart structure if this is channel A. */
980 /* Disable all interrupts. */
981 duart_base
[DU_IMR
] = duart
->imr
= 0;
983 /* Output port config */
984 duart_base
[DU_OPCR
] = duart
->opcr
= 0;
990 * Set initial speed to an illegal code that can be changed to
993 duart
->chan
[0].icode
= duart
->chan
[0].ocode
= 0x2f;
994 duart
->chan
[1].icode
= duart
->chan
[1].ocode
= 0x2f;
995 duart
->chan
[0].ispeed
= duart
->chan
[0].ospeed
= 0;
996 duart
->chan
[1].ispeed
= duart
->chan
[1].ospeed
= 0;
999 duart
->acr
|= ACR_CT_TCLK1
; /* timer mode 1x clk */
1003 duart
->acr
|= ACR_DELTA_DCDA
; /* Set CD int */
1005 duart
->acr
|= ACR_DELTA_DCDB
; /* Set CD int */
1008 if (scnsir
== NULL
) {
1009 /* software intr: calls tty code, hence IPL_TTY */
1010 scnsir
= softint_establish(SOFTINT_SERIAL
, scnsoft
, NULL
);
1013 duart_base
[DU_ACR
] = (duart
->mode
& ACR_BRG
) | duart
->acr
;
1016 speed
= scnconsrate
;
1018 speed
= scndefaultrate
;
1020 scn_config(unit
, channel
, speed
, speed
, MR1_PNONE
| MR1_CS8
, MR2_STOP1
);
1022 maj
= cdevsw_lookup_major(&scn_cdevsw
);
1023 KASSERT(maj
!= NODEVMAJOR
);
1024 shutdownhook_establish(scncnreinit
, NULL
);
1025 /* Make sure console can do scncngetc */
1026 duart_base
[DU_OPSET
] = channel
? (OP_RTSB
| OP_DTRB
) :
1027 (OP_RTSA
| OP_DTRA
);
1030 /* Turn on the receiver and transmitters */
1031 ch_base
[CH_CR
] = CR_ENA_RX
| CR_ENA_TX
;
1033 /* Set up the interrupts. */
1034 duart
->imr
|= INT_IP
;
1038 if (sc
->sc_swflags
) {
1039 printf("%c flags %d", delim
, sc
->sc_swflags
);
1044 major
= cdevsw_lookup_major(&scn_cdevsw
);
1045 KASSERT(major
!= NODEVMAJOR
);
1046 if (kgdb_dev
== makedev(major
, unit
)) {
1048 kgdb_dev
= NODEV
; /* can't debug over console port */
1050 scninit(kgdb_dev
, kgdb_rate
);
1053 kgdb_attach(scncngetc
, scncnputc
, kgdb_dev
);
1054 if (kgdb_debug_init
) {
1055 printf("%c ", delim
);
1058 printf("%c kgdb enabled", delim
);
1068 scnopen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
1071 int unit
= DEV_UNIT(dev
);
1072 struct scn_softc
*sc
;
1076 if (unit
>= scn_cd
.cd_ndevs
)
1085 sc
->sc_tty
= sc
->sc_duart
->chan
[sc
->sc_channel
].tty
= tp
;
1089 tp
->t_oproc
= scnstart
;
1090 tp
->t_param
= scnparam
;
1091 tp
->t_hwiflow
= scnhwiflow
;
1094 if (kauth_authorize_device_tty(l
->l_cred
, KAUTH_DEVICE_TTY_OPEN
, tp
))
1097 mutex_spin_enter(&tty_lock
);
1099 if ((tp
->t_state
& TS_ISOPEN
) == 0 && tp
->t_wopen
== 0) {
1101 tp
->t_iflag
= TTYDEF_IFLAG
;
1102 tp
->t_oflag
= TTYDEF_OFLAG
;
1103 tp
->t_cflag
= SCNDEF_CFLAG
;
1105 sc
->sc_rx_blocked
= 0;
1107 if (sc
->sc_swflags
& SCN_SW_CLOCAL
)
1108 tp
->t_cflag
|= CLOCAL
;
1109 if (sc
->sc_swflags
& SCN_SW_CRTSCTS
)
1110 tp
->t_cflag
|= CCTS_OFLOW
| CRTS_IFLOW
;
1111 tp
->t_lflag
= TTYDEF_LFLAG
;
1112 if (sc
->sc_isconsole
)
1113 tp
->t_ispeed
= tp
->t_ospeed
= scnconsrate
;
1115 tp
->t_ispeed
= tp
->t_ospeed
= scndefaultrate
;
1116 scnparam(tp
, &tp
->t_termios
);
1119 /* Turn on DTR and RTS. */
1120 SCN_OP_BIS(sc
, sc
->sc_op_rts
| sc
->sc_op_dtr
);
1122 /* enable receiver interrupts */
1126 /* set carrier state; */
1127 if ((sc
->sc_swflags
& SCN_SW_SOFTCAR
) || /* check ttyflags */
1128 SCN_DCD(sc
) || /* check h/w */
1130 tp
->t_state
|= TS_CARR_ON
;
1132 tp
->t_state
&= ~TS_CARR_ON
;
1135 mutex_spin_exit(&tty_lock
);
1137 error
= ttyopen(tp
, SCN_DIALOUT(sc
), flags
& O_NONBLOCK
);
1138 if (error
) printf("ttyopen failed line %d, error %d\n", __LINE__
, error
);
1142 error
= (*tp
->t_linesw
->l_open
) (dev
, tp
);
1143 if (error
) printf("l_open failed line %d, error %d\n", __LINE__
, error
);
1150 if ((tp
->t_state
& TS_ISOPEN
) == 0 && tp
->t_wopen
== 0) {
1152 SCN_OP_BIC(sc
, sc
->sc_op_rts
| sc
->sc_op_dtr
);
1161 scnclose(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
1163 int unit
= DEV_UNIT(dev
);
1164 struct scn_softc
*sc
= SOFTC(unit
);
1165 struct tty
*tp
= sc
->sc_tty
;
1170 if ((tp
->t_state
& TS_ISOPEN
) == 0)
1173 (*tp
->t_linesw
->l_close
) (tp
, flags
);
1176 /* do not disable interrupts if debugging */
1177 major
= cdevsw_lookup_major(&scn_devsw
);
1178 KASSERT(major
!= cdevsw_lookup_major
);
1179 if (kgdb_dev
!= makedev(major
, unit
))
1181 if ((tp
->t_state
& TS_ISOPEN
) == 0) {
1184 if ((tp
->t_cflag
& HUPCL
) && (sc
->sc_swflags
& SCN_SW_SOFTCAR
) == 0) {
1185 SCN_OP_BIC(sc
, sc
->sc_op_dtr
);
1186 /* hold low for 1 second */
1187 tsleep(sc
, TTIPRI
, ttclos
, hz
);
1193 if ((tp
->t_state
& TS_ISOPEN
) == 0) {
1195 sc
->sc_tty
= (struct tty
*) NULL
;
1203 scnread(dev_t dev
, struct uio
*uio
, int flags
)
1205 struct scn_softc
*sc
= SOFTC(DEV_UNIT(dev
));
1206 struct tty
*tp
= sc
->sc_tty
;
1208 return ((*tp
->t_linesw
->l_read
) (tp
, uio
, flags
));
1212 scnwrite(dev_t dev
, struct uio
*uio
, int flags
)
1214 struct scn_softc
*sc
= SOFTC(DEV_UNIT(dev
));
1215 struct tty
*tp
= sc
->sc_tty
;
1217 return ((*tp
->t_linesw
->l_write
) (tp
, uio
, flags
));
1221 scnpoll(dev_t dev
, int events
, struct lwp
*l
)
1223 struct scn_softc
*sc
= SOFTC(DEV_UNIT(dev
));
1224 struct tty
*tp
= sc
->sc_tty
;
1226 return ((*tp
->t_linesw
->l_poll
)(tp
, events
, l
));
1232 struct scn_softc
*sc
= SOFTC(DEV_UNIT(dev
));
1237 /* Worker routines for interrupt processing */
1239 dcd_int(struct scn_softc
*sc
, struct tty
*tp
, u_char
new)
1242 if (sc
->sc_swflags
& SCN_SW_SOFTCAR
)
1246 printf("scn%d: dcd_int ip %x SCN_DCD %x new %x ipcr %x\n",
1248 sc
->sc_duart
->base
[DU_IP
],
1251 sc
->sc_duart
->base
[DU_IPCR
]
1255 /* XXX set some flag to have some lower (soft) int call line discipline? */
1256 if (!(*tp
->t_linesw
->l_modem
) (tp
, new == 0? 1: 0)) {
1257 SCN_OP_BIC(sc
, sc
->sc_op_rts
| sc
->sc_op_dtr
);
1262 * Print out a ring or fifo overrun error message.
1265 scnoverrun(int unit
, long *ptime
, const char *what
)
1268 if (*ptime
!= time_second
) {
1269 *ptime
= time_second
;
1270 log(LOG_WARNING
, "scn%d: %s overrun\n", unit
, what
);
1275 * Try to block or unblock input using hardware flow-control.
1276 * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
1277 * if this function returns non-zero, the TS_TBLOCK flag will
1278 * be set or cleared according to the "stop" arg passed.
1281 scnhwiflow(struct tty
*tp
, int stop
)
1283 int unit
= DEV_UNIT(tp
->t_dev
);
1284 struct scn_softc
*sc
= SOFTC(unit
);
1289 if (sc
->sc_rbput
- sc
->sc_rbget
- 1) {
1300 struct duart
*duart
= arg
;
1301 struct scn_softc
*sc0
= duart
->chan
[0].sc
;
1302 struct scn_softc
*sc1
= duart
->chan
[1].sc
;
1304 struct tty
*tp0
= (sc0
!= NULL
) ? sc0
->sc_tty
: NULL
;
1305 struct tty
*tp1
= (sc1
!= NULL
) ? sc1
->sc_tty
: NULL
;
1311 /* Check for RX interrupts first, since we cannot distinguish by irq. */
1315 /* Loop to pick up ALL pending interrupts for device. */
1317 rs_stat
= duart
->base
[DU_ISR
];
1321 if ((rs_stat
& INT_TXA
) && (tp0
->t_state
& TS_BUSY
)) {
1322 /* output char done. */
1323 tp0
->t_state
&= ~(TS_BUSY
| TS_FLUSH
);
1325 /* disable tx ints */
1326 duart
->imr
&= ~sc0
->sc_tx_int
;
1327 duart
->base
[DU_IMR
] = duart
->imr
;
1329 if (sc0
->sc_heldchanges
) {
1333 (*tp0
->t_linesw
->l_start
) (tp0
);
1339 if ((rs_stat
& INT_TXB
) && (tp1
->t_state
& TS_BUSY
)) {
1340 /* output char done. */
1341 tp1
->t_state
&= ~(TS_BUSY
| TS_FLUSH
);
1343 /* disable tx ints */
1344 duart
->imr
&= ~sc1
->sc_tx_int
;
1345 duart
->base
[DU_IMR
] = duart
->imr
;
1347 if (sc1
->sc_heldchanges
) {
1351 (*tp1
->t_linesw
->l_start
) (tp1
);
1355 if (rs_stat
& INT_IP
) {
1357 rs_ipcr
= duart
->base
[DU_IPCR
];
1359 if (rs_ipcr
& IPCR_DELTA_DCDA
&& tp0
!= NULL
) {
1360 dcd_int(sc0
, tp0
, rs_ipcr
& IPCR_DCDA
);
1362 if (rs_ipcr
& IPCR_DELTA_DCDB
&& tp1
!= NULL
) {
1363 dcd_int(sc1
, tp1
, rs_ipcr
& IPCR_DCDB
);
1372 * Handle rxrdy/ffull interrupt: QUICKLY poll both channels (checking
1373 * status first) and stash data in a ring buffer. Ring buffer scheme
1374 * borowed from sparc/zs.c requires NO interlock on data!
1376 * This interrupt should NOT be included in spltty() mask since it
1377 * invokes NO tty code! The whole point is to allow tty input as much
1378 * of the time as possible, while deferring "heavy" character
1379 * processing until later.
1381 * see scn.hw.README and scnsoft() for more info.
1383 * THIS ROUTINE SHOULD BE KEPT AS CLEAN AS POSSIBLE!!
1384 * IT'S A CANDIDATE FOR RECODING IN ASSEMBLER!!
1387 scn_rxintr(struct scn_softc
*sc
)
1395 while (work
<= 10) {
1396 #define SCN_GETCH(SC) \
1397 sr = (SC)->sc_chbase[CH_SR]; \
1398 if ((sr & SR_RX_RDY) == 0) \
1400 if (sr & (SR_PARITY | SR_FRAME | SR_BREAK | SR_OVERRUN)) \
1403 (SC)->sc_rbuf[i++ & SCN_RING_MASK] = (SC)->sc_chbase[CH_DAT]
1405 SCN_GETCH(sc
); SCN_GETCH(sc
); SCN_GETCH(sc
);
1406 /* XXX more here if 26C92? -plb */
1410 if (sc
->sc_isconsole
&& (sr
& SR_BREAK
)) {
1412 sr
= sc
->sc_chbase
[CH_SR
];
1416 if (sc
->sc_iskgdb
&& (sr
& SR_RX_RDY
)) {
1418 sr
= sc
->sc_chbase
[CH_SR
];
1422 sc
->sc_rbuf
[i
++ & SCN_RING_MASK
] = (sr
<< 8) | sc
->sc_chbase
[CH_DAT
];
1423 sc
->sc_chbase
[CH_CR
] = CR_CMD_RESET_ERR
; /* resets break? */
1427 * If ring is getting too full, try to block input.
1429 n
= i
- sc
->sc_rbget
;
1430 if (sc
->sc_rbhiwat
&& (n
> sc
->sc_rbhiwat
)) {
1431 /* If not CRTSCTS sc_rbhiwat is such that this
1435 SCN_OP_BIC(sc
, sc
->sc_op_rts
);
1436 sc
->sc_rx_blocked
= 1;
1444 scnrxintr(void *arg
)
1446 struct duart
*duart
= arg
;
1449 if (duart
->chan
[0].sc
!= NULL
)
1450 work
+= scn_rxintr(duart
->chan
[0].sc
);
1451 if (duart
->chan
[1].sc
!= NULL
)
1452 work
+= scn_rxintr(duart
->chan
[1].sc
);
1454 setsoftscn(); /* trigger s/w intr */
1462 * Here on soft interrupt (at spltty) to empty ring buffers.
1464 * Dave's original scheme was to use the DUART receiver timeout
1465 * interrupt. This requires 2692's (which my board doesn't have), and
1466 * I also liked the idea of using the C/T to generate alternate and/or
1467 * arbitrary bauds. -plb
1469 * The ringbuffer code comes from Chris Torek's SPARC 44bsd zs driver
1470 * (hence the LBL notice on top of this file), DOES NOT require
1471 * interlocking with interrupt levels!
1473 * The 44bsd sparc/zs driver reads the ring buffer from a separate
1474 * zssoftint, while the SunOS 4.x zs driver appears to use
1475 * timeout()'s. timeouts seem to be too slow to deal with high data
1476 * rates. I know, I tried them.
1484 struct timeval tend
;
1488 t
= (tend
.tv_sec
- tstart
.tv_sec
) * 1000000 + (tend
.tv_usec
- tstart
.tv_usec
);
1489 t
= (t
+ tick
/ 20) / (tick
/ 10);
1490 if (t
>= NJITTER
- 1) {
1496 for (unit
= 0; unit
< scn_cd
.cd_ndevs
; unit
++) {
1497 struct scn_softc
*sc
;
1508 sc
->sc_rbget
= sc
->sc_rbput
;
1512 if (tp
== NULL
|| tp
->t_state
& TS_TBLOCK
) {
1519 /* NOTE: fetch from rbput is atomic */
1520 while (get
!= (n
= sc
->sc_rbput
)) {
1522 * Compute the number of interrupts in the receive ring.
1523 * If the count is overlarge, we lost some events, and
1524 * must advance to the first valid one. It may get
1525 * overwritten if more data are arriving, but this is
1526 * too expensive to check and gains nothing (we already
1527 * lost out; all we can do at this point is trade one
1528 * kind of loss for another).
1531 if (n
> SCN_RING_SIZE
) {
1532 scnoverrun(unit
, &sc
->sc_rotime
, "ring");
1533 get
+= n
- SCN_RING_SIZE
;
1535 sc
->sc_ring_overruns
++;
1540 if (tp
->t_state
& TS_TBLOCK
) {
1544 /* Race to keep ahead of incoming interrupts. */
1545 c
= sc
->sc_rbuf
[get
++ & SCN_RING_MASK
];
1547 sr
= c
>> 8; /* extract status */
1548 c
&= 0xff; /* leave just character */
1550 if (sr
& SR_OVERRUN
) {
1551 scnoverrun(unit
, &sc
->sc_fotime
, "fifo");
1552 sc
->sc_fifo_overruns
++;
1554 if (sr
& SR_PARITY
) {
1556 sc
->sc_parity_errors
++;
1558 if (sr
& SR_FRAME
) {
1560 sc
->sc_framing_errors
++;
1562 if (sr
& SR_BREAK
) {
1565 * See DDB_CHECK() comments in
1568 if (sc
->sc_isconsole
)
1575 (*tp
->t_linesw
->l_rint
) (c
, tp
);
1577 if (sc
->sc_rx_blocked
&& n
< SCN_RING_THRESH
) {
1579 sc
->sc_rx_blocked
= 0;
1580 SCN_OP_BIS(sc
, sc
->sc_op_rts
);
1591 /* Convert TIOCM_xxx bits to output port bits. */
1592 static unsigned char
1593 opbits(struct scn_softc
*sc
, int tioc_bits
)
1596 return ((((tioc_bits
) & TIOCM_DTR
) ? sc
->sc_op_dtr
: 0) |
1597 (((tioc_bits
) & TIOCM_RTS
) ? sc
->sc_op_rts
: 0));
1601 scnioctl(dev_t dev
, u_long cmd
, void *data
, int flags
, struct lwp
*l
)
1603 int unit
= DEV_UNIT(dev
);
1604 struct scn_softc
*sc
= SOFTC(unit
);
1605 struct tty
*tp
= sc
->sc_tty
;
1608 error
= (*tp
->t_linesw
->l_ioctl
) (tp
, cmd
, data
, flags
, l
);
1609 if (error
!= EPASSTHROUGH
)
1612 error
= ttioctl(tp
, cmd
, data
, flags
, l
);
1613 if (error
!= EPASSTHROUGH
)
1618 sc
->sc_chbase
[CH_CR
] = CR_CMD_START_BRK
;
1622 sc
->sc_chbase
[CH_CR
] = CR_CMD_STOP_BRK
;
1626 SCN_OP_BIS(sc
, sc
->sc_op_dtr
| sc
->sc_op_rts
);
1630 SCN_OP_BIC(sc
, sc
->sc_op_dtr
| sc
->sc_op_rts
);
1635 unsigned char sbits
, cbits
;
1638 sbits
= opbits(sc
, *(int *) data
);
1640 /* get bits to clear */
1641 cbits
= ~sbits
& (sc
->sc_op_dtr
| sc
->sc_op_rts
);
1645 SCN_OP_BIS(sc
, sbits
);
1648 SCN_OP_BIC(sc
, cbits
);
1655 SCN_OP_BIS(sc
, opbits(sc
, *(int *) data
));
1659 SCN_OP_BIC(sc
, opbits(sc
, *(int *) data
));
1664 unsigned char ip
, op
;
1667 ip
= sc
->sc_duart
->base
[DU_IP
];
1669 * XXX sigh; cannot get op current state!! even if
1670 * maintained in private, RTS is done in h/w!!
1676 if (ip
& sc
->sc_ip_dcd
)
1678 if (ip
& sc
->sc_ip_cts
)
1682 if (op
& sc
->sc_op_dtr
)
1684 if (op
& sc
->sc_op_rts
)
1688 *(int *) data
= bits
;
1695 if (sc
->sc_swflags
& SCN_SW_SOFTCAR
)
1696 bits
|= TIOCFLAG_SOFTCAR
;
1697 if (sc
->sc_swflags
& SCN_SW_CLOCAL
)
1698 bits
|= TIOCFLAG_CLOCAL
;
1699 if (sc
->sc_swflags
& SCN_SW_CRTSCTS
)
1700 bits
|= TIOCFLAG_CRTSCTS
;
1701 if (sc
->sc_swflags
& SCN_SW_MDMBUF
)
1702 bits
|= TIOCFLAG_MDMBUF
;
1704 *(int *) data
= bits
;
1708 int userbits
, driverbits
= 0;
1710 error
= kauth_authorize_device_tty(l
->l_cred
,
1711 KAUTH_DEVICE_TTY_PRIVSET
, tp
);
1715 userbits
= *(int *) data
;
1716 if (userbits
& TIOCFLAG_SOFTCAR
)
1717 driverbits
|= SCN_SW_SOFTCAR
;
1718 if (userbits
& TIOCFLAG_CLOCAL
)
1719 driverbits
|= SCN_SW_CLOCAL
;
1720 if (userbits
& TIOCFLAG_CRTSCTS
)
1721 driverbits
|= SCN_SW_CRTSCTS
;
1722 if (userbits
& TIOCFLAG_MDMBUF
)
1723 driverbits
|= SCN_SW_MDMBUF
;
1725 sc
->sc_swflags
= driverbits
;
1731 return (EPASSTHROUGH
);
1737 scnparam(struct tty
*tp
, struct termios
*t
)
1739 int cflag
= t
->c_cflag
;
1740 int unit
= DEV_UNIT(tp
->t_dev
);
1743 struct scn_softc
*sc
= SOFTC(unit
);
1745 /* Is this a hang up? */
1746 if (t
->c_ospeed
== B0
) {
1747 SCN_OP_BIC(sc
, sc
->sc_op_dtr
);
1748 /* leave DTR down. see comment in scnclose() -plb */
1754 if (cflag
& PARENB
) {
1755 if ((cflag
& PARODD
) == 0)
1769 switch (cflag
& CSIZE
) {
1785 if (cflag
& CCTS_OFLOW
)
1788 if (cflag
& CRTS_IFLOW
) {
1790 sc
->sc_rbhiwat
= SCN_RING_HIWAT
;
1795 error
= scn_config(unit
, sc
->sc_channel
, t
->c_ispeed
,
1796 t
->c_ospeed
, mr1
, mr2
);
1798 /* If successful, copy to tty */
1800 tp
->t_ispeed
= t
->c_ispeed
;
1801 tp
->t_ospeed
= t
->c_ospeed
;
1802 tp
->t_cflag
= cflag
;
1808 * Start or restart a transmission.
1811 scnstart(struct tty
*tp
)
1814 int unit
= DEV_UNIT(tp
->t_dev
);
1815 struct scn_softc
*sc
= SOFTC(unit
);
1818 if (tp
->t_state
& (TS_BUSY
| TS_TIMEOUT
| TS_TTSTOP
))
1823 tp
->t_state
|= TS_BUSY
;
1825 while (sc
->sc_chbase
[CH_SR
] & SR_TX_RDY
) {
1826 if ((c
= getc(&tp
->t_outq
)) == -1)
1828 sc
->sc_chbase
[CH_DAT
] = c
;
1830 sc
->sc_duart
->imr
|= (sc
->sc_tx_int
| sc
->sc_rx_int
);
1831 sc
->sc_duart
->base
[DU_IMR
] = sc
->sc_duart
->imr
;
1838 * Stop output on a line.
1842 scnstop(struct tty
*tp
, int flags
)
1847 if (tp
->t_state
& TS_BUSY
) {
1848 if ((tp
->t_state
& TS_TTSTOP
) == 0)
1849 tp
->t_state
|= TS_FLUSH
;
1855 * Following are all routines needed for SCN to act as console.
1859 scncnprobe(struct consdev
*cn
)
1864 scncnreinit(void *v
)
1866 volatile u_char
*du_base
=
1867 (volatile u_char
*)MIPS_PHYS_TO_KSEG1(0x1fb80004);
1870 SCN_CONSCHAN
? (OP_RTSB
| OP_DTRB
) : (OP_RTSA
| OP_DTRA
);
1874 scncninit(struct consdev
*cn
)
1878 /* initialize required fields */
1879 major
= cdevsw_lookup_major(&scn_cdevsw
);
1880 KASSERT(major
!= NODEV
);
1881 cn
->cn_dev
= makedev(major
, SCN_CONSOLE
);
1882 cn
->cn_pri
= CN_REMOTE
;
1884 scninit(cn
->cn_dev
, scnconsrate
);
1887 /* Used by scncninit and kgdb startup. */
1889 scninit(dev_t dev
, int rate
)
1891 /* XXX - maintain PROM's settings */
1893 volatile u_char
*du_base
=
1894 (volatile u_char
*)MIPS_PHYS_TO_KSEG1(0x1fb80004);
1895 int unit
= DEV_UNIT(dev
);
1898 SCN_CONSCHAN
? (OP_RTSB
| OP_DTRB
) : (OP_RTSA
| OP_DTRA
);
1899 scn_config(unit
, SCN_CONSCHAN
, rate
, rate
,
1900 MR1_PNONE
| MR1_CS8
, MR2_STOP1
);
1906 * Console kernel input character routine.
1909 scncngetc(dev_t dev
)
1911 volatile u_char
*ch_base
=
1912 (volatile u_char
*)MIPS_PHYS_TO_KSEG1(0x1fb80004);
1918 while ((ch_base
[CH_SR
] & SR_RX_RDY
) == 0)
1920 c
= ch_base
[CH_DAT
];
1927 scncnpollc(dev_t dev
, int on
)
1932 * Console kernel output character routine.
1935 scncnputc(dev_t dev
, int c
)
1937 volatile u_char
*ch_base
=
1938 (volatile u_char
*)MIPS_PHYS_TO_KSEG1(0x1fb80004);
1939 volatile u_char
*du_base
=
1940 (volatile u_char
*)MIPS_PHYS_TO_KSEG1(0x1fb80004);
1946 scncnputc(dev
, '\r');
1948 while ((ch_base
[CH_SR
] & SR_TX_RDY
) == 0)
1950 ch_base
[CH_DAT
] = c
;
1951 while ((ch_base
[CH_SR
] & SR_TX_RDY
) == 0)