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