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