footbridge_com.c revision 1.29 1 /* $NetBSD: footbridge_com.c,v 1.29 2009/03/14 14:45:55 dsl 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.29 2009/03/14 14:45:55 dsl 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 <machine/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 struct device 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(struct device *, struct cfdata *, void *);
104 static void fcom_attach(struct device *, struct device *, 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(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 fcomopen, fcomclose, fcomread, fcomwrite, fcomioctl,
132 nostop, fcomtty, fcompoll, nommap, ttykqfilter, D_TTY
133 };
134
135 void fcominit(bus_space_tag_t, bus_space_handle_t, int, int);
136 void fcominitcons(bus_space_tag_t, bus_space_handle_t);
137
138 bus_space_tag_t fcomconstag;
139 bus_space_handle_t fcomconsioh;
140 extern int comcnmode;
141 extern int comcnspeed;
142
143 #define COMUNIT(x) (minor(x))
144 #ifndef CONUNIT
145 #define CONUNIT 0
146 #endif
147
148 /*
149 * The console is set up at init time, well in advance of the reset of the
150 * system and thus we have a private bus space tag for the console.
151 *
152 * The tag is provided by fcom_io.c and fcom_io_asm.S
153 */
154 extern struct bus_space fcomcons_bs_tag;
155
156 /*
157 * int fcom_probe(struct device *parent, struct cfdata *cf, void *aux)
158 *
159 * Make sure we are trying to attach a com device and then
160 * probe for one.
161 */
162
163 static int
164 fcom_probe(parent, cf, aux)
165 struct device *parent;
166 struct cfdata *cf;
167 void *aux;
168 {
169 union footbridge_attach_args *fba = aux;
170
171 if (strcmp(fba->fba_name, "fcom") == 0)
172 return(1);
173 return(0);
174 }
175
176 /*
177 * void fcom_attach(struct device *parent, struct device *self, void *aux)
178 *
179 * attach the com device
180 */
181
182 static void
183 fcom_attach(parent, self, aux)
184 struct device *parent, *self;
185 void *aux;
186 {
187 union footbridge_attach_args *fba = aux;
188 struct fcom_softc *sc = (struct fcom_softc *)self;
189
190 /* Set up the softc */
191 sc->sc_iot = fba->fba_fca.fca_iot;
192 sc->sc_ioh = fba->fba_fca.fca_ioh;
193 callout_init(&sc->sc_softintr_ch, 0);
194 sc->sc_rx_irq = fba->fba_fca.fca_rx_irq;
195 sc->sc_tx_irq = fba->fba_fca.fca_tx_irq;
196 sc->sc_hwflags = 0;
197 sc->sc_swflags = 0;
198
199 /* If we have a console tag then make a note of it */
200 if (fcomconstag)
201 sc->sc_hwflags |= HW_FLAG_CONSOLE;
202
203 if (sc->sc_hwflags & HW_FLAG_CONSOLE) {
204 int major;
205
206 /* locate the major number */
207 major = cdevsw_lookup_major(&fcom_cdevsw);
208
209 cn_tab->cn_dev = makedev(major, device_unit(&sc->sc_dev));
210 printf(": console");
211 }
212 printf("\n");
213
214 sc->sc_ih = footbridge_intr_claim(sc->sc_rx_irq, IPL_SERIAL,
215 "serial rx", fcom_rxintr, sc);
216 if (sc->sc_ih == NULL)
217 panic("%s: Cannot install rx interrupt handler",
218 sc->sc_dev.dv_xname);
219 }
220
221 static void fcomstart(struct tty *);
222 static int fcomparam(struct tty *, struct termios *);
223
224 int
225 fcomopen(dev_t dev, int flag, int mode, struct lwp *l)
226 {
227 struct fcom_softc *sc;
228 struct tty *tp;
229
230 sc = device_lookup_private(&fcom_cd, minor(dev));
231 if (!sc)
232 return ENXIO;
233 if (!(tp = sc->sc_tty))
234 sc->sc_tty = tp = ttymalloc();
235 if (!sc->sc_rxbuffer[0]) {
236 sc->sc_rxbuffer[0] = malloc(RX_BUFFER_SIZE, M_DEVBUF, M_WAITOK);
237 sc->sc_rxbuffer[1] = malloc(RX_BUFFER_SIZE, M_DEVBUF, M_WAITOK);
238 sc->sc_rxpos = 0;
239 sc->sc_rxcur = 0;
240 sc->sc_rxbuf = sc->sc_rxbuffer[sc->sc_rxcur];
241 if (!sc->sc_rxbuf)
242 panic("%s: Cannot allocate rx buffer memory",
243 sc->sc_dev.dv_xname);
244 }
245 tp->t_oproc = fcomstart;
246 tp->t_param = fcomparam;
247 tp->t_dev = dev;
248
249 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
250 return (EBUSY);
251
252 if (!(tp->t_state & TS_ISOPEN && tp->t_wopen == 0)) {
253 ttychars(tp);
254 tp->t_cflag = TTYDEF_CFLAG;
255 tp->t_iflag = TTYDEF_IFLAG;
256 tp->t_oflag = TTYDEF_OFLAG;
257 tp->t_lflag = TTYDEF_LFLAG;
258
259 /*
260 * Initialize the termios status to the defaults. Add in the
261 * sticky bits from TIOCSFLAGS.
262 */
263 tp->t_ispeed = 0;
264 if (ISSET(sc->sc_hwflags, HW_FLAG_CONSOLE))
265 tp->t_ospeed = comcnspeed;
266 else
267 tp->t_ospeed = TTYDEF_SPEED;
268
269 fcomparam(tp, &tp->t_termios);
270 ttsetwater(tp);
271 }
272 tp->t_state |= TS_CARR_ON;
273
274 return (*tp->t_linesw->l_open)(dev, tp);
275 }
276
277 int
278 fcomclose(dev_t dev, int flag, int mode, struct lwp *l)
279 {
280 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(dev));
281 struct tty *tp = sc->sc_tty;
282 /* XXX This is for cons.c. */
283 if (!ISSET(tp->t_state, TS_ISOPEN))
284 return (0);
285
286 (*tp->t_linesw->l_close)(tp, flag);
287 ttyclose(tp);
288 #ifdef DIAGNOSTIC
289 if (sc->sc_rxbuffer[0] == NULL)
290 panic("fcomclose: rx buffers not allocated");
291 #endif /* DIAGNOSTIC */
292 free(sc->sc_rxbuffer[0], M_DEVBUF);
293 free(sc->sc_rxbuffer[1], M_DEVBUF);
294 sc->sc_rxbuffer[0] = NULL;
295 sc->sc_rxbuffer[1] = NULL;
296
297 return 0;
298 }
299
300 int
301 fcomread(dev_t dev, struct uio *uio, int flag)
302 {
303 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(dev));
304 struct tty *tp = sc->sc_tty;
305
306 return (*tp->t_linesw->l_read)(tp, uio, flag);
307 }
308
309 int
310 fcomwrite(dev_t dev, struct uio *uio, int flag)
311 {
312 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(dev));
313 struct tty *tp = sc->sc_tty;
314
315 return (*tp->t_linesw->l_write)(tp, uio, flag);
316 }
317
318 int
319 fcompoll(dev_t dev, int events, struct lwp *l)
320 {
321 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(dev));
322 struct tty *tp = sc->sc_tty;
323
324 return ((*tp->t_linesw->l_poll)(tp, events, l));
325 }
326
327 int
328 fcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
329 {
330 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(dev));
331 struct tty *tp = sc->sc_tty;
332 int error;
333
334 if ((error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l)) !=
335 EPASSTHROUGH)
336 return error;
337 if ((error = ttioctl(tp, cmd, data, flag, l)) != EPASSTHROUGH)
338 return error;
339
340 switch (cmd) {
341 case TIOCGFLAGS:
342 *(int *)data = sc->sc_swflags;
343 break;
344
345 case TIOCSFLAGS:
346 error = kauth_authorize_device_tty(l->l_cred,
347 KAUTH_DEVICE_TTY_PRIVSET, tp);
348 if (error)
349 return (error);
350 sc->sc_swflags = *(int *)data;
351 break;
352 }
353
354 return EPASSTHROUGH;
355 }
356
357 struct tty *
358 fcomtty(dev_t dev)
359 {
360 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(dev));
361
362 return sc->sc_tty;
363 }
364
365 static void
366 fcomstart(struct tty *tp)
367 {
368 struct clist *cl;
369 int s, len;
370 u_char buf[64];
371 int loop;
372 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(tp->t_dev));
373 bus_space_tag_t iot = sc->sc_iot;
374 bus_space_handle_t ioh = sc->sc_ioh;
375 int timo;
376
377 s = spltty();
378 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
379 (void)splx(s);
380 return;
381 }
382 tp->t_state |= TS_BUSY;
383 (void)splx(s);
384
385 /* s = splserial();*/
386 /* wait for any pending transmission to finish */
387 timo = 100000;
388 while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) && --timo)
389 ;
390
391 s = splserial();
392 if (bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) {
393 tp->t_state |= TS_TIMEOUT;
394 callout_schedule(&tp->t_rstrt_ch, 1);
395 (void)splx(s);
396 return;
397 }
398
399 (void)splx(s);
400
401 cl = &tp->t_outq;
402 len = q_to_b(cl, buf, 64);
403 for (loop = 0; loop < len; ++loop) {
404 /* s = splserial();*/
405
406 bus_space_write_4(iot, ioh, UART_DATA, buf[loop]);
407
408 /* wait for this transmission to complete */
409 timo = 100000;
410 while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) && --timo)
411 ;
412 /* (void)splx(s);*/
413 }
414 s = spltty();
415 tp->t_state &= ~TS_BUSY;
416 if (ttypull(tp)) {
417 tp->t_state |= TS_TIMEOUT;
418 callout_schedule(&tp->t_rstrt_ch, 1);
419 }
420 (void)splx(s);
421 }
422
423 static int
424 fcomparam(struct tty *tp, struct termios *t)
425 {
426 struct fcom_softc *sc = device_lookup_private(&fcom_cd, minor(tp->t_dev));
427 bus_space_tag_t iot = sc->sc_iot;
428 bus_space_handle_t ioh = sc->sc_ioh;
429 int baudrate;
430 int h_ubrlcr;
431 int m_ubrlcr;
432 int l_ubrlcr;
433 int s;
434
435 /* check requested parameters */
436 if (t->c_ospeed < 0)
437 return (EINVAL);
438 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
439 return (EINVAL);
440
441 switch (t->c_ospeed) {
442 case B1200:
443 case B2400:
444 case B4800:
445 case B9600:
446 case B19200:
447 case B38400:
448 baudrate = UART_BRD(dc21285_fclk, t->c_ospeed);
449 break;
450 default:
451 baudrate = UART_BRD(dc21285_fclk, 9600);
452 break;
453 }
454
455 l_ubrlcr = baudrate & 0xff;
456 m_ubrlcr = (baudrate >> 8) & 0xf;
457 h_ubrlcr = 0;
458
459 switch (ISSET(t->c_cflag, CSIZE)) {
460 case CS5:
461 h_ubrlcr |= UART_DATA_BITS_5;
462 break;
463 case CS6:
464 h_ubrlcr |= UART_DATA_BITS_6;
465 break;
466 case CS7:
467 h_ubrlcr |= UART_DATA_BITS_7;
468 break;
469 case CS8:
470 h_ubrlcr |= UART_DATA_BITS_8;
471 break;
472 }
473
474 if (ISSET(t->c_cflag, PARENB)) {
475 h_ubrlcr |= UART_PARITY_ENABLE;
476 if (ISSET(t->c_cflag, PARODD))
477 h_ubrlcr |= UART_ODD_PARITY;
478 else
479 h_ubrlcr |= UART_EVEN_PARITY;
480 }
481
482 if (ISSET(t->c_cflag, CSTOPB))
483 h_ubrlcr |= UART_STOP_BITS_2;
484
485 bus_space_write_4(iot, ioh, UART_L_UBRLCR, l_ubrlcr);
486 bus_space_write_4(iot, ioh, UART_M_UBRLCR, m_ubrlcr);
487 bus_space_write_4(iot, ioh, UART_H_UBRLCR, h_ubrlcr);
488
489 s = splserial();
490
491 sc->sc_l_ubrlcr = l_ubrlcr;
492 sc->sc_m_ubrlcr = m_ubrlcr;
493 sc->sc_h_ubrlcr = h_ubrlcr;
494
495 /*
496 * For the console, always force CLOCAL and !HUPCL, so that the port
497 * is always active.
498 */
499 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
500 ISSET(sc->sc_hwflags, HW_FLAG_CONSOLE)) {
501 SET(t->c_cflag, CLOCAL);
502 CLR(t->c_cflag, HUPCL);
503 }
504
505 /* and copy to tty */
506 tp->t_ispeed = 0;
507 tp->t_ospeed = t->c_ospeed;
508 tp->t_cflag = t->c_cflag;
509
510 bus_space_write_4(iot, ioh, UART_L_UBRLCR, l_ubrlcr);
511 bus_space_write_4(iot, ioh, UART_M_UBRLCR, m_ubrlcr);
512 bus_space_write_4(iot, ioh, UART_H_UBRLCR, h_ubrlcr);
513
514 (void)splx(s);
515
516 return (0);
517 }
518
519 static int softint_scheduled = 0;
520
521 static void
522 fcom_softintr(arg)
523 void *arg;
524 {
525 struct fcom_softc *sc = arg;
526 struct tty *tp = sc->sc_tty;
527 int s;
528 int loop;
529 int len;
530 char *ptr;
531
532 s = spltty();
533 ptr = sc->sc_rxbuf;
534 len = sc->sc_rxpos;
535 sc->sc_rxcur ^= 1;
536 sc->sc_rxbuf = sc->sc_rxbuffer[sc->sc_rxcur];
537 sc->sc_rxpos = 0;
538 (void)splx(s);
539
540 for (loop = 0; loop < len; ++loop)
541 (*tp->t_linesw->l_rint)(ptr[loop], tp);
542 softint_scheduled = 0;
543 }
544
545 #if 0
546 static int
547 fcom_txintr(arg)
548 void *arg;
549 {
550 /* struct fcom_softc *sc = arg;*/
551
552 printf("fcom_txintr()\n");
553 return(0);
554 }
555 #endif
556
557 static int
558 fcom_rxintr(arg)
559 void *arg;
560 {
561 struct fcom_softc *sc = arg;
562 bus_space_tag_t iot = sc->sc_iot;
563 bus_space_handle_t ioh = sc->sc_ioh;
564 struct tty *tp = sc->sc_tty;
565 int status;
566 int byte;
567
568 do {
569 status = bus_space_read_4(iot, ioh, UART_FLAGS);
570 if ((status & UART_RX_FULL))
571 break;
572 byte = bus_space_read_4(iot, ioh, UART_DATA);
573 status = bus_space_read_4(iot, ioh, UART_RX_STAT);
574 #if defined(DDB) && DDB_KEYCODE > 0
575 /*
576 * Temporary hack so that I can force the kernel into
577 * the debugger via the serial port
578 */
579 if (byte == DDB_KEYCODE) Debugger();
580 #endif
581 if (tp && (tp->t_state & TS_ISOPEN))
582 if (sc->sc_rxpos < RX_BUFFER_SIZE) {
583 sc->sc_rxbuf[sc->sc_rxpos++] = byte;
584 if (!softint_scheduled) {
585 softint_scheduled = 1;
586 callout_reset(&sc->sc_softintr_ch,
587 1, fcom_softintr, sc);
588 }
589 }
590 } while (1);
591 return(0);
592 }
593
594 #if 0
595 void
596 fcom_iflush(sc)
597 struct fcom_softc *sc;
598 {
599 bus_space_tag_t iot = sc->sc_iot;
600 bus_space_handle_t ioh = sc->sc_ioh;
601
602 /* flush any pending I/O */
603 while (!ISSET(bus_space_read_4(iot, ioh, UART_FLAGS), UART_RX_FULL))
604 (void) bus_space_read_4(iot, ioh, UART_DATA);
605 }
606 #endif
607
608 /*
609 * Following are all routines needed for COM to act as console
610 */
611
612 #if 0
613 void
614 fcomcnprobe(cp)
615 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(cp)
631 struct consdev *cp;
632 {
633 fcomconstag = &fcomcons_bs_tag;
634
635 if (bus_space_map(fcomconstag, DC21285_ARMCSR_BASE, DC21285_ARMCSR_SIZE, 0, &fcomconsioh))
636 panic("fcomcninit: mapping failed");
637
638 fcominitcons(fcomconstag, fcomconsioh);
639 }
640 #endif
641
642 int
643 fcomcnattach(iobase, rate, cflag)
644 u_int iobase;
645 int rate;
646 tcflag_t cflag;
647 {
648 static struct consdev fcomcons = {
649 NULL, NULL, fcomcngetc, fcomcnputc, fcomcnpollc, NULL,
650 NULL, NULL, NODEV, CN_NORMAL
651 };
652
653 fcomconstag = &fcomcons_bs_tag;
654
655 if (bus_space_map(fcomconstag, iobase, DC21285_ARMCSR_SIZE,
656 0, &fcomconsioh))
657 panic("fcomcninit: mapping failed");
658
659 fcominit(fcomconstag, fcomconsioh, rate, cflag);
660
661 cn_tab = &fcomcons;
662
663 /* comcnspeed = rate;
664 comcnmode = cflag;*/
665 return (0);
666 }
667
668 int
669 fcomcndetach(void)
670 {
671 bus_space_unmap(fcomconstag, fcomconsioh, DC21285_ARMCSR_SIZE);
672
673 cn_tab = NULL;
674 return (0);
675 }
676
677 /*
678 * Initialize UART to known state.
679 */
680 void
681 fcominit(iot, ioh, rate, mode)
682 bus_space_tag_t iot;
683 bus_space_handle_t ioh;
684 int rate;
685 int mode;
686 {
687 int baudrate;
688 int h_ubrlcr;
689 int m_ubrlcr;
690 int l_ubrlcr;
691
692 switch (rate) {
693 case B1200:
694 case B2400:
695 case B4800:
696 case B9600:
697 case B19200:
698 case B38400:
699 baudrate = UART_BRD(dc21285_fclk, rate);
700 break;
701 default:
702 baudrate = UART_BRD(dc21285_fclk, 9600);
703 break;
704 }
705
706 h_ubrlcr = 0;
707 switch (mode & CSIZE) {
708 case CS5:
709 h_ubrlcr |= UART_DATA_BITS_5;
710 break;
711 case CS6:
712 h_ubrlcr |= UART_DATA_BITS_6;
713 break;
714 case CS7:
715 h_ubrlcr |= UART_DATA_BITS_7;
716 break;
717 case CS8:
718 h_ubrlcr |= UART_DATA_BITS_8;
719 break;
720 }
721
722 if (mode & PARENB)
723 h_ubrlcr |= UART_PARITY_ENABLE;
724 if (mode & PARODD)
725 h_ubrlcr |= UART_ODD_PARITY;
726 else
727 h_ubrlcr |= UART_EVEN_PARITY;
728
729 if (mode & CSTOPB)
730 h_ubrlcr |= UART_STOP_BITS_2;
731
732 m_ubrlcr = (baudrate >> 8) & 0xf;
733 l_ubrlcr = baudrate & 0xff;
734
735 bus_space_write_4(iot, ioh, UART_L_UBRLCR, l_ubrlcr);
736 bus_space_write_4(iot, ioh, UART_M_UBRLCR, m_ubrlcr);
737 bus_space_write_4(iot, ioh, UART_H_UBRLCR, h_ubrlcr);
738 }
739 #if 0
740 /*
741 * Set UART for console use. Do normal init, then enable interrupts.
742 */
743 void
744 fcominitcons(iot, ioh)
745 bus_space_tag_t iot;
746 bus_space_handle_t ioh;
747 {
748 int s = splserial();
749
750 fcominit(iot, ioh, comcnspeed, comcnmode);
751
752 delay(10000);
753
754 (void)splx(s);
755 }
756 #endif
757
758 int
759 fcomcngetc(dev)
760 dev_t dev;
761 {
762 int s = splserial();
763 bus_space_tag_t iot = fcomconstag;
764 bus_space_handle_t ioh = fcomconsioh;
765 u_char stat, c;
766
767 while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_RX_FULL) != 0)
768 ;
769 c = bus_space_read_4(iot, ioh, UART_DATA);
770 stat = bus_space_read_4(iot, ioh, UART_RX_STAT);
771 (void)splx(s);
772 #if defined(DDB) && DDB_KEYCODE > 0
773 /*
774 * Temporary hack so that I can force the kernel into
775 * the debugger via the serial port
776 */
777 if (c == DDB_KEYCODE) Debugger();
778 #endif
779
780 return (c);
781 }
782
783 /*
784 * Console kernel output character routine.
785 */
786 void
787 fcomcnputc(dev, c)
788 dev_t dev;
789 int c;
790 {
791 int s = splserial();
792 bus_space_tag_t iot = fcomconstag;
793 bus_space_handle_t ioh = fcomconsioh;
794 int timo;
795
796 /* wait for any pending transmission to finish */
797 timo = 50000;
798 while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) && --timo)
799 ;
800 bus_space_write_4(iot, ioh, UART_DATA, c);
801
802 /* wait for this transmission to complete */
803 timo = 1500000;
804 while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) && --timo)
805 ;
806 /* Clear interrupt status here */
807 (void)splx(s);
808 }
809
810 void
811 fcomcnpollc(dev, on)
812 dev_t dev;
813 int on;
814 {
815 }
816