1 /* $OpenBSD: pluart.c,v 1.14 2022/07/02 08:50:42 visa Exp $ */
2 /*
3 * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
4 * Copyright (c) 2005 Dale Rahn <drahn@dalerahn.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/param.h>
20 #include <sys/ioctl.h>
21 #include <sys/proc.h>
22 #include <sys/tty.h>
23 #include <sys/uio.h>
24 #include <sys/systm.h>
25 #include <sys/time.h>
26 #include <sys/device.h>
27 #include <sys/syslog.h>
28 #include <sys/conf.h>
29 #include <sys/fcntl.h>
30 #include <sys/kernel.h>
31
32 #include <machine/bus.h>
33
34 #include <dev/ic/pluartvar.h>
35 #include <dev/cons.h>
36
37 #ifdef DDB
38 #include <ddb/db_var.h>
39 #endif
40
41 #define DEVUNIT(x) (minor(x) & 0x7f)
42 #define DEVCUA(x) (minor(x) & 0x80)
43
44 #define UART_DR 0x00 /* Data register */
45 #define UART_DR_DATA(x) ((x) & 0xf)
46 #define UART_DR_FE (1 << 8) /* Framing error */
47 #define UART_DR_PE (1 << 9) /* Parity error */
48 #define UART_DR_BE (1 << 10) /* Break error */
49 #define UART_DR_OE (1 << 11) /* Overrun error */
50 #define UART_RSR 0x04 /* Receive status register */
51 #define UART_RSR_FE (1 << 0) /* Framing error */
52 #define UART_RSR_PE (1 << 1) /* Parity error */
53 #define UART_RSR_BE (1 << 2) /* Break error */
54 #define UART_RSR_OE (1 << 3) /* Overrun error */
55 #define UART_ECR 0x04 /* Error clear register */
56 #define UART_ECR_FE (1 << 0) /* Framing error */
57 #define UART_ECR_PE (1 << 1) /* Parity error */
58 #define UART_ECR_BE (1 << 2) /* Break error */
59 #define UART_ECR_OE (1 << 3) /* Overrun error */
60 #define UART_FR 0x18 /* Flag register */
61 #define UART_FR_CTS (1 << 0) /* Clear to send */
62 #define UART_FR_DSR (1 << 1) /* Data set ready */
63 #define UART_FR_DCD (1 << 2) /* Data carrier detect */
64 #define UART_FR_BUSY (1 << 3) /* UART busy */
65 #define UART_FR_RXFE (1 << 4) /* Receive FIFO empty */
66 #define UART_FR_TXFF (1 << 5) /* Transmit FIFO full */
67 #define UART_FR_RXFF (1 << 6) /* Receive FIFO full */
68 #define UART_FR_TXFE (1 << 7) /* Transmit FIFO empty */
69 #define UART_FR_RI (1 << 8) /* Ring indicator */
70 #define UART_ILPR 0x20 /* IrDA low-power counter register */
71 #define UART_ILPR_ILPDVSR ((x) & 0xf) /* IrDA low-power divisor */
72 #define UART_IBRD 0x24 /* Integer baud rate register */
73 #define UART_IBRD_DIVINT(x) ((x) & 0xffff) /* Integer baud rate divisor */
74 #define UART_FBRD 0x28 /* Fractional baud rate register */
75 #define UART_FBRD_DIVFRAC(x) ((x) & 0x3f) /* Fractional baud rate divisor */
76 #define UART_LCR_H 0x2c /* Line control register */
77 #define UART_LCR_H_BRK (1 << 0) /* Send break */
78 #define UART_LCR_H_PEN (1 << 1) /* Parity enable */
79 #define UART_LCR_H_EPS (1 << 2) /* Even parity select */
80 #define UART_LCR_H_STP2 (1 << 3) /* Two stop bits select */
81 #define UART_LCR_H_FEN (1 << 4) /* Enable FIFOs */
82 #define UART_LCR_H_WLEN5 (0x0 << 5) /* Word length: 5 bits */
83 #define UART_LCR_H_WLEN6 (0x1 << 5) /* Word length: 6 bits */
84 #define UART_LCR_H_WLEN7 (0x2 << 5) /* Word length: 7 bits */
85 #define UART_LCR_H_WLEN8 (0x3 << 5) /* Word length: 8 bits */
86 #define UART_LCR_H_SPS (1 << 7) /* Stick parity select */
87 #define UART_CR 0x30 /* Control register */
88 #define UART_CR_UARTEN (1 << 0) /* UART enable */
89 #define UART_CR_SIREN (1 << 1) /* SIR enable */
90 #define UART_CR_SIRLP (1 << 2) /* IrDA SIR low power mode */
91 #define UART_CR_LBE (1 << 7) /* Loop back enable */
92 #define UART_CR_TXE (1 << 8) /* Transmit enable */
93 #define UART_CR_RXE (1 << 9) /* Receive enable */
94 #define UART_CR_DTR (1 << 10) /* Data transmit enable */
95 #define UART_CR_RTS (1 << 11) /* Request to send */
96 #define UART_CR_OUT1 (1 << 12)
97 #define UART_CR_OUT2 (1 << 13)
98 #define UART_CR_CTSE (1 << 14) /* CTS hardware flow control enable */
99 #define UART_CR_RTSE (1 << 15) /* RTS hardware flow control enable */
100 #define UART_IFLS 0x34 /* Interrupt FIFO level select register */
101 #define UART_IFLS_RX_SHIFT 3 /* RX level in bits [5:3] */
102 #define UART_IFLS_TX_SHIFT 0 /* TX level in bits [2:0] */
103 #define UART_IFLS_1_8 0 /* FIFO 1/8 full */
104 #define UART_IFLS_1_4 1 /* FIFO 1/4 full */
105 #define UART_IFLS_1_2 2 /* FIFO 1/2 full */
106 #define UART_IFLS_3_4 3 /* FIFO 3/4 full */
107 #define UART_IFLS_7_8 4 /* FIFO 7/8 full */
108 #define UART_IMSC 0x38 /* Interrupt mask set/clear register */
109 #define UART_IMSC_RIMIM (1 << 0)
110 #define UART_IMSC_CTSMIM (1 << 1)
111 #define UART_IMSC_DCDMIM (1 << 2)
112 #define UART_IMSC_DSRMIM (1 << 3)
113 #define UART_IMSC_RXIM (1 << 4)
114 #define UART_IMSC_TXIM (1 << 5)
115 #define UART_IMSC_RTIM (1 << 6)
116 #define UART_IMSC_FEIM (1 << 7)
117 #define UART_IMSC_PEIM (1 << 8)
118 #define UART_IMSC_BEIM (1 << 9)
119 #define UART_IMSC_OEIM (1 << 10)
120 #define UART_RIS 0x3c /* Raw interrupt status register */
121 #define UART_MIS 0x40 /* Masked interrupt status register */
122 #define UART_ICR 0x44 /* Interrupt clear register */
123 #define UART_DMACR 0x48 /* DMA control register */
124 #define UART_PID0 0xfe0 /* Peripheral identification register 0 */
125 #define UART_PID1 0xfe4 /* Peripheral identification register 1 */
126 #define UART_PID2 0xfe8 /* Peripheral identification register 2 */
127 #define UART_PID2_REV(x) (((x) & 0xf0) >> 4)
128 #define UART_PID3 0xfec /* Peripheral identification register 3 */
129 #define UART_SPACE 0x100
130
131 #define UART_FIFO_SIZE 16
132 #define UART_FIFO_SIZE_R3 32
133
134 void pluartcnprobe(struct consdev *cp);
135 void pluartcninit(struct consdev *cp);
136 int pluartcngetc(dev_t dev);
137 void pluartcnputc(dev_t dev, int c);
138 void pluartcnpollc(dev_t dev, int on);
139 int pluart_param(struct tty *tp, struct termios *t);
140 void pluart_start(struct tty *);
141 void pluart_diag(void *arg);
142 void pluart_raisedtr(void *arg);
143 void pluart_softint(void *arg);
144 struct pluart_softc *pluart_sc(dev_t dev);
145
146 /* XXX - we imitate 'com' serial ports and take over their entry points */
147 /* XXX: These belong elsewhere */
148 cdev_decl(com);
149 cdev_decl(pluart);
150
151 struct cfdriver pluart_cd = {
152 NULL, "pluart", DV_TTY
153 };
154
155 int pluartdefaultrate = B38400;
156 int pluartconsrate = B38400;
157 bus_space_tag_t pluartconsiot;
158 bus_space_handle_t pluartconsioh;
159 bus_addr_t pluartconsaddr;
160 tcflag_t pluartconscflag = TTYDEF_CFLAG;
161
162 struct cdevsw pluartdev =
163 cdev_tty_init(3/*XXX NUART */ ,pluart); /* 12: serial port */
164
165 void
pluart_attach_common(struct pluart_softc * sc,int console)166 pluart_attach_common(struct pluart_softc *sc, int console)
167 {
168 int fifolen, fr, lcr, maj;
169
170 if ((sc->sc_hwflags & COM_HW_SBSA) == 0) {
171 if (sc->sc_hwrev == 0)
172 sc->sc_hwrev = UART_PID2_REV(bus_space_read_4(sc->sc_iot,
173 sc->sc_ioh, UART_PID2));
174 if (sc->sc_hwrev < 3)
175 fifolen = UART_FIFO_SIZE;
176 else
177 fifolen = UART_FIFO_SIZE_R3;
178 printf(": rev %d, %d byte fifo\n", sc->sc_hwrev, fifolen);
179 } else {
180 /*
181 * The SBSA UART is PL011 r1p5 compliant which implies revision
182 * 3 with a 32 byte FIFO. However, we cannot expect to configure
183 * RX/TX interrupt levels using the UARTIFLS register making it
184 * impossible to make assumptions about the number of available
185 * bytes in the FIFO. Therefore disable FIFO support for such
186 * devices.
187 */
188 fifolen = 0;
189 printf("\n");
190 }
191
192 if (console) {
193 /* Locate the major number. */
194 for (maj = 0; maj < nchrdev; maj++)
195 if (cdevsw[maj].d_open == pluartopen)
196 break;
197 cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
198
199 printf("%s: console\n", sc->sc_dev.dv_xname);
200 SET(sc->sc_hwflags, COM_HW_CONSOLE);
201 }
202
203 timeout_set(&sc->sc_diag_tmo, pluart_diag, sc);
204 timeout_set(&sc->sc_dtr_tmo, pluart_raisedtr, sc);
205 sc->sc_si = softintr_establish(IPL_TTY, pluart_softint, sc);
206
207 if(sc->sc_si == NULL)
208 panic("%s: can't establish soft interrupt.",
209 sc->sc_dev.dv_xname);
210
211 /* Flush transmit before enabling FIFO. */
212 for (;;) {
213 fr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_FR);
214 if (fr & UART_FR_TXFE)
215 break;
216 delay(100);
217 }
218
219 if (fifolen > 0) {
220 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IFLS,
221 (UART_IFLS_3_4 << UART_IFLS_RX_SHIFT) |
222 (UART_IFLS_1_4 << UART_IFLS_TX_SHIFT));
223 }
224 sc->sc_imsc = UART_IMSC_RXIM | UART_IMSC_RTIM;
225 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, sc->sc_imsc);
226 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff);
227
228
229 lcr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H);
230 if (fifolen > 0)
231 lcr |= UART_LCR_H_FEN;
232 else
233 lcr &= ~UART_LCR_H_FEN;
234 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, lcr);
235 }
236
237 int
pluart_intr(void * arg)238 pluart_intr(void *arg)
239 {
240 struct pluart_softc *sc = arg;
241 bus_space_tag_t iot = sc->sc_iot;
242 bus_space_handle_t ioh = sc->sc_ioh;
243 struct tty *tp = sc->sc_tty;
244 u_int16_t is;
245 u_int16_t *p;
246 u_int16_t c;
247
248 is = bus_space_read_4(iot, ioh, UART_MIS);
249 bus_space_write_4(iot, ioh, UART_ICR, is & ~UART_IMSC_TXIM);
250
251 if (sc->sc_tty == NULL)
252 return 0;
253
254 if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_RTIM) &&
255 !ISSET(is, UART_IMSC_TXIM))
256 return 0;
257
258 if (ISSET(is, UART_IMSC_TXIM) && ISSET(tp->t_state, TS_BUSY)) {
259 CLR(tp->t_state, TS_BUSY | TS_FLUSH);
260 if (sc->sc_halt > 0)
261 wakeup(&tp->t_outq);
262 (*linesw[tp->t_line].l_start)(tp);
263 }
264
265 p = sc->sc_ibufp;
266
267 while (!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFE)) {
268 c = bus_space_read_2(iot, ioh, UART_DR);
269 if (c & UART_DR_BE) {
270 #ifdef DDB
271 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
272 if (db_console)
273 db_enter();
274 continue;
275 }
276 #endif
277 c = 0;
278 }
279 if (p >= sc->sc_ibufend) {
280 sc->sc_floods++;
281 if (sc->sc_errors++ == 0)
282 timeout_add_sec(&sc->sc_diag_tmo, 60);
283 } else {
284 *p++ = c;
285 if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS)) {
286 /* XXX */
287 //CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
288 //bus_space_write_4(iot, ioh, IMXUART_UCR3,
289 // sc->sc_ucr3);
290 }
291 }
292 /* XXX - msr stuff ? */
293 }
294 sc->sc_ibufp = p;
295
296 softintr_schedule(sc->sc_si);
297
298 return 1;
299 }
300
301 int
pluart_param(struct tty * tp,struct termios * t)302 pluart_param(struct tty *tp, struct termios *t)
303 {
304 struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
305 int ospeed = t->c_ospeed;
306 int error;
307 tcflag_t oldcflag;
308
309 if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
310 return EINVAL;
311
312 switch (ISSET(t->c_cflag, CSIZE)) {
313 case CS5:
314 return EINVAL;
315 case CS6:
316 return EINVAL;
317 case CS7:
318 //CLR(sc->sc_ucr2, IMXUART_CR2_WS);
319 break;
320 case CS8:
321 //SET(sc->sc_ucr2, IMXUART_CR2_WS);
322 break;
323 }
324 // bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
325
326 /*
327 if (ISSET(t->c_cflag, PARENB)) {
328 SET(sc->sc_ucr2, IMXUART_CR2_PREN);
329 bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
330 }
331 */
332 /* STOPB - XXX */
333 if (ospeed == 0) {
334 /* lower dtr */
335 }
336
337 if (sc->sc_clkfreq != 0 && ospeed != 0 && ospeed != tp->t_ospeed) {
338 int cr, div, lcr;
339
340 while (ISSET(tp->t_state, TS_BUSY)) {
341 ++sc->sc_halt;
342 error = ttysleep(tp, &tp->t_outq,
343 TTOPRI | PCATCH, "pluartprm");
344 --sc->sc_halt;
345 if (error) {
346 pluart_start(tp);
347 return (error);
348 }
349 }
350
351 /*
352 * Writes to IBRD and FBRD are made effective first when LCR_H
353 * is written.
354 */
355 lcr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H);
356
357 /* The UART must be disabled while changing the baud rate. */
358 cr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_CR);
359 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_CR,
360 cr & ~UART_CR_UARTEN);
361
362 /*
363 * The baud rate divisor is expressed relative to the UART clock
364 * frequency where IBRD represents the quotient using 16 bits
365 * and FBRD the remainder using 6 bits. The PL011 specification
366 * provides the following formula:
367 *
368 * uartclk/(16 * baudrate)
369 *
370 * The formula can be estimated by scaling it with the
371 * precision 64 (2^6) and letting the resulting upper 16 bits
372 * represents the quotient and the lower 6 bits the remainder:
373 *
374 * 64 * uartclk/(16 * baudrate) = 4 * uartclk/baudrate
375 */
376 div = 4 * sc->sc_clkfreq / ospeed;
377 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IBRD,
378 UART_IBRD_DIVINT(div >> 6));
379 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_FBRD,
380 UART_FBRD_DIVFRAC(div));
381 /* Commit baud rate change. */
382 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, lcr);
383 /* Enable UART. */
384 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_CR, cr);
385 }
386
387 /* setup fifo */
388
389 /* When not using CRTSCTS, RTS follows DTR. */
390 /* sc->sc_dtr = MCR_DTR; */
391
392 /* and copy to tty */
393 tp->t_ispeed = t->c_ispeed;
394 tp->t_ospeed = t->c_ospeed;
395 oldcflag = tp->t_cflag;
396 tp->t_cflag = t->c_cflag;
397
398 /*
399 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
400 * stop the device.
401 */
402 /* XXX */
403
404 pluart_start(tp);
405
406 return 0;
407 }
408
409 void
pluart_start(struct tty * tp)410 pluart_start(struct tty *tp)
411 {
412 struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
413 bus_space_tag_t iot = sc->sc_iot;
414 bus_space_handle_t ioh = sc->sc_ioh;
415 int s;
416
417 s = spltty();
418 if (ISSET(tp->t_state, TS_BUSY))
419 goto out;
420 if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
421 goto stopped;
422 ttwakeupwr(tp);
423 if (tp->t_outq.c_cc == 0)
424 goto stopped;
425 SET(tp->t_state, TS_BUSY);
426
427 /* Enable transmit interrupt. */
428 if (!ISSET(sc->sc_imsc, UART_IMSC_TXIM)) {
429 sc->sc_imsc |= UART_IMSC_TXIM;
430 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC,
431 sc->sc_imsc);
432 }
433
434 while (tp->t_outq.c_cc > 0) {
435 uint16_t fr;
436
437 fr = bus_space_read_4(iot, ioh, UART_FR);
438 if (ISSET(fr, UART_FR_TXFF))
439 break;
440
441 bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq));
442 }
443
444 out:
445 splx(s);
446 return;
447
448 stopped:
449 /* Disable transmit interrupt. */
450 if (ISSET(sc->sc_imsc, UART_IMSC_TXIM)) {
451 sc->sc_imsc &= ~UART_IMSC_TXIM;
452 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC,
453 sc->sc_imsc);
454 }
455 splx(s);
456 }
457
458 void
pluart_diag(void * arg)459 pluart_diag(void *arg)
460 {
461 struct pluart_softc *sc = arg;
462 int overflows, floods;
463 int s;
464
465 s = spltty();
466 sc->sc_errors = 0;
467 overflows = sc->sc_overflows;
468 sc->sc_overflows = 0;
469 floods = sc->sc_floods;
470 sc->sc_floods = 0;
471 splx(s);
472 log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
473 sc->sc_dev.dv_xname,
474 overflows, overflows == 1 ? "" : "s",
475 floods, floods == 1 ? "" : "s");
476 }
477
478 void
pluart_raisedtr(void * arg)479 pluart_raisedtr(void *arg)
480 {
481 //struct pluart_softc *sc = arg;
482
483 //SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
484 //bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3);
485 }
486
487 void
pluart_softint(void * arg)488 pluart_softint(void *arg)
489 {
490 struct pluart_softc *sc = arg;
491 struct tty *tp;
492 u_int16_t *ibufp;
493 u_int16_t *ibufend;
494 int c;
495 int err;
496 int s;
497
498 if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
499 return;
500
501 tp = sc->sc_tty;
502 s = spltty();
503
504 ibufp = sc->sc_ibuf;
505 ibufend = sc->sc_ibufp;
506
507 if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
508 splx(s);
509 return;
510 }
511
512 sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
513 sc->sc_ibufs[1] : sc->sc_ibufs[0];
514 sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
515 sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
516
517 #if 0
518 if (ISSET(tp->t_cflag, CRTSCTS) &&
519 !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) {
520 /* XXX */
521 SET(sc->sc_ucr3, IMXUART_CR3_DSR);
522 bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3,
523 sc->sc_ucr3);
524 }
525 #endif
526
527 splx(s);
528
529 while (ibufp < ibufend) {
530 c = *ibufp++;
531 /*
532 if (ISSET(c, IMXUART_RX_OVERRUN)) {
533 sc->sc_overflows++;
534 if (sc->sc_errors++ == 0)
535 timeout_add_sec(&sc->sc_diag_tmo, 60);
536 }
537 */
538 /* This is ugly, but fast. */
539
540 err = 0;
541 /*
542 if (ISSET(c, IMXUART_RX_PRERR))
543 err |= TTY_PE;
544 if (ISSET(c, IMXUART_RX_FRMERR))
545 err |= TTY_FE;
546 */
547 c = (c & 0xff) | err;
548 (*linesw[tp->t_line].l_rint)(c, tp);
549 }
550 }
551
552 int
pluartopen(dev_t dev,int flag,int mode,struct proc * p)553 pluartopen(dev_t dev, int flag, int mode, struct proc *p)
554 {
555 int unit = DEVUNIT(dev);
556 struct pluart_softc *sc;
557 bus_space_tag_t iot;
558 bus_space_handle_t ioh;
559 struct tty *tp;
560 int s;
561 int error = 0;
562
563 if (unit >= pluart_cd.cd_ndevs)
564 return ENXIO;
565 sc = pluart_cd.cd_devs[unit];
566 if (sc == NULL)
567 return ENXIO;
568
569 s = spltty();
570 if (sc->sc_tty == NULL)
571 tp = sc->sc_tty = ttymalloc(0);
572 else
573 tp = sc->sc_tty;
574
575 splx(s);
576
577 tp->t_oproc = pluart_start;
578 tp->t_param = pluart_param;
579 tp->t_dev = dev;
580
581 if (!ISSET(tp->t_state, TS_ISOPEN)) {
582 SET(tp->t_state, TS_WOPEN);
583 ttychars(tp);
584 tp->t_iflag = TTYDEF_IFLAG;
585 tp->t_oflag = TTYDEF_OFLAG;
586
587 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
588 tp->t_cflag = pluartconscflag;
589 else
590 tp->t_cflag = TTYDEF_CFLAG;
591 if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
592 SET(tp->t_cflag, CLOCAL);
593 if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
594 SET(tp->t_cflag, CRTSCTS);
595 if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
596 SET(tp->t_cflag, MDMBUF);
597 tp->t_lflag = TTYDEF_LFLAG;
598 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
599 tp->t_ispeed = tp->t_ospeed = pluartconsrate;
600 else
601 tp->t_ispeed = tp->t_ospeed = pluartdefaultrate;
602
603 s = spltty();
604
605 sc->sc_initialize = 1;
606 pluart_param(tp, &tp->t_termios);
607 ttsetwater(tp);
608 sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
609 sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
610 sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
611
612 iot = sc->sc_iot;
613 ioh = sc->sc_ioh;
614
615 #if 0
616 sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1);
617 sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2);
618 sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3);
619 sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4);
620
621 /* interrupt after one char on tx/rx */
622 /* reference frequency divider: 1 */
623 bus_space_write_4(iot, ioh, IMXUART_UFCR,
624 1 << IMXUART_FCR_TXTL_SH |
625 5 << IMXUART_FCR_RFDIV_SH |
626 1 << IMXUART_FCR_RXTL_SH);
627
628 SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN);
629 SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
630 bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
631 bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
632
633 /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */
634 SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
635 bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
636 #endif
637
638 SET(tp->t_state, TS_CARR_ON); /* XXX */
639
640
641 } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
642 return EBUSY;
643 else
644 s = spltty();
645
646 if (DEVCUA(dev)) {
647 if (ISSET(tp->t_state, TS_ISOPEN)) {
648 splx(s);
649 return EBUSY;
650 }
651 sc->sc_cua = 1;
652 } else {
653 /* tty (not cua) device; wait for carrier if necessary */
654 if (ISSET(flag, O_NONBLOCK)) {
655 if (sc->sc_cua) {
656 /* Opening TTY non-blocking... but the CUA is busy */
657 splx(s);
658 return EBUSY;
659 }
660 } else {
661 while (sc->sc_cua ||
662 (!ISSET(tp->t_cflag, CLOCAL) &&
663 !ISSET(tp->t_state, TS_CARR_ON))) {
664 SET(tp->t_state, TS_WOPEN);
665 error = ttysleep(tp, &tp->t_rawq,
666 TTIPRI | PCATCH, ttopen);
667 /*
668 * If TS_WOPEN has been reset, that means the
669 * cua device has been closed. We don't want
670 * to fail in that case,
671 * so just go around again.
672 */
673 if (error && ISSET(tp->t_state, TS_WOPEN)) {
674 CLR(tp->t_state, TS_WOPEN);
675 splx(s);
676 return error;
677 }
678 }
679 }
680 }
681 splx(s);
682 return (*linesw[tp->t_line].l_open)(dev,tp,p);
683 }
684
685 int
pluartclose(dev_t dev,int flag,int mode,struct proc * p)686 pluartclose(dev_t dev, int flag, int mode, struct proc *p)
687 {
688 int unit = DEVUNIT(dev);
689 struct pluart_softc *sc = pluart_cd.cd_devs[unit];
690 //bus_space_tag_t iot = sc->sc_iot;
691 //bus_space_handle_t ioh = sc->sc_ioh;
692 struct tty *tp = sc->sc_tty;
693 int s;
694
695 /* XXX This is for cons.c. */
696 if (!ISSET(tp->t_state, TS_ISOPEN))
697 return 0;
698
699 (*linesw[tp->t_line].l_close)(tp, flag, p);
700 s = spltty();
701 if (ISSET(tp->t_state, TS_WOPEN)) {
702 /* tty device is waiting for carrier; drop dtr then re-raise */
703 //CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
704 //bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
705 timeout_add_sec(&sc->sc_dtr_tmo, 2);
706 }
707 CLR(tp->t_state, TS_BUSY | TS_FLUSH);
708
709 sc->sc_cua = 0;
710 splx(s);
711 ttyclose(tp);
712
713 return 0;
714 }
715
716 int
pluartread(dev_t dev,struct uio * uio,int flag)717 pluartread(dev_t dev, struct uio *uio, int flag)
718 {
719 struct tty *tty;
720
721 tty = pluarttty(dev);
722 if (tty == NULL)
723 return ENODEV;
724
725 return((*linesw[tty->t_line].l_read)(tty, uio, flag));
726 }
727
728 int
pluartwrite(dev_t dev,struct uio * uio,int flag)729 pluartwrite(dev_t dev, struct uio *uio, int flag)
730 {
731 struct tty *tty;
732
733 tty = pluarttty(dev);
734 if (tty == NULL)
735 return ENODEV;
736
737 return((*linesw[tty->t_line].l_write)(tty, uio, flag));
738 }
739
740 int
pluartioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)741 pluartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
742 {
743 struct pluart_softc *sc;
744 struct tty *tp;
745 int error;
746
747 sc = pluart_sc(dev);
748 if (sc == NULL)
749 return (ENODEV);
750
751 tp = sc->sc_tty;
752 if (tp == NULL)
753 return (ENXIO);
754
755 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
756 if (error >= 0)
757 return (error);
758
759 error = ttioctl(tp, cmd, data, flag, p);
760 if (error >= 0)
761 return (error);
762
763 switch(cmd) {
764 case TIOCSBRK:
765 break;
766 case TIOCCBRK:
767 break;
768 case TIOCSDTR:
769 break;
770 case TIOCCDTR:
771 break;
772 case TIOCMSET:
773 break;
774 case TIOCMBIS:
775 break;
776 case TIOCMBIC:
777 break;
778 case TIOCMGET:
779 break;
780 case TIOCGFLAGS:
781 break;
782 case TIOCSFLAGS:
783 error = suser(p);
784 if (error != 0)
785 return(EPERM);
786 break;
787 default:
788 return (ENOTTY);
789 }
790
791 return 0;
792 }
793
794 int
pluartstop(struct tty * tp,int flag)795 pluartstop(struct tty *tp, int flag)
796 {
797 return 0;
798 }
799
800 struct tty *
pluarttty(dev_t dev)801 pluarttty(dev_t dev)
802 {
803 int unit;
804 struct pluart_softc *sc;
805 unit = DEVUNIT(dev);
806 if (unit >= pluart_cd.cd_ndevs)
807 return NULL;
808 sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
809 if (sc == NULL)
810 return NULL;
811 return sc->sc_tty;
812 }
813
814 struct pluart_softc *
pluart_sc(dev_t dev)815 pluart_sc(dev_t dev)
816 {
817 int unit;
818 struct pluart_softc *sc;
819 unit = DEVUNIT(dev);
820 if (unit >= pluart_cd.cd_ndevs)
821 return NULL;
822 sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
823 return sc;
824 }
825
826
827 /* serial console */
828 void
pluartcnprobe(struct consdev * cp)829 pluartcnprobe(struct consdev *cp)
830 {
831 }
832
833 void
pluartcninit(struct consdev * cp)834 pluartcninit(struct consdev *cp)
835 {
836 }
837
838 int
pluartcnattach(bus_space_tag_t iot,bus_addr_t iobase,int rate,tcflag_t cflag)839 pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
840 {
841 static struct consdev pluartcons = {
842 NULL, NULL, pluartcngetc, pluartcnputc, pluartcnpollc, NULL,
843 NODEV, CN_MIDPRI
844 };
845 int maj;
846
847 if (bus_space_map(iot, iobase, UART_SPACE, 0, &pluartconsioh))
848 return ENOMEM;
849
850 /* Disable FIFO. */
851 bus_space_write_4(iot, pluartconsioh, UART_LCR_H,
852 bus_space_read_4(iot, pluartconsioh, UART_LCR_H) & ~UART_LCR_H_FEN);
853
854 /* Look for major of com(4) to replace. */
855 for (maj = 0; maj < nchrdev; maj++)
856 if (cdevsw[maj].d_open == comopen)
857 break;
858 if (maj == nchrdev)
859 return ENXIO;
860
861 cn_tab = &pluartcons;
862 cn_tab->cn_dev = makedev(maj, 0);
863 cdevsw[maj] = pluartdev; /* KLUDGE */
864
865 pluartconsiot = iot;
866 pluartconsaddr = iobase;
867 pluartconscflag = cflag;
868 pluartconsrate = rate;
869
870 return 0;
871 }
872
873 int
pluartcngetc(dev_t dev)874 pluartcngetc(dev_t dev)
875 {
876 int c;
877 int s;
878 s = splhigh();
879 while ((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
880 UART_FR_RXFE))
881 ;
882 c = bus_space_read_4(pluartconsiot, pluartconsioh, UART_DR);
883 splx(s);
884 return c;
885 }
886
887 void
pluartcnputc(dev_t dev,int c)888 pluartcnputc(dev_t dev, int c)
889 {
890 int s;
891 s = splhigh();
892 while ((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
893 UART_FR_TXFF))
894 ;
895 bus_space_write_4(pluartconsiot, pluartconsioh, UART_DR, (uint8_t)c);
896 splx(s);
897 }
898
899 void
pluartcnpollc(dev_t dev,int on)900 pluartcnpollc(dev_t dev, int on)
901 {
902 }
903