sci.c revision 1.26.4.2 1 1.26.4.2 nathanw /* $NetBSD: sci.c,v 1.26.4.2 2002/08/27 23:45:23 nathanw Exp $ */
2 1.26.4.2 nathanw
3 1.26.4.2 nathanw /*-
4 1.26.4.2 nathanw * Copyright (C) 1999 T.Horiuchi and SAITOH Masanobu. All rights reserved.
5 1.26.4.2 nathanw *
6 1.26.4.2 nathanw * Redistribution and use in source and binary forms, with or without
7 1.26.4.2 nathanw * modification, are permitted provided that the following conditions
8 1.26.4.2 nathanw * are met:
9 1.26.4.2 nathanw * 1. Redistributions of source code must retain the above copyright
10 1.26.4.2 nathanw * notice, this list of conditions and the following disclaimer.
11 1.26.4.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
12 1.26.4.2 nathanw * notice, this list of conditions and the following disclaimer in the
13 1.26.4.2 nathanw * documentation and/or other materials provided with the distribution.
14 1.26.4.2 nathanw * 3. The name of the author may not be used to endorse or promote products
15 1.26.4.2 nathanw * derived from this software without specific prior written permission.
16 1.26.4.2 nathanw *
17 1.26.4.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 1.26.4.2 nathanw * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 1.26.4.2 nathanw * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 1.26.4.2 nathanw * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 1.26.4.2 nathanw * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 1.26.4.2 nathanw * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 1.26.4.2 nathanw * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 1.26.4.2 nathanw * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 1.26.4.2 nathanw * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 1.26.4.2 nathanw * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 1.26.4.2 nathanw */
28 1.26.4.2 nathanw
29 1.26.4.2 nathanw /*-
30 1.26.4.2 nathanw * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
31 1.26.4.2 nathanw * All rights reserved.
32 1.26.4.2 nathanw *
33 1.26.4.2 nathanw * This code is derived from software contributed to The NetBSD Foundation
34 1.26.4.2 nathanw * by Charles M. Hannum.
35 1.26.4.2 nathanw *
36 1.26.4.2 nathanw * Redistribution and use in source and binary forms, with or without
37 1.26.4.2 nathanw * modification, are permitted provided that the following conditions
38 1.26.4.2 nathanw * are met:
39 1.26.4.2 nathanw * 1. Redistributions of source code must retain the above copyright
40 1.26.4.2 nathanw * notice, this list of conditions and the following disclaimer.
41 1.26.4.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
42 1.26.4.2 nathanw * notice, this list of conditions and the following disclaimer in the
43 1.26.4.2 nathanw * documentation and/or other materials provided with the distribution.
44 1.26.4.2 nathanw * 3. All advertising materials mentioning features or use of this software
45 1.26.4.2 nathanw * must display the following acknowledgement:
46 1.26.4.2 nathanw * This product includes software developed by the NetBSD
47 1.26.4.2 nathanw * Foundation, Inc. and its contributors.
48 1.26.4.2 nathanw * 4. Neither the name of The NetBSD Foundation nor the names of its
49 1.26.4.2 nathanw * contributors may be used to endorse or promote products derived
50 1.26.4.2 nathanw * from this software without specific prior written permission.
51 1.26.4.2 nathanw *
52 1.26.4.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
53 1.26.4.2 nathanw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
54 1.26.4.2 nathanw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
55 1.26.4.2 nathanw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
56 1.26.4.2 nathanw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
57 1.26.4.2 nathanw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
58 1.26.4.2 nathanw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
59 1.26.4.2 nathanw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
60 1.26.4.2 nathanw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
61 1.26.4.2 nathanw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
62 1.26.4.2 nathanw * POSSIBILITY OF SUCH DAMAGE.
63 1.26.4.2 nathanw */
64 1.26.4.2 nathanw
65 1.26.4.2 nathanw /*
66 1.26.4.2 nathanw * Copyright (c) 1991 The Regents of the University of California.
67 1.26.4.2 nathanw * All rights reserved.
68 1.26.4.2 nathanw *
69 1.26.4.2 nathanw * Redistribution and use in source and binary forms, with or without
70 1.26.4.2 nathanw * modification, are permitted provided that the following conditions
71 1.26.4.2 nathanw * are met:
72 1.26.4.2 nathanw * 1. Redistributions of source code must retain the above copyright
73 1.26.4.2 nathanw * notice, this list of conditions and the following disclaimer.
74 1.26.4.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
75 1.26.4.2 nathanw * notice, this list of conditions and the following disclaimer in the
76 1.26.4.2 nathanw * documentation and/or other materials provided with the distribution.
77 1.26.4.2 nathanw * 3. All advertising materials mentioning features or use of this software
78 1.26.4.2 nathanw * must display the following acknowledgement:
79 1.26.4.2 nathanw * This product includes software developed by the University of
80 1.26.4.2 nathanw * California, Berkeley and its contributors.
81 1.26.4.2 nathanw * 4. Neither the name of the University nor the names of its contributors
82 1.26.4.2 nathanw * may be used to endorse or promote products derived from this software
83 1.26.4.2 nathanw * without specific prior written permission.
84 1.26.4.2 nathanw *
85 1.26.4.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
86 1.26.4.2 nathanw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
87 1.26.4.2 nathanw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
88 1.26.4.2 nathanw * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
89 1.26.4.2 nathanw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
90 1.26.4.2 nathanw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
91 1.26.4.2 nathanw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
92 1.26.4.2 nathanw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
93 1.26.4.2 nathanw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
94 1.26.4.2 nathanw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
95 1.26.4.2 nathanw * SUCH DAMAGE.
96 1.26.4.2 nathanw *
97 1.26.4.2 nathanw * @(#)com.c 7.5 (Berkeley) 5/16/91
98 1.26.4.2 nathanw */
99 1.26.4.2 nathanw
100 1.26.4.2 nathanw /*
101 1.26.4.2 nathanw * SH internal serial driver
102 1.26.4.2 nathanw *
103 1.26.4.2 nathanw * This code is derived from both z8530tty.c and com.c
104 1.26.4.2 nathanw */
105 1.26.4.2 nathanw
106 1.26.4.2 nathanw #include "opt_kgdb.h"
107 1.26.4.2 nathanw #include "opt_sci.h"
108 1.26.4.2 nathanw
109 1.26.4.2 nathanw #include <sys/param.h>
110 1.26.4.2 nathanw #include <sys/systm.h>
111 1.26.4.2 nathanw #include <sys/tty.h>
112 1.26.4.2 nathanw #include <sys/proc.h>
113 1.26.4.2 nathanw #include <sys/conf.h>
114 1.26.4.2 nathanw #include <sys/file.h>
115 1.26.4.2 nathanw #include <sys/syslog.h>
116 1.26.4.2 nathanw #include <sys/kernel.h>
117 1.26.4.2 nathanw #include <sys/device.h>
118 1.26.4.2 nathanw #include <sys/malloc.h>
119 1.26.4.2 nathanw
120 1.26.4.2 nathanw #include <dev/cons.h>
121 1.26.4.2 nathanw
122 1.26.4.2 nathanw #include <sh3/clock.h>
123 1.26.4.2 nathanw #include <sh3/scireg.h>
124 1.26.4.2 nathanw #include <sh3/pfcreg.h>
125 1.26.4.2 nathanw #include <sh3/tmureg.h>
126 1.26.4.2 nathanw #include <sh3/exception.h>
127 1.26.4.2 nathanw #include <machine/intr.h>
128 1.26.4.2 nathanw
129 1.26.4.2 nathanw static void scistart(struct tty *);
130 1.26.4.2 nathanw static int sciparam(struct tty *, struct termios *);
131 1.26.4.2 nathanw
132 1.26.4.2 nathanw void scicnprobe(struct consdev *);
133 1.26.4.2 nathanw void scicninit(struct consdev *);
134 1.26.4.2 nathanw void scicnputc(dev_t, int);
135 1.26.4.2 nathanw int scicngetc(dev_t);
136 1.26.4.2 nathanw void scicnpoolc(dev_t, int);
137 1.26.4.2 nathanw int sciintr(void *);
138 1.26.4.2 nathanw
139 1.26.4.2 nathanw struct sci_softc {
140 1.26.4.2 nathanw struct device sc_dev; /* boilerplate */
141 1.26.4.2 nathanw struct tty *sc_tty;
142 1.26.4.2 nathanw void *sc_si;
143 1.26.4.2 nathanw struct callout sc_diag_ch;
144 1.26.4.2 nathanw
145 1.26.4.2 nathanw #if 0
146 1.26.4.2 nathanw bus_space_tag_t sc_iot; /* ISA i/o space identifier */
147 1.26.4.2 nathanw bus_space_handle_t sc_ioh; /* ISA io handle */
148 1.26.4.2 nathanw
149 1.26.4.2 nathanw int sc_drq;
150 1.26.4.2 nathanw
151 1.26.4.2 nathanw int sc_frequency;
152 1.26.4.2 nathanw #endif
153 1.26.4.2 nathanw
154 1.26.4.2 nathanw u_int sc_overflows,
155 1.26.4.2 nathanw sc_floods,
156 1.26.4.2 nathanw sc_errors; /* number of retries so far */
157 1.26.4.2 nathanw u_char sc_status[7]; /* copy of registers */
158 1.26.4.2 nathanw
159 1.26.4.2 nathanw int sc_hwflags;
160 1.26.4.2 nathanw int sc_swflags;
161 1.26.4.2 nathanw u_int sc_fifolen; /* XXX always 0? */
162 1.26.4.2 nathanw
163 1.26.4.2 nathanw u_int sc_r_hiwat,
164 1.26.4.2 nathanw sc_r_lowat;
165 1.26.4.2 nathanw u_char *volatile sc_rbget,
166 1.26.4.2 nathanw *volatile sc_rbput;
167 1.26.4.2 nathanw volatile u_int sc_rbavail;
168 1.26.4.2 nathanw u_char *sc_rbuf,
169 1.26.4.2 nathanw *sc_ebuf;
170 1.26.4.2 nathanw
171 1.26.4.2 nathanw u_char *sc_tba; /* transmit buffer address */
172 1.26.4.2 nathanw u_int sc_tbc, /* transmit byte count */
173 1.26.4.2 nathanw sc_heldtbc;
174 1.26.4.2 nathanw
175 1.26.4.2 nathanw volatile u_char sc_rx_flags, /* receiver blocked */
176 1.26.4.2 nathanw #define RX_TTY_BLOCKED 0x01
177 1.26.4.2 nathanw #define RX_TTY_OVERFLOWED 0x02
178 1.26.4.2 nathanw #define RX_IBUF_BLOCKED 0x04
179 1.26.4.2 nathanw #define RX_IBUF_OVERFLOWED 0x08
180 1.26.4.2 nathanw #define RX_ANY_BLOCK 0x0f
181 1.26.4.2 nathanw sc_tx_busy, /* working on an output chunk */
182 1.26.4.2 nathanw sc_tx_done, /* done with one output chunk */
183 1.26.4.2 nathanw sc_tx_stopped, /* H/W level stop (lost CTS) */
184 1.26.4.2 nathanw sc_st_check, /* got a status interrupt */
185 1.26.4.2 nathanw sc_rx_ready;
186 1.26.4.2 nathanw
187 1.26.4.2 nathanw volatile u_char sc_heldchange;
188 1.26.4.2 nathanw };
189 1.26.4.2 nathanw
190 1.26.4.2 nathanw /* controller driver configuration */
191 1.26.4.2 nathanw static int sci_match(struct device *, struct cfdata *, void *);
192 1.26.4.2 nathanw static void sci_attach(struct device *, struct device *, void *);
193 1.26.4.2 nathanw
194 1.26.4.2 nathanw void sci_break(struct sci_softc *, int);
195 1.26.4.2 nathanw void sci_iflush(struct sci_softc *);
196 1.26.4.2 nathanw
197 1.26.4.2 nathanw #define integrate static inline
198 1.26.4.2 nathanw #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
199 1.26.4.2 nathanw void scisoft(void *);
200 1.26.4.2 nathanw #else
201 1.26.4.2 nathanw #ifndef __NO_SOFT_SERIAL_INTERRUPT
202 1.26.4.2 nathanw void scisoft(void);
203 1.26.4.2 nathanw #else
204 1.26.4.2 nathanw void scisoft(void *);
205 1.26.4.2 nathanw #endif
206 1.26.4.2 nathanw #endif
207 1.26.4.2 nathanw integrate void sci_rxsoft(struct sci_softc *, struct tty *);
208 1.26.4.2 nathanw integrate void sci_txsoft(struct sci_softc *, struct tty *);
209 1.26.4.2 nathanw integrate void sci_stsoft(struct sci_softc *, struct tty *);
210 1.26.4.2 nathanw integrate void sci_schedrx(struct sci_softc *);
211 1.26.4.2 nathanw void scidiag(void *);
212 1.26.4.2 nathanw
213 1.26.4.2 nathanw #define SCIUNIT_MASK 0x7ffff
214 1.26.4.2 nathanw #define SCIDIALOUT_MASK 0x80000
215 1.26.4.2 nathanw
216 1.26.4.2 nathanw #define SCIUNIT(x) (minor(x) & SCIUNIT_MASK)
217 1.26.4.2 nathanw #define SCIDIALOUT(x) (minor(x) & SCIDIALOUT_MASK)
218 1.26.4.2 nathanw
219 1.26.4.2 nathanw /* Macros to clear/set/test flags. */
220 1.26.4.2 nathanw #define SET(t, f) (t) |= (f)
221 1.26.4.2 nathanw #define CLR(t, f) (t) &= ~(f)
222 1.26.4.2 nathanw #define ISSET(t, f) ((t) & (f))
223 1.26.4.2 nathanw
224 1.26.4.2 nathanw /* Hardware flag masks */
225 1.26.4.2 nathanw #define SCI_HW_NOIEN 0x01
226 1.26.4.2 nathanw #define SCI_HW_FIFO 0x02
227 1.26.4.2 nathanw #define SCI_HW_FLOW 0x08
228 1.26.4.2 nathanw #define SCI_HW_DEV_OK 0x20
229 1.26.4.2 nathanw #define SCI_HW_CONSOLE 0x40
230 1.26.4.2 nathanw #define SCI_HW_KGDB 0x80
231 1.26.4.2 nathanw
232 1.26.4.2 nathanw /* Buffer size for character buffer */
233 1.26.4.2 nathanw #define SCI_RING_SIZE 2048
234 1.26.4.2 nathanw
235 1.26.4.2 nathanw /* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */
236 1.26.4.2 nathanw u_int sci_rbuf_hiwat = (SCI_RING_SIZE * 1) / 4;
237 1.26.4.2 nathanw u_int sci_rbuf_lowat = (SCI_RING_SIZE * 3) / 4;
238 1.26.4.2 nathanw
239 1.26.4.2 nathanw #define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */
240 1.26.4.2 nathanw int sciconscflag = CONMODE;
241 1.26.4.2 nathanw int sciisconsole = 0;
242 1.26.4.2 nathanw
243 1.26.4.2 nathanw #ifdef SCICN_SPEED
244 1.26.4.2 nathanw int scicn_speed = SCICN_SPEED;
245 1.26.4.2 nathanw #else
246 1.26.4.2 nathanw int scicn_speed = 9600;
247 1.26.4.2 nathanw #endif
248 1.26.4.2 nathanw
249 1.26.4.2 nathanw #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
250 1.26.4.2 nathanw
251 1.26.4.2 nathanw #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
252 1.26.4.2 nathanw #ifdef __NO_SOFT_SERIAL_INTERRUPT
253 1.26.4.2 nathanw volatile int sci_softintr_scheduled;
254 1.26.4.2 nathanw struct callout sci_soft_ch = CALLOUT_INITIALIZER;
255 1.26.4.2 nathanw #endif
256 1.26.4.2 nathanw #endif
257 1.26.4.2 nathanw
258 1.26.4.2 nathanw u_int sci_rbuf_size = SCI_RING_SIZE;
259 1.26.4.2 nathanw
260 1.26.4.2 nathanw struct cfattach sci_ca = {
261 1.26.4.2 nathanw sizeof(struct sci_softc), sci_match, sci_attach
262 1.26.4.2 nathanw };
263 1.26.4.2 nathanw
264 1.26.4.2 nathanw extern struct cfdriver sci_cd;
265 1.26.4.2 nathanw
266 1.26.4.2 nathanw cdev_decl(sci);
267 1.26.4.2 nathanw
268 1.26.4.2 nathanw void InitializeSci (unsigned int);
269 1.26.4.2 nathanw
270 1.26.4.2 nathanw /*
271 1.26.4.2 nathanw * following functions are debugging prupose only
272 1.26.4.2 nathanw */
273 1.26.4.2 nathanw #define CR 0x0D
274 1.26.4.2 nathanw #define I2C_ADRS (*(volatile unsigned int *)0xa8000000)
275 1.26.4.2 nathanw #define USART_ON (unsigned int)~0x08
276 1.26.4.2 nathanw
277 1.26.4.2 nathanw void sci_putc(unsigned char);
278 1.26.4.2 nathanw unsigned char sci_getc(void);
279 1.26.4.2 nathanw int SciErrCheck(void);
280 1.26.4.2 nathanw
281 1.26.4.2 nathanw /*
282 1.26.4.2 nathanw * InitializeSci
283 1.26.4.2 nathanw * : unsigned int bps;
284 1.26.4.2 nathanw * : SCI(Serial Communication Interface)
285 1.26.4.2 nathanw */
286 1.26.4.2 nathanw
287 1.26.4.2 nathanw void
288 1.26.4.2 nathanw InitializeSci(unsigned int bps)
289 1.26.4.2 nathanw {
290 1.26.4.2 nathanw
291 1.26.4.2 nathanw /* Initialize SCR */
292 1.26.4.2 nathanw SHREG_SCSCR = 0x00;
293 1.26.4.2 nathanw
294 1.26.4.2 nathanw /* Serial Mode Register */
295 1.26.4.2 nathanw SHREG_SCSMR = 0x00; /* Async,8bit,NonParity,Even,1Stop,NoMulti */
296 1.26.4.2 nathanw
297 1.26.4.2 nathanw /* Bit Rate Register */
298 1.26.4.2 nathanw SHREG_SCBRR = divrnd(sh_clock_get_pclock(), 32 * bps) - 1;
299 1.26.4.2 nathanw
300 1.26.4.2 nathanw /*
301 1.26.4.2 nathanw * wait 1mSec, because Send/Recv must begin 1 bit period after
302 1.26.4.2 nathanw * BRR is set.
303 1.26.4.2 nathanw */
304 1.26.4.2 nathanw delay(1000);
305 1.26.4.2 nathanw
306 1.26.4.2 nathanw /* Send permission, Receive permission ON */
307 1.26.4.2 nathanw SHREG_SCSCR = SCSCR_TE | SCSCR_RE;
308 1.26.4.2 nathanw
309 1.26.4.2 nathanw /* Serial Status Register */
310 1.26.4.2 nathanw SHREG_SCSSR &= SCSSR_TDRE; /* Clear Status */
311 1.26.4.2 nathanw
312 1.26.4.2 nathanw #if 0
313 1.26.4.2 nathanw I2C_ADRS &= ~0x08; /* enable RS-232C */
314 1.26.4.2 nathanw #endif
315 1.26.4.2 nathanw }
316 1.26.4.2 nathanw
317 1.26.4.2 nathanw
318 1.26.4.2 nathanw /*
319 1.26.4.2 nathanw * sci_putc
320 1.26.4.2 nathanw * : unsigned char c;
321 1.26.4.2 nathanw */
322 1.26.4.2 nathanw void
323 1.26.4.2 nathanw sci_putc(unsigned char c)
324 1.26.4.2 nathanw {
325 1.26.4.2 nathanw
326 1.26.4.2 nathanw /* wait for ready */
327 1.26.4.2 nathanw while ((SHREG_SCSSR & SCSSR_TDRE) == NULL)
328 1.26.4.2 nathanw ;
329 1.26.4.2 nathanw
330 1.26.4.2 nathanw /* write send data to send register */
331 1.26.4.2 nathanw SHREG_SCTDR = c;
332 1.26.4.2 nathanw
333 1.26.4.2 nathanw /* clear ready flag */
334 1.26.4.2 nathanw SHREG_SCSSR &= ~SCSSR_TDRE;
335 1.26.4.2 nathanw }
336 1.26.4.2 nathanw
337 1.26.4.2 nathanw /*
338 1.26.4.2 nathanw * : SciErrCheck
339 1.26.4.2 nathanw * 0x20 = over run
340 1.26.4.2 nathanw * 0x10 = frame error
341 1.26.4.2 nathanw * 0x80 = parity error
342 1.26.4.2 nathanw */
343 1.26.4.2 nathanw int
344 1.26.4.2 nathanw SciErrCheck(void)
345 1.26.4.2 nathanw {
346 1.26.4.2 nathanw
347 1.26.4.2 nathanw return(SHREG_SCSSR & (SCSSR_ORER | SCSSR_FER | SCSSR_PER));
348 1.26.4.2 nathanw }
349 1.26.4.2 nathanw
350 1.26.4.2 nathanw /*
351 1.26.4.2 nathanw * sci_getc
352 1.26.4.2 nathanw */
353 1.26.4.2 nathanw unsigned char
354 1.26.4.2 nathanw sci_getc(void)
355 1.26.4.2 nathanw {
356 1.26.4.2 nathanw unsigned char c, err_c;
357 1.26.4.2 nathanw
358 1.26.4.2 nathanw while (((err_c = SHREG_SCSSR)
359 1.26.4.2 nathanw & (SCSSR_RDRF | SCSSR_ORER | SCSSR_FER | SCSSR_PER)) == 0)
360 1.26.4.2 nathanw ;
361 1.26.4.2 nathanw if ((err_c & (SCSSR_ORER | SCSSR_FER | SCSSR_PER)) != 0) {
362 1.26.4.2 nathanw SHREG_SCSSR &= ~(SCSSR_ORER | SCSSR_FER | SCSSR_PER);
363 1.26.4.2 nathanw return(err_c |= 0x80);
364 1.26.4.2 nathanw }
365 1.26.4.2 nathanw
366 1.26.4.2 nathanw c = SHREG_SCRDR;
367 1.26.4.2 nathanw
368 1.26.4.2 nathanw SHREG_SCSSR &= ~SCSSR_RDRF;
369 1.26.4.2 nathanw
370 1.26.4.2 nathanw return(c);
371 1.26.4.2 nathanw }
372 1.26.4.2 nathanw
373 1.26.4.2 nathanw #if 0
374 1.26.4.2 nathanw #define SCI_MAX_UNITS 2
375 1.26.4.2 nathanw #else
376 1.26.4.2 nathanw #define SCI_MAX_UNITS 1
377 1.26.4.2 nathanw #endif
378 1.26.4.2 nathanw
379 1.26.4.2 nathanw
380 1.26.4.2 nathanw static int
381 1.26.4.2 nathanw sci_match(struct device *parent, struct cfdata *cfp, void *aux)
382 1.26.4.2 nathanw {
383 1.26.4.2 nathanw
384 1.26.4.2 nathanw if (strcmp(cfp->cf_driver->cd_name, "sci")
385 1.26.4.2 nathanw || cfp->cf_unit >= SCI_MAX_UNITS) //XXX __BROKEN_CONFIG_UNIT_USAGE
386 1.26.4.2 nathanw return 0;
387 1.26.4.2 nathanw
388 1.26.4.2 nathanw return 1;
389 1.26.4.2 nathanw }
390 1.26.4.2 nathanw
391 1.26.4.2 nathanw static void
392 1.26.4.2 nathanw sci_attach(struct device *parent, struct device *self, void *aux)
393 1.26.4.2 nathanw {
394 1.26.4.2 nathanw struct sci_softc *sc = (struct sci_softc *)self;
395 1.26.4.2 nathanw struct tty *tp;
396 1.26.4.2 nathanw
397 1.26.4.2 nathanw sc->sc_hwflags = 0; /* XXX */
398 1.26.4.2 nathanw sc->sc_swflags = 0; /* XXX */
399 1.26.4.2 nathanw sc->sc_fifolen = 0; /* XXX */
400 1.26.4.2 nathanw
401 1.26.4.2 nathanw if (sciisconsole) {
402 1.26.4.2 nathanw SET(sc->sc_hwflags, SCI_HW_CONSOLE);
403 1.26.4.2 nathanw SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
404 1.26.4.2 nathanw printf("\n%s: console\n", sc->sc_dev.dv_xname);
405 1.26.4.2 nathanw } else {
406 1.26.4.2 nathanw InitializeSci(9600);
407 1.26.4.2 nathanw printf("\n");
408 1.26.4.2 nathanw }
409 1.26.4.2 nathanw
410 1.26.4.2 nathanw callout_init(&sc->sc_diag_ch);
411 1.26.4.2 nathanw
412 1.26.4.2 nathanw intc_intr_establish(SH_INTEVT_SCI_ERI, IST_LEVEL, IPL_SERIAL, sciintr,
413 1.26.4.2 nathanw sc);
414 1.26.4.2 nathanw intc_intr_establish(SH_INTEVT_SCI_RXI, IST_LEVEL, IPL_SERIAL, sciintr,
415 1.26.4.2 nathanw sc);
416 1.26.4.2 nathanw intc_intr_establish(SH_INTEVT_SCI_TXI, IST_LEVEL, IPL_SERIAL, sciintr,
417 1.26.4.2 nathanw sc);
418 1.26.4.2 nathanw intc_intr_establish(SH_INTEVT_SCI_TEI, IST_LEVEL, IPL_SERIAL, sciintr,
419 1.26.4.2 nathanw sc);
420 1.26.4.2 nathanw
421 1.26.4.2 nathanw #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
422 1.26.4.2 nathanw sc->sc_si = softintr_establish(IPL_SOFTSERIAL, scisoft, sc);
423 1.26.4.2 nathanw #endif
424 1.26.4.2 nathanw SET(sc->sc_hwflags, SCI_HW_DEV_OK);
425 1.26.4.2 nathanw
426 1.26.4.2 nathanw tp = ttymalloc();
427 1.26.4.2 nathanw tp->t_oproc = scistart;
428 1.26.4.2 nathanw tp->t_param = sciparam;
429 1.26.4.2 nathanw tp->t_hwiflow = NULL;
430 1.26.4.2 nathanw
431 1.26.4.2 nathanw sc->sc_tty = tp;
432 1.26.4.2 nathanw sc->sc_rbuf = malloc(sci_rbuf_size << 1, M_DEVBUF, M_NOWAIT);
433 1.26.4.2 nathanw if (sc->sc_rbuf == NULL) {
434 1.26.4.2 nathanw printf("%s: unable to allocate ring buffer\n",
435 1.26.4.2 nathanw sc->sc_dev.dv_xname);
436 1.26.4.2 nathanw return;
437 1.26.4.2 nathanw }
438 1.26.4.2 nathanw sc->sc_ebuf = sc->sc_rbuf + (sci_rbuf_size << 1);
439 1.26.4.2 nathanw
440 1.26.4.2 nathanw tty_attach(tp);
441 1.26.4.2 nathanw }
442 1.26.4.2 nathanw
443 1.26.4.2 nathanw /*
444 1.26.4.2 nathanw * Start or restart transmission.
445 1.26.4.2 nathanw */
446 1.26.4.2 nathanw static void
447 1.26.4.2 nathanw scistart(struct tty *tp)
448 1.26.4.2 nathanw {
449 1.26.4.2 nathanw struct sci_softc *sc = sci_cd.cd_devs[SCIUNIT(tp->t_dev)];
450 1.26.4.2 nathanw int s;
451 1.26.4.2 nathanw
452 1.26.4.2 nathanw s = spltty();
453 1.26.4.2 nathanw if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
454 1.26.4.2 nathanw goto out;
455 1.26.4.2 nathanw if (sc->sc_tx_stopped)
456 1.26.4.2 nathanw goto out;
457 1.26.4.2 nathanw
458 1.26.4.2 nathanw if (tp->t_outq.c_cc <= tp->t_lowat) {
459 1.26.4.2 nathanw if (ISSET(tp->t_state, TS_ASLEEP)) {
460 1.26.4.2 nathanw CLR(tp->t_state, TS_ASLEEP);
461 1.26.4.2 nathanw wakeup(&tp->t_outq);
462 1.26.4.2 nathanw }
463 1.26.4.2 nathanw selwakeup(&tp->t_wsel);
464 1.26.4.2 nathanw if (tp->t_outq.c_cc == 0)
465 1.26.4.2 nathanw goto out;
466 1.26.4.2 nathanw }
467 1.26.4.2 nathanw
468 1.26.4.2 nathanw /* Grab the first contiguous region of buffer space. */
469 1.26.4.2 nathanw {
470 1.26.4.2 nathanw u_char *tba;
471 1.26.4.2 nathanw int tbc;
472 1.26.4.2 nathanw
473 1.26.4.2 nathanw tba = tp->t_outq.c_cf;
474 1.26.4.2 nathanw tbc = ndqb(&tp->t_outq, 0);
475 1.26.4.2 nathanw
476 1.26.4.2 nathanw (void)splserial();
477 1.26.4.2 nathanw
478 1.26.4.2 nathanw sc->sc_tba = tba;
479 1.26.4.2 nathanw sc->sc_tbc = tbc;
480 1.26.4.2 nathanw }
481 1.26.4.2 nathanw
482 1.26.4.2 nathanw SET(tp->t_state, TS_BUSY);
483 1.26.4.2 nathanw sc->sc_tx_busy = 1;
484 1.26.4.2 nathanw
485 1.26.4.2 nathanw /* Enable transmit completion interrupts if necessary. */
486 1.26.4.2 nathanw SHREG_SCSCR |= SCSCR_TIE | SCSCR_RIE;
487 1.26.4.2 nathanw
488 1.26.4.2 nathanw /* Output the first byte of the contiguous buffer. */
489 1.26.4.2 nathanw {
490 1.26.4.2 nathanw if (sc->sc_tbc > 0) {
491 1.26.4.2 nathanw sci_putc(*(sc->sc_tba));
492 1.26.4.2 nathanw sc->sc_tba++;
493 1.26.4.2 nathanw sc->sc_tbc--;
494 1.26.4.2 nathanw }
495 1.26.4.2 nathanw }
496 1.26.4.2 nathanw out:
497 1.26.4.2 nathanw splx(s);
498 1.26.4.2 nathanw return;
499 1.26.4.2 nathanw }
500 1.26.4.2 nathanw
501 1.26.4.2 nathanw /*
502 1.26.4.2 nathanw * Set SCI tty parameters from termios.
503 1.26.4.2 nathanw * XXX - Should just copy the whole termios after
504 1.26.4.2 nathanw * making sure all the changes could be done.
505 1.26.4.2 nathanw */
506 1.26.4.2 nathanw static int
507 1.26.4.2 nathanw sciparam(struct tty *tp, struct termios *t)
508 1.26.4.2 nathanw {
509 1.26.4.2 nathanw struct sci_softc *sc = sci_cd.cd_devs[SCIUNIT(tp->t_dev)];
510 1.26.4.2 nathanw int ospeed = t->c_ospeed;
511 1.26.4.2 nathanw int s;
512 1.26.4.2 nathanw
513 1.26.4.2 nathanw if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
514 1.26.4.2 nathanw return (EIO);
515 1.26.4.2 nathanw
516 1.26.4.2 nathanw /* Check requested parameters. */
517 1.26.4.2 nathanw if (ospeed < 0)
518 1.26.4.2 nathanw return (EINVAL);
519 1.26.4.2 nathanw if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
520 1.26.4.2 nathanw return (EINVAL);
521 1.26.4.2 nathanw
522 1.26.4.2 nathanw /*
523 1.26.4.2 nathanw * For the console, always force CLOCAL and !HUPCL, so that the port
524 1.26.4.2 nathanw * is always active.
525 1.26.4.2 nathanw */
526 1.26.4.2 nathanw if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
527 1.26.4.2 nathanw ISSET(sc->sc_hwflags, SCI_HW_CONSOLE)) {
528 1.26.4.2 nathanw SET(t->c_cflag, CLOCAL);
529 1.26.4.2 nathanw CLR(t->c_cflag, HUPCL);
530 1.26.4.2 nathanw }
531 1.26.4.2 nathanw
532 1.26.4.2 nathanw /*
533 1.26.4.2 nathanw * If there were no changes, don't do anything. This avoids dropping
534 1.26.4.2 nathanw * input and improves performance when all we did was frob things like
535 1.26.4.2 nathanw * VMIN and VTIME.
536 1.26.4.2 nathanw */
537 1.26.4.2 nathanw if (tp->t_ospeed == t->c_ospeed &&
538 1.26.4.2 nathanw tp->t_cflag == t->c_cflag)
539 1.26.4.2 nathanw return (0);
540 1.26.4.2 nathanw
541 1.26.4.2 nathanw #if 0
542 1.26.4.2 nathanw /* XXX (msaitoh) */
543 1.26.4.2 nathanw lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag);
544 1.26.4.2 nathanw #endif
545 1.26.4.2 nathanw
546 1.26.4.2 nathanw s = splserial();
547 1.26.4.2 nathanw
548 1.26.4.2 nathanw /*
549 1.26.4.2 nathanw * Set the FIFO threshold based on the receive speed.
550 1.26.4.2 nathanw *
551 1.26.4.2 nathanw * * If it's a low speed, it's probably a mouse or some other
552 1.26.4.2 nathanw * interactive device, so set the threshold low.
553 1.26.4.2 nathanw * * If it's a high speed, trim the trigger level down to prevent
554 1.26.4.2 nathanw * overflows.
555 1.26.4.2 nathanw * * Otherwise set it a bit higher.
556 1.26.4.2 nathanw */
557 1.26.4.2 nathanw #if 0
558 1.26.4.2 nathanw /* XXX (msaitoh) */
559 1.26.4.2 nathanw if (ISSET(sc->sc_hwflags, SCI_HW_HAYESP))
560 1.26.4.2 nathanw sc->sc_fifo = FIFO_DMA_MODE | FIFO_ENABLE | FIFO_TRIGGER_8;
561 1.26.4.2 nathanw else if (ISSET(sc->sc_hwflags, SCI_HW_FIFO))
562 1.26.4.2 nathanw sc->sc_fifo = FIFO_ENABLE |
563 1.26.4.2 nathanw (t->c_ospeed <= 1200 ? FIFO_TRIGGER_1 :
564 1.26.4.2 nathanw t->c_ospeed <= 38400 ? FIFO_TRIGGER_8 : FIFO_TRIGGER_4);
565 1.26.4.2 nathanw else
566 1.26.4.2 nathanw sc->sc_fifo = 0;
567 1.26.4.2 nathanw #endif
568 1.26.4.2 nathanw
569 1.26.4.2 nathanw /* And copy to tty. */
570 1.26.4.2 nathanw tp->t_ispeed = 0;
571 1.26.4.2 nathanw tp->t_ospeed = t->c_ospeed;
572 1.26.4.2 nathanw tp->t_cflag = t->c_cflag;
573 1.26.4.2 nathanw
574 1.26.4.2 nathanw if (!sc->sc_heldchange) {
575 1.26.4.2 nathanw if (sc->sc_tx_busy) {
576 1.26.4.2 nathanw sc->sc_heldtbc = sc->sc_tbc;
577 1.26.4.2 nathanw sc->sc_tbc = 0;
578 1.26.4.2 nathanw sc->sc_heldchange = 1;
579 1.26.4.2 nathanw }
580 1.26.4.2 nathanw #if 0
581 1.26.4.2 nathanw /* XXX (msaitoh) */
582 1.26.4.2 nathanw else
583 1.26.4.2 nathanw sci_loadchannelregs(sc);
584 1.26.4.2 nathanw #endif
585 1.26.4.2 nathanw }
586 1.26.4.2 nathanw
587 1.26.4.2 nathanw if (!ISSET(t->c_cflag, CHWFLOW)) {
588 1.26.4.2 nathanw /* Disable the high water mark. */
589 1.26.4.2 nathanw sc->sc_r_hiwat = 0;
590 1.26.4.2 nathanw sc->sc_r_lowat = 0;
591 1.26.4.2 nathanw if (ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) {
592 1.26.4.2 nathanw CLR(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
593 1.26.4.2 nathanw sci_schedrx(sc);
594 1.26.4.2 nathanw }
595 1.26.4.2 nathanw } else {
596 1.26.4.2 nathanw sc->sc_r_hiwat = sci_rbuf_hiwat;
597 1.26.4.2 nathanw sc->sc_r_lowat = sci_rbuf_lowat;
598 1.26.4.2 nathanw }
599 1.26.4.2 nathanw
600 1.26.4.2 nathanw splx(s);
601 1.26.4.2 nathanw
602 1.26.4.2 nathanw #ifdef SCI_DEBUG
603 1.26.4.2 nathanw if (sci_debug)
604 1.26.4.2 nathanw scistatus(sc, "sciparam ");
605 1.26.4.2 nathanw #endif
606 1.26.4.2 nathanw
607 1.26.4.2 nathanw if (!ISSET(t->c_cflag, CHWFLOW)) {
608 1.26.4.2 nathanw if (sc->sc_tx_stopped) {
609 1.26.4.2 nathanw sc->sc_tx_stopped = 0;
610 1.26.4.2 nathanw scistart(tp);
611 1.26.4.2 nathanw }
612 1.26.4.2 nathanw }
613 1.26.4.2 nathanw
614 1.26.4.2 nathanw return (0);
615 1.26.4.2 nathanw }
616 1.26.4.2 nathanw
617 1.26.4.2 nathanw void
618 1.26.4.2 nathanw sci_iflush(struct sci_softc *sc)
619 1.26.4.2 nathanw {
620 1.26.4.2 nathanw unsigned char err_c;
621 1.26.4.2 nathanw volatile unsigned char c;
622 1.26.4.2 nathanw
623 1.26.4.2 nathanw if (((err_c = SHREG_SCSSR)
624 1.26.4.2 nathanw & (SCSSR_RDRF | SCSSR_ORER | SCSSR_FER | SCSSR_PER)) != 0) {
625 1.26.4.2 nathanw
626 1.26.4.2 nathanw if ((err_c & (SCSSR_ORER | SCSSR_FER | SCSSR_PER)) != 0) {
627 1.26.4.2 nathanw SHREG_SCSSR &= ~(SCSSR_ORER | SCSSR_FER | SCSSR_PER);
628 1.26.4.2 nathanw return;
629 1.26.4.2 nathanw }
630 1.26.4.2 nathanw
631 1.26.4.2 nathanw c = SHREG_SCRDR;
632 1.26.4.2 nathanw
633 1.26.4.2 nathanw SHREG_SCSSR &= ~SCSSR_RDRF;
634 1.26.4.2 nathanw }
635 1.26.4.2 nathanw }
636 1.26.4.2 nathanw
637 1.26.4.2 nathanw int
638 1.26.4.2 nathanw sciopen(dev_t dev, int flag, int mode, struct proc *p)
639 1.26.4.2 nathanw {
640 1.26.4.2 nathanw int unit = SCIUNIT(dev);
641 1.26.4.2 nathanw struct sci_softc *sc;
642 1.26.4.2 nathanw struct tty *tp;
643 1.26.4.2 nathanw int s, s2;
644 1.26.4.2 nathanw int error;
645 1.26.4.2 nathanw
646 1.26.4.2 nathanw if (unit >= sci_cd.cd_ndevs)
647 1.26.4.2 nathanw return (ENXIO);
648 1.26.4.2 nathanw sc = sci_cd.cd_devs[unit];
649 1.26.4.2 nathanw if (sc == 0 || !ISSET(sc->sc_hwflags, SCI_HW_DEV_OK) ||
650 1.26.4.2 nathanw sc->sc_rbuf == NULL)
651 1.26.4.2 nathanw return (ENXIO);
652 1.26.4.2 nathanw
653 1.26.4.2 nathanw if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
654 1.26.4.2 nathanw return (ENXIO);
655 1.26.4.2 nathanw
656 1.26.4.2 nathanw #ifdef KGDB
657 1.26.4.2 nathanw /*
658 1.26.4.2 nathanw * If this is the kgdb port, no other use is permitted.
659 1.26.4.2 nathanw */
660 1.26.4.2 nathanw if (ISSET(sc->sc_hwflags, SCI_HW_KGDB))
661 1.26.4.2 nathanw return (EBUSY);
662 1.26.4.2 nathanw #endif
663 1.26.4.2 nathanw
664 1.26.4.2 nathanw tp = sc->sc_tty;
665 1.26.4.2 nathanw
666 1.26.4.2 nathanw if (ISSET(tp->t_state, TS_ISOPEN) &&
667 1.26.4.2 nathanw ISSET(tp->t_state, TS_XCLUDE) &&
668 1.26.4.2 nathanw p->p_ucred->cr_uid != 0)
669 1.26.4.2 nathanw return (EBUSY);
670 1.26.4.2 nathanw
671 1.26.4.2 nathanw s = spltty();
672 1.26.4.2 nathanw
673 1.26.4.2 nathanw /*
674 1.26.4.2 nathanw * Do the following iff this is a first open.
675 1.26.4.2 nathanw */
676 1.26.4.2 nathanw if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
677 1.26.4.2 nathanw struct termios t;
678 1.26.4.2 nathanw
679 1.26.4.2 nathanw tp->t_dev = dev;
680 1.26.4.2 nathanw
681 1.26.4.2 nathanw s2 = splserial();
682 1.26.4.2 nathanw
683 1.26.4.2 nathanw /* Turn on interrupts. */
684 1.26.4.2 nathanw SHREG_SCSCR |= SCSCR_TIE | SCSCR_RIE;
685 1.26.4.2 nathanw
686 1.26.4.2 nathanw splx(s2);
687 1.26.4.2 nathanw
688 1.26.4.2 nathanw /*
689 1.26.4.2 nathanw * Initialize the termios status to the defaults. Add in the
690 1.26.4.2 nathanw * sticky bits from TIOCSFLAGS.
691 1.26.4.2 nathanw */
692 1.26.4.2 nathanw t.c_ispeed = 0;
693 1.26.4.2 nathanw if (ISSET(sc->sc_hwflags, SCI_HW_CONSOLE)) {
694 1.26.4.2 nathanw t.c_ospeed = scicn_speed;
695 1.26.4.2 nathanw t.c_cflag = sciconscflag;
696 1.26.4.2 nathanw } else {
697 1.26.4.2 nathanw t.c_ospeed = TTYDEF_SPEED;
698 1.26.4.2 nathanw t.c_cflag = TTYDEF_CFLAG;
699 1.26.4.2 nathanw }
700 1.26.4.2 nathanw if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
701 1.26.4.2 nathanw SET(t.c_cflag, CLOCAL);
702 1.26.4.2 nathanw if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
703 1.26.4.2 nathanw SET(t.c_cflag, CRTSCTS);
704 1.26.4.2 nathanw if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
705 1.26.4.2 nathanw SET(t.c_cflag, MDMBUF);
706 1.26.4.2 nathanw /* Make sure sciparam() will do something. */
707 1.26.4.2 nathanw tp->t_ospeed = 0;
708 1.26.4.2 nathanw (void) sciparam(tp, &t);
709 1.26.4.2 nathanw tp->t_iflag = TTYDEF_IFLAG;
710 1.26.4.2 nathanw tp->t_oflag = TTYDEF_OFLAG;
711 1.26.4.2 nathanw tp->t_lflag = TTYDEF_LFLAG;
712 1.26.4.2 nathanw ttychars(tp);
713 1.26.4.2 nathanw ttsetwater(tp);
714 1.26.4.2 nathanw
715 1.26.4.2 nathanw s2 = splserial();
716 1.26.4.2 nathanw
717 1.26.4.2 nathanw /* Clear the input ring, and unblock. */
718 1.26.4.2 nathanw sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
719 1.26.4.2 nathanw sc->sc_rbavail = sci_rbuf_size;
720 1.26.4.2 nathanw sci_iflush(sc);
721 1.26.4.2 nathanw CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
722 1.26.4.2 nathanw #if 0
723 1.26.4.2 nathanw /* XXX (msaitoh) */
724 1.26.4.2 nathanw sci_hwiflow(sc);
725 1.26.4.2 nathanw #endif
726 1.26.4.2 nathanw
727 1.26.4.2 nathanw #ifdef SCI_DEBUG
728 1.26.4.2 nathanw if (sci_debug)
729 1.26.4.2 nathanw scistatus(sc, "sciopen ");
730 1.26.4.2 nathanw #endif
731 1.26.4.2 nathanw
732 1.26.4.2 nathanw splx(s2);
733 1.26.4.2 nathanw }
734 1.26.4.2 nathanw
735 1.26.4.2 nathanw splx(s);
736 1.26.4.2 nathanw
737 1.26.4.2 nathanw error = ttyopen(tp, SCIDIALOUT(dev), ISSET(flag, O_NONBLOCK));
738 1.26.4.2 nathanw if (error)
739 1.26.4.2 nathanw goto bad;
740 1.26.4.2 nathanw
741 1.26.4.2 nathanw error = (*tp->t_linesw->l_open)(dev, tp);
742 1.26.4.2 nathanw if (error)
743 1.26.4.2 nathanw goto bad;
744 1.26.4.2 nathanw
745 1.26.4.2 nathanw return (0);
746 1.26.4.2 nathanw
747 1.26.4.2 nathanw bad:
748 1.26.4.2 nathanw
749 1.26.4.2 nathanw return (error);
750 1.26.4.2 nathanw }
751 1.26.4.2 nathanw
752 1.26.4.2 nathanw int
753 1.26.4.2 nathanw sciclose(dev_t dev, int flag, int mode, struct proc *p)
754 1.26.4.2 nathanw {
755 1.26.4.2 nathanw struct sci_softc *sc = sci_cd.cd_devs[SCIUNIT(dev)];
756 1.26.4.2 nathanw struct tty *tp = sc->sc_tty;
757 1.26.4.2 nathanw
758 1.26.4.2 nathanw /* XXX This is for cons.c. */
759 1.26.4.2 nathanw if (!ISSET(tp->t_state, TS_ISOPEN))
760 1.26.4.2 nathanw return (0);
761 1.26.4.2 nathanw
762 1.26.4.2 nathanw (*tp->t_linesw->l_close)(tp, flag);
763 1.26.4.2 nathanw ttyclose(tp);
764 1.26.4.2 nathanw
765 1.26.4.2 nathanw if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
766 1.26.4.2 nathanw return (0);
767 1.26.4.2 nathanw
768 1.26.4.2 nathanw return (0);
769 1.26.4.2 nathanw }
770 1.26.4.2 nathanw
771 1.26.4.2 nathanw int
772 1.26.4.2 nathanw sciread(dev_t dev, struct uio *uio, int flag)
773 1.26.4.2 nathanw {
774 1.26.4.2 nathanw struct sci_softc *sc = sci_cd.cd_devs[SCIUNIT(dev)];
775 1.26.4.2 nathanw struct tty *tp = sc->sc_tty;
776 1.26.4.2 nathanw
777 1.26.4.2 nathanw return ((*tp->t_linesw->l_read)(tp, uio, flag));
778 1.26.4.2 nathanw }
779 1.26.4.2 nathanw
780 1.26.4.2 nathanw int
781 1.26.4.2 nathanw sciwrite(dev_t dev, struct uio *uio, int flag)
782 1.26.4.2 nathanw {
783 1.26.4.2 nathanw struct sci_softc *sc = sci_cd.cd_devs[SCIUNIT(dev)];
784 1.26.4.2 nathanw struct tty *tp = sc->sc_tty;
785 1.26.4.2 nathanw
786 1.26.4.2 nathanw return ((*tp->t_linesw->l_write)(tp, uio, flag));
787 1.26.4.2 nathanw }
788 1.26.4.2 nathanw
789 1.26.4.2 nathanw int
790 1.26.4.2 nathanw scipoll(dev_t dev, int events, struct proc *p)
791 1.26.4.2 nathanw {
792 1.26.4.2 nathanw struct sci_softc *sc = sci_cd.cd_devs[SCIUNIT(dev)];
793 1.26.4.2 nathanw struct tty *tp = sc->sc_tty;
794 1.26.4.2 nathanw
795 1.26.4.2 nathanw return ((*tp->t_linesw->l_poll)(tp, events, p));
796 1.26.4.2 nathanw }
797 1.26.4.2 nathanw
798 1.26.4.2 nathanw struct tty *
799 1.26.4.2 nathanw scitty(dev_t dev)
800 1.26.4.2 nathanw {
801 1.26.4.2 nathanw struct sci_softc *sc = sci_cd.cd_devs[SCIUNIT(dev)];
802 1.26.4.2 nathanw struct tty *tp = sc->sc_tty;
803 1.26.4.2 nathanw
804 1.26.4.2 nathanw return (tp);
805 1.26.4.2 nathanw }
806 1.26.4.2 nathanw
807 1.26.4.2 nathanw int
808 1.26.4.2 nathanw sciioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
809 1.26.4.2 nathanw {
810 1.26.4.2 nathanw struct sci_softc *sc = sci_cd.cd_devs[SCIUNIT(dev)];
811 1.26.4.2 nathanw struct tty *tp = sc->sc_tty;
812 1.26.4.2 nathanw int error;
813 1.26.4.2 nathanw int s;
814 1.26.4.2 nathanw
815 1.26.4.2 nathanw if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
816 1.26.4.2 nathanw return (EIO);
817 1.26.4.2 nathanw
818 1.26.4.2 nathanw error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
819 1.26.4.2 nathanw if (error != EPASSTHROUGH)
820 1.26.4.2 nathanw return (error);
821 1.26.4.2 nathanw
822 1.26.4.2 nathanw error = ttioctl(tp, cmd, data, flag, p);
823 1.26.4.2 nathanw if (error != EPASSTHROUGH)
824 1.26.4.2 nathanw return (error);
825 1.26.4.2 nathanw
826 1.26.4.2 nathanw error = 0;
827 1.26.4.2 nathanw
828 1.26.4.2 nathanw s = splserial();
829 1.26.4.2 nathanw
830 1.26.4.2 nathanw switch (cmd) {
831 1.26.4.2 nathanw case TIOCSBRK:
832 1.26.4.2 nathanw sci_break(sc, 1);
833 1.26.4.2 nathanw break;
834 1.26.4.2 nathanw
835 1.26.4.2 nathanw case TIOCCBRK:
836 1.26.4.2 nathanw sci_break(sc, 0);
837 1.26.4.2 nathanw break;
838 1.26.4.2 nathanw
839 1.26.4.2 nathanw case TIOCGFLAGS:
840 1.26.4.2 nathanw *(int *)data = sc->sc_swflags;
841 1.26.4.2 nathanw break;
842 1.26.4.2 nathanw
843 1.26.4.2 nathanw case TIOCSFLAGS:
844 1.26.4.2 nathanw error = suser(p->p_ucred, &p->p_acflag);
845 1.26.4.2 nathanw if (error)
846 1.26.4.2 nathanw break;
847 1.26.4.2 nathanw sc->sc_swflags = *(int *)data;
848 1.26.4.2 nathanw break;
849 1.26.4.2 nathanw
850 1.26.4.2 nathanw default:
851 1.26.4.2 nathanw error = EPASSTHROUGH;
852 1.26.4.2 nathanw break;
853 1.26.4.2 nathanw }
854 1.26.4.2 nathanw
855 1.26.4.2 nathanw splx(s);
856 1.26.4.2 nathanw
857 1.26.4.2 nathanw return (error);
858 1.26.4.2 nathanw }
859 1.26.4.2 nathanw
860 1.26.4.2 nathanw integrate void
861 1.26.4.2 nathanw sci_schedrx(struct sci_softc *sc)
862 1.26.4.2 nathanw {
863 1.26.4.2 nathanw
864 1.26.4.2 nathanw sc->sc_rx_ready = 1;
865 1.26.4.2 nathanw
866 1.26.4.2 nathanw /* Wake up the poller. */
867 1.26.4.2 nathanw #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
868 1.26.4.2 nathanw softintr_schedule(sc->sc_si);
869 1.26.4.2 nathanw #else
870 1.26.4.2 nathanw #ifndef __NO_SOFT_SERIAL_INTERRUPT
871 1.26.4.2 nathanw setsoftserial();
872 1.26.4.2 nathanw #else
873 1.26.4.2 nathanw if (!sci_softintr_scheduled) {
874 1.26.4.2 nathanw sci_softintr_scheduled = 1;
875 1.26.4.2 nathanw callout_reset(&sci_soft_ch, 1, scisoft, NULL);
876 1.26.4.2 nathanw }
877 1.26.4.2 nathanw #endif
878 1.26.4.2 nathanw #endif
879 1.26.4.2 nathanw }
880 1.26.4.2 nathanw
881 1.26.4.2 nathanw void
882 1.26.4.2 nathanw sci_break(struct sci_softc *sc, int onoff)
883 1.26.4.2 nathanw {
884 1.26.4.2 nathanw
885 1.26.4.2 nathanw if (onoff)
886 1.26.4.2 nathanw SHREG_SCSSR &= ~SCSSR_TDRE;
887 1.26.4.2 nathanw else
888 1.26.4.2 nathanw SHREG_SCSSR |= SCSSR_TDRE;
889 1.26.4.2 nathanw
890 1.26.4.2 nathanw #if 0 /* XXX */
891 1.26.4.2 nathanw if (!sc->sc_heldchange) {
892 1.26.4.2 nathanw if (sc->sc_tx_busy) {
893 1.26.4.2 nathanw sc->sc_heldtbc = sc->sc_tbc;
894 1.26.4.2 nathanw sc->sc_tbc = 0;
895 1.26.4.2 nathanw sc->sc_heldchange = 1;
896 1.26.4.2 nathanw } else
897 1.26.4.2 nathanw sci_loadchannelregs(sc);
898 1.26.4.2 nathanw }
899 1.26.4.2 nathanw #endif
900 1.26.4.2 nathanw }
901 1.26.4.2 nathanw
902 1.26.4.2 nathanw /*
903 1.26.4.2 nathanw * Stop output, e.g., for ^S or output flush.
904 1.26.4.2 nathanw */
905 1.26.4.2 nathanw void
906 1.26.4.2 nathanw scistop(struct tty *tp, int flag)
907 1.26.4.2 nathanw {
908 1.26.4.2 nathanw struct sci_softc *sc = sci_cd.cd_devs[SCIUNIT(tp->t_dev)];
909 1.26.4.2 nathanw int s;
910 1.26.4.2 nathanw
911 1.26.4.2 nathanw s = splserial();
912 1.26.4.2 nathanw if (ISSET(tp->t_state, TS_BUSY)) {
913 1.26.4.2 nathanw /* Stop transmitting at the next chunk. */
914 1.26.4.2 nathanw sc->sc_tbc = 0;
915 1.26.4.2 nathanw sc->sc_heldtbc = 0;
916 1.26.4.2 nathanw if (!ISSET(tp->t_state, TS_TTSTOP))
917 1.26.4.2 nathanw SET(tp->t_state, TS_FLUSH);
918 1.26.4.2 nathanw }
919 1.26.4.2 nathanw splx(s);
920 1.26.4.2 nathanw }
921 1.26.4.2 nathanw
922 1.26.4.2 nathanw void
923 1.26.4.2 nathanw scidiag(void *arg)
924 1.26.4.2 nathanw {
925 1.26.4.2 nathanw struct sci_softc *sc = arg;
926 1.26.4.2 nathanw int overflows, floods;
927 1.26.4.2 nathanw int s;
928 1.26.4.2 nathanw
929 1.26.4.2 nathanw s = splserial();
930 1.26.4.2 nathanw overflows = sc->sc_overflows;
931 1.26.4.2 nathanw sc->sc_overflows = 0;
932 1.26.4.2 nathanw floods = sc->sc_floods;
933 1.26.4.2 nathanw sc->sc_floods = 0;
934 1.26.4.2 nathanw sc->sc_errors = 0;
935 1.26.4.2 nathanw splx(s);
936 1.26.4.2 nathanw
937 1.26.4.2 nathanw log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n",
938 1.26.4.2 nathanw sc->sc_dev.dv_xname,
939 1.26.4.2 nathanw overflows, overflows == 1 ? "" : "s",
940 1.26.4.2 nathanw floods, floods == 1 ? "" : "s");
941 1.26.4.2 nathanw }
942 1.26.4.2 nathanw
943 1.26.4.2 nathanw integrate void
944 1.26.4.2 nathanw sci_rxsoft(struct sci_softc *sc, struct tty *tp)
945 1.26.4.2 nathanw {
946 1.26.4.2 nathanw int (*rint)(int c, struct tty *tp) = tp->t_linesw->l_rint;
947 1.26.4.2 nathanw u_char *get, *end;
948 1.26.4.2 nathanw u_int cc, scc;
949 1.26.4.2 nathanw u_char ssr;
950 1.26.4.2 nathanw int code;
951 1.26.4.2 nathanw int s;
952 1.26.4.2 nathanw
953 1.26.4.2 nathanw end = sc->sc_ebuf;
954 1.26.4.2 nathanw get = sc->sc_rbget;
955 1.26.4.2 nathanw scc = cc = sci_rbuf_size - sc->sc_rbavail;
956 1.26.4.2 nathanw
957 1.26.4.2 nathanw if (cc == sci_rbuf_size) {
958 1.26.4.2 nathanw sc->sc_floods++;
959 1.26.4.2 nathanw if (sc->sc_errors++ == 0)
960 1.26.4.2 nathanw callout_reset(&sc->sc_diag_ch, 60 * hz, scidiag, sc);
961 1.26.4.2 nathanw }
962 1.26.4.2 nathanw
963 1.26.4.2 nathanw while (cc) {
964 1.26.4.2 nathanw code = get[0];
965 1.26.4.2 nathanw ssr = get[1];
966 1.26.4.2 nathanw if (ISSET(ssr, SCSSR_FER | SCSSR_PER)) {
967 1.26.4.2 nathanw if (ISSET(ssr, SCSSR_FER))
968 1.26.4.2 nathanw SET(code, TTY_FE);
969 1.26.4.2 nathanw if (ISSET(ssr, SCSSR_PER))
970 1.26.4.2 nathanw SET(code, TTY_PE);
971 1.26.4.2 nathanw }
972 1.26.4.2 nathanw if ((*rint)(code, tp) == -1) {
973 1.26.4.2 nathanw /*
974 1.26.4.2 nathanw * The line discipline's buffer is out of space.
975 1.26.4.2 nathanw */
976 1.26.4.2 nathanw if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
977 1.26.4.2 nathanw /*
978 1.26.4.2 nathanw * We're either not using flow control, or the
979 1.26.4.2 nathanw * line discipline didn't tell us to block for
980 1.26.4.2 nathanw * some reason. Either way, we have no way to
981 1.26.4.2 nathanw * know when there's more space available, so
982 1.26.4.2 nathanw * just drop the rest of the data.
983 1.26.4.2 nathanw */
984 1.26.4.2 nathanw get += cc << 1;
985 1.26.4.2 nathanw if (get >= end)
986 1.26.4.2 nathanw get -= sci_rbuf_size << 1;
987 1.26.4.2 nathanw cc = 0;
988 1.26.4.2 nathanw } else {
989 1.26.4.2 nathanw /*
990 1.26.4.2 nathanw * Don't schedule any more receive processing
991 1.26.4.2 nathanw * until the line discipline tells us there's
992 1.26.4.2 nathanw * space available (through scihwiflow()).
993 1.26.4.2 nathanw * Leave the rest of the data in the input
994 1.26.4.2 nathanw * buffer.
995 1.26.4.2 nathanw */
996 1.26.4.2 nathanw SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
997 1.26.4.2 nathanw }
998 1.26.4.2 nathanw break;
999 1.26.4.2 nathanw }
1000 1.26.4.2 nathanw get += 2;
1001 1.26.4.2 nathanw if (get >= end)
1002 1.26.4.2 nathanw get = sc->sc_rbuf;
1003 1.26.4.2 nathanw cc--;
1004 1.26.4.2 nathanw }
1005 1.26.4.2 nathanw
1006 1.26.4.2 nathanw if (cc != scc) {
1007 1.26.4.2 nathanw sc->sc_rbget = get;
1008 1.26.4.2 nathanw s = splserial();
1009 1.26.4.2 nathanw cc = sc->sc_rbavail += scc - cc;
1010 1.26.4.2 nathanw /* Buffers should be ok again, release possible block. */
1011 1.26.4.2 nathanw if (cc >= sc->sc_r_lowat) {
1012 1.26.4.2 nathanw if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
1013 1.26.4.2 nathanw CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
1014 1.26.4.2 nathanw SHREG_SCSCR |= SCSCR_RIE;
1015 1.26.4.2 nathanw }
1016 1.26.4.2 nathanw #if 0
1017 1.26.4.2 nathanw if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) {
1018 1.26.4.2 nathanw CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED);
1019 1.26.4.2 nathanw sci_hwiflow(sc);
1020 1.26.4.2 nathanw }
1021 1.26.4.2 nathanw #endif
1022 1.26.4.2 nathanw }
1023 1.26.4.2 nathanw splx(s);
1024 1.26.4.2 nathanw }
1025 1.26.4.2 nathanw }
1026 1.26.4.2 nathanw
1027 1.26.4.2 nathanw integrate void
1028 1.26.4.2 nathanw sci_txsoft(sc, tp)
1029 1.26.4.2 nathanw struct sci_softc *sc;
1030 1.26.4.2 nathanw struct tty *tp;
1031 1.26.4.2 nathanw {
1032 1.26.4.2 nathanw
1033 1.26.4.2 nathanw CLR(tp->t_state, TS_BUSY);
1034 1.26.4.2 nathanw if (ISSET(tp->t_state, TS_FLUSH))
1035 1.26.4.2 nathanw CLR(tp->t_state, TS_FLUSH);
1036 1.26.4.2 nathanw else
1037 1.26.4.2 nathanw ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
1038 1.26.4.2 nathanw (*tp->t_linesw->l_start)(tp);
1039 1.26.4.2 nathanw }
1040 1.26.4.2 nathanw
1041 1.26.4.2 nathanw integrate void
1042 1.26.4.2 nathanw sci_stsoft(struct sci_softc *sc, struct tty *tp)
1043 1.26.4.2 nathanw {
1044 1.26.4.2 nathanw #if 0
1045 1.26.4.2 nathanw /* XXX (msaitoh) */
1046 1.26.4.2 nathanw u_char msr, delta;
1047 1.26.4.2 nathanw int s;
1048 1.26.4.2 nathanw
1049 1.26.4.2 nathanw s = splserial();
1050 1.26.4.2 nathanw msr = sc->sc_msr;
1051 1.26.4.2 nathanw delta = sc->sc_msr_delta;
1052 1.26.4.2 nathanw sc->sc_msr_delta = 0;
1053 1.26.4.2 nathanw splx(s);
1054 1.26.4.2 nathanw
1055 1.26.4.2 nathanw if (ISSET(delta, sc->sc_msr_dcd)) {
1056 1.26.4.2 nathanw /*
1057 1.26.4.2 nathanw * Inform the tty layer that carrier detect changed.
1058 1.26.4.2 nathanw */
1059 1.26.4.2 nathanw (void) (*tp->t_linesw->l_modem)(tp, ISSET(msr, MSR_DCD));
1060 1.26.4.2 nathanw }
1061 1.26.4.2 nathanw
1062 1.26.4.2 nathanw if (ISSET(delta, sc->sc_msr_cts)) {
1063 1.26.4.2 nathanw /* Block or unblock output according to flow control. */
1064 1.26.4.2 nathanw if (ISSET(msr, sc->sc_msr_cts)) {
1065 1.26.4.2 nathanw sc->sc_tx_stopped = 0;
1066 1.26.4.2 nathanw (*tp->t_linesw->l_start)(tp);
1067 1.26.4.2 nathanw } else {
1068 1.26.4.2 nathanw sc->sc_tx_stopped = 1;
1069 1.26.4.2 nathanw }
1070 1.26.4.2 nathanw }
1071 1.26.4.2 nathanw
1072 1.26.4.2 nathanw #ifdef SCI_DEBUG
1073 1.26.4.2 nathanw if (sci_debug)
1074 1.26.4.2 nathanw scistatus(sc, "sci_stsoft");
1075 1.26.4.2 nathanw #endif
1076 1.26.4.2 nathanw #endif
1077 1.26.4.2 nathanw }
1078 1.26.4.2 nathanw
1079 1.26.4.2 nathanw #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
1080 1.26.4.2 nathanw void
1081 1.26.4.2 nathanw scisoft(void *arg)
1082 1.26.4.2 nathanw {
1083 1.26.4.2 nathanw struct sci_softc *sc = arg;
1084 1.26.4.2 nathanw struct tty *tp;
1085 1.26.4.2 nathanw
1086 1.26.4.2 nathanw if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
1087 1.26.4.2 nathanw return;
1088 1.26.4.2 nathanw
1089 1.26.4.2 nathanw {
1090 1.26.4.2 nathanw #else
1091 1.26.4.2 nathanw void
1092 1.26.4.2 nathanw #ifndef __NO_SOFT_SERIAL_INTERRUPT
1093 1.26.4.2 nathanw scisoft()
1094 1.26.4.2 nathanw #else
1095 1.26.4.2 nathanw scisoft(void *arg)
1096 1.26.4.2 nathanw #endif
1097 1.26.4.2 nathanw {
1098 1.26.4.2 nathanw struct sci_softc *sc;
1099 1.26.4.2 nathanw struct tty *tp;
1100 1.26.4.2 nathanw int unit;
1101 1.26.4.2 nathanw #ifdef __NO_SOFT_SERIAL_INTERRUPT
1102 1.26.4.2 nathanw int s;
1103 1.26.4.2 nathanw
1104 1.26.4.2 nathanw s = splsoftserial();
1105 1.26.4.2 nathanw sci_softintr_scheduled = 0;
1106 1.26.4.2 nathanw #endif
1107 1.26.4.2 nathanw
1108 1.26.4.2 nathanw for (unit = 0; unit < sci_cd.cd_ndevs; unit++) {
1109 1.26.4.2 nathanw sc = sci_cd.cd_devs[unit];
1110 1.26.4.2 nathanw if (sc == NULL || !ISSET(sc->sc_hwflags, SCI_HW_DEV_OK))
1111 1.26.4.2 nathanw continue;
1112 1.26.4.2 nathanw
1113 1.26.4.2 nathanw if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
1114 1.26.4.2 nathanw continue;
1115 1.26.4.2 nathanw
1116 1.26.4.2 nathanw tp = sc->sc_tty;
1117 1.26.4.2 nathanw if (tp == NULL)
1118 1.26.4.2 nathanw continue;
1119 1.26.4.2 nathanw if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0)
1120 1.26.4.2 nathanw continue;
1121 1.26.4.2 nathanw #endif
1122 1.26.4.2 nathanw tp = sc->sc_tty;
1123 1.26.4.2 nathanw
1124 1.26.4.2 nathanw if (sc->sc_rx_ready) {
1125 1.26.4.2 nathanw sc->sc_rx_ready = 0;
1126 1.26.4.2 nathanw sci_rxsoft(sc, tp);
1127 1.26.4.2 nathanw }
1128 1.26.4.2 nathanw
1129 1.26.4.2 nathanw #if 0
1130 1.26.4.2 nathanw if (sc->sc_st_check) {
1131 1.26.4.2 nathanw sc->sc_st_check = 0;
1132 1.26.4.2 nathanw sci_stsoft(sc, tp);
1133 1.26.4.2 nathanw }
1134 1.26.4.2 nathanw #endif
1135 1.26.4.2 nathanw
1136 1.26.4.2 nathanw if (sc->sc_tx_done) {
1137 1.26.4.2 nathanw sc->sc_tx_done = 0;
1138 1.26.4.2 nathanw sci_txsoft(sc, tp);
1139 1.26.4.2 nathanw }
1140 1.26.4.2 nathanw }
1141 1.26.4.2 nathanw
1142 1.26.4.2 nathanw #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
1143 1.26.4.2 nathanw #ifdef __NO_SOFT_SERIAL_INTERRUPT
1144 1.26.4.2 nathanw splx(s);
1145 1.26.4.2 nathanw #endif
1146 1.26.4.2 nathanw #endif
1147 1.26.4.2 nathanw }
1148 1.26.4.2 nathanw
1149 1.26.4.2 nathanw int
1150 1.26.4.2 nathanw sciintr(void *arg)
1151 1.26.4.2 nathanw {
1152 1.26.4.2 nathanw struct sci_softc *sc = arg;
1153 1.26.4.2 nathanw u_char *put, *end;
1154 1.26.4.2 nathanw u_int cc;
1155 1.26.4.2 nathanw u_short ssr;
1156 1.26.4.2 nathanw
1157 1.26.4.2 nathanw if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
1158 1.26.4.2 nathanw return (0);
1159 1.26.4.2 nathanw
1160 1.26.4.2 nathanw end = sc->sc_ebuf;
1161 1.26.4.2 nathanw put = sc->sc_rbput;
1162 1.26.4.2 nathanw cc = sc->sc_rbavail;
1163 1.26.4.2 nathanw
1164 1.26.4.2 nathanw do {
1165 1.26.4.2 nathanw ssr = SHREG_SCSSR;
1166 1.26.4.2 nathanw if (ISSET(ssr, SCSSR_FER)) {
1167 1.26.4.2 nathanw SHREG_SCSSR &= ~(SCSSR_ORER | SCSSR_PER | SCSSR_FER);
1168 1.26.4.2 nathanw #if defined(DDB) || defined(KGDB)
1169 1.26.4.2 nathanw #ifdef SH4
1170 1.26.4.2 nathanw if ((SHREG_SCSPTR & SCSPTR_SPB0DT) != 0) {
1171 1.26.4.2 nathanw #else
1172 1.26.4.2 nathanw if ((SHREG_SCSPDR & SCSPDR_SCP0DT) != 0) {
1173 1.26.4.2 nathanw #endif
1174 1.26.4.2 nathanw #ifdef DDB
1175 1.26.4.2 nathanw if (ISSET(sc->sc_hwflags, SCI_HW_CONSOLE)) {
1176 1.26.4.2 nathanw console_debugger();
1177 1.26.4.2 nathanw }
1178 1.26.4.2 nathanw #endif
1179 1.26.4.2 nathanw #ifdef KGDB
1180 1.26.4.2 nathanw if (ISSET(sc->sc_hwflags, SCI_HW_KGDB)) {
1181 1.26.4.2 nathanw kgdb_connect(1);
1182 1.26.4.2 nathanw }
1183 1.26.4.2 nathanw #endif
1184 1.26.4.2 nathanw }
1185 1.26.4.2 nathanw #endif /* DDB || KGDB */
1186 1.26.4.2 nathanw }
1187 1.26.4.2 nathanw if ((SHREG_SCSSR & SCSSR_RDRF) != 0) {
1188 1.26.4.2 nathanw if (cc > 0) {
1189 1.26.4.2 nathanw put[0] = SHREG_SCRDR;
1190 1.26.4.2 nathanw put[1] = SHREG_SCSSR & 0x00ff;
1191 1.26.4.2 nathanw
1192 1.26.4.2 nathanw put += 2;
1193 1.26.4.2 nathanw if (put >= end)
1194 1.26.4.2 nathanw put = sc->sc_rbuf;
1195 1.26.4.2 nathanw cc--;
1196 1.26.4.2 nathanw }
1197 1.26.4.2 nathanw
1198 1.26.4.2 nathanw SHREG_SCSSR &= ~(SCSSR_ORER | SCSSR_FER | SCSSR_PER |
1199 1.26.4.2 nathanw SCSSR_RDRF);
1200 1.26.4.2 nathanw
1201 1.26.4.2 nathanw /*
1202 1.26.4.2 nathanw * Current string of incoming characters ended because
1203 1.26.4.2 nathanw * no more data was available or we ran out of space.
1204 1.26.4.2 nathanw * Schedule a receive event if any data was received.
1205 1.26.4.2 nathanw * If we're out of space, turn off receive interrupts.
1206 1.26.4.2 nathanw */
1207 1.26.4.2 nathanw sc->sc_rbput = put;
1208 1.26.4.2 nathanw sc->sc_rbavail = cc;
1209 1.26.4.2 nathanw if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
1210 1.26.4.2 nathanw sc->sc_rx_ready = 1;
1211 1.26.4.2 nathanw
1212 1.26.4.2 nathanw /*
1213 1.26.4.2 nathanw * See if we are in danger of overflowing a buffer. If
1214 1.26.4.2 nathanw * so, use hardware flow control to ease the pressure.
1215 1.26.4.2 nathanw */
1216 1.26.4.2 nathanw if (!ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED) &&
1217 1.26.4.2 nathanw cc < sc->sc_r_hiwat) {
1218 1.26.4.2 nathanw SET(sc->sc_rx_flags, RX_IBUF_BLOCKED);
1219 1.26.4.2 nathanw #if 0
1220 1.26.4.2 nathanw sci_hwiflow(sc);
1221 1.26.4.2 nathanw #endif
1222 1.26.4.2 nathanw }
1223 1.26.4.2 nathanw
1224 1.26.4.2 nathanw /*
1225 1.26.4.2 nathanw * If we're out of space, disable receive interrupts
1226 1.26.4.2 nathanw * until the queue has drained a bit.
1227 1.26.4.2 nathanw */
1228 1.26.4.2 nathanw if (!cc) {
1229 1.26.4.2 nathanw SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
1230 1.26.4.2 nathanw SHREG_SCSCR &= ~SCSCR_RIE;
1231 1.26.4.2 nathanw }
1232 1.26.4.2 nathanw } else {
1233 1.26.4.2 nathanw if (SHREG_SCSSR & SCSSR_RDRF) {
1234 1.26.4.2 nathanw SHREG_SCSCR &= ~(SCSCR_TIE | SCSCR_RIE);
1235 1.26.4.2 nathanw delay(10);
1236 1.26.4.2 nathanw SHREG_SCSCR |= SCSCR_TIE | SCSCR_RIE;
1237 1.26.4.2 nathanw continue;
1238 1.26.4.2 nathanw }
1239 1.26.4.2 nathanw }
1240 1.26.4.2 nathanw } while (SHREG_SCSSR & SCSSR_RDRF);
1241 1.26.4.2 nathanw
1242 1.26.4.2 nathanw #if 0
1243 1.26.4.2 nathanw msr = bus_space_read_1(iot, ioh, sci_msr);
1244 1.26.4.2 nathanw delta = msr ^ sc->sc_msr;
1245 1.26.4.2 nathanw sc->sc_msr = msr;
1246 1.26.4.2 nathanw if (ISSET(delta, sc->sc_msr_mask)) {
1247 1.26.4.2 nathanw SET(sc->sc_msr_delta, delta);
1248 1.26.4.2 nathanw
1249 1.26.4.2 nathanw /*
1250 1.26.4.2 nathanw * Pulse-per-second clock signal on edge of DCD?
1251 1.26.4.2 nathanw */
1252 1.26.4.2 nathanw if (ISSET(delta, sc->sc_ppsmask)) {
1253 1.26.4.2 nathanw struct timeval tv;
1254 1.26.4.2 nathanw if (ISSET(msr, sc->sc_ppsmask) ==
1255 1.26.4.2 nathanw sc->sc_ppsassert) {
1256 1.26.4.2 nathanw /* XXX nanotime() */
1257 1.26.4.2 nathanw microtime(&tv);
1258 1.26.4.2 nathanw TIMEVAL_TO_TIMESPEC(&tv,
1259 1.26.4.2 nathanw &sc->ppsinfo.assert_timestamp);
1260 1.26.4.2 nathanw if (sc->ppsparam.mode & PPS_OFFSETASSERT) {
1261 1.26.4.2 nathanw timespecadd(&sc->ppsinfo.assert_timestamp,
1262 1.26.4.2 nathanw &sc->ppsparam.assert_offset,
1263 1.26.4.2 nathanw &sc->ppsinfo.assert_timestamp);
1264 1.26.4.2 nathanw TIMESPEC_TO_TIMEVAL(&tv, &sc->ppsinfo.assert_timestamp);
1265 1.26.4.2 nathanw }
1266 1.26.4.2 nathanw
1267 1.26.4.2 nathanw #ifdef PPS_SYNC
1268 1.26.4.2 nathanw if (sc->ppsparam.mode & PPS_HARDPPSONASSERT)
1269 1.26.4.2 nathanw hardpps(&tv, tv.tv_usec);
1270 1.26.4.2 nathanw #endif
1271 1.26.4.2 nathanw sc->ppsinfo.assert_sequence++;
1272 1.26.4.2 nathanw sc->ppsinfo.current_mode =
1273 1.26.4.2 nathanw sc->ppsparam.mode;
1274 1.26.4.2 nathanw
1275 1.26.4.2 nathanw } else if (ISSET(msr, sc->sc_ppsmask) ==
1276 1.26.4.2 nathanw sc->sc_ppsclear) {
1277 1.26.4.2 nathanw /* XXX nanotime() */
1278 1.26.4.2 nathanw microtime(&tv);
1279 1.26.4.2 nathanw TIMEVAL_TO_TIMESPEC(&tv,
1280 1.26.4.2 nathanw &sc->ppsinfo.clear_timestamp);
1281 1.26.4.2 nathanw if (sc->ppsparam.mode & PPS_OFFSETCLEAR) {
1282 1.26.4.2 nathanw timespecadd(&sc->ppsinfo.clear_timestamp,
1283 1.26.4.2 nathanw &sc->ppsparam.clear_offset,
1284 1.26.4.2 nathanw &sc->ppsinfo.clear_timestamp);
1285 1.26.4.2 nathanw TIMESPEC_TO_TIMEVAL(&tv, &sc->ppsinfo.clear_timestamp);
1286 1.26.4.2 nathanw }
1287 1.26.4.2 nathanw
1288 1.26.4.2 nathanw #ifdef PPS_SYNC
1289 1.26.4.2 nathanw if (sc->ppsparam.mode & PPS_HARDPPSONCLEAR)
1290 1.26.4.2 nathanw hardpps(&tv, tv.tv_usec);
1291 1.26.4.2 nathanw #endif
1292 1.26.4.2 nathanw sc->ppsinfo.clear_sequence++;
1293 1.26.4.2 nathanw sc->ppsinfo.current_mode =
1294 1.26.4.2 nathanw sc->ppsparam.mode;
1295 1.26.4.2 nathanw }
1296 1.26.4.2 nathanw }
1297 1.26.4.2 nathanw
1298 1.26.4.2 nathanw /*
1299 1.26.4.2 nathanw * Stop output immediately if we lose the output
1300 1.26.4.2 nathanw * flow control signal or carrier detect.
1301 1.26.4.2 nathanw */
1302 1.26.4.2 nathanw if (ISSET(~msr, sc->sc_msr_mask)) {
1303 1.26.4.2 nathanw sc->sc_tbc = 0;
1304 1.26.4.2 nathanw sc->sc_heldtbc = 0;
1305 1.26.4.2 nathanw #ifdef SCI_DEBUG
1306 1.26.4.2 nathanw if (sci_debug)
1307 1.26.4.2 nathanw scistatus(sc, "sciintr ");
1308 1.26.4.2 nathanw #endif
1309 1.26.4.2 nathanw }
1310 1.26.4.2 nathanw
1311 1.26.4.2 nathanw sc->sc_st_check = 1;
1312 1.26.4.2 nathanw }
1313 1.26.4.2 nathanw #endif
1314 1.26.4.2 nathanw
1315 1.26.4.2 nathanw /*
1316 1.26.4.2 nathanw * Done handling any receive interrupts. See if data can be
1317 1.26.4.2 nathanw * transmitted as well. Schedule tx done event if no data left
1318 1.26.4.2 nathanw * and tty was marked busy.
1319 1.26.4.2 nathanw */
1320 1.26.4.2 nathanw if ((SHREG_SCSSR & SCSSR_TDRE) != 0) {
1321 1.26.4.2 nathanw /*
1322 1.26.4.2 nathanw * If we've delayed a parameter change, do it now, and restart
1323 1.26.4.2 nathanw * output.
1324 1.26.4.2 nathanw */
1325 1.26.4.2 nathanw if (sc->sc_heldchange) {
1326 1.26.4.2 nathanw sc->sc_heldchange = 0;
1327 1.26.4.2 nathanw sc->sc_tbc = sc->sc_heldtbc;
1328 1.26.4.2 nathanw sc->sc_heldtbc = 0;
1329 1.26.4.2 nathanw }
1330 1.26.4.2 nathanw
1331 1.26.4.2 nathanw /* Output the next chunk of the contiguous buffer, if any. */
1332 1.26.4.2 nathanw if (sc->sc_tbc > 0) {
1333 1.26.4.2 nathanw sci_putc(*(sc->sc_tba));
1334 1.26.4.2 nathanw sc->sc_tba++;
1335 1.26.4.2 nathanw sc->sc_tbc--;
1336 1.26.4.2 nathanw } else {
1337 1.26.4.2 nathanw /* Disable transmit completion interrupts if necessary. */
1338 1.26.4.2 nathanw #if 0
1339 1.26.4.2 nathanw if (ISSET(sc->sc_ier, IER_ETXRDY))
1340 1.26.4.2 nathanw #endif
1341 1.26.4.2 nathanw SHREG_SCSCR &= ~SCSCR_TIE;
1342 1.26.4.2 nathanw
1343 1.26.4.2 nathanw if (sc->sc_tx_busy) {
1344 1.26.4.2 nathanw sc->sc_tx_busy = 0;
1345 1.26.4.2 nathanw sc->sc_tx_done = 1;
1346 1.26.4.2 nathanw }
1347 1.26.4.2 nathanw }
1348 1.26.4.2 nathanw }
1349 1.26.4.2 nathanw
1350 1.26.4.2 nathanw /* Wake up the poller. */
1351 1.26.4.2 nathanw #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
1352 1.26.4.2 nathanw softintr_schedule(sc->sc_si);
1353 1.26.4.2 nathanw #else
1354 1.26.4.2 nathanw #ifndef __NO_SOFT_SERIAL_INTERRUPT
1355 1.26.4.2 nathanw setsoftserial();
1356 1.26.4.2 nathanw #else
1357 1.26.4.2 nathanw if (!sci_softintr_scheduled) {
1358 1.26.4.2 nathanw sci_softintr_scheduled = 1;
1359 1.26.4.2 nathanw callout_reset(&sci_soft_ch, 1, scisoft, 1);
1360 1.26.4.2 nathanw }
1361 1.26.4.2 nathanw #endif
1362 1.26.4.2 nathanw #endif
1363 1.26.4.2 nathanw
1364 1.26.4.2 nathanw #if NRND > 0 && defined(RND_SCI)
1365 1.26.4.2 nathanw rnd_add_uint32(&sc->rnd_source, iir | lsr);
1366 1.26.4.2 nathanw #endif
1367 1.26.4.2 nathanw
1368 1.26.4.2 nathanw return (1);
1369 1.26.4.2 nathanw }
1370 1.26.4.2 nathanw
1371 1.26.4.2 nathanw void
1372 1.26.4.2 nathanw scicnprobe(cp)
1373 1.26.4.2 nathanw struct consdev *cp;
1374 1.26.4.2 nathanw {
1375 1.26.4.2 nathanw int maj;
1376 1.26.4.2 nathanw
1377 1.26.4.2 nathanw /* locate the major number */
1378 1.26.4.2 nathanw for (maj = 0; maj < nchrdev; maj++)
1379 1.26.4.2 nathanw if (cdevsw[maj].d_open == sciopen)
1380 1.26.4.2 nathanw break;
1381 1.26.4.2 nathanw
1382 1.26.4.2 nathanw /* Initialize required fields. */
1383 1.26.4.2 nathanw cp->cn_dev = makedev(maj, 0);
1384 1.26.4.2 nathanw #ifdef SCICONSOLE
1385 1.26.4.2 nathanw cp->cn_pri = CN_REMOTE;
1386 1.26.4.2 nathanw #else
1387 1.26.4.2 nathanw cp->cn_pri = CN_NORMAL;
1388 1.26.4.2 nathanw #endif
1389 1.26.4.2 nathanw }
1390 1.26.4.2 nathanw
1391 1.26.4.2 nathanw void
1392 1.26.4.2 nathanw scicninit(struct consdev *cp)
1393 1.26.4.2 nathanw {
1394 1.26.4.2 nathanw
1395 1.26.4.2 nathanw InitializeSci(scicn_speed);
1396 1.26.4.2 nathanw sciisconsole = 1;
1397 1.26.4.2 nathanw }
1398 1.26.4.2 nathanw
1399 1.26.4.2 nathanw int
1400 1.26.4.2 nathanw scicngetc(dev_t dev)
1401 1.26.4.2 nathanw {
1402 1.26.4.2 nathanw int c;
1403 1.26.4.2 nathanw int s;
1404 1.26.4.2 nathanw
1405 1.26.4.2 nathanw s = splserial();
1406 1.26.4.2 nathanw c = sci_getc();
1407 1.26.4.2 nathanw splx(s);
1408 1.26.4.2 nathanw
1409 1.26.4.2 nathanw return (c);
1410 1.26.4.2 nathanw }
1411 1.26.4.2 nathanw
1412 1.26.4.2 nathanw void
1413 1.26.4.2 nathanw scicnputc(dev_t dev, int c)
1414 1.26.4.2 nathanw {
1415 1.26.4.2 nathanw int s;
1416 1.26.4.2 nathanw
1417 1.26.4.2 nathanw s = splserial();
1418 1.26.4.2 nathanw sci_putc((u_char)c);
1419 1.26.4.2 nathanw splx(s);
1420 1.26.4.2 nathanw }
1421