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