footbridge_com.c revision 1.37 1 /* $NetBSD: footbridge_com.c,v 1.37 2014/03/16 05:20:23 dholland Exp $ */
2
3 /*-
4 * Copyright (c) 1997 Mark Brinicombe
5 * Copyright (c) 1997 Causality Limited
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Mark Brinicombe
18 * for the NetBSD Project.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * COM driver, using the footbridge UART
36 */
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: footbridge_com.c,v 1.37 2014/03/16 05:20:23 dholland Exp $");
40
41 #include "opt_ddb.h"
42 #include "opt_ddbparam.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/ioctl.h>
47 #include <sys/select.h>
48 #include <sys/tty.h>
49 #include <sys/proc.h>
50 #include <sys/conf.h>
51 #include <sys/syslog.h>
52 #include <sys/device.h>
53 #include <sys/malloc.h>
54 #include <sys/termios.h>
55 #include <sys/kauth.h>
56 #include <sys/bus.h>
57 #include <machine/intr.h>
58 #include <arm/footbridge/dc21285mem.h>
59 #include <arm/footbridge/dc21285reg.h>
60 #include <arm/footbridge/footbridgevar.h>
61 #include <arm/footbridge/footbridge.h>
62
63 #include <dev/cons.h>
64
65 #include "fcom.h"
66
67 extern u_int dc21285_fclk;
68
69
70 #ifdef DDB
71 /*
72 * Define the keycode recognised as a request to call the debugger
73 * A value of 0 disables the feature when DDB is built in
74 */
75 #ifndef DDB_KEYCODE
76 #define DDB_KEYCODE 0
77 #endif /* DDB_KEYCODE */
78 #endif /* DDB */
79
80 struct fcom_softc {
81 device_t sc_dev;
82 bus_space_tag_t sc_iot;
83 bus_space_handle_t sc_ioh;
84 void *sc_ih;
85 struct callout sc_softintr_ch;
86 int sc_rx_irq;
87 int sc_tx_irq;
88 int sc_hwflags;
89 #define HW_FLAG_CONSOLE 0x01
90 int sc_swflags;
91 int sc_l_ubrlcr;
92 int sc_m_ubrlcr;
93 int sc_h_ubrlcr;
94 char *sc_rxbuffer[2];
95 char *sc_rxbuf;
96 int sc_rxpos;
97 int sc_rxcur;
98 struct tty *sc_tty;
99 };
100
101 #define RX_BUFFER_SIZE 0x100
102
103 static int fcom_probe(device_t, cfdata_t, void *);
104 static void fcom_attach(device_t, device_t, void *);
105 static void fcom_softintr(void *);
106
107 static int fcom_rxintr(void *);
108 /*static int fcom_txintr(void *);*/
109
110 /*struct consdev;*/
111 /*void fcomcnprobe(struct consdev *);
112 void fcomcninit(struct consdev *);*/
113 int fcomcngetc(dev_t);
114 void fcomcnputc(dev_t, int);
115 void fcomcnpollc(dev_t, int);
116
117 CFATTACH_DECL_NEW(fcom, sizeof(struct fcom_softc),
118 fcom_probe, fcom_attach, NULL, NULL);
119
120 extern struct cfdriver fcom_cd;
121
122 dev_type_open(fcomopen);
123 dev_type_close(fcomclose);
124 dev_type_read(fcomread);
125 dev_type_write(fcomwrite);
126 dev_type_ioctl(fcomioctl);
127 dev_type_tty(fcomtty);
128 dev_type_poll(fcompoll);
129
130 const struct cdevsw fcom_cdevsw = {
131 .d_open = fcomopen,
132 .d_close = fcomclose,
133 .d_read = fcomread,
134 .d_write = fcomwrite,
135 .d_ioctl = fcomioctl,
136 .d_stop = nostop,
137 .d_tty = fcomtty,
138 .d_poll = fcompoll,
139 .d_mmap = nommap,
140 .d_kqfilter = ttykqfilter,
141 .d_flag = D_TTY
142 };
143
144 void fcominit(bus_space_tag_t, bus_space_handle_t, int, int);
145 void fcominitcons(bus_space_tag_t, bus_space_handle_t);
146
147 bus_space_tag_t fcomconstag;
148 bus_space_handle_t fcomconsioh;
149 extern int comcnmode;
150 extern int comcnspeed;
151
152 #define COMUNIT(x) (minor(x))
153 #ifndef CONUNIT
154 #define CONUNIT 0
155 #endif
156
157 /*
158 * The console is set up at init time, well in advance of the reset of the
159 * system and thus we have a private bus space tag for the console.
160 *
161 * The tag is provided by fcom_io.c and fcom_io_asm.S
162 */
163 extern struct bus_space fcomcons_bs_tag;
164
165 /*
166 * int fcom_probe(device_t parent, cfdata_t cf, void *aux)
167 *
168 * Make sure we are trying to attach a com device and then
169 * probe for one.
170 */
171
172 static int
173 fcom_probe(device_t parent, cfdata_t cf, void *aux)
174 {
175 union footbridge_attach_args *fba = aux;
176
177 if (strcmp(fba->fba_name, "fcom") == 0)
178 return(1);
179 return(0);
180 }
181
182 /*
183 * void fcom_attach(device_t parent, device_t self, void *aux)
184 *
185 * attach the com device
186 */
187
188 static void
189 fcom_attach(device_t parent, device_t self, void *aux)
190 {
191 union footbridge_attach_args *fba = aux;
192 struct fcom_softc *sc = device_private(self);
193
194 /* Set up the softc */
195 sc->sc_dev = self;
196 sc->sc_iot = fba->fba_fca.fca_iot;
197 sc->sc_ioh = fba->fba_fca.fca_ioh;
198 callout_init(&sc->sc_softintr_ch, 0);
199 sc->sc_rx_irq = fba->fba_fca.fca_rx_irq;
200 sc->sc_tx_irq = fba->fba_fca.fca_tx_irq;
201 sc->sc_hwflags = 0;
202 sc->sc_swflags = 0;
203
204 /* If we have a console tag then make a note of it */
205 if (fcomconstag)
206 sc->sc_hwflags |= HW_FLAG_CONSOLE;
207
208 if (sc->sc_hwflags & HW_FLAG_CONSOLE) {
209 int major;
210
211 /* locate the major number */
212 major = cdevsw_lookup_major(&fcom_cdevsw);
213
214 cn_tab->cn_dev = makedev(major, device_unit(sc->sc_dev));
215 aprint_normal(": console");
216 }
217 aprint_normal("\n");
218
219 sc->sc_ih = footbridge_intr_claim(sc->sc_rx_irq, IPL_SERIAL,
220 "serial rx", fcom_rxintr, sc);
221 if (sc->sc_ih == NULL)
222 panic("%s: Cannot install rx interrupt handler",
223 device_xname(sc->sc_dev));
224 }
225
226 static void fcomstart(struct tty *);
227 static int fcomparam(struct tty *, struct termios *);
228
229 int
230 fcomopen(dev_t dev, int flag, int mode, struct lwp *l)
231 {
232 struct fcom_softc *sc;
233 struct tty *tp;
234
235 sc = device_lookup_private(&fcom_cd, minor(dev));
236 if (!sc)
237 return ENXIO;
238 if (!(tp = sc->sc_tty))
239 sc->sc_tty = tp = tty_alloc();
240 if (!sc->sc_rxbuffer[0]) {
241 sc->sc_rxbuffer[0] = malloc(RX_BUFFER_SIZE, M_DEVBUF, M_WAITOK);
242 sc->sc_rxbuffer[1] = malloc(RX_BUFFER_SIZE, M_DEVBUF, M_WAITOK);
243 sc->sc_rxpos = 0;
244 sc->sc_rxcur = 0;
245 sc->sc_rxbuf = sc->sc_rxbuffer[sc->sc_rxcur];
246 if (!sc->sc_rxbuf)
247 panic("%s: Cannot allocate rx buffer memory",
248 device_xname(sc->sc_dev));
249 }
250 tp->t_oproc = fcomstart;
251 tp->t_param = fcomparam;
252 tp->t_dev = dev;
253
254 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
255 return (EBUSY);
256
257 if (!(tp->t_state & TS_ISOPEN && tp->t_wopen == 0)) {
258 ttychars(tp);
259 tp->t_cflag = TTYDEF_CFLAG;
260 tp->t_iflag = TTYDEF_IFLAG;
261 tp->t_oflag = TTYDEF_OFLAG;
262 tp->t_lflag = TTYDEF_LFLAG;
263
264 /*
265 * Initialize the termios status to the defaults. Add in the
266 * sticky bits from TIOCSFLAGS.
267 */
268 tp->t_ispeed = 0;
269 if (ISSET(sc->sc_hwflags, HW_FLAG_CONSOLE))
270 tp->t_ospeed = comcnspeed;
271 else
272 tp->t_ospeed = TTYDEF_SPEED;
273
274 fcomparam(tp, &tp->t_termios);
275 ttsetwater(tp);
276 }
277 tp->t_state |= TS_CARR_ON;
278
279 return (*tp->t_linesw->l_open)(dev, tp);
280 }
281
282 int
283 fcomclose(dev_t dev, int flag, int mode, struct lwp *l)
284 {
285 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(dev));
286 struct tty *tp = sc->sc_tty;
287 /* XXX This is for cons.c. */
288 if (!ISSET(tp->t_state, TS_ISOPEN))
289 return (0);
290
291 (*tp->t_linesw->l_close)(tp, flag);
292 ttyclose(tp);
293 #ifdef DIAGNOSTIC
294 if (sc->sc_rxbuffer[0] == NULL)
295 panic("fcomclose: rx buffers not allocated");
296 #endif /* DIAGNOSTIC */
297 free(sc->sc_rxbuffer[0], M_DEVBUF);
298 free(sc->sc_rxbuffer[1], M_DEVBUF);
299 sc->sc_rxbuffer[0] = NULL;
300 sc->sc_rxbuffer[1] = NULL;
301
302 return 0;
303 }
304
305 int
306 fcomread(dev_t dev, struct uio *uio, int flag)
307 {
308 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(dev));
309 struct tty *tp = sc->sc_tty;
310
311 return (*tp->t_linesw->l_read)(tp, uio, flag);
312 }
313
314 int
315 fcomwrite(dev_t dev, struct uio *uio, int flag)
316 {
317 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(dev));
318 struct tty *tp = sc->sc_tty;
319
320 return (*tp->t_linesw->l_write)(tp, uio, flag);
321 }
322
323 int
324 fcompoll(dev_t dev, int events, struct lwp *l)
325 {
326 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(dev));
327 struct tty *tp = sc->sc_tty;
328
329 return ((*tp->t_linesw->l_poll)(tp, events, l));
330 }
331
332 int
333 fcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
334 {
335 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(dev));
336 struct tty *tp = sc->sc_tty;
337 int error;
338
339 if ((error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l)) !=
340 EPASSTHROUGH)
341 return error;
342 if ((error = ttioctl(tp, cmd, data, flag, l)) != EPASSTHROUGH)
343 return error;
344
345 switch (cmd) {
346 case TIOCGFLAGS:
347 *(int *)data = sc->sc_swflags;
348 break;
349
350 case TIOCSFLAGS:
351 error = kauth_authorize_device_tty(l->l_cred,
352 KAUTH_DEVICE_TTY_PRIVSET, tp);
353 if (error)
354 return (error);
355 sc->sc_swflags = *(int *)data;
356 break;
357 }
358
359 return EPASSTHROUGH;
360 }
361
362 struct tty *
363 fcomtty(dev_t dev)
364 {
365 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(dev));
366
367 return sc->sc_tty;
368 }
369
370 static void
371 fcomstart(struct tty *tp)
372 {
373 struct clist *cl;
374 int s, len;
375 u_char buf[64];
376 int loop;
377 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(tp->t_dev));
378 bus_space_tag_t iot = sc->sc_iot;
379 bus_space_handle_t ioh = sc->sc_ioh;
380 int timo;
381
382 s = spltty();
383 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
384 (void)splx(s);
385 return;
386 }
387 tp->t_state |= TS_BUSY;
388 (void)splx(s);
389
390 /* s = splserial();*/
391 /* wait for any pending transmission to finish */
392 timo = 100000;
393 while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) && --timo)
394 ;
395
396 s = splserial();
397 if (bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) {
398 tp->t_state |= TS_TIMEOUT;
399 callout_schedule(&tp->t_rstrt_ch, 1);
400 (void)splx(s);
401 return;
402 }
403
404 (void)splx(s);
405
406 cl = &tp->t_outq;
407 len = q_to_b(cl, buf, 64);
408 for (loop = 0; loop < len; ++loop) {
409 /* s = splserial();*/
410
411 bus_space_write_4(iot, ioh, UART_DATA, buf[loop]);
412
413 /* wait for this transmission to complete */
414 timo = 100000;
415 while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) && --timo)
416 ;
417 /* (void)splx(s);*/
418 }
419 s = spltty();
420 tp->t_state &= ~TS_BUSY;
421 if (ttypull(tp)) {
422 tp->t_state |= TS_TIMEOUT;
423 callout_schedule(&tp->t_rstrt_ch, 1);
424 }
425 (void)splx(s);
426 }
427
428 static int
429 fcomparam(struct tty *tp, struct termios *t)
430 {
431 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(tp->t_dev));
432 bus_space_tag_t iot = sc->sc_iot;
433 bus_space_handle_t ioh = sc->sc_ioh;
434 int baudrate;
435 int h_ubrlcr;
436 int m_ubrlcr;
437 int l_ubrlcr;
438 int s;
439
440 /* check requested parameters */
441 if (t->c_ospeed < 0)
442 return (EINVAL);
443 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
444 return (EINVAL);
445
446 switch (t->c_ospeed) {
447 case B1200:
448 case B2400:
449 case B4800:
450 case B9600:
451 case B19200:
452 case B38400:
453 baudrate = UART_BRD(dc21285_fclk, t->c_ospeed);
454 break;
455 default:
456 baudrate = UART_BRD(dc21285_fclk, 9600);
457 break;
458 }
459
460 l_ubrlcr = baudrate & 0xff;
461 m_ubrlcr = (baudrate >> 8) & 0xf;
462 h_ubrlcr = 0;
463
464 switch (ISSET(t->c_cflag, CSIZE)) {
465 case CS5:
466 h_ubrlcr |= UART_DATA_BITS_5;
467 break;
468 case CS6:
469 h_ubrlcr |= UART_DATA_BITS_6;
470 break;
471 case CS7:
472 h_ubrlcr |= UART_DATA_BITS_7;
473 break;
474 case CS8:
475 h_ubrlcr |= UART_DATA_BITS_8;
476 break;
477 }
478
479 if (ISSET(t->c_cflag, PARENB)) {
480 h_ubrlcr |= UART_PARITY_ENABLE;
481 if (ISSET(t->c_cflag, PARODD))
482 h_ubrlcr |= UART_ODD_PARITY;
483 else
484 h_ubrlcr |= UART_EVEN_PARITY;
485 }
486
487 if (ISSET(t->c_cflag, CSTOPB))
488 h_ubrlcr |= UART_STOP_BITS_2;
489
490 bus_space_write_4(iot, ioh, UART_L_UBRLCR, l_ubrlcr);
491 bus_space_write_4(iot, ioh, UART_M_UBRLCR, m_ubrlcr);
492 bus_space_write_4(iot, ioh, UART_H_UBRLCR, h_ubrlcr);
493
494 s = splserial();
495
496 sc->sc_l_ubrlcr = l_ubrlcr;
497 sc->sc_m_ubrlcr = m_ubrlcr;
498 sc->sc_h_ubrlcr = h_ubrlcr;
499
500 /*
501 * For the console, always force CLOCAL and !HUPCL, so that the port
502 * is always active.
503 */
504 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
505 ISSET(sc->sc_hwflags, HW_FLAG_CONSOLE)) {
506 SET(t->c_cflag, CLOCAL);
507 CLR(t->c_cflag, HUPCL);
508 }
509
510 /* and copy to tty */
511 tp->t_ispeed = 0;
512 tp->t_ospeed = t->c_ospeed;
513 tp->t_cflag = t->c_cflag;
514
515 bus_space_write_4(iot, ioh, UART_L_UBRLCR, l_ubrlcr);
516 bus_space_write_4(iot, ioh, UART_M_UBRLCR, m_ubrlcr);
517 bus_space_write_4(iot, ioh, UART_H_UBRLCR, h_ubrlcr);
518
519 (void)splx(s);
520
521 return (0);
522 }
523
524 static int softint_scheduled = 0;
525
526 static void
527 fcom_softintr(void *arg)
528 {
529 struct fcom_softc *sc = arg;
530 struct tty *tp = sc->sc_tty;
531 int s;
532 int loop;
533 int len;
534 char *ptr;
535
536 s = spltty();
537 ptr = sc->sc_rxbuf;
538 len = sc->sc_rxpos;
539 sc->sc_rxcur ^= 1;
540 sc->sc_rxbuf = sc->sc_rxbuffer[sc->sc_rxcur];
541 sc->sc_rxpos = 0;
542 (void)splx(s);
543
544 for (loop = 0; loop < len; ++loop)
545 (*tp->t_linesw->l_rint)(ptr[loop], tp);
546 softint_scheduled = 0;
547 }
548
549 #if 0
550 static int
551 fcom_txintr(void *arg)
552 {
553 /* struct fcom_softc *sc = arg;*/
554
555 printf("fcom_txintr()\n");
556 return(0);
557 }
558 #endif
559
560 static int
561 fcom_rxintr(void *arg)
562 {
563 struct fcom_softc *sc = arg;
564 bus_space_tag_t iot = sc->sc_iot;
565 bus_space_handle_t ioh = sc->sc_ioh;
566 struct tty *tp = sc->sc_tty;
567 int status;
568 int byte;
569
570 do {
571 status = bus_space_read_4(iot, ioh, UART_FLAGS);
572 if ((status & UART_RX_FULL))
573 break;
574 byte = bus_space_read_4(iot, ioh, UART_DATA);
575 status = bus_space_read_4(iot, ioh, UART_RX_STAT);
576 #if defined(DDB) && DDB_KEYCODE > 0
577 /*
578 * Temporary hack so that I can force the kernel into
579 * the debugger via the serial port
580 */
581 if (byte == DDB_KEYCODE) Debugger();
582 #endif
583 if (tp && (tp->t_state & TS_ISOPEN))
584 if (sc->sc_rxpos < RX_BUFFER_SIZE) {
585 sc->sc_rxbuf[sc->sc_rxpos++] = byte;
586 if (!softint_scheduled) {
587 softint_scheduled = 1;
588 callout_reset(&sc->sc_softintr_ch,
589 1, fcom_softintr, sc);
590 }
591 }
592 } while (1);
593 return(0);
594 }
595
596 #if 0
597 void
598 fcom_iflush(struct fcom_softc *sc)
599 {
600 bus_space_tag_t iot = sc->sc_iot;
601 bus_space_handle_t ioh = sc->sc_ioh;
602
603 /* flush any pending I/O */
604 while (!ISSET(bus_space_read_4(iot, ioh, UART_FLAGS), UART_RX_FULL))
605 (void) bus_space_read_4(iot, ioh, UART_DATA);
606 }
607 #endif
608
609 /*
610 * Following are all routines needed for COM to act as console
611 */
612
613 #if 0
614 void
615 fcomcnprobe(struct consdev *cp)
616 {
617 int major;
618
619 /* Serial console is always present so no probe */
620
621 /* locate the major number */
622 major = cdevsw_lookup_major(&fcom_cdevsw);
623
624 /* initialize required fields */
625 cp->cn_dev = makedev(major, CONUNIT);
626 cp->cn_pri = CN_REMOTE; /* Force a serial port console */
627 }
628
629 void
630 fcomcninit(struct consdev *cp)
631 {
632 fcomconstag = &fcomcons_bs_tag;
633
634 if (bus_space_map(fcomconstag, DC21285_ARMCSR_BASE, DC21285_ARMCSR_SIZE, 0, &fcomconsioh))
635 panic("fcomcninit: mapping failed");
636
637 fcominitcons(fcomconstag, fcomconsioh);
638 }
639 #endif
640
641 int
642 fcomcnattach(u_int iobase, int rate, tcflag_t cflag)
643 {
644 static struct consdev fcomcons = {
645 NULL, NULL, fcomcngetc, fcomcnputc, fcomcnpollc, NULL,
646 NULL, NULL, NODEV, CN_NORMAL
647 };
648
649 fcomconstag = &fcomcons_bs_tag;
650
651 if (bus_space_map(fcomconstag, iobase, DC21285_ARMCSR_SIZE,
652 0, &fcomconsioh))
653 panic("fcomcninit: mapping failed");
654
655 fcominit(fcomconstag, fcomconsioh, rate, cflag);
656
657 cn_tab = &fcomcons;
658
659 /* comcnspeed = rate;
660 comcnmode = cflag;*/
661 return (0);
662 }
663
664 int
665 fcomcndetach(void)
666 {
667 bus_space_unmap(fcomconstag, fcomconsioh, DC21285_ARMCSR_SIZE);
668
669 cn_tab = NULL;
670 return (0);
671 }
672
673 /*
674 * Initialize UART to known state.
675 */
676 void
677 fcominit(bus_space_tag_t iot, bus_space_handle_t ioh, int rate, int mode)
678 {
679 int baudrate;
680 int h_ubrlcr;
681 int m_ubrlcr;
682 int l_ubrlcr;
683
684 switch (rate) {
685 case B1200:
686 case B2400:
687 case B4800:
688 case B9600:
689 case B19200:
690 case B38400:
691 baudrate = UART_BRD(dc21285_fclk, rate);
692 break;
693 default:
694 baudrate = UART_BRD(dc21285_fclk, 9600);
695 break;
696 }
697
698 h_ubrlcr = 0;
699 switch (mode & CSIZE) {
700 case CS5:
701 h_ubrlcr |= UART_DATA_BITS_5;
702 break;
703 case CS6:
704 h_ubrlcr |= UART_DATA_BITS_6;
705 break;
706 case CS7:
707 h_ubrlcr |= UART_DATA_BITS_7;
708 break;
709 case CS8:
710 h_ubrlcr |= UART_DATA_BITS_8;
711 break;
712 }
713
714 if (mode & PARENB)
715 h_ubrlcr |= UART_PARITY_ENABLE;
716 if (mode & PARODD)
717 h_ubrlcr |= UART_ODD_PARITY;
718 else
719 h_ubrlcr |= UART_EVEN_PARITY;
720
721 if (mode & CSTOPB)
722 h_ubrlcr |= UART_STOP_BITS_2;
723
724 m_ubrlcr = (baudrate >> 8) & 0xf;
725 l_ubrlcr = baudrate & 0xff;
726
727 bus_space_write_4(iot, ioh, UART_L_UBRLCR, l_ubrlcr);
728 bus_space_write_4(iot, ioh, UART_M_UBRLCR, m_ubrlcr);
729 bus_space_write_4(iot, ioh, UART_H_UBRLCR, h_ubrlcr);
730 }
731 #if 0
732 /*
733 * Set UART for console use. Do normal init, then enable interrupts.
734 */
735 void
736 fcominitcons(bus_space_tag_t iot, bus_space_handle_t ioh)
737 {
738 int s = splserial();
739
740 fcominit(iot, ioh, comcnspeed, comcnmode);
741
742 delay(10000);
743
744 (void)splx(s);
745 }
746 #endif
747
748 int
749 fcomcngetc(dev_t dev)
750 {
751 int s = splserial();
752 bus_space_tag_t iot = fcomconstag;
753 bus_space_handle_t ioh = fcomconsioh;
754 u_char c;
755
756 while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_RX_FULL) != 0)
757 ;
758 c = bus_space_read_4(iot, ioh, UART_DATA);
759 (void)bus_space_read_4(iot, ioh, UART_RX_STAT);
760 (void)splx(s);
761 #if defined(DDB) && DDB_KEYCODE > 0
762 /*
763 * Temporary hack so that I can force the kernel into
764 * the debugger via the serial port
765 */
766 if (c == DDB_KEYCODE) Debugger();
767 #endif
768
769 return (c);
770 }
771
772 /*
773 * Console kernel output character routine.
774 */
775 void
776 fcomcnputc(dev_t dev, int c)
777 {
778 int s = splserial();
779 bus_space_tag_t iot = fcomconstag;
780 bus_space_handle_t ioh = fcomconsioh;
781 int timo;
782
783 /* wait for any pending transmission to finish */
784 timo = 50000;
785 while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) && --timo)
786 ;
787 bus_space_write_4(iot, ioh, UART_DATA, c);
788
789 /* wait for this transmission to complete */
790 timo = 1500000;
791 while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) && --timo)
792 ;
793 /* Clear interrupt status here */
794 (void)splx(s);
795 }
796
797 void
798 fcomcnpollc(dev_t dev, int on)
799 {
800 }
801