1 /* $OpenBSD: imxuart.c,v 1.13 2022/07/02 08:50:42 visa Exp $ */
2 /*
3 * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/ioctl.h>
20 #include <sys/proc.h>
21 #include <sys/tty.h>
22 #include <sys/uio.h>
23 #include <sys/systm.h>
24 #include <sys/time.h>
25 #include <sys/device.h>
26 #include <sys/syslog.h>
27 #include <sys/conf.h>
28 #include <sys/fcntl.h>
29 #include <sys/kernel.h>
30
31 #include <machine/bus.h>
32 #include <machine/fdt.h>
33
34 #include <dev/cons.h>
35
36 #ifdef DDB
37 #include <ddb/db_var.h>
38 #endif
39
40 #include <dev/fdt/imxuartreg.h>
41
42 #include <dev/ofw/openfirm.h>
43 #include <dev/ofw/ofw_clock.h>
44 #include <dev/ofw/ofw_pinctrl.h>
45 #include <dev/ofw/fdt.h>
46
47 #define DEVUNIT(x) (minor(x) & 0x7f)
48 #define DEVCUA(x) (minor(x) & 0x80)
49
50 struct imxuart_softc {
51 struct device sc_dev;
52 bus_space_tag_t sc_iot;
53 bus_space_handle_t sc_ioh;
54 int sc_node;
55 struct soft_intrhand *sc_si;
56 void *sc_irq;
57 struct tty *sc_tty;
58 struct timeout sc_diag_tmo;
59 struct timeout sc_dtr_tmo;
60 int sc_overflows;
61 int sc_floods;
62 int sc_errors;
63 int sc_halt;
64 u_int16_t sc_ucr1;
65 u_int16_t sc_ucr2;
66 u_int16_t sc_ucr3;
67 u_int16_t sc_ucr4;
68 u_int8_t sc_hwflags;
69 #define COM_HW_NOIEN 0x01
70 #define COM_HW_FIFO 0x02
71 #define COM_HW_SIR 0x20
72 #define COM_HW_CONSOLE 0x40
73 u_int8_t sc_swflags;
74 #define COM_SW_SOFTCAR 0x01
75 #define COM_SW_CLOCAL 0x02
76 #define COM_SW_CRTSCTS 0x04
77 #define COM_SW_MDMBUF 0x08
78 #define COM_SW_PPS 0x10
79
80 u_int8_t sc_initialize;
81 u_int8_t sc_cua;
82 u_int16_t *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
83 #define IMXUART_IBUFSIZE 128
84 #define IMXUART_IHIGHWATER 100
85 u_int16_t sc_ibufs[2][IMXUART_IBUFSIZE];
86 };
87
88 int imxuart_match(struct device *, void *, void *);
89 void imxuart_attach(struct device *, struct device *, void *);
90
91 void imxuartcnprobe(struct consdev *cp);
92 void imxuartcninit(struct consdev *cp);
93 int imxuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
94 tcflag_t cflag);
95 int imxuartcngetc(dev_t dev);
96 void imxuartcnputc(dev_t dev, int c);
97 void imxuartcnpollc(dev_t dev, int on);
98 int imxuart_param(struct tty *tp, struct termios *t);
99 void imxuart_start(struct tty *);
100 void imxuart_diag(void *arg);
101 void imxuart_raisedtr(void *arg);
102 void imxuart_softint(void *arg);
103 struct imxuart_softc *imxuart_sc(dev_t dev);
104
105 int imxuart_intr(void *);
106
107 /* XXX - we imitate 'com' serial ports and take over their entry points */
108 /* XXX: These belong elsewhere */
109 cdev_decl(com);
110 cdev_decl(imxuart);
111
112 struct cfdriver imxuart_cd = {
113 NULL, "imxuart", DV_TTY
114 };
115
116 const struct cfattach imxuart_ca = {
117 sizeof(struct imxuart_softc), imxuart_match, imxuart_attach
118 };
119
120 bus_space_tag_t imxuartconsiot;
121 bus_space_handle_t imxuartconsioh;
122 bus_addr_t imxuartconsaddr;
123 tcflag_t imxuartconscflag = TTYDEF_CFLAG;
124 int imxuartdefaultrate = B115200;
125
126 struct cdevsw imxuartdev =
127 cdev_tty_init(3/*XXX NIMXUART */ ,imxuart); /* 12: serial port */
128
129 void
imxuart_init_cons(void)130 imxuart_init_cons(void)
131 {
132 struct fdt_reg reg;
133 void *node;
134
135 if ((node = fdt_find_cons("fsl,imx21-uart")) == NULL &&
136 (node = fdt_find_cons("fsl,imx6q-uart")) == NULL)
137 return;
138
139 if (fdt_get_reg(node, 0, ®))
140 return;
141
142 imxuartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
143 }
144
145 int
imxuart_match(struct device * parent,void * match,void * aux)146 imxuart_match(struct device *parent, void *match, void *aux)
147 {
148 struct fdt_attach_args *faa = aux;
149
150 return (OF_is_compatible(faa->fa_node, "fsl,imx21-uart") ||
151 OF_is_compatible(faa->fa_node, "fsl,imx6q-uart"));
152 }
153
154 void
imxuart_attach(struct device * parent,struct device * self,void * aux)155 imxuart_attach(struct device *parent, struct device *self, void *aux)
156 {
157 struct imxuart_softc *sc = (struct imxuart_softc *) self;
158 struct fdt_attach_args *faa = aux;
159 int maj;
160
161 if (faa->fa_nreg < 1)
162 return;
163
164 pinctrl_byname(faa->fa_node, "default");
165
166 sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY,
167 imxuart_intr, sc, sc->sc_dev.dv_xname);
168
169 sc->sc_node = faa->fa_node;
170 sc->sc_iot = faa->fa_iot;
171 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
172 faa->fa_reg[0].size, 0, &sc->sc_ioh))
173 panic("imxuartattach: bus_space_map failed!");
174
175 if (faa->fa_reg[0].addr == imxuartconsaddr) {
176 /* Locate the major number. */
177 for (maj = 0; maj < nchrdev; maj++)
178 if (cdevsw[maj].d_open == imxuartopen)
179 break;
180 cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
181
182 SET(sc->sc_hwflags, COM_HW_CONSOLE);
183 printf(": console");
184 }
185
186 timeout_set(&sc->sc_diag_tmo, imxuart_diag, sc);
187 timeout_set(&sc->sc_dtr_tmo, imxuart_raisedtr, sc);
188 sc->sc_si = softintr_establish(IPL_TTY, imxuart_softint, sc);
189
190 if(sc->sc_si == NULL)
191 panic("%s: can't establish soft interrupt.",
192 sc->sc_dev.dv_xname);
193
194 printf("\n");
195 }
196
197 int
imxuart_intr(void * arg)198 imxuart_intr(void *arg)
199 {
200 struct imxuart_softc *sc = arg;
201 bus_space_tag_t iot = sc->sc_iot;
202 bus_space_handle_t ioh = sc->sc_ioh;
203 struct tty *tp = sc->sc_tty;
204 u_int16_t sr1;
205 u_int16_t *p;
206 u_int16_t c;
207
208 sr1 = bus_space_read_2(iot, ioh, IMXUART_USR1);
209 if (ISSET(sr1, IMXUART_SR1_TRDY) && ISSET(tp->t_state, TS_BUSY)) {
210 CLR(tp->t_state, TS_BUSY | TS_FLUSH);
211 if (sc->sc_halt > 0)
212 wakeup(&tp->t_outq);
213 (*linesw[tp->t_line].l_start)(tp);
214 }
215
216 if (sc->sc_tty == NULL)
217 return(0);
218
219 if(!ISSET(bus_space_read_2(iot, ioh, IMXUART_USR2), IMXUART_SR2_RDR))
220 return 0;
221
222 p = sc->sc_ibufp;
223
224 while(ISSET(bus_space_read_2(iot, ioh, IMXUART_USR2), IMXUART_SR2_RDR)) {
225 c = bus_space_read_2(iot, ioh, IMXUART_URXD);
226 if (ISSET(c, IMXUART_RX_BRK)) {
227 #ifdef DDB
228 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
229 if (db_console)
230 db_enter();
231 continue;
232 }
233 #endif
234 c &= ~0xff;
235 }
236 if (p >= sc->sc_ibufend) {
237 sc->sc_floods++;
238 if (sc->sc_errors++ == 0)
239 timeout_add_sec(&sc->sc_diag_tmo, 60);
240 } else {
241 *p++ = c;
242 if (p == sc->sc_ibufhigh &&
243 ISSET(tp->t_cflag, CRTSCTS)) {
244 /* XXX */
245 CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
246 bus_space_write_2(iot, ioh, IMXUART_UCR3,
247 sc->sc_ucr3);
248 }
249
250 }
251 /* XXX - msr stuff ? */
252 }
253 sc->sc_ibufp = p;
254
255 softintr_schedule(sc->sc_si);
256
257 return 1;
258 }
259
260 int
imxuart_param(struct tty * tp,struct termios * t)261 imxuart_param(struct tty *tp, struct termios *t)
262 {
263 struct imxuart_softc *sc = imxuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
264 bus_space_tag_t iot = sc->sc_iot;
265 bus_space_handle_t ioh = sc->sc_ioh;
266 int ospeed = t->c_ospeed;
267 int error;
268 tcflag_t oldcflag;
269
270
271 if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
272 return EINVAL;
273
274 switch (ISSET(t->c_cflag, CSIZE)) {
275 case CS5:
276 return EINVAL;
277 case CS6:
278 return EINVAL;
279 case CS7:
280 CLR(sc->sc_ucr2, IMXUART_CR2_WS);
281 break;
282 case CS8:
283 SET(sc->sc_ucr2, IMXUART_CR2_WS);
284 break;
285 }
286 // bus_space_write_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
287
288 if (ISSET(t->c_cflag, PARENB)) {
289 SET(sc->sc_ucr2, IMXUART_CR2_PREN);
290 bus_space_write_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
291 }
292 /* STOPB - XXX */
293 if (ospeed == 0) {
294 /* lower dtr */
295 }
296
297 if (ospeed != 0) {
298 while (ISSET(tp->t_state, TS_BUSY)) {
299 ++sc->sc_halt;
300 error = ttysleep(tp, &tp->t_outq,
301 TTOPRI | PCATCH, "imxuartprm");
302 --sc->sc_halt;
303 if (error) {
304 imxuart_start(tp);
305 return (error);
306 }
307 }
308 /* set speed */
309 }
310
311 /* setup fifo */
312
313 /* When not using CRTSCTS, RTS follows DTR. */
314 /* sc->sc_dtr = MCR_DTR; */
315
316
317 /* and copy to tty */
318 tp->t_ispeed = t->c_ispeed;
319 tp->t_ospeed = t->c_ospeed;
320 oldcflag = tp->t_cflag;
321 tp->t_cflag = t->c_cflag;
322
323 /*
324 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
325 * stop the device.
326 */
327 /* XXX */
328
329 imxuart_start(tp);
330
331 return 0;
332 }
333
334 void
imxuart_start(struct tty * tp)335 imxuart_start(struct tty *tp)
336 {
337 struct imxuart_softc *sc = imxuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
338 bus_space_tag_t iot = sc->sc_iot;
339 bus_space_handle_t ioh = sc->sc_ioh;
340
341 int s;
342 s = spltty();
343 if (ISSET(tp->t_state, TS_BUSY)) {
344 splx(s);
345 return;
346 }
347 if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
348 goto stopped;
349 #ifdef DAMNFUCKSHIT
350 /* clear to send (IE the RTS pin on this shit) is not directly \
351 * readable - skip check for now
352 */
353 if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, IMXUART_CTS))
354 goto stopped;
355 #endif
356 if (tp->t_outq.c_cc <= tp->t_lowat) {
357 if (ISSET(tp->t_state, TS_ASLEEP)) {
358 CLR(tp->t_state, TS_ASLEEP);
359 wakeup(&tp->t_outq);
360 }
361 if (tp->t_outq.c_cc == 0)
362 goto stopped;
363 selwakeup(&tp->t_wsel);
364 }
365 SET(tp->t_state, TS_BUSY);
366
367 if (!ISSET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN)) {
368 SET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN);
369 bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
370 }
371
372 {
373 u_char buf[32];
374 int n = q_to_b(&tp->t_outq, buf, 32/*XXX*/);
375 int i;
376 for (i = 0; i < n; i++)
377 bus_space_write_1(iot, ioh, IMXUART_UTXD, buf[i]);
378 }
379 splx(s);
380 return;
381 stopped:
382 if (ISSET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN)) {
383 CLR(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN);
384 bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
385 }
386 splx(s);
387 }
388
389 void
imxuart_diag(void * arg)390 imxuart_diag(void *arg)
391 {
392 struct imxuart_softc *sc = arg;
393 int overflows, floods;
394 int s;
395
396 s = spltty();
397 sc->sc_errors = 0;
398 overflows = sc->sc_overflows;
399 sc->sc_overflows = 0;
400 floods = sc->sc_floods;
401 sc->sc_floods = 0;
402 splx(s);
403 log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
404 sc->sc_dev.dv_xname,
405 overflows, overflows == 1 ? "" : "s",
406 floods, floods == 1 ? "" : "s");
407 }
408
409 void
imxuart_raisedtr(void * arg)410 imxuart_raisedtr(void *arg)
411 {
412 struct imxuart_softc *sc = arg;
413
414 SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
415 bus_space_write_2(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3);
416 }
417
418 void
imxuart_softint(void * arg)419 imxuart_softint(void *arg)
420 {
421 struct imxuart_softc *sc = arg;
422 struct tty *tp;
423 u_int16_t *ibufp;
424 u_int16_t *ibufend;
425 int c;
426 int err;
427 int s;
428
429 if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
430 return;
431
432 tp = sc->sc_tty;
433 s = spltty();
434
435 ibufp = sc->sc_ibuf;
436 ibufend = sc->sc_ibufp;
437
438 if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
439 splx(s);
440 return;
441 }
442
443 sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
444 sc->sc_ibufs[1] : sc->sc_ibufs[0];
445 sc->sc_ibufhigh = sc->sc_ibuf + IMXUART_IHIGHWATER;
446 sc->sc_ibufend = sc->sc_ibuf + IMXUART_IBUFSIZE;
447
448 if (ISSET(tp->t_cflag, CRTSCTS) &&
449 !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) {
450 /* XXX */
451 SET(sc->sc_ucr3, IMXUART_CR3_DSR);
452 bus_space_write_2(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3,
453 sc->sc_ucr3);
454 }
455
456 splx(s);
457
458 while (ibufp < ibufend) {
459 c = *ibufp++;
460 if (ISSET(c, IMXUART_RX_OVERRUN)) {
461 sc->sc_overflows++;
462 if (sc->sc_errors++ == 0)
463 timeout_add_sec(&sc->sc_diag_tmo, 60);
464 }
465 /* This is ugly, but fast. */
466
467 err = 0;
468 if (ISSET(c, IMXUART_RX_PRERR))
469 err |= TTY_PE;
470 if (ISSET(c, IMXUART_RX_FRMERR))
471 err |= TTY_FE;
472 c = (c & 0xff) | err;
473 (*linesw[tp->t_line].l_rint)(c, tp);
474 }
475 }
476
477 int
imxuartopen(dev_t dev,int flag,int mode,struct proc * p)478 imxuartopen(dev_t dev, int flag, int mode, struct proc *p)
479 {
480 int unit = DEVUNIT(dev);
481 struct imxuart_softc *sc;
482 bus_space_tag_t iot;
483 bus_space_handle_t ioh;
484 struct tty *tp;
485 int s;
486 int error = 0;
487
488 if (unit >= imxuart_cd.cd_ndevs)
489 return ENXIO;
490 sc = imxuart_cd.cd_devs[unit];
491 if (sc == NULL)
492 return ENXIO;
493
494 s = spltty();
495 if (sc->sc_tty == NULL)
496 tp = sc->sc_tty = ttymalloc(0);
497 else
498 tp = sc->sc_tty;
499
500 splx(s);
501
502 tp->t_oproc = imxuart_start;
503 tp->t_param = imxuart_param;
504 tp->t_dev = dev;
505
506 if (!ISSET(tp->t_state, TS_ISOPEN)) {
507 SET(tp->t_state, TS_WOPEN);
508 ttychars(tp);
509 tp->t_iflag = TTYDEF_IFLAG;
510 tp->t_oflag = TTYDEF_OFLAG;
511
512 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
513 tp->t_cflag = imxuartconscflag;
514 else
515 tp->t_cflag = TTYDEF_CFLAG;
516 if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
517 SET(tp->t_cflag, CLOCAL);
518 if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
519 SET(tp->t_cflag, CRTSCTS);
520 if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
521 SET(tp->t_cflag, MDMBUF);
522 tp->t_lflag = TTYDEF_LFLAG;
523 tp->t_ispeed = tp->t_ospeed = imxuartdefaultrate;
524
525 s = spltty();
526
527 sc->sc_initialize = 1;
528 imxuart_param(tp, &tp->t_termios);
529 ttsetwater(tp);
530 sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
531 sc->sc_ibufhigh = sc->sc_ibuf + IMXUART_IHIGHWATER;
532 sc->sc_ibufend = sc->sc_ibuf + IMXUART_IBUFSIZE;
533
534 iot = sc->sc_iot;
535 ioh = sc->sc_ioh;
536
537 sc->sc_ucr1 = bus_space_read_2(iot, ioh, IMXUART_UCR1);
538 sc->sc_ucr2 = bus_space_read_2(iot, ioh, IMXUART_UCR2);
539 sc->sc_ucr3 = bus_space_read_2(iot, ioh, IMXUART_UCR3);
540 sc->sc_ucr4 = bus_space_read_2(iot, ioh, IMXUART_UCR4);
541
542 /* interrupt after one char on tx/rx */
543 /* reference frequency divider: 1 */
544 bus_space_write_2(iot, ioh, IMXUART_UFCR,
545 1 << IMXUART_FCR_TXTL_SH |
546 5 << IMXUART_FCR_RFDIV_SH |
547 1 << IMXUART_FCR_RXTL_SH);
548
549 bus_space_write_2(iot, ioh, IMXUART_UBIR,
550 (imxuartdefaultrate / 100) - 1);
551
552 /* formula: clk / (rfdiv * 1600) */
553 bus_space_write_2(iot, ioh, IMXUART_UBMR,
554 clock_get_frequency(sc->sc_node, "per") / 1600);
555
556 SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN);
557 SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
558 bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
559 bus_space_write_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
560
561 /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */
562 SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
563 bus_space_write_2(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
564
565 SET(tp->t_state, TS_CARR_ON); /* XXX */
566
567
568 } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
569 return EBUSY;
570 else
571 s = spltty();
572
573 if (DEVCUA(dev)) {
574 if (ISSET(tp->t_state, TS_ISOPEN)) {
575 splx(s);
576 return EBUSY;
577 }
578 sc->sc_cua = 1;
579 } else {
580 /* tty (not cua) device; wait for carrier if necessary */
581 if (ISSET(flag, O_NONBLOCK)) {
582 if (sc->sc_cua) {
583 /* Opening TTY non-blocking... but the CUA is busy */
584 splx(s);
585 return EBUSY;
586 }
587 } else {
588 while (sc->sc_cua ||
589 (!ISSET(tp->t_cflag, CLOCAL) &&
590 !ISSET(tp->t_state, TS_CARR_ON))) {
591 SET(tp->t_state, TS_WOPEN);
592 error = ttysleep(tp, &tp->t_rawq,
593 TTIPRI | PCATCH, ttopen);
594 /*
595 * If TS_WOPEN has been reset, that means the
596 * cua device has been closed. We don't want
597 * to fail in that case,
598 * so just go around again.
599 */
600 if (error && ISSET(tp->t_state, TS_WOPEN)) {
601 CLR(tp->t_state, TS_WOPEN);
602 splx(s);
603 return error;
604 }
605 }
606 }
607 }
608 splx(s);
609 return (*linesw[tp->t_line].l_open)(dev,tp,p);
610 }
611
612 int
imxuartclose(dev_t dev,int flag,int mode,struct proc * p)613 imxuartclose(dev_t dev, int flag, int mode, struct proc *p)
614 {
615 int unit = DEVUNIT(dev);
616 struct imxuart_softc *sc = imxuart_cd.cd_devs[unit];
617 bus_space_tag_t iot = sc->sc_iot;
618 bus_space_handle_t ioh = sc->sc_ioh;
619 struct tty *tp = sc->sc_tty;
620 int s;
621
622 /* XXX This is for cons.c. */
623 if (!ISSET(tp->t_state, TS_ISOPEN))
624 return 0;
625
626 (*linesw[tp->t_line].l_close)(tp, flag, p);
627 s = spltty();
628 if (ISSET(tp->t_state, TS_WOPEN)) {
629 /* tty device is waiting for carrier; drop dtr then re-raise */
630 CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
631 bus_space_write_2(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
632 timeout_add_sec(&sc->sc_dtr_tmo, 2);
633 }
634 CLR(tp->t_state, TS_BUSY | TS_FLUSH);
635
636 sc->sc_cua = 0;
637 splx(s);
638 ttyclose(tp);
639
640 return 0;
641 }
642
643 int
imxuartread(dev_t dev,struct uio * uio,int flag)644 imxuartread(dev_t dev, struct uio *uio, int flag)
645 {
646 struct tty *tty;
647
648 tty = imxuarttty(dev);
649 if (tty == NULL)
650 return ENODEV;
651
652 return((*linesw[tty->t_line].l_read)(tty, uio, flag));
653 }
654
655 int
imxuartwrite(dev_t dev,struct uio * uio,int flag)656 imxuartwrite(dev_t dev, struct uio *uio, int flag)
657 {
658 struct tty *tty;
659
660 tty = imxuarttty(dev);
661 if (tty == NULL)
662 return ENODEV;
663
664 return((*linesw[tty->t_line].l_write)(tty, uio, flag));
665 }
666
667 int
imxuartioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)668 imxuartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
669 {
670 struct imxuart_softc *sc;
671 struct tty *tp;
672 int error;
673
674 sc = imxuart_sc(dev);
675 if (sc == NULL)
676 return (ENODEV);
677
678 tp = sc->sc_tty;
679 if (tp == NULL)
680 return (ENXIO);
681
682 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
683 if (error >= 0)
684 return (error);
685
686 error = ttioctl(tp, cmd, data, flag, p);
687 if (error >= 0)
688 return (error);
689
690 switch(cmd) {
691 case TIOCSBRK:
692 /* */
693 break;
694
695 case TIOCCBRK:
696 /* */
697 break;
698
699 case TIOCSDTR:
700 #if 0
701 (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
702 #endif
703 break;
704
705 case TIOCCDTR:
706 #if 0
707 (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
708 #endif
709 break;
710
711 case TIOCMSET:
712 #if 0
713 (void) clmctl(dev, *(int *) data, DMSET);
714 #endif
715 break;
716
717 case TIOCMBIS:
718 #if 0
719 (void) clmctl(dev, *(int *) data, DMBIS);
720 #endif
721 break;
722
723 case TIOCMBIC:
724 #if 0
725 (void) clmctl(dev, *(int *) data, DMBIC);
726 #endif
727 break;
728
729 case TIOCMGET:
730 #if 0
731 *(int *)data = clmctl(dev, 0, DMGET);
732 #endif
733 break;
734
735 case TIOCGFLAGS:
736 #if 0
737 *(int *)data = cl->cl_swflags;
738 #endif
739 break;
740
741 case TIOCSFLAGS:
742 error = suser(p);
743 if (error != 0)
744 return(EPERM);
745
746 #if 0
747 cl->cl_swflags = *(int *)data;
748 cl->cl_swflags &= /* only allow valid flags */
749 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
750 #endif
751 break;
752 default:
753 return (ENOTTY);
754 }
755
756 return 0;
757 }
758
759 int
imxuartstop(struct tty * tp,int flag)760 imxuartstop(struct tty *tp, int flag)
761 {
762 return 0;
763 }
764
765 struct tty *
imxuarttty(dev_t dev)766 imxuarttty(dev_t dev)
767 {
768 int unit;
769 struct imxuart_softc *sc;
770 unit = DEVUNIT(dev);
771 if (unit >= imxuart_cd.cd_ndevs)
772 return NULL;
773 sc = (struct imxuart_softc *)imxuart_cd.cd_devs[unit];
774 if (sc == NULL)
775 return NULL;
776 return sc->sc_tty;
777 }
778
779 struct imxuart_softc *
imxuart_sc(dev_t dev)780 imxuart_sc(dev_t dev)
781 {
782 int unit;
783 struct imxuart_softc *sc;
784 unit = DEVUNIT(dev);
785 if (unit >= imxuart_cd.cd_ndevs)
786 return NULL;
787 sc = (struct imxuart_softc *)imxuart_cd.cd_devs[unit];
788 return sc;
789 }
790
791
792 /* serial console */
793 void
imxuartcnprobe(struct consdev * cp)794 imxuartcnprobe(struct consdev *cp)
795 {
796 }
797
798 void
imxuartcninit(struct consdev * cp)799 imxuartcninit(struct consdev *cp)
800 {
801 }
802
803 int
imxuartcnattach(bus_space_tag_t iot,bus_addr_t iobase,int rate,tcflag_t cflag)804 imxuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
805 {
806 static struct consdev imxuartcons = {
807 NULL, NULL, imxuartcngetc, imxuartcnputc, imxuartcnpollc, NULL,
808 NODEV, CN_MIDPRI
809 };
810 int maj;
811
812 if (bus_space_map(iot, iobase, IMXUART_SPACE, 0, &imxuartconsioh))
813 return ENOMEM;
814
815 /* Look for major of com(4) to replace. */
816 for (maj = 0; maj < nchrdev; maj++)
817 if (cdevsw[maj].d_open == comopen)
818 break;
819 if (maj == nchrdev)
820 return ENXIO;
821
822 cn_tab = &imxuartcons;
823 cn_tab->cn_dev = makedev(maj, 0);
824 cdevsw[maj] = imxuartdev; /* KLUDGE */
825
826 imxuartconsiot = iot;
827 imxuartconsaddr = iobase;
828 imxuartconscflag = cflag;
829
830 // XXXX: Overwrites some sensitive bits, recheck later.
831 /*
832 bus_space_write_2(imxuartconsiot, imxuartconsioh, IMXUART_UCR1,
833 IMXUART_CR1_EN);
834 bus_space_write_2(imxuartconsiot, imxuartconsioh, IMXUART_UCR2,
835 IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
836 */
837
838 return 0;
839 }
840
841 int
imxuartcngetc(dev_t dev)842 imxuartcngetc(dev_t dev)
843 {
844 int c;
845 int s;
846 s = splhigh();
847 while((bus_space_read_2(imxuartconsiot, imxuartconsioh, IMXUART_USR2) &
848 IMXUART_SR2_RDR) == 0)
849 ;
850 c = bus_space_read_1(imxuartconsiot, imxuartconsioh, IMXUART_URXD);
851 splx(s);
852 return c;
853 }
854
855 void
imxuartcnputc(dev_t dev,int c)856 imxuartcnputc(dev_t dev, int c)
857 {
858 int s;
859 s = splhigh();
860 bus_space_write_1(imxuartconsiot, imxuartconsioh, IMXUART_UTXD, (uint8_t)c);
861 while((bus_space_read_2(imxuartconsiot, imxuartconsioh, IMXUART_USR2) &
862 IMXUART_SR2_TXDC) == 0)
863 ;
864 splx(s);
865 }
866
867 void
imxuartcnpollc(dev_t dev,int on)868 imxuartcnpollc(dev_t dev, int on)
869 {
870 }
871