1 /*-
2 * Copyright (c) 2003 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/conf.h>
34 #include <sys/cons.h>
35 #include <sys/fcntl.h>
36 #include <sys/interrupt.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/reboot.h>
40 #include <machine/bus.h>
41 #include <sys/rman.h>
42 #include <sys/tty.h>
43 #include <machine/resource.h>
44 #include <machine/stdarg.h>
45
46 #include <dev/uart/uart.h>
47 #include <dev/uart/uart_bus.h>
48 #include <dev/uart/uart_cpu.h>
49
50 #include "uart_if.h"
51
52 static cn_probe_t uart_cnprobe;
53 static cn_init_t uart_cninit;
54 static cn_init_t uart_cnresume;
55 static cn_term_t uart_cnterm;
56 static cn_getc_t uart_cngetc;
57 static cn_putc_t uart_cnputc;
58 static cn_grab_t uart_cngrab;
59 static cn_ungrab_t uart_cnungrab;
60
61 static tsw_open_t uart_tty_open;
62 static tsw_close_t uart_tty_close;
63 static tsw_outwakeup_t uart_tty_outwakeup;
64 static tsw_inwakeup_t uart_tty_inwakeup;
65 static tsw_ioctl_t uart_tty_ioctl;
66 static tsw_param_t uart_tty_param;
67 static tsw_modem_t uart_tty_modem;
68 static tsw_free_t uart_tty_free;
69 static tsw_busy_t uart_tty_busy;
70
71 CONSOLE_DRIVER(
72 uart,
73 .cn_resume = uart_cnresume,
74 );
75
76 static struct uart_devinfo uart_console;
77
78 static void
uart_cnprobe(struct consdev * cp)79 uart_cnprobe(struct consdev *cp)
80 {
81
82 cp->cn_pri = CN_DEAD;
83
84 KASSERT(uart_console.cookie == NULL, ("foo"));
85
86 if (uart_cpu_getdev(UART_DEV_CONSOLE, &uart_console))
87 return;
88
89 if (uart_probe(&uart_console))
90 return;
91
92 strlcpy(cp->cn_name, uart_driver_name, sizeof(cp->cn_name));
93 cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
94 cp->cn_arg = &uart_console;
95 }
96
97 static void
uart_cninit(struct consdev * cp)98 uart_cninit(struct consdev *cp)
99 {
100 struct uart_devinfo *di;
101
102 /*
103 * Yedi trick: we need to be able to define cn_dev before we go
104 * single- or multi-user. The problem is that we don't know at
105 * this time what the device will be. Hence, we need to link from
106 * the uart_devinfo to the consdev that corresponds to it so that
107 * we can define cn_dev in uart_bus_attach() when we find the
108 * device during bus enumeration. That's when we'll know what the
109 * the unit number will be.
110 */
111 di = cp->cn_arg;
112 KASSERT(di->cookie == NULL, ("foo"));
113 di->cookie = cp;
114 di->type = UART_DEV_CONSOLE;
115 uart_add_sysdev(di);
116 uart_init(di);
117 }
118
119 static void
uart_cnresume(struct consdev * cp)120 uart_cnresume(struct consdev *cp)
121 {
122
123 uart_init(cp->cn_arg);
124 }
125
126 static void
uart_cnterm(struct consdev * cp)127 uart_cnterm(struct consdev *cp)
128 {
129
130 uart_term(cp->cn_arg);
131 }
132
133 static void
uart_cngrab(struct consdev * cp)134 uart_cngrab(struct consdev *cp)
135 {
136
137 uart_grab(cp->cn_arg);
138 }
139
140 static void
uart_cnungrab(struct consdev * cp)141 uart_cnungrab(struct consdev *cp)
142 {
143
144 uart_ungrab(cp->cn_arg);
145 }
146
147 static void
uart_cnputc(struct consdev * cp,int c)148 uart_cnputc(struct consdev *cp, int c)
149 {
150
151 uart_putc(cp->cn_arg, c);
152 }
153
154 static int
uart_cngetc(struct consdev * cp)155 uart_cngetc(struct consdev *cp)
156 {
157
158 return (uart_poll(cp->cn_arg));
159 }
160
161 static int
uart_tty_open(struct tty * tp)162 uart_tty_open(struct tty *tp)
163 {
164 struct uart_softc *sc;
165
166 sc = tty_softc(tp);
167
168 if (sc == NULL || sc->sc_leaving)
169 return (ENXIO);
170
171 sc->sc_opened = 1;
172 return (0);
173 }
174
175 static void
uart_tty_close(struct tty * tp)176 uart_tty_close(struct tty *tp)
177 {
178 struct uart_softc *sc;
179
180 sc = tty_softc(tp);
181 if (sc == NULL || sc->sc_leaving || !sc->sc_opened)
182 return;
183
184 if (sc->sc_hwiflow)
185 UART_IOCTL(sc, UART_IOCTL_IFLOW, 0);
186 if (sc->sc_hwoflow)
187 UART_IOCTL(sc, UART_IOCTL_OFLOW, 0);
188 if (sc->sc_sysdev == NULL)
189 UART_SETSIG(sc, SER_DDTR | SER_DRTS);
190
191 wakeup(sc);
192 sc->sc_opened = 0;
193 }
194
195 static void
uart_tty_outwakeup(struct tty * tp)196 uart_tty_outwakeup(struct tty *tp)
197 {
198 struct uart_softc *sc;
199
200 sc = tty_softc(tp);
201 if (sc == NULL || sc->sc_leaving)
202 return;
203
204 if (sc->sc_txbusy)
205 return;
206
207 /*
208 * Respect RTS/CTS (output) flow control if enabled and not already
209 * handled by hardware.
210 */
211 if ((tp->t_termios.c_cflag & CCTS_OFLOW) && !sc->sc_hwoflow &&
212 !(sc->sc_hwsig & SER_CTS))
213 return;
214
215 sc->sc_txdatasz = ttydisc_getc(tp, sc->sc_txbuf, sc->sc_txfifosz);
216 if (sc->sc_txdatasz != 0)
217 UART_TRANSMIT(sc);
218 }
219
220 static void
uart_tty_inwakeup(struct tty * tp)221 uart_tty_inwakeup(struct tty *tp)
222 {
223 struct uart_softc *sc;
224
225 sc = tty_softc(tp);
226 if (sc == NULL || sc->sc_leaving)
227 return;
228
229 if (sc->sc_isquelch) {
230 if ((tp->t_termios.c_cflag & CRTS_IFLOW) && !sc->sc_hwiflow)
231 UART_SETSIG(sc, SER_DRTS|SER_RTS);
232 sc->sc_isquelch = 0;
233 uart_sched_softih(sc, SER_INT_RXREADY);
234 }
235 }
236
237 static int
uart_tty_ioctl(struct tty * tp,u_long cmd,caddr_t data,struct thread * td __unused)238 uart_tty_ioctl(struct tty *tp, u_long cmd, caddr_t data,
239 struct thread *td __unused)
240 {
241 struct uart_softc *sc;
242
243 sc = tty_softc(tp);
244
245 switch (cmd) {
246 case TIOCSBRK:
247 UART_IOCTL(sc, UART_IOCTL_BREAK, 1);
248 return (0);
249 case TIOCCBRK:
250 UART_IOCTL(sc, UART_IOCTL_BREAK, 0);
251 return (0);
252 default:
253 return pps_ioctl(cmd, data, &sc->sc_pps);
254 }
255 }
256
257 static int
uart_tty_param(struct tty * tp,struct termios * t)258 uart_tty_param(struct tty *tp, struct termios *t)
259 {
260 struct uart_softc *sc;
261 int databits, parity, stopbits;
262
263 sc = tty_softc(tp);
264 if (sc == NULL || sc->sc_leaving)
265 return (ENODEV);
266 if (t->c_ispeed != t->c_ospeed && t->c_ospeed != 0)
267 return (EINVAL);
268 if (t->c_ospeed == 0) {
269 UART_SETSIG(sc, SER_DDTR | SER_DRTS);
270 return (0);
271 }
272 switch (t->c_cflag & CSIZE) {
273 case CS5: databits = 5; break;
274 case CS6: databits = 6; break;
275 case CS7: databits = 7; break;
276 default: databits = 8; break;
277 }
278 stopbits = (t->c_cflag & CSTOPB) ? 2 : 1;
279 if (t->c_cflag & PARENB)
280 parity = (t->c_cflag & PARODD) ? UART_PARITY_ODD :
281 UART_PARITY_EVEN;
282 else
283 parity = UART_PARITY_NONE;
284 if (UART_PARAM(sc, t->c_ospeed, databits, stopbits, parity) != 0)
285 return (EINVAL);
286 UART_SETSIG(sc, SER_DDTR | SER_DTR);
287 /* Set input flow control state. */
288 if (!sc->sc_hwiflow) {
289 if ((t->c_cflag & CRTS_IFLOW) && sc->sc_isquelch)
290 UART_SETSIG(sc, SER_DRTS);
291 else
292 UART_SETSIG(sc, SER_DRTS | SER_RTS);
293 } else
294 UART_IOCTL(sc, UART_IOCTL_IFLOW, (t->c_cflag & CRTS_IFLOW));
295 /* Set output flow control state. */
296 if (sc->sc_hwoflow)
297 UART_IOCTL(sc, UART_IOCTL_OFLOW, (t->c_cflag & CCTS_OFLOW));
298
299 return (0);
300 }
301
302 static int
uart_tty_modem(struct tty * tp,int biton,int bitoff)303 uart_tty_modem(struct tty *tp, int biton, int bitoff)
304 {
305 struct uart_softc *sc;
306
307 sc = tty_softc(tp);
308 if (biton != 0 || bitoff != 0)
309 UART_SETSIG(sc, SER_DELTA(bitoff | biton) | biton);
310 return (sc->sc_hwsig);
311 }
312
313 void
uart_tty_intr(void * arg)314 uart_tty_intr(void *arg)
315 {
316 struct uart_softc *sc = arg;
317 struct tty *tp;
318 int c, err = 0, pend, sig, xc;
319
320 if (sc->sc_leaving)
321 return;
322
323 pend = atomic_readandclear_32(&sc->sc_ttypend);
324 if (!(pend & SER_INT_MASK))
325 return;
326
327 tp = sc->sc_u.u_tty.tp;
328 tty_lock(tp);
329
330 if (pend & SER_INT_RXREADY) {
331 while (!uart_rx_empty(sc) && !sc->sc_isquelch) {
332 xc = uart_rx_peek(sc);
333 c = xc & 0xff;
334 if (xc & UART_STAT_FRAMERR)
335 err |= TRE_FRAMING;
336 if (xc & UART_STAT_OVERRUN)
337 err |= TRE_OVERRUN;
338 if (xc & UART_STAT_PARERR)
339 err |= TRE_PARITY;
340 if (ttydisc_rint(tp, c, err) != 0) {
341 sc->sc_isquelch = 1;
342 if ((tp->t_termios.c_cflag & CRTS_IFLOW) &&
343 !sc->sc_hwiflow)
344 UART_SETSIG(sc, SER_DRTS);
345 } else
346 uart_rx_next(sc);
347 }
348 }
349
350 if (pend & SER_INT_BREAK)
351 ttydisc_rint(tp, 0, TRE_BREAK);
352
353 if (pend & SER_INT_SIGCHG) {
354 sig = pend & SER_INT_SIGMASK;
355 if (sig & SER_DDCD)
356 ttydisc_modem(tp, sig & SER_DCD);
357 if (sig & SER_DCTS)
358 uart_tty_outwakeup(tp);
359 }
360
361 if (pend & SER_INT_TXIDLE)
362 uart_tty_outwakeup(tp);
363 ttydisc_rint_done(tp);
364 tty_unlock(tp);
365 }
366
367 static void
uart_tty_free(void * arg __unused)368 uart_tty_free(void *arg __unused)
369 {
370
371 /*
372 * XXX: uart(4) could reuse the device unit number before it is
373 * being freed by the TTY layer. We should use this hook to free
374 * the device unit number, but unfortunately newbus does not
375 * seem to support such a construct.
376 */
377 }
378
379 static bool
uart_tty_busy(struct tty * tp)380 uart_tty_busy(struct tty *tp)
381 {
382 struct uart_softc *sc;
383
384 sc = tty_softc(tp);
385 if (sc == NULL || sc->sc_leaving)
386 return (FALSE);
387
388 return (sc->sc_txbusy);
389 }
390
391 static struct ttydevsw uart_tty_class = {
392 .tsw_flags = TF_INITLOCK|TF_CALLOUT,
393 .tsw_open = uart_tty_open,
394 .tsw_close = uart_tty_close,
395 .tsw_outwakeup = uart_tty_outwakeup,
396 .tsw_inwakeup = uart_tty_inwakeup,
397 .tsw_ioctl = uart_tty_ioctl,
398 .tsw_param = uart_tty_param,
399 .tsw_modem = uart_tty_modem,
400 .tsw_free = uart_tty_free,
401 .tsw_busy = uart_tty_busy,
402 };
403
404 int
uart_tty_attach(struct uart_softc * sc)405 uart_tty_attach(struct uart_softc *sc)
406 {
407 struct tty *tp;
408 int unit;
409
410 sc->sc_u.u_tty.tp = tp = tty_alloc(&uart_tty_class, sc);
411
412 unit = device_get_unit(sc->sc_dev);
413
414 if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
415 sprintf(((struct consdev *)sc->sc_sysdev->cookie)->cn_name,
416 "ttyu%r", unit);
417 tty_init_console(tp, sc->sc_sysdev->baudrate);
418 }
419
420 swi_add(&tty_intr_event, uart_driver_name, uart_tty_intr, sc, SWI_TTY,
421 INTR_TYPE_TTY, &sc->sc_softih);
422
423 tty_makedev(tp, NULL, "u%r", unit);
424
425 return (0);
426 }
427
428 int
uart_tty_detach(struct uart_softc * sc)429 uart_tty_detach(struct uart_softc *sc)
430 {
431 struct tty *tp;
432
433 tp = sc->sc_u.u_tty.tp;
434
435 tty_lock(tp);
436 swi_remove(sc->sc_softih);
437 tty_rel_gone(tp);
438
439 return (0);
440 }
441
442 struct mtx *
uart_tty_getlock(struct uart_softc * sc)443 uart_tty_getlock(struct uart_softc *sc)
444 {
445
446 if (sc->sc_u.u_tty.tp != NULL)
447 return (tty_getlock(sc->sc_u.u_tty.tp));
448 else
449 return (NULL);
450 }
451