]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/uart/uart_tty.c
This commit was generated by cvs2svn to compensate for changes in r146539,
[FreeBSD/FreeBSD.git] / sys / dev / uart / uart_tty.c
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/termios.h>
43 #include <sys/tty.h>
44 #include <machine/resource.h>
45 #include <machine/stdarg.h>
46
47 #include <dev/uart/uart.h>
48 #include <dev/uart/uart_bus.h>
49 #include <dev/uart/uart_cpu.h>
50
51 #include "uart_if.h"
52
53 static cn_probe_t uart_cnprobe;
54 static cn_init_t uart_cninit;
55 static cn_term_t uart_cnterm;
56 static cn_getc_t uart_cngetc;
57 static cn_checkc_t uart_cncheckc;
58 static cn_putc_t uart_cnputc;
59
60 CONS_DRIVER(uart, uart_cnprobe, uart_cninit, uart_cnterm, uart_cngetc,
61     uart_cncheckc, uart_cnputc, NULL);
62
63 static struct uart_devinfo uart_console;
64
65 static void
66 uart_cnprobe(struct consdev *cp)
67 {
68
69         cp->cn_pri = CN_DEAD;
70
71         KASSERT(uart_console.cookie == NULL, ("foo"));
72
73         if (uart_cpu_getdev(UART_DEV_CONSOLE, &uart_console))
74                 return;
75
76         if (uart_probe(&uart_console))
77                 return;
78
79         strlcpy(cp->cn_name, uart_driver_name, sizeof(cp->cn_name));
80         cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
81         cp->cn_arg = &uart_console;
82 }
83
84 static void
85 uart_cninit(struct consdev *cp)
86 {
87         struct uart_devinfo *di;
88
89         /*
90          * Yedi trick: we need to be able to define cn_dev before we go
91          * single- or multi-user. The problem is that we don't know at
92          * this time what the device will be. Hence, we need to link from
93          * the uart_devinfo to the consdev that corresponds to it so that
94          * we can define cn_dev in uart_bus_attach() when we find the
95          * device during bus enumeration. That's when we'll know what the
96          * the unit number will be.
97          */
98         di = cp->cn_arg;
99         KASSERT(di->cookie == NULL, ("foo"));
100         di->cookie = cp;
101         di->type = UART_DEV_CONSOLE;
102         uart_add_sysdev(di);
103         uart_init(di);
104 }
105
106 static void
107 uart_cnterm(struct consdev *cp)
108 {
109
110         uart_term(cp->cn_arg);
111 }
112
113 static void
114 uart_cnputc(struct consdev *cp, int c)
115 {
116
117         uart_putc(cp->cn_arg, c);
118 }
119
120 static int
121 uart_cncheckc(struct consdev *cp)
122 {
123
124         return (uart_poll(cp->cn_arg));
125 }
126
127 static int
128 uart_cngetc(struct consdev *cp)
129 {
130
131         return (uart_getc(cp->cn_arg));
132 }
133
134 static int
135 uart_tty_open(struct tty *tp, struct cdev *dev)
136 {
137         struct uart_softc *sc;
138
139         sc = tp->t_sc;
140         sc->sc_opened = 1;
141         return (0);
142 }
143
144 static void
145 uart_tty_close(struct tty *tp)
146 {
147         struct uart_softc *sc;
148
149         sc = tp->t_sc;
150         if (sc == NULL || sc->sc_leaving || !sc->sc_opened) 
151                 return;
152
153         if (sc->sc_hwiflow)
154                 UART_IOCTL(sc, UART_IOCTL_IFLOW, 0);
155         if (sc->sc_hwoflow)
156                 UART_IOCTL(sc, UART_IOCTL_OFLOW, 0);
157         if (sc->sc_sysdev == NULL)
158                 UART_SETSIG(sc, SER_DDTR | SER_DRTS);
159
160         wakeup(sc);
161         sc->sc_opened = 0;
162         return;
163 }
164
165 static void
166 uart_tty_oproc(struct tty *tp)
167 {
168         struct uart_softc *sc;
169
170         sc = tp->t_sc;
171         if (sc == NULL || sc->sc_leaving)
172                 return;
173
174         /*
175          * Handle input flow control. Note that if we have hardware support,
176          * we don't do anything here. We continue to receive until our buffer
177          * is full. At that time we cannot empty the UART itself and it will
178          * de-assert RTS for us. In that situation we're completely stuffed.
179          * Without hardware support, we need to toggle RTS ourselves.
180          */
181         if ((tp->t_cflag & CRTS_IFLOW) && !sc->sc_hwiflow) {
182                 if ((tp->t_state & TS_TBLOCK) &&
183                     (sc->sc_hwsig & SER_RTS))
184                         UART_SETSIG(sc, SER_DRTS);
185                 else if (!(tp->t_state & TS_TBLOCK) &&
186                     !(sc->sc_hwsig & SER_RTS))
187                         UART_SETSIG(sc, SER_DRTS|SER_RTS);
188         }
189
190         if (tp->t_state & TS_TTSTOP)
191                 return;
192
193         if ((tp->t_state & TS_BUSY) || sc->sc_txbusy)
194                 return;
195
196         if (tp->t_outq.c_cc == 0) {
197                 ttwwakeup(tp);
198                 return;
199         }
200
201         sc->sc_txdatasz = q_to_b(&tp->t_outq, sc->sc_txbuf, sc->sc_txfifosz);
202         tp->t_state |= TS_BUSY;
203         UART_TRANSMIT(sc);
204         ttwwakeup(tp);
205 }
206
207 static int
208 uart_tty_param(struct tty *tp, struct termios *t)
209 {
210         struct uart_softc *sc;
211         int databits, parity, stopbits;
212
213         sc = tp->t_sc;
214         if (sc == NULL || sc->sc_leaving)
215                 return (ENODEV);
216         if (t->c_ispeed != t->c_ospeed && t->c_ospeed != 0)
217                 return (EINVAL);
218         /* Fixate certain parameters for system devices. */
219         if (sc->sc_sysdev != NULL) {
220                 t->c_ispeed = t->c_ospeed = sc->sc_sysdev->baudrate;
221                 t->c_cflag |= CLOCAL;
222                 t->c_cflag &= ~HUPCL;
223         }
224         if (t->c_ospeed == 0) {
225                 UART_SETSIG(sc, SER_DDTR | SER_DRTS);
226                 return (0);
227         }
228         switch (t->c_cflag & CSIZE) {
229         case CS5:       databits = 5; break;
230         case CS6:       databits = 6; break;
231         case CS7:       databits = 7; break;
232         default:        databits = 8; break;
233         }
234         stopbits = (t->c_cflag & CSTOPB) ? 2 : 1;
235         if (t->c_cflag & PARENB)
236                 parity = (t->c_cflag & PARODD) ? UART_PARITY_ODD
237                     : UART_PARITY_EVEN;
238         else
239                 parity = UART_PARITY_NONE;
240         if (UART_PARAM(sc, t->c_ospeed, databits, stopbits, parity) != 0)
241                 return (EINVAL);
242         UART_SETSIG(sc, SER_DDTR | SER_DTR);
243         /* Set input flow control state. */
244         if (!sc->sc_hwiflow) {
245                 if ((t->c_cflag & CRTS_IFLOW) && (tp->t_state & TS_TBLOCK))
246                         UART_SETSIG(sc, SER_DRTS);
247                 else
248                         UART_SETSIG(sc, SER_DRTS | SER_RTS);
249         } else
250                 UART_IOCTL(sc, UART_IOCTL_IFLOW, (t->c_cflag & CRTS_IFLOW));
251         /* Set output flow control state. */
252         if (sc->sc_hwoflow)
253                 UART_IOCTL(sc, UART_IOCTL_OFLOW, (t->c_cflag & CCTS_OFLOW));
254         ttsetwater(tp);
255         return (0);
256 }
257
258 static int
259 uart_tty_modem(struct tty *tp, int biton, int bitoff)
260 {
261         struct uart_softc *sc;
262
263         sc = tp->t_sc;
264         if (biton != 0 || bitoff != 0)
265                 UART_SETSIG(sc, SER_DELTA(bitoff|biton) | biton);
266         return (sc->sc_hwsig);
267 }
268
269 static void
270 uart_tty_break(struct tty *tp, int state)
271 {
272         struct uart_softc *sc;
273
274         sc = tp->t_sc;
275         UART_IOCTL(sc, UART_IOCTL_BREAK, state);
276 }
277
278 static void
279 uart_tty_stop(struct tty *tp, int rw)
280 {
281         struct uart_softc *sc;
282
283         sc = tp->t_sc;
284         if (sc == NULL || sc->sc_leaving)
285                 return;
286         if (rw & FWRITE) {
287                 if (sc->sc_txbusy) {
288                         sc->sc_txbusy = 0;
289                         UART_FLUSH(sc, UART_FLUSH_TRANSMITTER);
290                 }
291                 tp->t_state &= ~TS_BUSY;
292         }
293         if (rw & FREAD) {
294                 UART_FLUSH(sc, UART_FLUSH_RECEIVER);
295                 sc->sc_rxget = sc->sc_rxput = 0;
296         }
297 }
298
299 void
300 uart_tty_intr(void *arg)
301 {
302         struct uart_softc *sc = arg;
303         struct tty *tp;
304         int c, pend, sig, xc;
305
306         if (sc->sc_leaving)
307                 return;
308
309         pend = atomic_readandclear_32(&sc->sc_ttypend);
310         if (!(pend & UART_IPEND_MASK))
311                 return;
312
313         tp = sc->sc_u.u_tty.tp;
314
315         if (pend & UART_IPEND_RXREADY) {
316                 while (!uart_rx_empty(sc) && !(tp->t_state & TS_TBLOCK)) {
317                         xc = uart_rx_get(sc);
318                         c = xc & 0xff;
319                         if (xc & UART_STAT_FRAMERR)
320                                 c |= TTY_FE;
321                         if (xc & UART_STAT_PARERR)
322                                 c |= TTY_PE;
323                         ttyld_rint(tp, c);
324                 }
325         }
326
327         if (pend & UART_IPEND_BREAK) {
328                 if (tp != NULL && !(tp->t_iflag & IGNBRK))
329                         ttyld_rint(tp, 0);
330         }
331
332         if (pend & UART_IPEND_SIGCHG) {
333                 sig = pend & UART_IPEND_SIGMASK;
334                 if (sig & SER_DDCD)
335                         ttyld_modem(tp, sig & SER_DCD);
336                 if ((sig & SER_DCTS) && (tp->t_cflag & CCTS_OFLOW) &&
337                     !sc->sc_hwoflow) {
338                         if (sig & SER_CTS) {
339                                 tp->t_state &= ~TS_TTSTOP;
340                                 ttyld_start(tp);
341                         } else
342                                 tp->t_state |= TS_TTSTOP;
343                 }
344         }
345
346         if (pend & UART_IPEND_TXIDLE) {
347                 tp->t_state &= ~TS_BUSY;
348                 ttyld_start(tp);
349         }
350 }
351
352 int
353 uart_tty_attach(struct uart_softc *sc)
354 {
355         struct tty *tp;
356         int unit;
357
358         tp = ttyalloc();
359         sc->sc_u.u_tty.tp = tp;
360         tp->t_sc = sc;
361
362         unit = device_get_unit(sc->sc_dev);
363
364         tp->t_oproc = uart_tty_oproc;
365         tp->t_param = uart_tty_param;
366         tp->t_stop = uart_tty_stop;
367         tp->t_modem = uart_tty_modem;
368         tp->t_break = uart_tty_break;
369         tp->t_open = uart_tty_open;
370         tp->t_close = uart_tty_close;
371
372         tp->t_pps = &sc->sc_pps;
373
374         if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
375                 sprintf(((struct consdev *)sc->sc_sysdev->cookie)->cn_name,
376                     "ttyu%r", unit);
377                 ttyconsolemode(tp, 0);
378         }
379
380         swi_add(&tty_ithd, uart_driver_name, uart_tty_intr, sc, SWI_TTY,
381             INTR_TYPE_TTY, &sc->sc_softih);
382
383         ttycreate(tp, NULL, 0, MINOR_CALLOUT, "u%r", unit);
384
385         return (0);
386 }
387
388 int uart_tty_detach(struct uart_softc *sc)
389 {
390         struct tty *tp;
391
392         tp = sc->sc_u.u_tty.tp;
393         tp->t_pps = NULL;
394         ttygone(tp);
395         ithread_remove_handler(sc->sc_softih);
396         ttyfree(tp);
397
398         return (0);
399 }