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