1 /* $OpenBSD: sbbc.c,v 1.14 2021/10/24 17:05:04 mpi Exp $ */ 2 /* 3 * Copyright (c) 2008 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/conf.h> 20 #include <sys/device.h> 21 #include <sys/malloc.h> 22 #include <sys/proc.h> 23 #include <sys/timeout.h> 24 #include <sys/tty.h> 25 #include <sys/systm.h> 26 27 #ifdef DDB 28 #include <ddb/db_var.h> 29 #endif 30 31 #include <machine/autoconf.h> 32 #include <machine/conf.h> 33 #include <machine/openfirm.h> 34 #include <machine/sparc64.h> 35 36 #include <dev/cons.h> 37 38 #include <dev/pci/pcidevs.h> 39 #include <dev/pci/pcireg.h> 40 #include <dev/pci/pcivar.h> 41 42 #include <dev/clock_subr.h> 43 44 extern todr_chip_handle_t todr_handle; 45 46 #define SBBC_PCI_BAR PCI_MAPREG_START 47 48 #define SBBC_REGS_OFFSET 0x800000 49 #define SBBC_REGS_SIZE 0x6230 50 #define SBBC_EPLD_OFFSET 0x8e0000 51 #define SBBC_EPLD_SIZE 0x20 52 #define SBBC_SRAM_OFFSET 0x900000 53 #define SBBC_SRAM_SIZE 0x20000 /* 128KB SRAM */ 54 55 #define SBBC_PCI_INT_STATUS 0x2320 56 #define SBBC_PCI_INT_ENABLE 0x2330 57 #define SBBC_PCI_ENABLE_INT_A 0x11 58 59 #define SBBC_EPLD_INTERRUPT 0x13 60 #define SBBC_EPLD_INTERRUPT_ON 0x01 61 62 #define SBBC_SRAM_CONS_IN 0x00000001 63 #define SBBC_SRAM_CONS_OUT 0x00000002 64 #define SBBC_SRAM_CONS_BRK 0x00000004 65 #define SBBC_SRAM_CONS_SPACE_IN 0x00000008 66 #define SBBC_SRAM_CONS_SPACE_OUT 0x00000010 67 68 #define SBBC_MAX_TAGS 32 69 70 struct sbbc_sram_tag { 71 char tag_key[8]; 72 uint32_t tag_size; 73 uint32_t tag_offset; 74 }; 75 76 struct sbbc_sram_toc { 77 char toc_magic[8]; 78 uint8_t toc_reserved; 79 uint8_t toc_type; 80 uint16_t toc_version; 81 uint32_t toc_ntags; 82 struct sbbc_sram_tag toc_tag[SBBC_MAX_TAGS]; 83 }; 84 85 /* Time of day service. */ 86 struct sbbc_sram_tod { 87 uint32_t tod_magic; 88 uint32_t tod_version; 89 uint64_t tod_time; 90 uint64_t tod_skew; 91 uint32_t tod_reserved; 92 uint32_t tod_heartbeat; 93 uint32_t tod_timeout; 94 }; 95 96 #define SBBC_TOD_MAGIC 0x54443100 /* "TD1" */ 97 #define SBBC_TOD_VERSION 1 98 99 /* Console service. */ 100 struct sbbc_sram_cons { 101 uint32_t cons_magic; 102 uint32_t cons_version; 103 uint32_t cons_size; 104 105 uint32_t cons_in_begin; 106 uint32_t cons_in_end; 107 uint32_t cons_in_rdptr; 108 uint32_t cons_in_wrptr; 109 110 uint32_t cons_out_begin; 111 uint32_t cons_out_end; 112 uint32_t cons_out_rdptr; 113 uint32_t cons_out_wrptr; 114 }; 115 116 #define SBBC_CONS_MAGIC 0x434f4e00 /* "CON" */ 117 #define SBBC_CONS_VERSION 1 118 119 struct sbbc_softc { 120 struct device sc_dv; 121 bus_space_tag_t sc_iot; 122 bus_space_handle_t sc_regs_ioh; 123 bus_space_handle_t sc_epld_ioh; 124 bus_space_handle_t sc_sram_ioh; 125 caddr_t sc_sram; 126 uint32_t sc_sram_toc; 127 void * sc_ih; 128 129 struct sparc_bus_space_tag sc_bbt; 130 131 struct tty *sc_tty; 132 caddr_t sc_sram_cons; 133 uint32_t *sc_sram_solscie; 134 uint32_t *sc_sram_solscir; 135 uint32_t *sc_sram_scsolie; 136 uint32_t *sc_sram_scsolir; 137 void *sc_cons_si; 138 }; 139 140 struct sbbc_softc *sbbc_cons_input; 141 struct sbbc_softc *sbbc_cons_output; 142 143 int sbbc_match(struct device *, void *, void *); 144 void sbbc_attach(struct device *, struct device *, void *); 145 146 const struct cfattach sbbc_ca = { 147 sizeof(struct sbbc_softc), sbbc_match, sbbc_attach 148 }; 149 150 struct cfdriver sbbc_cd = { 151 NULL, "sbbc", DV_DULL 152 }; 153 154 int sbbc_intr(void *); 155 void sbbc_send_intr(struct sbbc_softc *sc); 156 157 void sbbc_attach_tod(struct sbbc_softc *, uint32_t); 158 int sbbc_tod_gettime(todr_chip_handle_t, struct timeval *); 159 int sbbc_tod_settime(todr_chip_handle_t, struct timeval *); 160 161 void sbbc_attach_cons(struct sbbc_softc *, uint32_t); 162 void sbbc_intr_cons(struct sbbc_softc *, uint32_t); 163 void sbbc_softintr_cons(void *); 164 int sbbc_cnlookc(dev_t, int *); 165 int sbbc_cngetc(dev_t); 166 void sbbc_cnputc(dev_t, int); 167 void sbbcstart(struct tty *); 168 int sbbcparam(struct tty *, struct termios *); 169 170 int 171 sbbc_match(struct device *parent, void *match, void *aux) 172 { 173 struct pci_attach_args *pa = aux; 174 175 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN && 176 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_SBBC)) 177 return (1); 178 179 return (0); 180 } 181 182 void 183 sbbc_attach(struct device *parent, struct device *self, void *aux) 184 { 185 struct sbbc_softc *sc = (void *)self; 186 struct pci_attach_args *pa = aux; 187 struct sbbc_sram_toc *toc; 188 bus_addr_t base; 189 bus_size_t size; 190 pci_intr_handle_t ih; 191 int chosen, iosram; 192 int i; 193 194 /* XXX Don't byteswap. */ 195 sc->sc_bbt = *pa->pa_memt; 196 sc->sc_bbt.sasi = ASI_PRIMARY; 197 sc->sc_iot = &sc->sc_bbt; 198 199 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, SBBC_PCI_BAR, 200 PCI_MAPREG_TYPE_MEM, &base, &size, NULL)) { 201 printf(": can't find register space\n"); 202 return; 203 } 204 205 if (bus_space_map(sc->sc_iot, base + SBBC_REGS_OFFSET, 206 SBBC_REGS_SIZE, 0, &sc->sc_regs_ioh)) { 207 printf(": can't map register space\n"); 208 return; 209 } 210 211 if (bus_space_map(sc->sc_iot, base + SBBC_EPLD_OFFSET, 212 SBBC_EPLD_SIZE, 0, &sc->sc_epld_ioh)) { 213 printf(": can't map EPLD registers\n"); 214 goto unmap_regs; 215 } 216 217 if (bus_space_map(sc->sc_iot, base + SBBC_SRAM_OFFSET, 218 SBBC_SRAM_SIZE, 0, &sc->sc_sram_ioh)) { 219 printf(": can't map SRAM\n"); 220 goto unmap_epld; 221 } 222 223 if (pci_intr_map(pa, &ih)) { 224 printf(": unable to map interrupt\n"); 225 goto unmap_sram; 226 } 227 printf(": %s\n", pci_intr_string(pa->pa_pc, ih)); 228 229 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY, 230 sbbc_intr, sc, sc->sc_dv.dv_xname); 231 if (sc->sc_ih == NULL) { 232 printf("%s: unable to establish interrupt\n", sc->sc_dv.dv_xname); 233 goto unmap_sram; 234 } 235 236 bus_space_write_4(sc->sc_iot, sc->sc_regs_ioh, 237 SBBC_PCI_INT_ENABLE, SBBC_PCI_ENABLE_INT_A); 238 239 /* Check if we are the chosen one. */ 240 chosen = OF_finddevice("/chosen"); 241 if (OF_getprop(chosen, "iosram", &iosram, sizeof(iosram)) <= 0 || 242 PCITAG_NODE(pa->pa_tag) != iosram) 243 return; 244 245 /* SRAM TOC offset defaults to 0. */ 246 if (OF_getprop(chosen, "iosram-toc", &sc->sc_sram_toc, 247 sizeof(sc->sc_sram_toc)) <= 0) 248 sc->sc_sram_toc = 0; 249 250 sc->sc_sram = bus_space_vaddr(sc->sc_iot, sc->sc_sram_ioh); 251 toc = (struct sbbc_sram_toc *)(sc->sc_sram + sc->sc_sram_toc); 252 253 for (i = 0; i < toc->toc_ntags; i++) { 254 if (strcmp(toc->toc_tag[i].tag_key, "SOLSCIE") == 0) 255 sc->sc_sram_solscie = (uint32_t *) 256 (sc->sc_sram + toc->toc_tag[i].tag_offset); 257 if (strcmp(toc->toc_tag[i].tag_key, "SOLSCIR") == 0) 258 sc->sc_sram_solscir = (uint32_t *) 259 (sc->sc_sram + toc->toc_tag[i].tag_offset); 260 if (strcmp(toc->toc_tag[i].tag_key, "SCSOLIE") == 0) 261 sc->sc_sram_scsolie = (uint32_t *) 262 (sc->sc_sram + toc->toc_tag[i].tag_offset); 263 if (strcmp(toc->toc_tag[i].tag_key, "SCSOLIR") == 0) 264 sc->sc_sram_scsolir = (uint32_t *) 265 (sc->sc_sram + toc->toc_tag[i].tag_offset); 266 } 267 268 for (i = 0; i < toc->toc_ntags; i++) { 269 if (strcmp(toc->toc_tag[i].tag_key, "TODDATA") == 0) 270 sbbc_attach_tod(sc, toc->toc_tag[i].tag_offset); 271 if (strcmp(toc->toc_tag[i].tag_key, "SOLCONS") == 0) 272 sbbc_attach_cons(sc, toc->toc_tag[i].tag_offset); 273 } 274 275 return; 276 277 unmap_sram: 278 bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_SRAM_SIZE); 279 unmap_epld: 280 bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_EPLD_SIZE); 281 unmap_regs: 282 bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_REGS_SIZE); 283 } 284 285 int 286 sbbc_intr(void *arg) 287 { 288 struct sbbc_softc *sc = arg; 289 uint32_t status, reason; 290 291 status = bus_space_read_4(sc->sc_iot, sc->sc_regs_ioh, 292 SBBC_PCI_INT_STATUS); 293 if (status == 0) 294 return (0); 295 296 /* Sigh, we cannot use compare and swap for non-cachable memory. */ 297 reason = *sc->sc_sram_scsolir; 298 *sc->sc_sram_scsolir = 0; 299 300 sbbc_intr_cons(sc, reason); 301 302 /* Ack interrupt. */ 303 bus_space_write_4(sc->sc_iot, sc->sc_regs_ioh, 304 SBBC_PCI_INT_STATUS, status); 305 return (1); 306 } 307 308 void 309 sbbc_send_intr(struct sbbc_softc *sc) 310 { 311 bus_space_write_1(sc->sc_iot, sc->sc_epld_ioh, 312 SBBC_EPLD_INTERRUPT, SBBC_EPLD_INTERRUPT_ON); 313 } 314 315 void 316 sbbc_attach_tod(struct sbbc_softc *sc, uint32_t offset) 317 { 318 struct sbbc_sram_tod *tod; 319 todr_chip_handle_t handle; 320 321 tod = (struct sbbc_sram_tod *)(sc->sc_sram + offset); 322 if (tod->tod_magic != SBBC_TOD_MAGIC || 323 tod->tod_version < SBBC_TOD_VERSION) 324 return; 325 326 handle = malloc(sizeof(struct todr_chip_handle), M_DEVBUF, M_NOWAIT); 327 if (handle == NULL) 328 panic("couldn't allocate todr_handle"); 329 330 handle->cookie = tod; 331 handle->todr_gettime = sbbc_tod_gettime; 332 handle->todr_settime = sbbc_tod_settime; 333 334 handle->bus_cookie = NULL; 335 handle->todr_setwen = NULL; 336 todr_handle = handle; 337 } 338 339 int 340 sbbc_tod_gettime(todr_chip_handle_t handle, struct timeval *tv) 341 { 342 struct sbbc_sram_tod *tod = handle->cookie; 343 344 tv->tv_sec = tod->tod_time + tod->tod_skew; 345 tv->tv_usec = 0; 346 return (0); 347 } 348 349 int 350 sbbc_tod_settime(todr_chip_handle_t handle, struct timeval *tv) 351 { 352 struct sbbc_sram_tod *tod = handle->cookie; 353 354 tod->tod_skew = tv->tv_sec - tod->tod_time; 355 return (0); 356 } 357 358 void 359 sbbc_attach_cons(struct sbbc_softc *sc, uint32_t offset) 360 { 361 struct sbbc_sram_cons *cons; 362 int sgcn_is_input, sgcn_is_output, node, maj; 363 char buf[32]; 364 365 if (sc->sc_sram_solscie == NULL || sc->sc_sram_solscir == NULL || 366 sc->sc_sram_scsolie == NULL || sc->sc_sram_scsolir == NULL) 367 return; 368 369 cons = (struct sbbc_sram_cons *)(sc->sc_sram + offset); 370 if (cons->cons_magic != SBBC_CONS_MAGIC || 371 cons->cons_version < SBBC_CONS_VERSION) 372 return; 373 374 sc->sc_sram_cons = sc->sc_sram + offset; 375 sbbc_cons_input = sbbc_cons_output = sc; 376 sgcn_is_input = sgcn_is_output = 0; 377 378 sc->sc_cons_si = softintr_establish(IPL_TTY, sbbc_softintr_cons, sc); 379 if (sc->sc_cons_si == NULL) 380 panic("%s: can't establish soft interrupt", 381 sc->sc_dv.dv_xname); 382 383 *sc->sc_sram_solscie |= SBBC_SRAM_CONS_OUT; 384 *sc->sc_sram_scsolie |= SBBC_SRAM_CONS_IN | SBBC_SRAM_CONS_BRK; 385 386 /* Take over console input. */ 387 prom_serengeti_set_console_input("CON_CLNT"); 388 389 /* Check for console input. */ 390 node = OF_instance_to_package(OF_stdin()); 391 if (OF_getprop(node, "name", buf, sizeof(buf)) > 0) 392 sgcn_is_input = (strcmp(buf, "sgcn") == 0); 393 394 /* Check for console output. */ 395 node = OF_instance_to_package(OF_stdout()); 396 if (OF_getprop(node, "name", buf, sizeof(buf)) > 0) 397 sgcn_is_output = (strcmp(buf, "sgcn") == 0); 398 399 if (sgcn_is_input) { 400 cn_tab->cn_pollc = nullcnpollc; 401 cn_tab->cn_getc = sbbc_cngetc; 402 } 403 404 if (sgcn_is_output) 405 cn_tab->cn_putc = sbbc_cnputc; 406 407 if (sgcn_is_input || sgcn_is_output) { 408 /* Locate the major number. */ 409 for (maj = 0; maj < nchrdev; maj++) 410 if (cdevsw[maj].d_open == sbbcopen) 411 break; 412 cn_tab->cn_dev = makedev(maj, sc->sc_dv.dv_unit); 413 414 /* Let current output drain. */ 415 DELAY(2000000); 416 417 printf("%s: console\n", sc->sc_dv.dv_xname); 418 } 419 } 420 421 void 422 sbbc_intr_cons(struct sbbc_softc *sc, uint32_t reason) 423 { 424 #ifdef DDB 425 if ((reason & SBBC_SRAM_CONS_BRK) && sc == sbbc_cons_input) { 426 if (db_console) 427 db_enter(); 428 } 429 #endif 430 431 if ((reason & SBBC_SRAM_CONS_IN) && sc->sc_tty) 432 softintr_schedule(sc->sc_cons_si); 433 } 434 435 void 436 sbbc_softintr_cons(void *arg) 437 { 438 struct sbbc_softc *sc = arg; 439 struct sbbc_sram_cons *cons = (void *)sc->sc_sram_cons; 440 uint32_t rdptr = cons->cons_in_rdptr; 441 struct tty *tp = sc->sc_tty; 442 int c; 443 444 while (rdptr != cons->cons_in_wrptr) { 445 if (tp->t_state & TS_ISOPEN) { 446 c = *(sc->sc_sram_cons + rdptr); 447 (*linesw[tp->t_line].l_rint)(c, tp); 448 } 449 450 if (++rdptr == cons->cons_in_end) 451 rdptr = cons->cons_in_begin; 452 } 453 454 cons->cons_in_rdptr = rdptr; 455 } 456 457 int 458 sbbc_cnlookc(dev_t dev, int *cp) 459 { 460 struct sbbc_softc *sc = sbbc_cons_input; 461 struct sbbc_sram_cons *cons = (void *)sc->sc_sram_cons; 462 uint32_t rdptr = cons->cons_in_rdptr; 463 464 if (rdptr == cons->cons_in_wrptr) 465 return (0); 466 467 *cp = *(sc->sc_sram_cons + rdptr); 468 if (++rdptr == cons->cons_in_end) 469 rdptr = cons->cons_in_begin; 470 cons->cons_in_rdptr = rdptr; 471 472 return (1); 473 } 474 475 int 476 sbbc_cngetc(dev_t dev) 477 { 478 int c; 479 480 while(!sbbc_cnlookc(dev, &c)) 481 ; 482 483 return (c); 484 } 485 486 void 487 sbbc_cnputc(dev_t dev, int c) 488 { 489 struct sbbc_softc *sc = sbbc_cons_output; 490 struct sbbc_sram_cons *cons = (void *)sc->sc_sram_cons; 491 uint32_t wrptr = cons->cons_out_wrptr; 492 493 *(sc->sc_sram_cons + wrptr) = c; 494 if (++wrptr == cons->cons_out_end) 495 wrptr = cons->cons_out_begin; 496 cons->cons_out_wrptr = wrptr; 497 498 *sc->sc_sram_solscir |= SBBC_SRAM_CONS_OUT; 499 sbbc_send_intr(sc); 500 } 501 502 int 503 sbbcopen(dev_t dev, int flag, int mode, struct proc *p) 504 { 505 struct sbbc_softc *sc; 506 struct tty *tp; 507 int unit = minor(dev); 508 509 if (unit >= sbbc_cd.cd_ndevs) 510 return (ENXIO); 511 sc = sbbc_cd.cd_devs[unit]; 512 if (sc == NULL) 513 return (ENXIO); 514 515 if (sc->sc_tty) 516 tp = sc->sc_tty; 517 else 518 tp = sc->sc_tty = ttymalloc(0); 519 520 tp->t_oproc = sbbcstart; 521 tp->t_param = sbbcparam; 522 tp->t_dev = dev; 523 if ((tp->t_state & TS_ISOPEN) == 0) { 524 ttychars(tp); 525 tp->t_iflag = TTYDEF_IFLAG; 526 tp->t_oflag = TTYDEF_OFLAG; 527 tp->t_cflag = TTYDEF_CFLAG; 528 tp->t_lflag = TTYDEF_LFLAG; 529 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 530 ttsetwater(tp); 531 } else if ((tp->t_state & TS_XCLUDE) && suser(p)) 532 return (EBUSY); 533 tp->t_state |= TS_CARR_ON; 534 535 return ((*linesw[tp->t_line].l_open)(dev, tp, p)); 536 } 537 538 int 539 sbbcclose(dev_t dev, int flag, int mode, struct proc *p) 540 { 541 struct sbbc_softc *sc; 542 struct tty *tp; 543 int unit = minor(dev); 544 545 if (unit >= sbbc_cd.cd_ndevs) 546 return (ENXIO); 547 sc = sbbc_cd.cd_devs[unit]; 548 if (sc == NULL) 549 return (ENXIO); 550 551 tp = sc->sc_tty; 552 (*linesw[tp->t_line].l_close)(tp, flag, p); 553 ttyclose(tp); 554 return (0); 555 } 556 557 int 558 sbbcread(dev_t dev, struct uio *uio, int flag) 559 { 560 struct sbbc_softc *sc; 561 struct tty *tp; 562 int unit = minor(dev); 563 564 if (unit >= sbbc_cd.cd_ndevs) 565 return (ENXIO); 566 sc = sbbc_cd.cd_devs[unit]; 567 if (sc == NULL) 568 return (ENXIO); 569 570 tp = sc->sc_tty; 571 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 572 } 573 574 int 575 sbbcwrite(dev_t dev, struct uio *uio, int flag) 576 { 577 struct sbbc_softc *sc; 578 struct tty *tp; 579 int unit = minor(dev); 580 581 if (unit >= sbbc_cd.cd_ndevs) 582 return (ENXIO); 583 sc = sbbc_cd.cd_devs[unit]; 584 if (sc == NULL) 585 return (ENXIO); 586 587 tp = sc->sc_tty; 588 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 589 } 590 591 int 592 sbbcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 593 { 594 struct sbbc_softc *sc; 595 struct tty *tp; 596 int unit = minor(dev); 597 int error; 598 599 if (unit >= sbbc_cd.cd_ndevs) 600 return (ENXIO); 601 sc = sbbc_cd.cd_devs[unit]; 602 if (sc == NULL) 603 return (ENXIO); 604 605 tp = sc->sc_tty; 606 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 607 if (error >= 0) 608 return error; 609 error = ttioctl(tp, cmd, data, flag, p); 610 if (error >= 0) 611 return (error); 612 613 return (ENOTTY); 614 } 615 616 void 617 sbbcstart(struct tty *tp) 618 { 619 int s; 620 621 s = spltty(); 622 if (tp->t_state & (TS_TTSTOP | TS_BUSY)) { 623 splx(s); 624 return; 625 } 626 ttwakeupwr(tp); 627 tp->t_state |= TS_BUSY; 628 while (tp->t_outq.c_cc != 0) 629 sbbc_cnputc(tp->t_dev, getc(&tp->t_outq)); 630 tp->t_state &= ~TS_BUSY; 631 splx(s); 632 } 633 634 int 635 sbbcstop(struct tty *tp, int flag) 636 { 637 int s; 638 639 s = spltty(); 640 if (tp->t_state & TS_BUSY) 641 if ((tp->t_state & TS_TTSTOP) == 0) 642 tp->t_state |= TS_FLUSH; 643 splx(s); 644 return (0); 645 } 646 647 struct tty * 648 sbbctty(dev_t dev) 649 { 650 struct sbbc_softc *sc; 651 int unit = minor(dev); 652 653 if (unit >= sbbc_cd.cd_ndevs) 654 return (NULL); 655 sc = sbbc_cd.cd_devs[unit]; 656 if (sc == NULL) 657 return (NULL); 658 659 return sc->sc_tty; 660 } 661 662 int 663 sbbcparam(struct tty *tp, struct termios *t) 664 { 665 tp->t_ispeed = t->c_ispeed; 666 tp->t_ospeed = t->c_ospeed; 667 tp->t_cflag = t->c_cflag; 668 return (0); 669 } 670