1/*- 2 * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org> 3 * based on work by Slawa Olhovchenkov 4 * John Prince <johnp@knight-trosoft.com> 5 * Eric Hernes 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32/*- 33 * TODO: 34 * Figure out what the con bios stuff is supposed to do 35 * Test with *LOTS* more cards - I only have a PCI8r and an ISA Xem. 36 */ 37 38#include "opt_compat.h" 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/proc.h> 43#include <sys/conf.h> 44#include <sys/linker.h> 45#include <sys/kernel.h> 46#include <sys/mbuf.h> 47#include <sys/malloc.h> 48#include <sys/module.h> 49#include <sys/tty.h> 50#include <sys/syslog.h> 51#include <sys/fcntl.h> 52#include <sys/serial.h> 53#include <sys/bus.h> 54#include <machine/resource.h> 55 56#include <sys/digiio.h> 57#include <dev/digi/digireg.h> 58#include <dev/digi/digi.h> 59#include <dev/digi/digi_mod.h> 60#include <dev/digi/digi_pci.h> 61 62static t_open_t digiopen; 63static d_open_t digicopen; 64static d_close_t digicclose; 65static t_ioctl_t digiioctl; 66static d_ioctl_t digisioctl; 67static d_ioctl_t digicioctl; 68 69static void digistop(struct tty *tp, int rw); 70static void digibreak(struct tty *tp, int brk); 71static int digimodem(struct tty *tp, int sigon, int sigoff); 72static void digi_poll(void *ptr); 73static void digi_freemoduledata(struct digi_softc *); 74static void fepcmd(struct digi_p *port, int cmd, int op, int ncmds); 75static void digistart(struct tty *tp); 76static int digiparam(struct tty *tp, struct termios *t); 77static void digiclose(struct tty *tp); 78static void digi_intr(void *); 79static int digi_init(struct digi_softc *_sc); 80static int digi_loadmoduledata(struct digi_softc *); 81static int digi_inuse(struct digi_softc *); 82static void digi_free_state(struct digi_softc *); 83 84#define fepcmd_b(port, cmd, op1, op2, ncmds) \ 85 fepcmd(port, cmd, (op2 << 8) | op1, ncmds) 86#define fepcmd_w fepcmd 87 88struct con_bios { 89 struct con_bios *next; 90 u_char *bios; 91 size_t size; 92}; 93 94static struct con_bios *con_bios_list; 95devclass_t digi_devclass; 96static char driver_name[] = "digi"; 97unsigned digi_debug = 0; 98 99static struct speedtab digispeedtab[] = { 100 { 0, 0}, /* old (sysV-like) Bx codes */ 101 { 50, 1}, 102 { 75, 2}, 103 { 110, 3}, 104 { 134, 4}, 105 { 150, 5}, 106 { 200, 6}, 107 { 300, 7}, 108 { 600, 8}, 109 { 1200, 9}, 110 { 1800, 10}, 111 { 2400, 11}, 112 { 4800, 12}, 113 { 9600, 13}, 114 { 19200, 14}, 115 { 38400, 15}, 116 { 57600, (02000 | 1)}, 117 { 76800, (02000 | 2)}, 118 { 115200, (02000 | 3)}, 119 { 230400, (02000 | 6)}, 120 { -1, -1} 121}; 122 123const struct digi_control_signals digi_xixe_signals = { 124 0x02, 0x08, 0x10, 0x20, 0x40, 0x80 125}; 126 127const struct digi_control_signals digi_normal_signals = { 128 0x02, 0x80, 0x20, 0x10, 0x40, 0x01 129}; 130 131static struct cdevsw digi_csw = { 132 .d_version = D_VERSION, 133 .d_open = digicopen, 134 .d_close = digicclose, 135 .d_ioctl = digicioctl, 136 .d_name = driver_name, 137 .d_flags = D_TTY | D_NEEDGIANT, 138}; 139 140static void 141digi_poll(void *ptr) 142{ 143 struct digi_softc *sc; 144 145 sc = (struct digi_softc *)ptr; 146 callout_handle_init(&sc->callout); 147 digi_intr(sc); 148 sc->callout = timeout(digi_poll, sc, (hz >= 200) ? hz / 100 : 1); 149} 150 151static void 152digi_int_test(void *v) 153{ 154 struct digi_softc *sc = v; 155 156 callout_handle_init(&sc->inttest); 157#ifdef DIGI_INTERRUPT 158 if (sc->intr_timestamp.tv_sec || sc->intr_timestamp.tv_usec) { 159 /* interrupt OK! */ 160 return; 161 } 162 log(LOG_ERR, "digi%d: Interrupt didn't work, use polled mode\n", unit); 163#endif 164 sc->callout = timeout(digi_poll, sc, (hz >= 200) ? hz / 100 : 1); 165} 166 167static void 168digi_freemoduledata(struct digi_softc *sc) 169{ 170 if (sc->fep.data != NULL) { 171 free(sc->fep.data, M_TTYS); 172 sc->fep.data = NULL; 173 } 174 if (sc->link.data != NULL) { 175 free(sc->link.data, M_TTYS); 176 sc->link.data = NULL; 177 } 178 if (sc->bios.data != NULL) { 179 free(sc->bios.data, M_TTYS); 180 sc->bios.data = NULL; 181 } 182} 183 184static int 185digi_bcopy(const void *vfrom, void *vto, size_t sz) 186{ 187 volatile const char *from = (volatile const char *)vfrom; 188 volatile char *to = (volatile char *)vto; 189 size_t i; 190 191 for (i = 0; i < sz; i++) 192 *to++ = *from++; 193 194 from = (const volatile char *)vfrom; 195 to = (volatile char *)vto; 196 for (i = 0; i < sz; i++) 197 if (*to++ != *from++) 198 return (0); 199 return (1); 200} 201 202void 203digi_delay(struct digi_softc *sc, const char *txt, u_long timo) 204{ 205 if (cold) 206 DELAY(timo * 1000000 / hz); 207 else 208 tsleep(sc, PUSER | PCATCH, txt, timo); 209} 210 211static int 212digi_init(struct digi_softc *sc) 213{ 214 int i, cnt, resp; 215 u_char *ptr; 216 int lowwater; 217 struct digi_p *port; 218 volatile struct board_chan *bc; 219 struct tty *tp; 220 221 ptr = NULL; 222 223 if (sc->status == DIGI_STATUS_DISABLED) { 224 log(LOG_ERR, "digi%d: Cannot init a disabled card\n", 225 sc->res.unit); 226 return (EIO); 227 } 228 if (sc->bios.data == NULL) { 229 log(LOG_ERR, "digi%d: Cannot init without BIOS\n", 230 sc->res.unit); 231 return (EIO); 232 } 233#if 0 234 if (sc->link.data == NULL && sc->model >= PCCX) { 235 log(LOG_ERR, "digi%d: Cannot init without link info\n", 236 sc->res.unit); 237 return (EIO); 238 } 239#endif 240 if (sc->fep.data == NULL) { 241 log(LOG_ERR, "digi%d: Cannot init without fep code\n", 242 sc->res.unit); 243 return (EIO); 244 } 245 sc->status = DIGI_STATUS_NOTINIT; 246 247 if (sc->numports) { 248 /* 249 * We're re-initialising - maybe because someone's attached 250 * another port module. For now, we just re-initialise 251 * everything. 252 */ 253 if (digi_inuse(sc)) 254 return (EBUSY); 255 256 digi_free_state(sc); 257 } 258 259 ptr = sc->setwin(sc, MISCGLOBAL); 260 for (i = 0; i < 16; i += 2) 261 vW(ptr + i) = 0; 262 263 switch (sc->model) { 264 case PCXEVE: 265 outb(sc->wport, 0xff); /* window 7 */ 266 ptr = sc->vmem + (BIOSCODE & 0x1fff); 267 268 if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) { 269 device_printf(sc->dev, "BIOS upload failed\n"); 270 return (EIO); 271 } 272 273 outb(sc->port, FEPCLR); 274 break; 275 276 case PCXE: 277 case PCXI: 278 case PCCX: 279 ptr = sc->setwin(sc, BIOSCODE + ((0xf000 - sc->mem_seg) << 4)); 280 if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) { 281 device_printf(sc->dev, "BIOS upload failed\n"); 282 return (EIO); 283 } 284 break; 285 286 case PCXEM: 287 case PCIEPCX: 288 case PCIXR: 289 if (sc->pcibus) 290 PCIPORT = FEPRST; 291 else 292 outb(sc->port, FEPRST | FEPMEM); 293 294 for (i = 0; ((sc->pcibus ? PCIPORT : inb(sc->port)) & 295 FEPMASK) != FEPRST; i++) { 296 if (i > hz) { 297 log(LOG_ERR, "digi%d: %s init reset failed\n", 298 sc->res.unit, sc->name); 299 return (EIO); 300 } 301 digi_delay(sc, "digiinit0", 5); 302 } 303 DLOG(DIGIDB_INIT, (sc->dev, "Got init reset after %d us\n", i)); 304 305 /* Now upload the BIOS */ 306 cnt = (sc->bios.size < sc->win_size - BIOSOFFSET) ? 307 sc->bios.size : sc->win_size - BIOSOFFSET; 308 309 ptr = sc->setwin(sc, BIOSOFFSET); 310 if (!digi_bcopy(sc->bios.data, ptr, cnt)) { 311 device_printf(sc->dev, "BIOS upload (1) failed\n"); 312 return (EIO); 313 } 314 315 if (cnt != sc->bios.size) { 316 /* and the second part */ 317 ptr = sc->setwin(sc, sc->win_size); 318 if (!digi_bcopy(sc->bios.data + cnt, ptr, 319 sc->bios.size - cnt)) { 320 device_printf(sc->dev, "BIOS upload failed\n"); 321 return (EIO); 322 } 323 } 324 325 ptr = sc->setwin(sc, 0); 326 vW(ptr + 0) = 0x0401; 327 vW(ptr + 2) = 0x0bf0; 328 vW(ptr + 4) = 0x0000; 329 vW(ptr + 6) = 0x0000; 330 331 break; 332 } 333 334 DLOG(DIGIDB_INIT, (sc->dev, "BIOS uploaded\n")); 335 336 ptr = sc->setwin(sc, MISCGLOBAL); 337 W(ptr) = 0; 338 339 if (sc->pcibus) { 340 PCIPORT = FEPCLR; 341 resp = FEPRST; 342 } else if (sc->model == PCXEVE) { 343 outb(sc->port, FEPCLR); 344 resp = FEPRST; 345 } else { 346 outb(sc->port, FEPCLR | FEPMEM); 347 resp = FEPRST | FEPMEM; 348 } 349 350 for (i = 0; ((sc->pcibus ? PCIPORT : inb(sc->port)) & FEPMASK) 351 == resp; i++) { 352 if (i > hz) { 353 log(LOG_ERR, "digi%d: BIOS start failed\n", 354 sc->res.unit); 355 return (EIO); 356 } 357 digi_delay(sc, "digibios0", 5); 358 } 359 360 DLOG(DIGIDB_INIT, (sc->dev, "BIOS started after %d us\n", i)); 361 362 for (i = 0; vW(ptr) != *(u_short *)"GD"; i++) { 363 if (i > 5*hz) { 364 log(LOG_ERR, "digi%d: BIOS boot failed " 365 "(0x%02x != 0x%02x)\n", 366 sc->res.unit, vW(ptr), *(u_short *)"GD"); 367 return (EIO); 368 } 369 digi_delay(sc, "digibios1", 5); 370 } 371 372 DLOG(DIGIDB_INIT, (sc->dev, "BIOS booted after %d iterations\n", i)); 373 374 if (sc->link.data != NULL) { 375 DLOG(DIGIDB_INIT, (sc->dev, "Loading link data\n")); 376 ptr = sc->setwin(sc, 0xcd0); 377 digi_bcopy(sc->link.data, ptr, 21); /* XXX 21 ? */ 378 } 379 380 /* load FEP/OS */ 381 382 switch (sc->model) { 383 case PCXE: 384 case PCXEVE: 385 case PCXI: 386 ptr = sc->setwin(sc, sc->model == PCXI ? 0x2000 : 0x0); 387 digi_bcopy(sc->fep.data, ptr, sc->fep.size); 388 389 /* A BIOS request to move our data to 0x2000 */ 390 ptr = sc->setwin(sc, MBOX); 391 vW(ptr + 0) = 2; 392 vW(ptr + 2) = sc->mem_seg + FEPCODESEG; 393 vW(ptr + 4) = 0; 394 vW(ptr + 6) = FEPCODESEG; 395 vW(ptr + 8) = 0; 396 vW(ptr + 10) = sc->fep.size; 397 398 /* Run the BIOS request */ 399 outb(sc->port, FEPREQ | FEPMEM); 400 outb(sc->port, FEPCLR | FEPMEM); 401 402 for (i = 0; W(ptr); i++) { 403 if (i > hz) { 404 log(LOG_ERR, "digi%d: FEP/OS move failed\n", 405 sc->res.unit); 406 sc->hidewin(sc); 407 return (EIO); 408 } 409 digi_delay(sc, "digifep0", 5); 410 } 411 DLOG(DIGIDB_INIT, 412 (sc->dev, "FEP/OS moved after %d iterations\n", i)); 413 414 /* Clear the confirm word */ 415 ptr = sc->setwin(sc, FEPSTAT); 416 vW(ptr + 0) = 0; 417 418 /* A BIOS request to execute the FEP/OS */ 419 ptr = sc->setwin(sc, MBOX); 420 vW(ptr + 0) = 0x01; 421 vW(ptr + 2) = FEPCODESEG; 422 vW(ptr + 4) = 0x04; 423 424 /* Run the BIOS request */ 425 outb(sc->port, FEPREQ); 426 outb(sc->port, FEPCLR); 427 428 ptr = sc->setwin(sc, FEPSTAT); 429 430 break; 431 432 case PCXEM: 433 case PCIEPCX: 434 case PCIXR: 435 DLOG(DIGIDB_INIT, (sc->dev, "Loading FEP/OS\n")); 436 437 cnt = (sc->fep.size < sc->win_size - BIOSOFFSET) ? 438 sc->fep.size : sc->win_size - BIOSOFFSET; 439 440 ptr = sc->setwin(sc, BIOSOFFSET); 441 digi_bcopy(sc->fep.data, ptr, cnt); 442 443 if (cnt != sc->fep.size) { 444 ptr = sc->setwin(sc, BIOSOFFSET + cnt); 445 digi_bcopy(sc->fep.data + cnt, ptr, 446 sc->fep.size - cnt); 447 } 448 449 DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS loaded\n")); 450 451 ptr = sc->setwin(sc, 0xc30); 452 W(ptr + 4) = 0x1004; 453 W(ptr + 6) = 0xbfc0; 454 W(ptr + 0) = 0x03; 455 W(ptr + 2) = 0x00; 456 457 /* Clear the confirm word */ 458 ptr = sc->setwin(sc, FEPSTAT); 459 W(ptr + 0) = 0; 460 461 if (sc->port) 462 outb(sc->port, 0); /* XXX necessary ? */ 463 464 break; 465 466 case PCCX: 467 ptr = sc->setwin(sc, 0xd000); 468 digi_bcopy(sc->fep.data, ptr, sc->fep.size); 469 470 /* A BIOS request to execute the FEP/OS */ 471 ptr = sc->setwin(sc, 0xc40); 472 W(ptr + 0) = 1; 473 W(ptr + 2) = FEPCODE >> 4; 474 W(ptr + 4) = 4; 475 476 /* Clear the confirm word */ 477 ptr = sc->setwin(sc, FEPSTAT); 478 W(ptr + 0) = 0; 479 480 /* Run the BIOS request */ 481 outb(sc->port, FEPREQ | FEPMEM); /* send interrupt to BIOS */ 482 outb(sc->port, FEPCLR | FEPMEM); 483 break; 484 } 485 486 /* Now wait 'till the FEP/OS has booted */ 487 for (i = 0; vW(ptr) != *(u_short *)"OS"; i++) { 488 if (i > 2*hz) { 489 log(LOG_ERR, "digi%d: FEP/OS start failed " 490 "(0x%02x != 0x%02x)\n", 491 sc->res.unit, vW(ptr), *(u_short *)"OS"); 492 sc->hidewin(sc); 493 return (EIO); 494 } 495 digi_delay(sc, "digifep1", 5); 496 } 497 498 DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS started after %d iterations\n", i)); 499 500 if (sc->model >= PCXEM) { 501 ptr = sc->setwin(sc, 0xe04); 502 vW(ptr) = 2; 503 ptr = sc->setwin(sc, 0xc02); 504 sc->numports = vW(ptr); 505 } else { 506 ptr = sc->setwin(sc, 0xc22); 507 sc->numports = vW(ptr); 508 } 509 510 if (sc->numports == 0) { 511 device_printf(sc->dev, "%s, 0 ports found\n", sc->name); 512 sc->hidewin(sc); 513 return (0); 514 } 515 516 device_printf(sc->dev, "%s, %d ports found\n", sc->name, sc->numports); 517 518 if (sc->ports) 519 free(sc->ports, M_TTYS); 520 sc->ports = malloc(sizeof(struct digi_p) * sc->numports, 521 M_TTYS, M_WAITOK | M_ZERO); 522 523 /* 524 * XXX Should read port 0xc90 for an array of 2byte values, 1 per 525 * port. If the value is 0, the port is broken.... 526 */ 527 528 ptr = sc->setwin(sc, 0); 529 530 /* We should now init per-port structures */ 531 bc = (volatile struct board_chan *)(ptr + CHANSTRUCT); 532 sc->gdata = (volatile struct global_data *)(ptr + FEP_GLOBAL); 533 534 sc->memcmd = ptr + sc->gdata->cstart; 535 sc->memevent = ptr + sc->gdata->istart; 536 537 for (i = 0; i < sc->numports; i++, bc++) { 538 port = sc->ports + i; 539 port->pnum = i; 540 port->sc = sc; 541 port->status = ENABLED; 542 port->bc = bc; 543 tp = port->tp = ttyalloc(); 544 tp->t_oproc = digistart; 545 tp->t_param = digiparam; 546 tp->t_modem = digimodem; 547 tp->t_break = digibreak; 548 tp->t_stop = digistop; 549 tp->t_cioctl = digisioctl; 550 tp->t_ioctl = digiioctl; 551 tp->t_open = digiopen; 552 tp->t_close = digiclose; 553 tp->t_sc = port; 554 555 if (sc->model == PCXEVE) { 556 port->txbuf = ptr + 557 (((bc->tseg - sc->mem_seg) << 4) & 0x1fff); 558 port->rxbuf = ptr + 559 (((bc->rseg - sc->mem_seg) << 4) & 0x1fff); 560 port->txwin = FEPWIN | ((bc->tseg - sc->mem_seg) >> 9); 561 port->rxwin = FEPWIN | ((bc->rseg - sc->mem_seg) >> 9); 562 } else if (sc->model == PCXI || sc->model == PCXE) { 563 port->txbuf = ptr + ((bc->tseg - sc->mem_seg) << 4); 564 port->rxbuf = ptr + ((bc->rseg - sc->mem_seg) << 4); 565 port->txwin = port->rxwin = 0; 566 } else { 567 port->txbuf = ptr + 568 (((bc->tseg - sc->mem_seg) << 4) % sc->win_size); 569 port->rxbuf = ptr + 570 (((bc->rseg - sc->mem_seg) << 4) % sc->win_size); 571 port->txwin = FEPWIN | 572 (((bc->tseg - sc->mem_seg) << 4) / sc->win_size); 573 port->rxwin = FEPWIN | 574 (((bc->rseg - sc->mem_seg) << 4) / sc->win_size); 575 } 576 port->txbufsize = bc->tmax + 1; 577 port->rxbufsize = bc->rmax + 1; 578 579 lowwater = port->txbufsize >> 2; 580 if (lowwater > 1024) 581 lowwater = 1024; 582 sc->setwin(sc, 0); 583 fepcmd_w(port, STXLWATER, lowwater, 10); 584 fepcmd_w(port, SRXLWATER, port->rxbufsize >> 2, 10); 585 fepcmd_w(port, SRXHWATER, (3 * port->rxbufsize) >> 2, 10); 586 587 bc->edelay = 100; 588 589 ttyinitmode(tp, 0, 0); 590 port->send_ring = 1; /* Default action on signal RI */ 591 ttycreate(tp, TS_CALLOUT, "D%r%r", sc->res.unit, i); 592 } 593 594 sc->hidewin(sc); 595 sc->inttest = timeout(digi_int_test, sc, hz); 596 /* fepcmd_w(&sc->ports[0], 0xff, 0, 0); */ 597 sc->status = DIGI_STATUS_ENABLED; 598 599 return (0); 600} 601 602static int 603digimodem(struct tty *tp, int sigon, int sigoff) 604{ 605 struct digi_softc *sc; 606 struct digi_p *port; 607 int bitand, bitor, mstat; 608 609 port = tp->t_sc; 610 sc = port->sc; 611 612 if (sigon == 0 && sigoff == 0) { 613 port->sc->setwin(port->sc, 0); 614 mstat = port->bc->mstat; 615 port->sc->hidewin(port->sc); 616 if (mstat & port->sc->csigs->rts) 617 sigon |= SER_RTS; 618 if (mstat & port->cd) 619 sigon |= SER_DCD; 620 if (mstat & port->dsr) 621 sigon |= SER_DSR; 622 if (mstat & port->sc->csigs->cts) 623 sigon |= SER_CTS; 624 if (mstat & port->sc->csigs->ri) 625 sigon |= SER_RI; 626 if (mstat & port->sc->csigs->dtr) 627 sigon |= SER_DTR; 628 return (sigon); 629 } 630 631 bitand = 0; 632 bitor = 0; 633 634 if (sigoff & SER_DTR) 635 bitand |= port->sc->csigs->dtr; 636 if (sigoff & SER_RTS) 637 bitand |= port->sc->csigs->rts; 638 if (sigon & SER_DTR) 639 bitor |= port->sc->csigs->dtr; 640 if (sigon & SER_RTS) 641 bitor |= port->sc->csigs->rts; 642 fepcmd_b(port, SETMODEM, bitor, ~bitand, 0); 643 return (0); 644} 645 646static int 647digicopen(struct cdev *dev, int flag, int mode, struct thread *td) 648{ 649 struct digi_softc *sc; 650 651 sc = dev->si_drv1; 652 if (sc->status != DIGI_STATUS_ENABLED) { 653 DLOG(DIGIDB_OPEN, (sc->dev, "Cannot open a disabled card\n")); 654 return (ENXIO); 655 } 656 sc->opencnt++; 657 return (0); 658} 659 660static int 661digiopen(struct tty *tp, struct cdev *dev) 662{ 663 int error; 664 struct digi_softc *sc; 665 struct digi_p *port; 666 volatile struct board_chan *bc; 667 668 port = tp->t_sc; 669 sc = port->sc; 670 671 if (sc->status != DIGI_STATUS_ENABLED) { 672 DLOG(DIGIDB_OPEN, (sc->dev, "Cannot open a disabled card\n")); 673 return (ENXIO); 674 } 675 bc = port->bc; 676 677 /* 678 * The device isn't open, so there are no conflicts. 679 * Initialize it. Initialization is done twice in many 680 * cases: to preempt sleeping callin opens if we are callout, 681 * and to complete a callin open after DCD rises. 682 */ 683 sc->setwin(sc, 0); 684 685 bc->rout = bc->rin; /* clear input queue */ 686 bc->idata = 1; 687 bc->iempty = 1; 688 bc->ilow = 1; 689 bc->mint = port->cd | port->sc->csigs->ri; 690 bc->tin = bc->tout; 691 if (port->ialtpin) { 692 port->cd = sc->csigs->dsr; 693 port->dsr = sc->csigs->cd; 694 } else { 695 port->cd = sc->csigs->cd; 696 port->dsr = sc->csigs->dsr; 697 } 698 tp->t_wopeners++; /* XXX required ? */ 699 error = digiparam(tp, &tp->t_termios); 700 tp->t_wopeners--; 701 702 return (error); 703} 704 705static int 706digicclose(struct cdev *dev, int flag, int mode, struct thread *td) 707{ 708 struct digi_softc *sc; 709 710 sc = dev->si_drv1; 711 sc->opencnt--; 712 return (0); 713} 714 715static void 716digidtrwakeup(void *chan) 717{ 718 struct digi_p *port = chan; 719 720 port->status &= ~DIGI_DTR_OFF; 721 wakeup(&port->tp->t_dtr_wait); 722 port->tp->t_wopeners--; 723} 724 725static void 726digiclose(struct tty *tp) 727{ 728 volatile struct board_chan *bc; 729 struct digi_p *port; 730 int s; 731 732 port = tp->t_sc; 733 bc = port->bc; 734 735 s = spltty(); 736 port->sc->setwin(port->sc, 0); 737 bc->idata = 0; 738 bc->iempty = 0; 739 bc->ilow = 0; 740 bc->mint = 0; 741 if ((tp->t_cflag & HUPCL) || 742 (!tp->t_actout && !(bc->mstat & port->cd) && 743 !(tp->t_init_in.c_cflag & CLOCAL)) || 744 !(tp->t_state & TS_ISOPEN)) { 745 digimodem(tp, 0, SER_DTR | SER_RTS); 746 if (tp->t_dtr_wait != 0) { 747 /* Schedule a wakeup of any callin devices */ 748 tp->t_wopeners++; 749 timeout(&digidtrwakeup, port, tp->t_dtr_wait); 750 port->status |= DIGI_DTR_OFF; 751 } 752 } 753 tp->t_actout = FALSE; 754 wakeup(&tp->t_actout); 755 wakeup(TSA_CARR_ON(tp)); 756 splx(s); 757} 758 759/* 760 * Load module "digi_<mod>.ko" and look for a symbol called digi_mod_<mod>. 761 * 762 * Populate sc->bios, sc->fep, and sc->link from this data. 763 * 764 * sc->fep.data, sc->bios.data and sc->link.data are malloc()d according 765 * to their respective sizes. 766 * 767 * The module is unloaded when we're done. 768 */ 769static int 770digi_loadmoduledata(struct digi_softc *sc) 771{ 772 struct digi_mod *digi_mod; 773 linker_file_t lf; 774 char *modfile, *sym; 775 caddr_t symptr; 776 int modlen, res; 777 778 KASSERT(sc->bios.data == NULL, ("Uninitialised BIOS variable")); 779 KASSERT(sc->fep.data == NULL, ("Uninitialised FEP variable")); 780 KASSERT(sc->link.data == NULL, ("Uninitialised LINK variable")); 781 KASSERT(sc->module != NULL, ("Uninitialised module name")); 782 783 modlen = strlen(sc->module); 784 modfile = malloc(modlen + 6, M_TEMP, M_WAITOK); 785 snprintf(modfile, modlen + 6, "digi_%s", sc->module); 786 if ((res = linker_reference_module(modfile, NULL, &lf)) != 0) 787 printf("%s: Failed %d to autoload module\n", modfile, res); 788 free(modfile, M_TEMP); 789 if (res != 0) 790 return (res); 791 792 sym = malloc(modlen + 10, M_TEMP, M_WAITOK); 793 snprintf(sym, modlen + 10, "digi_mod_%s", sc->module); 794 symptr = linker_file_lookup_symbol(lf, sym, 0); 795 free(sym, M_TEMP); 796 if (symptr == NULL) { 797 printf("digi_%s.ko: Symbol `%s' not found\n", sc->module, sym); 798 linker_release_module(NULL, NULL, lf); 799 return (EINVAL); 800 } 801 802 digi_mod = (struct digi_mod *)symptr; 803 if (digi_mod->dm_version != DIGI_MOD_VERSION) { 804 printf("digi_%s.ko: Invalid version %d (need %d)\n", 805 sc->module, digi_mod->dm_version, DIGI_MOD_VERSION); 806 linker_release_module(NULL, NULL, lf); 807 return (EINVAL); 808 } 809 810 sc->bios.size = digi_mod->dm_bios.size; 811 if (sc->bios.size != 0 && digi_mod->dm_bios.data != NULL) { 812 sc->bios.data = malloc(sc->bios.size, M_TTYS, M_WAITOK); 813 bcopy(digi_mod->dm_bios.data, sc->bios.data, sc->bios.size); 814 } 815 816 sc->fep.size = digi_mod->dm_fep.size; 817 if (sc->fep.size != 0 && digi_mod->dm_fep.data != NULL) { 818 sc->fep.data = malloc(sc->fep.size, M_TTYS, M_WAITOK); 819 bcopy(digi_mod->dm_fep.data, sc->fep.data, sc->fep.size); 820 } 821 822 sc->link.size = digi_mod->dm_link.size; 823 if (sc->link.size != 0 && digi_mod->dm_link.data != NULL) { 824 sc->link.data = malloc(sc->link.size, M_TTYS, M_WAITOK); 825 bcopy(digi_mod->dm_link.data, sc->link.data, sc->link.size); 826 } 827 828 linker_release_module(NULL, NULL, lf); 829 830 return (0); 831} 832 833static int 834digisioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 835{ 836 struct digi_p *port; 837 struct digi_softc *sc; 838 839 port = dev->si_drv1; 840 sc = port->sc; 841 842 switch (cmd) { 843 case DIGIIO_GETALTPIN: 844 if (ISINIT(dev)) 845 *(int *)data = port->ialtpin; 846 else if (ISLOCK(dev)) 847 *(int *)data = port->laltpin; 848 else 849 return (ENOTTY); 850 break; 851 case DIGIIO_SETALTPIN: 852 if (ISINIT(dev)) { 853 if (!port->laltpin) { 854 port->ialtpin = !!*(int *)data; 855 DLOG(DIGIDB_SET, (sc->dev, 856 "port%d: initial ALTPIN %s\n", port->pnum, 857 port->ialtpin ? "set" : "cleared")); 858 } 859 } else if (ISLOCK(dev)) { 860 port->laltpin = !!*(int *)data; 861 DLOG(DIGIDB_SET, (sc->dev, 862 "port%d: ALTPIN %slocked\n", 863 port->pnum, port->laltpin ? "" : "un")); 864 } else 865 return (ENOTTY); 866 break; 867 default: 868 return (ENOTTY); 869 } 870 return (0); 871} 872 873static int 874digicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 875{ 876 int error; 877 struct digi_softc *sc; 878 879 sc = dev->si_drv1; 880 881 if (sc->status == DIGI_STATUS_DISABLED) 882 return (ENXIO); 883 884 switch (cmd) { 885 case DIGIIO_DEBUG: 886#ifdef DEBUG 887 digi_debug = *(int *)data; 888 return (0); 889#else 890 device_printf(sc->dev, "DEBUG not defined\n"); 891 return (ENXIO); 892#endif 893 case DIGIIO_REINIT: 894 digi_loadmoduledata(sc); 895 error = digi_init(sc); 896 digi_freemoduledata(sc); 897 return (error); 898 899 case DIGIIO_MODEL: 900 *(enum digi_model *)data = sc->model; 901 return (0); 902 903 case DIGIIO_IDENT: 904 return (copyout(sc->name, *(char **)data, 905 strlen(sc->name) + 1)); 906 default: 907 return (ENOIOCTL); 908 } 909} 910 911static int 912digiioctl(struct tty *tp, u_long cmd, void *data, int flag, struct thread *td) 913{ 914 struct digi_softc *sc; 915 struct digi_p *port; 916#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 917 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 918 int ival; 919#endif 920 921 port = tp->t_sc; 922 sc = port->sc; 923 if (sc->status == DIGI_STATUS_DISABLED) 924 return (ENXIO); 925 926 if (!(port->status & ENABLED)) 927 return (ENXIO); 928 929 switch (cmd) { 930 case DIGIIO_GETALTPIN: 931 *(int *)data = !!(port->dsr == sc->csigs->cd); 932 return (0); 933 934 case DIGIIO_SETALTPIN: 935 if (!port->laltpin) { 936 if (*(int *)data) { 937 DLOG(DIGIDB_SET, (sc->dev, 938 "port%d: ALTPIN set\n", port->pnum)); 939 port->cd = sc->csigs->dsr; 940 port->dsr = sc->csigs->cd; 941 } else { 942 DLOG(DIGIDB_SET, (sc->dev, 943 "port%d: ALTPIN cleared\n", port->pnum)); 944 port->cd = sc->csigs->cd; 945 port->dsr = sc->csigs->dsr; 946 } 947 } 948 return (0); 949#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 950 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 951 case _IO('e', 'C'): 952 ival = IOCPARM_IVAL(data); 953 data = &ival; 954 /* FALLTHROUGH */ 955#endif 956 case DIGIIO_RING: 957 port->send_ring = (u_char)*(int *)data; 958 break; 959 default: 960 return (ENOTTY); 961 } 962 return (0); 963} 964 965static void 966digibreak(struct tty *tp, int brk) 967{ 968 struct digi_p *port; 969 970 port = tp->t_sc; 971 972 /* 973 * now it sends 400 millisecond break because I don't know 974 * how to send an infinite break 975 */ 976 if (brk) 977 fepcmd_w(port, SENDBREAK, 400, 10); 978} 979 980static int 981digiparam(struct tty *tp, struct termios *t) 982{ 983 struct digi_softc *sc; 984 struct digi_p *port; 985 int cflag; 986 int iflag; 987 int hflow; 988 int s; 989 int window; 990 991 port = tp->t_sc; 992 sc = port->sc; 993 DLOG(DIGIDB_SET, (sc->dev, "port%d: setting parameters\n", port->pnum)); 994 995 if (t->c_ispeed == 0) 996 t->c_ispeed = t->c_ospeed; 997 998 cflag = ttspeedtab(t->c_ospeed, digispeedtab); 999 1000 if (cflag < 0 || (cflag > 0 && t->c_ispeed != t->c_ospeed)) 1001 return (EINVAL); 1002 1003 s = splclock(); 1004 1005 window = sc->window; 1006 sc->setwin(sc, 0); 1007 1008 if (cflag == 0) { /* hangup */ 1009 DLOG(DIGIDB_SET, (sc->dev, "port%d: hangup\n", port->pnum)); 1010 digimodem(port->tp, 0, SER_DTR | SER_RTS); 1011 } else { 1012 digimodem(port->tp, SER_DTR | SER_RTS, 0); 1013 1014 DLOG(DIGIDB_SET, (sc->dev, "port%d: CBAUD = %d\n", port->pnum, 1015 cflag)); 1016 1017#if 0 1018 /* convert flags to sysV-style values */ 1019 if (t->c_cflag & PARODD) 1020 cflag |= 0x0200; 1021 if (t->c_cflag & PARENB) 1022 cflag |= 0x0100; 1023 if (t->c_cflag & CSTOPB) 1024 cflag |= 0x0080; 1025#else 1026 /* convert flags to sysV-style values */ 1027 if (t->c_cflag & PARODD) 1028 cflag |= FEP_PARODD; 1029 if (t->c_cflag & PARENB) 1030 cflag |= FEP_PARENB; 1031 if (t->c_cflag & CSTOPB) 1032 cflag |= FEP_CSTOPB; 1033 if (t->c_cflag & CLOCAL) 1034 cflag |= FEP_CLOCAL; 1035#endif 1036 1037 cflag |= (t->c_cflag & CSIZE) >> 4; 1038 DLOG(DIGIDB_SET, (sc->dev, "port%d: CFLAG = 0x%x\n", port->pnum, 1039 cflag)); 1040 fepcmd_w(port, SETCFLAGS, (unsigned)cflag, 0); 1041 } 1042 1043 iflag = 1044 t->c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP); 1045 if (port->c_iflag & IXON) 1046 iflag |= 0x400; 1047 if (port->c_iflag & IXANY) 1048 iflag |= 0x800; 1049 if (port->c_iflag & IXOFF) 1050 iflag |= 0x1000; 1051 1052 DLOG(DIGIDB_SET, (sc->dev, "port%d: set iflag = 0x%x\n", port->pnum, iflag)); 1053 fepcmd_w(port, SETIFLAGS, (unsigned)iflag, 0); 1054 1055 hflow = 0; 1056 if (t->c_cflag & CDTR_IFLOW) 1057 hflow |= sc->csigs->dtr; 1058 if (t->c_cflag & CRTS_IFLOW) 1059 hflow |= sc->csigs->rts; 1060 if (t->c_cflag & CCTS_OFLOW) 1061 hflow |= sc->csigs->cts; 1062 if (t->c_cflag & CDSR_OFLOW) 1063 hflow |= port->dsr; 1064 if (t->c_cflag & CCAR_OFLOW) 1065 hflow |= port->cd; 1066 1067 DLOG(DIGIDB_SET, (sc->dev, "port%d: set hflow = 0x%x\n", port->pnum, hflow)); 1068 fepcmd_w(port, SETHFLOW, 0xff00 | (unsigned)hflow, 0); 1069 1070 DLOG(DIGIDB_SET, (sc->dev, "port%d: set startc(0x%x), stopc(0x%x)\n", 1071 port->pnum, t->c_cc[VSTART], t->c_cc[VSTOP])); 1072 fepcmd_b(port, SONOFFC, t->c_cc[VSTART], t->c_cc[VSTOP], 0); 1073 1074 if (sc->window != 0) 1075 sc->towin(sc, 0); 1076 if (window != 0) 1077 sc->towin(sc, window); 1078 splx(s); 1079 1080 return (0); 1081} 1082 1083static void 1084digi_intr(void *vp) 1085{ 1086 struct digi_p *port; 1087 char *cxcon; 1088 struct digi_softc *sc; 1089 int ehead, etail; 1090 volatile struct board_chan *bc; 1091 struct tty *tp; 1092 int head, tail; 1093 int wrapmask; 1094 int size, window; 1095 struct event { 1096 u_char pnum; 1097 u_char event; 1098 u_char mstat; 1099 u_char lstat; 1100 } event; 1101 1102 sc = vp; 1103 1104 if (sc->status != DIGI_STATUS_ENABLED) { 1105 DLOG(DIGIDB_IRQ, (sc->dev, "interrupt on disabled board !\n")); 1106 return; 1107 } 1108 1109#ifdef DIGI_INTERRUPT 1110 microtime(&sc->intr_timestamp); 1111#endif 1112 1113 window = sc->window; 1114 sc->setwin(sc, 0); 1115 1116 if (sc->model >= PCXEM && W(sc->vmem + 0xd00)) { 1117 struct con_bios *con = con_bios_list; 1118 register u_char *ptr; 1119 1120 ptr = sc->vmem + W(sc->vmem + 0xd00); 1121 while (con) { 1122 if (ptr[1] && W(ptr + 2) == W(con->bios + 2)) 1123 /* Not first block -- exact match */ 1124 break; 1125 1126 if (W(ptr + 4) >= W(con->bios + 4) && 1127 W(ptr + 4) <= W(con->bios + 6)) 1128 /* Initial search concetrator BIOS */ 1129 break; 1130 } 1131 1132 if (con == NULL) { 1133 log(LOG_ERR, "digi%d: wanted bios LREV = 0x%04x" 1134 " not found!\n", sc->res.unit, W(ptr + 4)); 1135 W(ptr + 10) = 0; 1136 W(sc->vmem + 0xd00) = 0; 1137 goto eoi; 1138 } 1139 cxcon = con->bios; 1140 W(ptr + 4) = W(cxcon + 4); 1141 W(ptr + 6) = W(cxcon + 6); 1142 if (ptr[1] == 0) 1143 W(ptr + 2) = W(cxcon + 2); 1144 W(ptr + 8) = (ptr[1] << 6) + W(cxcon + 8); 1145 size = W(cxcon + 10) - (ptr[1] << 10); 1146 if (size <= 0) { 1147 W(ptr + 8) = W(cxcon + 8); 1148 W(ptr + 10) = 0; 1149 } else { 1150 if (size > 1024) 1151 size = 1024; 1152 W(ptr + 10) = size; 1153 bcopy(cxcon + (ptr[1] << 10), ptr + 12, size); 1154 } 1155 W(sc->vmem + 0xd00) = 0; 1156 goto eoi; 1157 } 1158 1159 ehead = sc->gdata->ein; 1160 etail = sc->gdata->eout; 1161 if (ehead == etail) { 1162#ifdef DEBUG 1163 sc->intr_count++; 1164 if (sc->intr_count % 6000 == 0) { 1165 DLOG(DIGIDB_IRQ, (sc->dev, 1166 "6000 useless polls %x %x\n", ehead, etail)); 1167 sc->intr_count = 0; 1168 } 1169#endif 1170 goto eoi; 1171 } 1172 while (ehead != etail) { 1173 event = *(volatile struct event *)(sc->memevent + etail); 1174 1175 etail = (etail + 4) & sc->gdata->imax; 1176 1177 if (event.pnum >= sc->numports) { 1178 log(LOG_ERR, "digi%d: port %d: got event" 1179 " on nonexisting port\n", sc->res.unit, 1180 event.pnum); 1181 continue; 1182 } 1183 port = &sc->ports[event.pnum]; 1184 bc = port->bc; 1185 tp = port->tp; 1186 1187 if (!(tp->t_state & TS_ISOPEN) && !tp->t_wopeners) { 1188 DLOG(DIGIDB_IRQ, (sc->dev, 1189 "port %d: event 0x%x on closed port\n", 1190 event.pnum, event.event)); 1191 bc->rout = bc->rin; 1192 bc->idata = 0; 1193 bc->iempty = 0; 1194 bc->ilow = 0; 1195 bc->mint = 0; 1196 continue; 1197 } 1198 if (event.event & ~ALL_IND) 1199 log(LOG_ERR, "digi%d: port%d: ? event 0x%x mstat 0x%x" 1200 " lstat 0x%x\n", sc->res.unit, event.pnum, 1201 event.event, event.mstat, event.lstat); 1202 1203 if (event.event & DATA_IND) { 1204 DLOG(DIGIDB_IRQ, (sc->dev, "port %d: DATA_IND\n", 1205 event.pnum)); 1206 wrapmask = port->rxbufsize - 1; 1207 head = bc->rin; 1208 tail = bc->rout; 1209 1210 size = 0; 1211 if (!(tp->t_state & TS_ISOPEN)) { 1212 bc->rout = head; 1213 goto end_of_data; 1214 } 1215 while (head != tail) { 1216 int top; 1217 1218 DLOG(DIGIDB_INT, (sc->dev, 1219 "port %d: p rx head = %d tail = %d\n", 1220 event.pnum, head, tail)); 1221 top = (head > tail) ? head : wrapmask + 1; 1222 sc->towin(sc, port->rxwin); 1223 size = top - tail; 1224 if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 1225 size = b_to_q((char *)port->rxbuf + 1226 tail, size, &tp->t_rawq); 1227 tail = top - size; 1228 ttwakeup(tp); 1229 } else for (; tail < top;) { 1230 ttyld_rint(tp, port->rxbuf[tail]); 1231 sc->towin(sc, port->rxwin); 1232 size--; 1233 tail++; 1234 if (tp->t_state & TS_TBLOCK) 1235 break; 1236 } 1237 tail &= wrapmask; 1238 sc->setwin(sc, 0); 1239 bc->rout = tail; 1240 head = bc->rin; 1241 if (size) 1242 break; 1243 } 1244 1245 if (bc->orun) { 1246 CE_RECORD(port, CE_OVERRUN); 1247 log(LOG_ERR, "digi%d: port%d: %s\n", 1248 sc->res.unit, event.pnum, 1249 digi_errortxt(CE_OVERRUN)); 1250 bc->orun = 0; 1251 } 1252end_of_data: 1253 if (size) { 1254 tp->t_state |= TS_TBLOCK; 1255 port->status |= PAUSE_RX; 1256 DLOG(DIGIDB_RX, (sc->dev, "port %d: pause RX\n", 1257 event.pnum)); 1258 } else { 1259 bc->idata = 1; 1260 } 1261 } 1262 1263 if (event.event & MODEMCHG_IND) { 1264 DLOG(DIGIDB_MODEM, (sc->dev, "port %d: MODEMCHG_IND\n", 1265 event.pnum)); 1266 1267 if ((event.mstat ^ event.lstat) & port->cd) { 1268 sc->hidewin(sc); 1269 ttyld_modem(tp, event.mstat & port->cd); 1270 sc->setwin(sc, 0); 1271 wakeup(TSA_CARR_ON(tp)); 1272 } 1273 1274 if (event.mstat & sc->csigs->ri) { 1275 DLOG(DIGIDB_RI, (sc->dev, "port %d: RING\n", 1276 event.pnum)); 1277 if (port->send_ring) { 1278 ttyld_rint(tp, 'R'); 1279 ttyld_rint(tp, 'I'); 1280 ttyld_rint(tp, 'N'); 1281 ttyld_rint(tp, 'G'); 1282 ttyld_rint(tp, '\r'); 1283 ttyld_rint(tp, '\n'); 1284 } 1285 } 1286 } 1287 if (event.event & BREAK_IND) { 1288 DLOG(DIGIDB_MODEM, (sc->dev, "port %d: BREAK_IND\n", 1289 event.pnum)); 1290 ttyld_rint(tp, TTY_BI); 1291 } 1292 if (event.event & (LOWTX_IND | EMPTYTX_IND)) { 1293 DLOG(DIGIDB_IRQ, (sc->dev, "port %d:%s%s\n", 1294 event.pnum, 1295 event.event & LOWTX_IND ? " LOWTX" : "", 1296 event.event & EMPTYTX_IND ? " EMPTYTX" : "")); 1297 ttyld_start(tp); 1298 } 1299 } 1300 sc->gdata->eout = etail; 1301eoi: 1302 if (sc->window != 0) 1303 sc->towin(sc, 0); 1304 if (window != 0) 1305 sc->towin(sc, window); 1306} 1307 1308static void 1309digistart(struct tty *tp) 1310{ 1311 struct digi_p *port; 1312 struct digi_softc *sc; 1313 volatile struct board_chan *bc; 1314 int head, tail; 1315 int size, ocount, totcnt = 0; 1316 int s; 1317 int wmask; 1318 1319 port = tp->t_sc; 1320 sc = port->sc; 1321 bc = port->bc; 1322 1323 wmask = port->txbufsize - 1; 1324 1325 s = spltty(); 1326 port->lcc = tp->t_outq.c_cc; 1327 sc->setwin(sc, 0); 1328 if (!(tp->t_state & TS_TBLOCK)) { 1329 if (port->status & PAUSE_RX) { 1330 DLOG(DIGIDB_RX, (sc->dev, "port %d: resume RX\n", 1331 port->pnum)); 1332 /* 1333 * CAREFUL - braces are needed here if the DLOG is 1334 * optimised out! 1335 */ 1336 } 1337 port->status &= ~PAUSE_RX; 1338 bc->idata = 1; 1339 } 1340 if (!(tp->t_state & TS_TTSTOP) && port->status & PAUSE_TX) { 1341 DLOG(DIGIDB_TX, (sc->dev, "port %d: resume TX\n", port->pnum)); 1342 port->status &= ~PAUSE_TX; 1343 fepcmd_w(port, RESUMETX, 0, 10); 1344 } 1345 if (tp->t_outq.c_cc == 0) 1346 tp->t_state &= ~TS_BUSY; 1347 else 1348 tp->t_state |= TS_BUSY; 1349 1350 head = bc->tin; 1351 while (tp->t_outq.c_cc != 0) { 1352 tail = bc->tout; 1353 DLOG(DIGIDB_INT, (sc->dev, "port%d: s tx head = %d tail = %d\n", 1354 port->pnum, head, tail)); 1355 1356 if (head < tail) 1357 size = tail - head - 1; 1358 else { 1359 size = port->txbufsize - head; 1360 if (tail == 0) 1361 size--; 1362 } 1363 1364 if (size == 0) 1365 break; 1366 sc->towin(sc, port->txwin); 1367 ocount = q_to_b(&tp->t_outq, port->txbuf + head, size); 1368 totcnt += ocount; 1369 head += ocount; 1370 head &= wmask; 1371 sc->setwin(sc, 0); 1372 bc->tin = head; 1373 bc->iempty = 1; 1374 bc->ilow = 1; 1375 } 1376 port->lostcc = tp->t_outq.c_cc; 1377 tail = bc->tout; 1378 if (head < tail) 1379 size = port->txbufsize - tail + head; 1380 else 1381 size = head - tail; 1382 1383 port->lbuf = size; 1384 DLOG(DIGIDB_INT, (sc->dev, "port%d: s total cnt = %d\n", port->pnum, totcnt)); 1385 ttwwakeup(tp); 1386 splx(s); 1387} 1388 1389static void 1390digistop(struct tty *tp, int rw) 1391{ 1392 struct digi_softc *sc; 1393 struct digi_p *port; 1394 1395 port = tp->t_sc; 1396 sc = port->sc; 1397 1398 DLOG(DIGIDB_TX, (sc->dev, "port %d: pause TX\n", port->pnum)); 1399 port->status |= PAUSE_TX; 1400 fepcmd_w(port, PAUSETX, 0, 10); 1401} 1402 1403static void 1404fepcmd(struct digi_p *port, int cmd, int op1, int ncmds) 1405{ 1406 u_char *mem; 1407 unsigned tail, head; 1408 int count, n; 1409 1410 mem = port->sc->memcmd; 1411 1412 port->sc->setwin(port->sc, 0); 1413 1414 head = port->sc->gdata->cin; 1415 mem[head + 0] = cmd; 1416 mem[head + 1] = port->pnum; 1417 *(u_short *)(mem + head + 2) = op1; 1418 1419 head = (head + 4) & port->sc->gdata->cmax; 1420 port->sc->gdata->cin = head; 1421 1422 for (count = FEPTIMEOUT; count > 0; count--) { 1423 head = port->sc->gdata->cin; 1424 tail = port->sc->gdata->cout; 1425 n = (head - tail) & port->sc->gdata->cmax; 1426 1427 if (n <= ncmds * sizeof(short) * 4) 1428 break; 1429 } 1430 if (count == 0) 1431 log(LOG_ERR, "digi%d: port%d: timeout on FEP command\n", 1432 port->sc->res.unit, port->pnum); 1433} 1434 1435const char * 1436digi_errortxt(int id) 1437{ 1438 static const char *error_desc[] = { 1439 "silo overflow", 1440 "interrupt-level buffer overflow", 1441 "tty-level buffer overflow", 1442 }; 1443 1444 KASSERT(id >= 0 && id < sizeof(error_desc) / sizeof(error_desc[0]), 1445 ("Unexpected digi error id %d\n", id)); 1446 1447 return (error_desc[id]); 1448} 1449 1450int 1451digi_attach(struct digi_softc *sc) 1452{ 1453 sc->res.ctldev = make_dev(&digi_csw, 1454 sc->res.unit << 16, UID_ROOT, GID_WHEEL, 1455 0600, "digi%r.ctl", sc->res.unit); 1456 sc->res.ctldev->si_drv1 = sc; 1457 1458 digi_loadmoduledata(sc); 1459 digi_init(sc); 1460 digi_freemoduledata(sc); 1461 1462 return (0); 1463} 1464 1465static int 1466digi_inuse(struct digi_softc *sc) 1467{ 1468 int i; 1469 struct digi_p *port; 1470 1471 port = &sc->ports[0]; 1472 for (i = 0; i < sc->numports; i++, port++) 1473 if (port->tp->t_state & TS_ISOPEN) { 1474 DLOG(DIGIDB_INIT, (sc->dev, "port%d: busy\n", i)); 1475 return (1); 1476 } else if (port->tp->t_wopeners || port->opencnt) { 1477 DLOG(DIGIDB_INIT, (sc->dev, "port%d: blocked in open\n", 1478 i)); 1479 return (1); 1480 } 1481 return (0); 1482} 1483 1484static void 1485digi_free_state(struct digi_softc *sc) 1486{ 1487 int i; 1488 1489 /* Blow it all away */ 1490 1491 for (i = 0; i < sc->numports; i++) 1492 ttygone(sc->ports[i].tp); 1493 1494 /* XXX: this might be better done as a ttypurge method */ 1495 untimeout(digi_poll, sc, sc->callout); 1496 callout_handle_init(&sc->callout); 1497 untimeout(digi_int_test, sc, sc->inttest); 1498 callout_handle_init(&sc->inttest); 1499 1500 for (i = 0; i < sc->numports; i++) 1501 ttyfree(sc->ports[i].tp); 1502 1503 bus_teardown_intr(sc->dev, sc->res.irq, sc->res.irqHandler); 1504#ifdef DIGI_INTERRUPT 1505 if (sc->res.irq != NULL) { 1506 bus_release_resource(dev, SYS_RES_IRQ, sc->res.irqrid, 1507 sc->res.irq); 1508 sc->res.irq = NULL; 1509 } 1510#endif 1511 if (sc->numports) { 1512 KASSERT(sc->ports, ("digi%d: Lost my ports ?", sc->res.unit)); 1513 free(sc->ports, M_TTYS); 1514 sc->ports = NULL; 1515 sc->numports = 0; 1516 } 1517 1518 sc->status = DIGI_STATUS_NOTINIT; 1519} 1520 1521int 1522digi_detach(device_t dev) 1523{ 1524 struct digi_softc *sc = device_get_softc(dev); 1525 1526 DLOG(DIGIDB_INIT, (sc->dev, "detaching\n")); 1527 1528 /* If we're INIT'd, numports must be 0 */ 1529 KASSERT(sc->numports == 0 || sc->status != DIGI_STATUS_NOTINIT, 1530 ("digi%d: numports(%d) & status(%d) are out of sync", 1531 sc->res.unit, sc->numports, (int)sc->status)); 1532 1533 if (digi_inuse(sc)) 1534 return (EBUSY); 1535 1536 digi_free_state(sc); 1537 1538 destroy_dev(sc->res.ctldev); 1539 1540 if (sc->res.mem != NULL) { 1541 bus_release_resource(dev, SYS_RES_MEMORY, sc->res.mrid, 1542 sc->res.mem); 1543 sc->res.mem = NULL; 1544 } 1545 if (sc->res.io != NULL) { 1546 bus_release_resource(dev, SYS_RES_IOPORT, sc->res.iorid, 1547 sc->res.io); 1548 sc->res.io = NULL; 1549 } 1550 1551 return (0); 1552} 1553 1554int 1555digi_shutdown(device_t dev) 1556{ 1557 return (0); 1558} 1559 1560MODULE_VERSION(digi, 1); 1561