digi.c revision 78414
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: head/sys/dev/digi/digi.c 78414 2001-06-18 15:10:20Z brian $ 30 */ 31 32/*- 33 * TODO: 34 * Allow altpin setups again 35 * Figure out what the con bios stuff is supposed to do 36 * Test with *LOTS* more cards - I only have a PCI8r and an ISA Xem. 37 */ 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/proc.h> 42#include <sys/conf.h> 43#include <sys/linker.h> 44#include <sys/kernel.h> 45#include <sys/mbuf.h> 46#include <sys/malloc.h> 47#include <sys/tty.h> 48#include <sys/syslog.h> 49#include <sys/fcntl.h> 50#include <sys/bus.h> 51#include <sys/bus.h> 52#include <machine/resource.h> 53 54#include <sys/digiio.h> 55#include <dev/digi/digireg.h> 56#include <dev/digi/digi.h> 57#include <dev/digi/digi_mod.h> 58#include <dev/digi/digi_pci.h> 59 60#define CDEV_MAJOR 162 61 62#define CTRL_DEV 0x800000 63#define CALLOUT_MASK 0x400000 64#define CONTROL_INIT_STATE 0x100000 65#define CONTROL_LOCK_STATE 0x200000 66#define CONTROL_MASK (CTRL_DEV|CONTROL_INIT_STATE|CONTROL_LOCK_STATE) 67#define UNIT_MASK 0x030000 68#define PORT_MASK 0x0000FF 69#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev))) 70#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK) 71#define MINOR_TO_UNIT(mynor) (((mynor) & UNIT_MASK)>>16) 72#define MINOR_TO_PORT(mynor) ((mynor) & PORT_MASK) 73 74static d_open_t digiopen; 75static d_close_t digiclose; 76static d_read_t digiread; 77static d_write_t digiwrite; 78static d_ioctl_t digiioctl; 79 80static void digistop(struct tty *tp, int rw); 81static int digimctl(struct digi_p *port, int bits, int how); 82static void digi_poll(void *ptr); 83static void digi_freemoduledata(struct digi_softc *); 84static void fepcmd(struct digi_p *port, int cmd, int op, int ncmds); 85static void digistart(struct tty *tp); 86static int digiparam(struct tty *tp, struct termios *t); 87static void digihardclose(struct digi_p *port); 88static void digi_intr(void *); 89static int digi_init(struct digi_softc *_sc); 90static int digi_loadmoduledata(struct digi_softc *); 91static int digi_inuse(struct digi_softc *); 92static void digi_free_state(struct digi_softc *); 93 94#define fepcmd_b(port, cmd, op1, op2, ncmds) \ 95 fepcmd(port, cmd, (op2 << 8) | op1, ncmds) 96#define fepcmd_w fepcmd 97 98 99static speed_t digidefaultrate = TTYDEF_SPEED; 100 101struct con_bios { 102 struct con_bios *next; 103 u_char *bios; 104 size_t size; 105}; 106 107struct con_bios *con_bios_list; 108devclass_t digi_devclass; 109static char driver_name[] = "digi"; 110unsigned digi_debug = 0; 111 112static struct speedtab digispeedtab[] = { 113 { 0, 0}, /* old (sysV-like) Bx codes */ 114 { 50, 1}, 115 { 75, 2}, 116 { 110, 3}, 117 { 134, 4}, 118 { 150, 5}, 119 { 200, 6}, 120 { 300, 7}, 121 { 600, 8}, 122 { 1200, 9}, 123 { 1800, 10}, 124 { 2400, 11}, 125 { 4800, 12}, 126 { 9600, 13}, 127 { 19200, 14}, 128 { 38400, 15}, 129 { 57600, (02000 | 1)}, 130 { 76800, (02000 | 2)}, 131 { 115200, (02000 | 3)}, 132 { 230400, (02000 | 6)}, 133 { -1, -1} 134}; 135 136const struct digi_control_signals digi_xixe_signals = { 137 0x02, 0x08, 0x10, 0x20, 0x40, 0x80 138}; 139 140const struct digi_control_signals digi_normal_signals = { 141 0x02, 0x80, 0x20, 0x10, 0x40, 0x01 142}; 143 144static struct cdevsw digi_sw = { 145 digiopen, /* open */ 146 digiclose, /* close */ 147 digiread, /* read */ 148 digiwrite, /* write */ 149 digiioctl, /* ioctl */ 150 ttypoll, /* poll */ 151 nommap, /* mmap */ 152 nostrategy, /* strategy */ 153 driver_name, /* name */ 154 CDEV_MAJOR, /* maj */ 155 nodump, /* dump */ 156 nopsize, /* psize */ 157 D_TTY | D_KQFILTER, /* flags */ 158 ttykqfilter /* bmaj */ 159}; 160 161int 162digi_modhandler(module_t mod, int event, void *arg) 163{ 164 static int ref = 0; 165 166 switch (event) { 167 case MOD_LOAD: 168 if (ref++ == 0) 169 cdevsw_add(&digi_sw); 170 break; 171 172 case MOD_UNLOAD: 173 if (--ref == 0) 174 cdevsw_remove(&digi_sw); 175 break; 176 } 177 178 return (0); 179} 180 181static void 182digi_poll(void *ptr) 183{ 184 struct digi_softc *sc; 185 186 sc = (struct digi_softc *)ptr; 187 callout_handle_init(&sc->callout); 188 digi_intr(sc); 189 sc->callout = timeout(digi_poll, sc, (hz >= 200) ? hz / 100 : 1); 190} 191 192static void 193digi_int_test(void *v) 194{ 195 struct digi_softc *sc = v; 196 197 callout_handle_init(&sc->inttest); 198#ifdef DIGI_INTERRUPT 199 if (sc->intr_timestamp.tv_sec || sc->intr_timestamp.tv_usec) { 200 /* interrupt OK! */ 201 return; 202 } 203 log(LOG_ERR, "digi%d: Interrupt didn't work, use polled mode\n", unit); 204#endif 205 sc->callout = timeout(digi_poll, sc, (hz >= 200) ? hz / 100 : 1); 206} 207 208static void 209digi_freemoduledata(struct digi_softc *sc) 210{ 211 if (sc->fep.data != NULL) { 212 free(sc->fep.data, M_TTYS); 213 sc->fep.data = NULL; 214 } 215 if (sc->link.data != NULL) { 216 free(sc->link.data, M_TTYS); 217 sc->link.data = NULL; 218 } 219 if (sc->bios.data != NULL) { 220 free(sc->bios.data, M_TTYS); 221 sc->bios.data = NULL; 222 } 223} 224 225static int 226digi_bcopy(const void *vfrom, void *vto, size_t sz) 227{ 228 volatile const char *from = (volatile const char *)vfrom; 229 volatile char *to = (volatile char *)vto; 230 size_t i; 231 232 for (i = 0; i < sz; i++) 233 *to++ = *from++; 234 235 from = (const volatile char *)vfrom; 236 to = (volatile char *)vto; 237 for (i = 0; i < sz; i++) 238 if (*to++ != *from++) 239 return (0); 240 return (1); 241} 242 243static int 244digi_init(struct digi_softc *sc) 245{ 246 int i, cnt, resp; 247 u_char *ptr; 248 int lowwater; 249 struct digi_p *port; 250 volatile struct board_chan *bc; 251 252 ptr = NULL; 253 254 if (sc->status == DIGI_STATUS_DISABLED) { 255 log(LOG_ERR, "digi%d: Cannot init a disabled card\n", 256 sc->res.unit); 257 return (EIO); 258 } 259 if (sc->bios.data == NULL) { 260 log(LOG_ERR, "digi%d: Cannot init without BIOS\n", 261 sc->res.unit); 262 return (EIO); 263 } 264#if 0 265 if (sc->link.data == NULL && sc->model >= PCCX) { 266 log(LOG_ERR, "digi%d: Cannot init without link info\n", 267 sc->res.unit); 268 return (EIO); 269 } 270#endif 271 if (sc->fep.data == NULL) { 272 log(LOG_ERR, "digi%d: Cannot init without fep code\n", 273 sc->res.unit); 274 return (EIO); 275 } 276 sc->status = DIGI_STATUS_NOTINIT; 277 278 if (sc->numports) { 279 /* 280 * We're re-initialising - maybe because someone's attached 281 * another port module. For now, we just re-initialise 282 * everything. 283 */ 284 if (digi_inuse(sc)) 285 return (EBUSY); 286 287 digi_free_state(sc); 288 } 289 290 ptr = sc->setwin(sc, MISCGLOBAL); 291 for (i = 0; i < 16; i += 2) 292 vW(ptr + i) = 0; 293 294 switch (sc->model) { 295 case PCXEVE: 296 outb(sc->wport, 0xff); /* window 7 */ 297 ptr = sc->vmem + (BIOSCODE & 0x1fff); 298 299 if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) { 300 device_printf(sc->dev, "BIOS upload failed\n"); 301 return (EIO); 302 } 303 304 outb(sc->port, FEPCLR); 305 break; 306 307 case PCXE: 308 case PCXI: 309 case PCCX: 310 ptr = sc->setwin(sc, BIOSCODE + ((0xf000 - sc->mem_seg) << 4)); 311 if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) { 312 device_printf(sc->dev, "BIOS upload failed\n"); 313 return (EIO); 314 } 315 break; 316 317 case PCXEM: 318 case PCIEPCX: 319 case PCIXR: 320 if (sc->model == PCIXR) 321 PCIPORT = FEPRST; 322 else 323 outb(sc->port, FEPRST | FEPMEM); 324 325 for (i = 0; ((sc->model == PCIXR ? PCIPORT : inb(sc->port)) & 326 FEPMASK) != FEPRST; i++) { 327 if (i > 1000) { 328 log(LOG_ERR, "digi%d: init reset failed\n", 329 sc->res.unit); 330 return (EIO); 331 } 332 tsleep(sc, PUSER | PCATCH, "digiinit0", 1); 333 } 334 DLOG(DIGIDB_INIT, (sc->dev, "Got init reset after %d us\n", i)); 335 336 /* Now upload the BIOS */ 337 cnt = (sc->bios.size < sc->win_size - BIOSOFFSET) ? 338 sc->bios.size : sc->win_size - BIOSOFFSET; 339 340 ptr = sc->setwin(sc, BIOSOFFSET); 341 if (!digi_bcopy(sc->bios.data, ptr, cnt)) { 342 device_printf(sc->dev, "BIOS upload (1) failed\n"); 343 return (EIO); 344 } 345 346 if (cnt != sc->bios.size) { 347 /* and the second part */ 348 ptr = sc->setwin(sc, sc->win_size); 349 if (!digi_bcopy(sc->bios.data + cnt, ptr, 350 sc->bios.size - cnt)) { 351 device_printf(sc->dev, "BIOS upload failed\n"); 352 return (EIO); 353 } 354 } 355 356 ptr = sc->setwin(sc, 0); 357 vW(ptr + 0) = 0x0401; 358 vW(ptr + 2) = 0x0bf0; 359 vW(ptr + 4) = 0x0000; 360 vW(ptr + 6) = 0x0000; 361 362 break; 363 } 364 365 DLOG(DIGIDB_INIT, (sc->dev, "BIOS uploaded\n")); 366 367 ptr = sc->setwin(sc, MISCGLOBAL); 368 W(ptr) = 0; 369 370 if (sc->model == PCIXR) { 371 PCIPORT = FEPCLR; 372 resp = FEPRST; 373 } else if (sc->model == PCXEVE) { 374 outb(sc->port, FEPCLR); 375 resp = FEPRST; 376 } else { 377 outb(sc->port, FEPCLR | FEPMEM); 378 resp = FEPRST | FEPMEM; 379 } 380 381 for (i = 0; ((sc->model == PCIXR ? PCIPORT : inb(sc->port)) & FEPMASK) 382 == resp; i++) { 383 if (i > 1000) { 384 log(LOG_ERR, "digi%d: BIOS start failed\n", 385 sc->res.unit); 386 return (EIO); 387 } 388 tsleep(sc, PUSER | PCATCH, "digibios0", 1); 389 } 390 391 DLOG(DIGIDB_INIT, (sc->dev, "BIOS started after %d us\n", i)); 392 393 for (i = 0; vW(ptr) != *(u_short *)"GD"; i++) { 394 if (i > 2000) { 395 log(LOG_ERR, "digi%d: BIOS boot failed " 396 "(0x%02x != 0x%02x)\n", 397 sc->res.unit, vW(ptr), *(u_short *)"GD"); 398 return (EIO); 399 } 400 tsleep(sc, PUSER | PCATCH, "digibios1", 1); 401 } 402 403 DLOG(DIGIDB_INIT, (sc->dev, "BIOS booted after %d iterations\n", i)); 404 405 if (sc->link.data != NULL) { 406 DLOG(DIGIDB_INIT, (sc->dev, "Loading link data\n")); 407 ptr = sc->setwin(sc, 0xcd0); 408 digi_bcopy(sc->link.data, ptr, 21); /* XXX 21 ? */ 409 } 410 411 /* load FEP/OS */ 412 413 switch (sc->model) { 414 case PCXE: 415 case PCXEVE: 416 case PCXI: 417 ptr = sc->setwin(sc, sc->model == PCXI ? 0x2000 : 0x0); 418 digi_bcopy(sc->fep.data, ptr, sc->fep.size); 419 420 /* A BIOS request to move our data to 0x2000 */ 421 ptr = sc->setwin(sc, MBOX); 422 vW(ptr + 0) = 2; 423 vW(ptr + 2) = sc->mem_seg + FEPCODESEG; 424 vW(ptr + 4) = 0; 425 vW(ptr + 6) = FEPCODESEG; 426 vW(ptr + 8) = 0; 427 vW(ptr + 10) = sc->fep.size; 428 429 /* Run the BIOS request */ 430 outb(sc->port, FEPREQ | FEPMEM); 431 outb(sc->port, FEPCLR | FEPMEM); 432 433 for (i = 0; W(ptr); i++) { 434 if (i > 10) { 435 log(LOG_ERR, "digi%d: FEP/OS move failed\n", 436 sc->res.unit); 437 sc->hidewin(sc); 438 return (EIO); 439 } 440 tsleep(sc, PUSER | PCATCH, "digifep0", 1); 441 } 442 DLOG(DIGIDB_INIT, 443 (sc->dev, "FEP/OS moved after %d iterations\n", i)); 444 445 /* Clear the confirm word */ 446 ptr = sc->setwin(sc, FEPSTAT); 447 vW(ptr + 0) = 0; 448 449 /* A BIOS request to execute the FEP/OS */ 450 ptr = sc->setwin(sc, MBOX); 451 vW(ptr + 0) = 0x01; 452 vW(ptr + 2) = FEPCODESEG; 453 vW(ptr + 4) = 0x04; 454 455 /* Run the BIOS request */ 456 outb(sc->port, FEPREQ); 457 outb(sc->port, FEPCLR); 458 459 ptr = sc->setwin(sc, FEPSTAT); 460 461 break; 462 463 case PCXEM: 464 case PCIEPCX: 465 case PCIXR: 466 DLOG(DIGIDB_INIT, (sc->dev, "Loading FEP/OS\n")); 467 468 cnt = (sc->fep.size < sc->win_size - BIOSOFFSET) ? 469 sc->fep.size : sc->win_size - BIOSOFFSET; 470 471 ptr = sc->setwin(sc, BIOSOFFSET); 472 digi_bcopy(sc->fep.data, ptr, cnt); 473 474 if (cnt != sc->fep.size) { 475 ptr = sc->setwin(sc, BIOSOFFSET + cnt); 476 digi_bcopy(sc->fep.data + cnt, ptr, 477 sc->fep.size - cnt); 478 } 479 480 DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS loaded\n")); 481 482 ptr = sc->setwin(sc, 0xc30); 483 W(ptr + 4) = 0x1004; 484 W(ptr + 6) = 0xbfc0; 485 W(ptr + 0) = 0x03; 486 W(ptr + 2) = 0x00; 487 488 /* Clear the confirm word */ 489 ptr = sc->setwin(sc, FEPSTAT); 490 W(ptr + 0) = 0; 491 492 if (sc->port) 493 outb(sc->port, 0); /* XXX necessary ? */ 494 495 break; 496 497 case PCCX: 498 ptr = sc->setwin(sc, 0xd000); 499 digi_bcopy(sc->fep.data, ptr, sc->fep.size); 500 501 /* A BIOS request to execute the FEP/OS */ 502 ptr = sc->setwin(sc, 0xc40); 503 W(ptr + 0) = 1; 504 W(ptr + 2) = FEPCODE >> 4; 505 W(ptr + 4) = 4; 506 507 /* Clear the confirm word */ 508 ptr = sc->setwin(sc, FEPSTAT); 509 W(ptr + 0) = 0; 510 511 /* Run the BIOS request */ 512 outb(sc->port, FEPREQ | FEPMEM); /* send interrupt to BIOS */ 513 outb(sc->port, FEPCLR | FEPMEM); 514 break; 515 } 516 517 /* Now wait 'till the FEP/OS has booted */ 518 for (i = 0; vW(ptr) != *(u_short *)"OS"; i++) { 519 if (i > 2000) { 520 log(LOG_ERR, "digi%d: FEP/OS start failed " 521 "(0x%02x != 0x%02x)\n", 522 sc->res.unit, vW(ptr), *(u_short *)"OS"); 523 sc->hidewin(sc); 524 return (EIO); 525 } 526 tsleep(sc, PUSER | PCATCH, "digifep1", 1); 527 } 528 529 DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS started after %d iterations\n", i)); 530 531 if (sc->model >= PCXEM) { 532 ptr = sc->setwin(sc, 0xe04); 533 vW(ptr) = 2; 534 ptr = sc->setwin(sc, 0xc02); 535 sc->numports = vW(ptr); 536 } else { 537 ptr = sc->setwin(sc, 0xc22); 538 sc->numports = vW(ptr); 539 } 540 541 if (sc->numports == 0) { 542 device_printf(sc->dev, "%s, 0 ports found\n", sc->name); 543 sc->hidewin(sc); 544 return (0); 545 } 546 547 if (sc->numports > 256) { 548 /* Our minor numbering scheme is broken for more than 256 */ 549 device_printf(sc->dev, "%s, 256 ports (%d ports found)\n", 550 sc->name, sc->numports); 551 sc->numports = 256; 552 } else 553 device_printf(sc->dev, "%s, %d ports found\n", sc->name, 554 sc->numports); 555 556 if (sc->ports) 557 free(sc->ports, M_TTYS); 558 sc->ports = malloc(sizeof(struct digi_p) * sc->numports, 559 M_TTYS, M_WAIT | M_ZERO); 560 561 if (sc->ttys) 562 free(sc->ttys, M_TTYS); 563 sc->ttys = malloc(sizeof(struct tty) * sc->numports, 564 M_TTYS, M_WAIT | M_ZERO); 565 566 /* 567 * XXX Should read port 0xc90 for an array of 2byte values, 1 per 568 * port. If the value is 0, the port is broken.... 569 */ 570 571 ptr = sc->setwin(sc, 0); 572 573 /* We should now init per-port structures */ 574 bc = (volatile struct board_chan *)(ptr + CHANSTRUCT); 575 sc->gdata = (volatile struct global_data *)(ptr + FEP_GLOBAL); 576 577 sc->memcmd = ptr + sc->gdata->cstart; 578 sc->memevent = ptr + sc->gdata->istart; 579 580 for (i = 0; i < sc->numports; i++, bc++) { 581 port = sc->ports + i; 582 port->pnum = i; 583 port->sc = sc; 584 port->status = ENABLED; 585 port->tp = sc->ttys + i; 586 port->bc = bc; 587 588 if (sc->model == PCXEVE) { 589 port->txbuf = ptr + 590 (((bc->tseg - sc->mem_seg) << 4) & 0x1fff); 591 port->rxbuf = ptr + 592 (((bc->rseg - sc->mem_seg) << 4) & 0x1fff); 593 port->txwin = FEPWIN | ((bc->tseg - sc->mem_seg) >> 9); 594 port->rxwin = FEPWIN | ((bc->rseg - sc->mem_seg) >> 9); 595 } else if (sc->model == PCXI || sc->model == PCXE) { 596 port->txbuf = ptr + ((bc->tseg - sc->mem_seg) << 4); 597 port->rxbuf = ptr + ((bc->rseg - sc->mem_seg) << 4); 598 port->txwin = port->rxwin = 0; 599 } else { 600 port->txbuf = ptr + 601 (((bc->tseg - sc->mem_seg) << 4) % sc->win_size); 602 port->rxbuf = ptr + 603 (((bc->rseg - sc->mem_seg) << 4) % sc->win_size); 604 port->txwin = FEPWIN | 605 (((bc->tseg - sc->mem_seg) << 4) / sc->win_size); 606 port->rxwin = FEPWIN | 607 (((bc->rseg - sc->mem_seg) << 4) / sc->win_size); 608 } 609 port->txbufsize = bc->tmax + 1; 610 port->rxbufsize = bc->rmax + 1; 611 612 lowwater = port->txbufsize >> 2; 613 if (lowwater > 1024) 614 lowwater = 1024; 615 sc->setwin(sc, 0); 616 fepcmd_w(port, STXLWATER, lowwater, 10); 617 fepcmd_w(port, SRXLWATER, port->rxbufsize >> 2, 10); 618 fepcmd_w(port, SRXHWATER, (3 * port->rxbufsize) >> 2, 10); 619 620 bc->edelay = 100; 621 port->dtr_wait = 3 * hz; 622 623 /* 624 * We don't use all the flags from <sys/ttydefaults.h> since 625 * they are only relevant for logins. It's important to have 626 * echo off initially so that the line doesn't start blathering 627 * before the echo flag can be turned off. 628 */ 629 port->it_in.c_iflag = 0; 630 port->it_in.c_oflag = 0; 631 port->it_in.c_cflag = TTYDEF_CFLAG; 632 port->it_in.c_lflag = 0; 633 termioschars(&port->it_in); 634 port->it_in.c_ispeed = port->it_in.c_ospeed = digidefaultrate; 635 port->it_out = port->it_in; 636 port->send_ring = 1; /* Default action on signal RI */ 637 638 port->dev[0] = make_dev(&digi_sw, (sc->res.unit << 16) + i, 639 UID_ROOT, GID_WHEEL, 0600, "ttyD%d.%d", sc->res.unit, i); 640 port->dev[1] = make_dev(&digi_sw, ((sc->res.unit << 16) + i) | 641 CONTROL_INIT_STATE, UID_ROOT, GID_WHEEL, 642 0600, "ttyiD%d.%d", sc->res.unit, i); 643 port->dev[2] = make_dev(&digi_sw, ((sc->res.unit << 16) + i) | 644 CONTROL_LOCK_STATE, UID_ROOT, GID_WHEEL, 645 0600, "ttylD%d.%d", sc->res.unit, i); 646 port->dev[3] = make_dev(&digi_sw, ((sc->res.unit << 16) + i) | 647 CALLOUT_MASK, UID_UUCP, GID_DIALER, 648 0660, "cuaD%d.%d", sc->res.unit, i); 649 port->dev[4] = make_dev(&digi_sw, ((sc->res.unit << 16) + i) | 650 CALLOUT_MASK | CONTROL_INIT_STATE, UID_UUCP, GID_DIALER, 651 0660, "cuaiD%d.%d", sc->res.unit, i); 652 port->dev[5] = make_dev(&digi_sw, ((sc->res.unit << 16) + i) | 653 CALLOUT_MASK | CONTROL_LOCK_STATE, UID_UUCP, GID_DIALER, 654 0660, "cualD%d.%d", sc->res.unit, i); 655 } 656 657 sc->hidewin(sc); 658 sc->inttest = timeout(digi_int_test, sc, hz); 659 /* fepcmd_w(&sc->ports[0], 0xff, 0, 0); */ 660 sc->status = DIGI_STATUS_ENABLED; 661 662 return (0); 663} 664 665static int 666digimctl(struct digi_p *port, int bits, int how) 667{ 668 int mstat; 669 670 if (how == DMGET) { 671 port->sc->setwin(port->sc, 0); 672 mstat = port->bc->mstat; 673 port->sc->hidewin(port->sc); 674 bits = TIOCM_LE; 675 if (mstat & port->sc->csigs->rts) 676 bits |= TIOCM_RTS; 677 if (mstat & port->sc->csigs->cd) 678 bits |= TIOCM_CD; 679 if (mstat & port->sc->csigs->dsr) 680 bits |= TIOCM_DSR; 681 if (mstat & port->sc->csigs->cts) 682 bits |= TIOCM_CTS; 683 if (mstat & port->sc->csigs->ri) 684 bits |= TIOCM_RI; 685 if (mstat & port->sc->csigs->dtr) 686 bits |= TIOCM_DTR; 687 return (bits); 688 } 689 690 /* Only DTR and RTS may be set */ 691 mstat = 0; 692 if (bits & TIOCM_DTR) 693 mstat |= port->sc->csigs->dtr; 694 if (bits & TIOCM_RTS) 695 mstat |= port->sc->csigs->rts; 696 697 switch (how) { 698 case DMSET: 699 fepcmd_b(port, SETMODEM, mstat, ~mstat, 0); 700 break; 701 case DMBIS: 702 fepcmd_b(port, SETMODEM, mstat, 0, 0); 703 break; 704 case DMBIC: 705 fepcmd_b(port, SETMODEM, 0, mstat, 0); 706 break; 707 } 708 709 return (0); 710} 711 712static void 713digi_disc_optim(struct tty *tp, struct termios *t, struct digi_p *port) 714{ 715 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP)) && 716 (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) && 717 (!(t->c_iflag & PARMRK) || 718 (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) && 719 !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) && 720 linesw[tp->t_line].l_rint == ttyinput) 721 tp->t_state |= TS_CAN_BYPASS_L_RINT; 722 else 723 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 724} 725 726int 727digiopen(dev_t dev, int flag, int mode, struct proc *p) 728{ 729 struct digi_softc *sc; 730 struct tty *tp; 731 int unit; 732 int pnum; 733 struct digi_p *port; 734 int s; 735 int error, mynor; 736 volatile struct board_chan *bc; 737 738 error = 0; 739 mynor = minor(dev); 740 unit = MINOR_TO_UNIT(minor(dev)); 741 pnum = MINOR_TO_PORT(minor(dev)); 742 743 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 744 if (!sc) 745 return (ENXIO); 746 747 if (sc->status != DIGI_STATUS_ENABLED) { 748 DLOG(DIGIDB_OPEN, (sc->dev, "Cannot open a disabled card\n")); 749 return (ENXIO); 750 } 751 if (pnum >= sc->numports) { 752 DLOG(DIGIDB_OPEN, (sc->dev, "port%d: Doesn't exist\n", pnum)); 753 return (ENXIO); 754 } 755 if (mynor & (CTRL_DEV | CONTROL_MASK)) { 756 sc->opencnt++; 757 return (0); 758 } 759 port = &sc->ports[pnum]; 760 tp = dev->si_tty = port->tp; 761 bc = port->bc; 762 763 s = spltty(); 764 765open_top: 766 while (port->status & DIGI_DTR_OFF) { 767 port->wopeners++; 768 error = tsleep(&port->dtr_wait, TTIPRI | PCATCH, "digidtr", 0); 769 port->wopeners--; 770 if (error) 771 goto out; 772 } 773 774 if (tp->t_state & TS_ISOPEN) { 775 /* 776 * The device is open, so everything has been initialized. 777 * Handle conflicts. 778 */ 779 if (mynor & CALLOUT_MASK) { 780 if (!port->active_out) { 781 error = EBUSY; 782 DLOG(DIGIDB_OPEN, (sc->dev, "port %d:" 783 " BUSY error = %d\n", pnum, error)); 784 goto out; 785 } 786 } else if (port->active_out) { 787 if (flag & O_NONBLOCK) { 788 error = EBUSY; 789 DLOG(DIGIDB_OPEN, (sc->dev, 790 "port %d: BUSY error = %d\n", pnum, error)); 791 goto out; 792 } 793 port->wopeners++; 794 error = tsleep(&port->active_out, TTIPRI | PCATCH, 795 "digibi", 0); 796 port->wopeners--; 797 if (error != 0) { 798 DLOG(DIGIDB_OPEN, (sc->dev, 799 "port %d: tsleep(digibi) error = %d\n", 800 pnum, error)); 801 goto out; 802 } 803 goto open_top; 804 } 805 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 806 error = EBUSY; 807 goto out; 808 } 809 } else { 810 /* 811 * The device isn't open, so there are no conflicts. 812 * Initialize it. Initialization is done twice in many 813 * cases: to preempt sleeping callin opens if we are callout, 814 * and to complete a callin open after DCD rises. 815 */ 816 tp->t_oproc = digistart; 817 tp->t_param = digiparam; 818 tp->t_stop = digistop; 819 tp->t_dev = dev; 820 tp->t_termios = (mynor & CALLOUT_MASK) ? 821 port->it_out : port->it_in; 822 sc->setwin(sc, 0); 823 824 bc->rout = bc->rin; /* clear input queue */ 825 bc->idata = 1; 826 bc->iempty = 1; 827 bc->ilow = 1; 828 bc->mint = port->sc->csigs->cd | port->sc->csigs->ri; 829 bc->tin = bc->tout; 830 port->wopeners++; /* XXX required ? */ 831 error = digiparam(tp, &tp->t_termios); 832 port->wopeners--; 833 834 if (error != 0) { 835 DLOG(DIGIDB_OPEN, (sc->dev, 836 "port %d: cxpparam error = %d\n", pnum, error)); 837 goto out; 838 } 839 ttsetwater(tp); 840 841 /* handle fake and initial DCD for callout devices */ 842 843 if (bc->mstat & port->sc->csigs->cd || mynor & CALLOUT_MASK) 844 linesw[tp->t_line].l_modem(tp, 1); 845 } 846 847 /* Wait for DCD if necessary */ 848 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK) && 849 !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { 850 port->wopeners++; 851 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "digidcd", 0); 852 port->wopeners--; 853 if (error != 0) { 854 DLOG(DIGIDB_OPEN, (sc->dev, 855 "port %d: tsleep(digidcd) error = %d\n", 856 pnum, error)); 857 goto out; 858 } 859 goto open_top; 860 } 861 error = linesw[tp->t_line].l_open(dev, tp); 862 DLOG(DIGIDB_OPEN, (sc->dev, "port %d: l_open error = %d\n", 863 pnum, error)); 864 865 digi_disc_optim(tp, &tp->t_termios, port); 866 867 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK) 868 port->active_out = TRUE; 869 870 if (tp->t_state & TS_ISOPEN) 871 sc->opencnt++; 872out: 873 splx(s); 874 875 if (!(tp->t_state & TS_ISOPEN)) 876 digihardclose(port); 877 878 DLOG(DIGIDB_OPEN, (sc->dev, "port %d: open() returns %d\n", 879 pnum, error)); 880 881 return (error); 882} 883 884int 885digiclose(dev_t dev, int flag, int mode, struct proc *p) 886{ 887 int mynor; 888 struct tty *tp; 889 int unit, pnum; 890 struct digi_softc *sc; 891 struct digi_p *port; 892 int s; 893 894 mynor = minor(dev); 895 unit = MINOR_TO_UNIT(mynor); 896 pnum = MINOR_TO_PORT(mynor); 897 898 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 899 KASSERT(sc, ("digi%d: softc not allocated in digiclose\n", unit)); 900 901 if (mynor & (CTRL_DEV | CONTROL_MASK)) { 902 sc->opencnt--; 903 return (0); 904 } 905 906 port = sc->ports + pnum; 907 tp = port->tp; 908 909 DLOG(DIGIDB_CLOSE, (sc->dev, "port %d: closing\n", pnum)); 910 911 s = spltty(); 912 linesw[tp->t_line].l_close(tp, flag); 913 digi_disc_optim(tp, &tp->t_termios, port); 914 digistop(tp, FREAD | FWRITE); 915 digihardclose(port); 916 ttyclose(tp); 917 if (--sc->opencnt == 0) 918 splx(s); 919 return (0); 920} 921 922static void 923digidtrwakeup(void *chan) 924{ 925 struct digi_p *port = chan; 926 927 port->status &= ~DIGI_DTR_OFF; 928 wakeup(&port->dtr_wait); 929 port->wopeners--; 930} 931 932static void 933digihardclose(struct digi_p *port) 934{ 935 volatile struct board_chan *bc; 936 int s; 937 938 bc = port->bc; 939 940 s = spltty(); 941 port->sc->setwin(port->sc, 0); 942 bc->idata = 0; 943 bc->iempty = 0; 944 bc->ilow = 0; 945 bc->mint = 0; 946 if ((port->tp->t_cflag & HUPCL) || 947 (!port->active_out && !(bc->mstat & port->sc->csigs->cd) && 948 !(port->it_in.c_cflag & CLOCAL)) || 949 !(port->tp->t_state & TS_ISOPEN)) { 950 digimctl(port, TIOCM_DTR | TIOCM_RTS, DMBIC); 951 if (port->dtr_wait != 0) { 952 /* Schedule a wakeup of any callin devices */ 953 port->wopeners++; 954 timeout(&digidtrwakeup, port, port->dtr_wait); 955 port->status |= DIGI_DTR_OFF; 956 } 957 } 958 port->active_out = FALSE; 959 wakeup(&port->active_out); 960 wakeup(TSA_CARR_ON(port->tp)); 961 splx(s); 962} 963 964int 965digiread(dev_t dev, struct uio *uio, int flag) 966{ 967 int mynor; 968 struct tty *tp; 969 int error, unit, pnum; 970 struct digi_softc *sc; 971 972 mynor = minor(dev); 973 if (mynor & CONTROL_MASK) 974 return (ENODEV); 975 976 unit = MINOR_TO_UNIT(mynor); 977 pnum = MINOR_TO_PORT(mynor); 978 979 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 980 KASSERT(sc, ("digi%d: softc not allocated in digiclose\n", unit)); 981 tp = &sc->ttys[pnum]; 982 983 error = linesw[tp->t_line].l_read(tp, uio, flag); 984 DLOG(DIGIDB_READ, (sc->dev, "port %d: read() returns %d\n", 985 pnum, error)); 986 987 return (error); 988} 989 990int 991digiwrite(dev_t dev, struct uio *uio, int flag) 992{ 993 int mynor; 994 struct tty *tp; 995 int error, unit, pnum; 996 struct digi_softc *sc; 997 998 mynor = minor(dev); 999 if (mynor & CONTROL_MASK) 1000 return (ENODEV); 1001 1002 unit = MINOR_TO_UNIT(mynor); 1003 pnum = MINOR_TO_PORT(mynor); 1004 1005 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 1006 KASSERT(sc, ("digi%d: softc not allocated in digiclose\n", unit)); 1007 tp = &sc->ttys[pnum]; 1008 1009 error = linesw[tp->t_line].l_write(tp, uio, flag); 1010 DLOG(DIGIDB_WRITE, (sc->dev, "port %d: write() returns %d\n", 1011 pnum, error)); 1012 1013 return (error); 1014} 1015 1016/* 1017 * Load module "digi_<mod>.ko" and look for a symbol called digi_mod_<mod>. 1018 * 1019 * Populate sc->bios, sc->fep, and sc->link from this data. 1020 * 1021 * sc->fep.data, sc->bios.data and sc->link.data are malloc()d according 1022 * to their respective sizes. 1023 * 1024 * The module is unloaded when we're done. 1025 */ 1026static int 1027digi_loadmoduledata(struct digi_softc *sc) 1028{ 1029 struct digi_mod *digi_mod; 1030 linker_file_t lf; 1031 char *modfile, *sym; 1032 caddr_t symptr; 1033 int modlen, res; 1034 1035 KASSERT(sc->bios.data == NULL, ("Uninitialised BIOS variable")); 1036 KASSERT(sc->fep.data == NULL, ("Uninitialised FEP variable")); 1037 KASSERT(sc->link.data == NULL, ("Uninitialised LINK variable")); 1038 KASSERT(sc->module != NULL, ("Uninitialised module name")); 1039 1040 modlen = strlen(sc->module); 1041 modfile = malloc(modlen + 6, M_TEMP, M_WAITOK); 1042 snprintf(modfile, modlen + 6, "digi_%s", sc->module); 1043 if ((res = linker_reference_module(modfile, &lf)) != 0) 1044 printf("%s: Failed %d to load module\n", modfile, res); 1045 free(modfile, M_TEMP); 1046 if (res != 0) 1047 return (res); 1048 1049 sym = malloc(modlen + 10, M_TEMP, M_WAITOK); 1050 snprintf(sym, modlen + 10, "digi_mod_%s", sc->module); 1051 if ((symptr = linker_file_lookup_symbol(lf, sym, 0)) == NULL) 1052 printf("digi_%s.ko: Symbol `%s' not found\n", sc->module, sym); 1053 free(sym, M_TEMP); 1054 1055 digi_mod = (struct digi_mod *)symptr; 1056 if (digi_mod->dm_version != DIGI_MOD_VERSION) { 1057 printf("digi_%s.ko: Invalid version %d (need %d)\n", 1058 sc->module, digi_mod->dm_version, DIGI_MOD_VERSION); 1059 linker_file_unload(lf); 1060 return (EINVAL); 1061 } 1062 1063 sc->bios.size = digi_mod->dm_bios.size; 1064 if (sc->bios.size != 0 && digi_mod->dm_bios.data != NULL) { 1065 sc->bios.data = malloc(sc->bios.size, M_TTYS, M_WAIT); 1066 bcopy(digi_mod->dm_bios.data, sc->bios.data, sc->bios.size); 1067 } 1068 1069 sc->fep.size = digi_mod->dm_fep.size; 1070 if (sc->fep.size != 0 && digi_mod->dm_fep.data != NULL) { 1071 sc->fep.data = malloc(sc->fep.size, M_TTYS, M_WAIT); 1072 bcopy(digi_mod->dm_fep.data, sc->fep.data, sc->fep.size); 1073 } 1074 1075 sc->link.size = digi_mod->dm_link.size; 1076 if (sc->link.size != 0 && digi_mod->dm_link.data != NULL) { 1077 sc->link.data = malloc(sc->link.size, M_TTYS, M_WAIT); 1078 bcopy(digi_mod->dm_link.data, sc->link.data, sc->link.size); 1079 } 1080 1081 linker_file_unload(lf); 1082 1083 return (0); 1084} 1085 1086static int 1087digiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 1088{ 1089 int unit, pnum, mynor, error, s; 1090 struct digi_softc *sc; 1091 struct digi_p *port; 1092 struct tty *tp; 1093#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1094 int oldcmd; 1095 struct termios term; 1096#endif 1097 1098 mynor = minor(dev); 1099 unit = MINOR_TO_UNIT(mynor); 1100 pnum = MINOR_TO_PORT(mynor); 1101 1102 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 1103 KASSERT(sc, ("digi%d: softc not allocated in digiioctl\n", unit)); 1104 1105 if (sc->status == DIGI_STATUS_DISABLED) 1106 return (ENXIO); 1107 1108 if (mynor & CTRL_DEV) { 1109 switch (cmd) { 1110 case DIGIIO_DEBUG: 1111#ifdef DEBUG 1112 digi_debug = *(int *)data; 1113 return (0); 1114#else 1115 device_printf(sc->dev, "DEBUG not defined\n"); 1116 return (ENXIO); 1117#endif 1118 case DIGIIO_REINIT: 1119 digi_loadmoduledata(sc); 1120 error = digi_init(sc); 1121 digi_freemoduledata(sc); 1122 return (error); 1123 1124 case DIGIIO_MODEL: 1125 *(enum digi_model *)data = sc->model; 1126 return (0); 1127 1128 case DIGIIO_IDENT: 1129 return (copyout(sc->name, *(char **)data, 1130 strlen(sc->name) + 1)); 1131 } 1132 } 1133 1134 if (pnum >= sc->numports) 1135 return (ENXIO); 1136 1137 port = sc->ports + pnum; 1138 if (!(port->status & ENABLED)) 1139 return (ENXIO); 1140 1141 tp = port->tp; 1142 1143 if (mynor & CONTROL_MASK) { 1144 struct termios *ct; 1145 1146 switch (mynor & CONTROL_MASK) { 1147 case CONTROL_INIT_STATE: 1148 ct = (mynor & CALLOUT_MASK) ? 1149 &port->it_out : &port->it_in; 1150 break; 1151 case CONTROL_LOCK_STATE: 1152 ct = (mynor & CALLOUT_MASK) ? 1153 &port->lt_out : &port->lt_in; 1154 break; 1155 default: 1156 return (ENODEV); /* /dev/nodev */ 1157 } 1158 1159 switch (cmd) { 1160 case TIOCSETA: 1161 error = suser(p); 1162 if (error != 0) 1163 return (error); 1164 *ct = *(struct termios *)data; 1165 1166 return (0); 1167 case TIOCGETA: 1168 *(struct termios *)data = *ct; 1169 1170 return (0); 1171 case TIOCGETD: 1172 *(int *)data = TTYDISC; 1173 return (0); 1174 case TIOCGWINSZ: 1175 bzero(data, sizeof(struct winsize)); 1176 return (0); 1177 default: 1178 return (ENOTTY); 1179 } 1180 } 1181 tp = port->tp; 1182#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1183 term = tp->t_termios; 1184 oldcmd = cmd; 1185 error = ttsetcompat(tp, &cmd, data, &term); 1186 if (error != 0) 1187 return (error); 1188 if (cmd != oldcmd) 1189 data = (caddr_t) & term; 1190#endif 1191 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 1192 int cc; 1193 struct termios *dt; 1194 struct termios *lt; 1195 1196 dt = (struct termios *)data; 1197 lt = (mynor & CALLOUT_MASK) ? &port->lt_out : &port->lt_in; 1198 1199 dt->c_iflag = 1200 (tp->t_iflag & lt->c_iflag) | (dt->c_iflag & ~lt->c_iflag); 1201 dt->c_oflag = 1202 (tp->t_oflag & lt->c_oflag) | (dt->c_oflag & ~lt->c_oflag); 1203 dt->c_cflag = 1204 (tp->t_cflag & lt->c_cflag) | (dt->c_cflag & ~lt->c_cflag); 1205 dt->c_lflag = 1206 (tp->t_lflag & lt->c_lflag) | (dt->c_lflag & ~lt->c_lflag); 1207 port->c_iflag = dt->c_iflag & (IXOFF | IXON | IXANY); 1208 dt->c_iflag &= ~(IXOFF | IXON | IXANY); 1209 for (cc = 0; cc < NCCS; ++cc) 1210 if (lt->c_cc[cc] != 0) 1211 dt->c_cc[cc] = tp->t_cc[cc]; 1212 if (lt->c_ispeed != 0) 1213 dt->c_ispeed = tp->t_ispeed; 1214 if (lt->c_ospeed != 0) 1215 dt->c_ospeed = tp->t_ospeed; 1216 } 1217 error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p); 1218 if (error == 0 && cmd == TIOCGETA) 1219 ((struct termios *)data)->c_iflag |= port->c_iflag; 1220 1221 if (error >= 0 && error != ENOIOCTL) 1222 return (error); 1223 s = spltty(); 1224 error = ttioctl(tp, cmd, data, flag); 1225 if (error == 0 && cmd == TIOCGETA) 1226 ((struct termios *)data)->c_iflag |= port->c_iflag; 1227 1228 digi_disc_optim(tp, &tp->t_termios, port); 1229 if (error >= 0 && error != ENOIOCTL) { 1230 splx(s); 1231 return (error); 1232 } 1233 sc->setwin(sc, 0); 1234 switch (cmd) { 1235 case DIGIIO_RING: 1236 port->send_ring = *(u_char *)data; 1237 break; 1238 case TIOCSBRK: 1239 /* 1240 * now it sends 250 millisecond break because I don't know 1241 * how to send an infinite break 1242 */ 1243 fepcmd_w(port, SENDBREAK, 250, 10); 1244 break; 1245 case TIOCCBRK: 1246 /* now it's empty */ 1247 break; 1248 case TIOCSDTR: 1249 digimctl(port, TIOCM_DTR, DMBIS); 1250 break; 1251 case TIOCCDTR: 1252 digimctl(port, TIOCM_DTR, DMBIC); 1253 break; 1254 case TIOCMSET: 1255 digimctl(port, *(int *)data, DMSET); 1256 break; 1257 case TIOCMBIS: 1258 digimctl(port, *(int *)data, DMBIS); 1259 break; 1260 case TIOCMBIC: 1261 digimctl(port, *(int *)data, DMBIC); 1262 break; 1263 case TIOCMGET: 1264 *(int *)data = digimctl(port, 0, DMGET); 1265 break; 1266 case TIOCMSDTRWAIT: 1267 error = suser(p); 1268 if (error != 0) { 1269 splx(s); 1270 return (error); 1271 } 1272 port->dtr_wait = *(int *)data *hz / 100; 1273 1274 break; 1275 case TIOCMGDTRWAIT: 1276 *(int *)data = port->dtr_wait * 100 / hz; 1277 break; 1278#ifdef DIGI_INTERRUPT 1279 case TIOCTIMESTAMP: 1280 *(struct timeval *)data = sc->intr_timestamp; 1281 1282 break; 1283#endif 1284 default: 1285 splx(s); 1286 return (ENOTTY); 1287 } 1288 splx(s); 1289 return (0); 1290} 1291 1292static int 1293digiparam(struct tty *tp, struct termios *t) 1294{ 1295 int mynor; 1296 int unit; 1297 int pnum; 1298 struct digi_softc *sc; 1299 struct digi_p *port; 1300 int cflag; 1301 int iflag; 1302 int hflow; 1303 int s; 1304 int window; 1305 1306 mynor = minor(tp->t_dev); 1307 unit = MINOR_TO_UNIT(mynor); 1308 pnum = MINOR_TO_PORT(mynor); 1309 1310 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 1311 KASSERT(sc, ("digi%d: softc not allocated in digiparam\n", unit)); 1312 1313 port = &sc->ports[pnum]; 1314 1315 DLOG(DIGIDB_SET, (sc->dev, "port%d: setting parameters\n", pnum)); 1316 1317 if (t->c_ispeed == 0) 1318 t->c_ispeed = t->c_ospeed; 1319 1320 cflag = ttspeedtab(t->c_ospeed, digispeedtab); 1321 1322 if (cflag < 0 || (cflag > 0 && t->c_ispeed != t->c_ospeed)) 1323 return (EINVAL); 1324 1325 s = splclock(); 1326 1327 window = sc->window; 1328 sc->setwin(sc, 0); 1329 1330 if (cflag == 0) { /* hangup */ 1331 DLOG(DIGIDB_SET, (sc->dev, "port%d: hangup\n", pnum)); 1332 digimctl(port, TIOCM_DTR | TIOCM_RTS, DMBIC); 1333 } else { 1334 digimctl(port, TIOCM_DTR | TIOCM_RTS, DMBIS); 1335 1336 DLOG(DIGIDB_SET, (sc->dev, "port%d: CBAUD = %d\n", pnum, 1337 cflag)); 1338 1339#if 0 1340 /* convert flags to sysV-style values */ 1341 if (t->c_cflag & PARODD) 1342 cflag |= 0x0200; 1343 if (t->c_cflag & PARENB) 1344 cflag |= 0x0100; 1345 if (t->c_cflag & CSTOPB) 1346 cflag |= 0x0080; 1347#else 1348 /* convert flags to sysV-style values */ 1349 if (t->c_cflag & PARODD) 1350 cflag |= FEP_PARODD; 1351 if (t->c_cflag & PARENB) 1352 cflag |= FEP_PARENB; 1353 if (t->c_cflag & CSTOPB) 1354 cflag |= FEP_CSTOPB; 1355 if (t->c_cflag & CLOCAL) 1356 cflag |= FEP_CLOCAL; 1357#endif 1358 1359 cflag |= (t->c_cflag & CSIZE) >> 4; 1360 DLOG(DIGIDB_SET, (sc->dev, "port%d: CFLAG = 0x%x\n", pnum, 1361 cflag)); 1362 fepcmd_w(port, SETCFLAGS, (unsigned)cflag, 0); 1363 } 1364 1365 iflag = 1366 t->c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP); 1367 if (port->c_iflag & IXON) 1368 iflag |= 0x400; 1369 if (port->c_iflag & IXANY) 1370 iflag |= 0x800; 1371 if (port->c_iflag & IXOFF) 1372 iflag |= 0x1000; 1373 1374 DLOG(DIGIDB_SET, (sc->dev, "port%d: set iflag = 0x%x\n", pnum, iflag)); 1375 fepcmd_w(port, SETIFLAGS, (unsigned)iflag, 0); 1376 1377 hflow = 0; 1378 if (t->c_cflag & CDTR_IFLOW) 1379 hflow |= sc->csigs->dtr; 1380 if (t->c_cflag & CRTS_IFLOW) 1381 hflow |= sc->csigs->rts; 1382 if (t->c_cflag & CCTS_OFLOW) 1383 hflow |= sc->csigs->cts; 1384 if (t->c_cflag & CDSR_OFLOW) 1385 hflow |= sc->csigs->dsr; 1386 if (t->c_cflag & CCAR_OFLOW) 1387 hflow |= sc->csigs->cd; 1388 1389 DLOG(DIGIDB_SET, (sc->dev, "port%d: set hflow = 0x%x\n", pnum, hflow)); 1390 fepcmd_w(port, SETHFLOW, 0xff00 | (unsigned)hflow, 0); 1391 1392 DLOG(DIGIDB_SET, (sc->dev, "port%d: set startc(0x%x), stopc(0x%x)\n", 1393 pnum, t->c_cc[VSTART], t->c_cc[VSTOP])); 1394 fepcmd_b(port, SONOFFC, t->c_cc[VSTART], t->c_cc[VSTOP], 0); 1395 1396 if (sc->window != 0) 1397 sc->towin(sc, 0); 1398 if (window != 0) 1399 sc->towin(sc, window); 1400 splx(s); 1401 1402 return (0); 1403} 1404 1405static void 1406digi_intr(void *vp) 1407{ 1408 struct digi_p *port; 1409 char *cxcon; 1410 struct digi_softc *sc; 1411 int ehead, etail; 1412 volatile struct board_chan *bc; 1413 struct tty *tp; 1414 int head, tail; 1415 int wrapmask; 1416 int size, window; 1417 struct event { 1418 u_char pnum; 1419 u_char event; 1420 u_char mstat; 1421 u_char lstat; 1422 } event; 1423 1424 sc = vp; 1425 1426 if (sc->status != DIGI_STATUS_ENABLED) { 1427 DLOG(DIGIDB_IRQ, (sc->dev, "interrupt on disabled board !\n")); 1428 return; 1429 } 1430 1431#ifdef DIGI_INTERRUPT 1432 microtime(&sc->intr_timestamp); 1433#endif 1434 1435 window = sc->window; 1436 sc->setwin(sc, 0); 1437 1438 if (sc->model >= PCXEM && W(sc->vmem + 0xd00)) { 1439 struct con_bios *con = con_bios_list; 1440 register u_char *ptr; 1441 1442 ptr = sc->vmem + W(sc->vmem + 0xd00); 1443 while (con) { 1444 if (ptr[1] && W(ptr + 2) == W(con->bios + 2)) 1445 /* Not first block -- exact match */ 1446 break; 1447 1448 if (W(ptr + 4) >= W(con->bios + 4) && 1449 W(ptr + 4) <= W(con->bios + 6)) 1450 /* Initial search concetrator BIOS */ 1451 break; 1452 } 1453 1454 if (con == NULL) { 1455 log(LOG_ERR, "digi%d: wanted bios LREV = 0x%04x" 1456 " not found!\n", sc->res.unit, W(ptr + 4)); 1457 W(ptr + 10) = 0; 1458 W(sc->vmem + 0xd00) = 0; 1459 goto eoi; 1460 } 1461 cxcon = con->bios; 1462 W(ptr + 4) = W(cxcon + 4); 1463 W(ptr + 6) = W(cxcon + 6); 1464 if (ptr[1] == 0) 1465 W(ptr + 2) = W(cxcon + 2); 1466 W(ptr + 8) = (ptr[1] << 6) + W(cxcon + 8); 1467 size = W(cxcon + 10) - (ptr[1] << 10); 1468 if (size <= 0) { 1469 W(ptr + 8) = W(cxcon + 8); 1470 W(ptr + 10) = 0; 1471 } else { 1472 if (size > 1024) 1473 size = 1024; 1474 W(ptr + 10) = size; 1475 bcopy(cxcon + (ptr[1] << 10), ptr + 12, size); 1476 } 1477 W(sc->vmem + 0xd00) = 0; 1478 goto eoi; 1479 } 1480 1481 ehead = sc->gdata->ein; 1482 etail = sc->gdata->eout; 1483 if (ehead == etail) { 1484#ifdef DEBUG 1485 sc->intr_count++; 1486 if (sc->intr_count % 6000 == 0) { 1487 DLOG(DIGIDB_IRQ, (sc->dev, 1488 "6000 useless polls %x %x\n", ehead, etail)); 1489 sc->intr_count = 0; 1490 } 1491#endif 1492 goto eoi; 1493 } 1494 while (ehead != etail) { 1495 event = *(volatile struct event *)(sc->memevent + etail); 1496 1497 etail = (etail + 4) & sc->gdata->imax; 1498 1499 if (event.pnum >= sc->numports) { 1500 log(LOG_ERR, "digi%d: port %d: got event" 1501 " on nonexisting port\n", sc->res.unit, 1502 event.pnum); 1503 continue; 1504 } 1505 port = &sc->ports[event.pnum]; 1506 bc = port->bc; 1507 tp = port->tp; 1508 1509 if (!(tp->t_state & TS_ISOPEN) && !port->wopeners) { 1510 DLOG(DIGIDB_IRQ, (sc->dev, 1511 "port %d: event 0x%x on closed port\n", 1512 event.pnum, event.event)); 1513 bc->rout = bc->rin; 1514 bc->idata = 0; 1515 bc->iempty = 0; 1516 bc->ilow = 0; 1517 bc->mint = 0; 1518 continue; 1519 } 1520 if (event.event & ~ALL_IND) 1521 log(LOG_ERR, "digi%d: port%d: ? event 0x%x mstat 0x%x" 1522 " lstat 0x%x\n", sc->res.unit, event.pnum, 1523 event.event, event.mstat, event.lstat); 1524 1525 if (event.event & DATA_IND) { 1526 DLOG(DIGIDB_IRQ, (sc->dev, "port %d: DATA_IND\n", 1527 event.pnum)); 1528 wrapmask = port->rxbufsize - 1; 1529 head = bc->rin; 1530 tail = bc->rout; 1531 1532 size = 0; 1533 if (!(tp->t_state & TS_ISOPEN)) { 1534 bc->rout = head; 1535 goto end_of_data; 1536 } 1537 while (head != tail) { 1538 int top; 1539 1540 DLOG(DIGIDB_INT, (sc->dev, 1541 "port %d: p rx head = %d tail = %d\n", 1542 event.pnum, head, tail)); 1543 top = (head > tail) ? head : wrapmask + 1; 1544 sc->towin(sc, port->rxwin); 1545 size = top - tail; 1546 if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 1547 size = b_to_q((char *)port->rxbuf + 1548 tail, size, &tp->t_rawq); 1549 tail = top - size; 1550 ttwakeup(tp); 1551 } else for (; tail < top;) { 1552 linesw[tp->t_line]. 1553 l_rint(port->rxbuf[tail], tp); 1554 sc->towin(sc, port->rxwin); 1555 size--; 1556 tail++; 1557 if (tp->t_state & TS_TBLOCK) 1558 break; 1559 } 1560 tail &= wrapmask; 1561 sc->setwin(sc, 0); 1562 bc->rout = tail; 1563 head = bc->rin; 1564 if (size) 1565 break; 1566 } 1567 1568 if (bc->orun) { 1569 CE_RECORD(port, CE_OVERRUN); 1570 log(LOG_ERR, "digi%d: port%d: %s\n", 1571 sc->res.unit, event.pnum, 1572 digi_errortxt(CE_OVERRUN)); 1573 bc->orun = 0; 1574 } 1575end_of_data: 1576 if (size) { 1577 tp->t_state |= TS_TBLOCK; 1578 port->status |= PAUSE_RX; 1579 DLOG(DIGIDB_RX, (sc->dev, "port %d: pause RX\n", 1580 event.pnum)); 1581 } else { 1582 bc->idata = 1; 1583 } 1584 } 1585 1586 if (event.event & MODEMCHG_IND) { 1587 DLOG(DIGIDB_MODEM, (sc->dev, "port %d: MODEMCHG_IND\n", 1588 event.pnum)); 1589 1590 if ((event.mstat ^ event.lstat) & port->sc->csigs->cd) { 1591 sc->hidewin(sc); 1592 linesw[tp->t_line].l_modem 1593 (tp, event.mstat & port->sc->csigs->cd); 1594 sc->setwin(sc, 0); 1595 wakeup(TSA_CARR_ON(tp)); 1596 } 1597 1598 if (event.mstat & sc->csigs->ri) { 1599 DLOG(DIGIDB_RI, (sc->dev, "port %d: RING\n", 1600 event.pnum)); 1601 if (port->send_ring) { 1602 linesw[tp->t_line].l_rint('R', tp); 1603 linesw[tp->t_line].l_rint('I', tp); 1604 linesw[tp->t_line].l_rint('N', tp); 1605 linesw[tp->t_line].l_rint('G', tp); 1606 linesw[tp->t_line].l_rint('\r', tp); 1607 linesw[tp->t_line].l_rint('\n', tp); 1608 } 1609 } 1610 } 1611 if (event.event & BREAK_IND) { 1612 DLOG(DIGIDB_MODEM, (sc->dev, "port %d: BREAK_IND\n", 1613 event.pnum)); 1614 linesw[tp->t_line].l_rint(TTY_BI, tp); 1615 } 1616 if (event.event & (LOWTX_IND | EMPTYTX_IND)) { 1617 DLOG(DIGIDB_IRQ, (sc->dev, "port %d:%s%s\n", 1618 event.pnum, 1619 event.event & LOWTX_IND ? " LOWTX" : "", 1620 event.event & EMPTYTX_IND ? " EMPTYTX" : "")); 1621 (*linesw[tp->t_line].l_start)(tp); 1622 } 1623 } 1624 sc->gdata->eout = etail; 1625eoi: 1626 if (sc->window != 0) 1627 sc->towin(sc, 0); 1628 if (window != 0) 1629 sc->towin(sc, window); 1630} 1631 1632static void 1633digistart(struct tty *tp) 1634{ 1635 int unit; 1636 int pnum; 1637 struct digi_p *port; 1638 struct digi_softc *sc; 1639 volatile struct board_chan *bc; 1640 int head, tail; 1641 int size, ocount, totcnt = 0; 1642 int s; 1643 int wmask; 1644 1645 unit = MINOR_TO_UNIT(minor(tp->t_dev)); 1646 pnum = MINOR_TO_PORT(minor(tp->t_dev)); 1647 1648 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 1649 KASSERT(sc, ("digi%d: softc not allocated in digistart\n", unit)); 1650 1651 port = &sc->ports[pnum]; 1652 bc = port->bc; 1653 1654 wmask = port->txbufsize - 1; 1655 1656 s = spltty(); 1657 port->lcc = tp->t_outq.c_cc; 1658 sc->setwin(sc, 0); 1659 if (!(tp->t_state & TS_TBLOCK)) { 1660 if (port->status & PAUSE_RX) { 1661 DLOG(DIGIDB_RX, (sc->dev, "port %d: resume RX\n", 1662 pnum)); 1663 /* 1664 * CAREFUL - braces are needed here if the DLOG is 1665 * optimised out! 1666 */ 1667 } 1668 port->status &= ~PAUSE_RX; 1669 bc->idata = 1; 1670 } 1671 if (!(tp->t_state & TS_TTSTOP) && port->status & PAUSE_TX) { 1672 DLOG(DIGIDB_TX, (sc->dev, "port %d: resume TX\n", pnum)); 1673 port->status &= ~PAUSE_TX; 1674 fepcmd_w(port, RESUMETX, 0, 10); 1675 } 1676 if (tp->t_outq.c_cc == 0) 1677 tp->t_state &= ~TS_BUSY; 1678 else 1679 tp->t_state |= TS_BUSY; 1680 1681 head = bc->tin; 1682 while (tp->t_outq.c_cc != 0) { 1683 tail = bc->tout; 1684 DLOG(DIGIDB_INT, (sc->dev, "port%d: s tx head = %d tail = %d\n", 1685 pnum, head, tail)); 1686 1687 if (head < tail) 1688 size = tail - head - 1; 1689 else { 1690 size = port->txbufsize - head; 1691 if (tail == 0) 1692 size--; 1693 } 1694 1695 if (size == 0) 1696 break; 1697 sc->towin(sc, port->txwin); 1698 ocount = q_to_b(&tp->t_outq, port->txbuf + head, size); 1699 totcnt += ocount; 1700 head += ocount; 1701 head &= wmask; 1702 sc->setwin(sc, 0); 1703 bc->tin = head; 1704 bc->iempty = 1; 1705 bc->ilow = 1; 1706 } 1707 port->lostcc = tp->t_outq.c_cc; 1708 tail = bc->tout; 1709 if (head < tail) 1710 size = port->txbufsize - tail + head; 1711 else 1712 size = head - tail; 1713 1714 port->lbuf = size; 1715 DLOG(DIGIDB_INT, (sc->dev, "port%d: s total cnt = %d\n", pnum, totcnt)); 1716 ttwwakeup(tp); 1717 splx(s); 1718} 1719 1720static void 1721digistop(struct tty *tp, int rw) 1722{ 1723 struct digi_softc *sc; 1724 int unit; 1725 int pnum; 1726 struct digi_p *port; 1727 1728 unit = MINOR_TO_UNIT(minor(tp->t_dev)); 1729 pnum = MINOR_TO_PORT(minor(tp->t_dev)); 1730 1731 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 1732 KASSERT(sc, ("digi%d: softc not allocated in digistop\n", unit)); 1733 port = sc->ports + pnum; 1734 1735 DLOG(DIGIDB_TX, (sc->dev, "port %d: pause TX\n", pnum)); 1736 port->status |= PAUSE_TX; 1737 fepcmd_w(port, PAUSETX, 0, 10); 1738} 1739 1740static void 1741fepcmd(struct digi_p *port, int cmd, int op1, int ncmds) 1742{ 1743 u_char *mem; 1744 unsigned tail, head; 1745 int count, n; 1746 1747 mem = port->sc->memcmd; 1748 1749 port->sc->setwin(port->sc, 0); 1750 1751 head = port->sc->gdata->cin; 1752 mem[head + 0] = cmd; 1753 mem[head + 1] = port->pnum; 1754 *(ushort *)(mem + head + 2) = op1; 1755 1756 head = (head + 4) & port->sc->gdata->cmax; 1757 port->sc->gdata->cin = head; 1758 1759 for (count = FEPTIMEOUT; count > 0; count--) { 1760 head = port->sc->gdata->cin; 1761 tail = port->sc->gdata->cout; 1762 n = (head - tail) & port->sc->gdata->cmax; 1763 1764 if (n <= ncmds * sizeof(short) * 4) 1765 break; 1766 } 1767 if (count == 0) 1768 log(LOG_ERR, "digi%d: port%d: timeout on FEP command\n", 1769 port->sc->res.unit, port->pnum); 1770} 1771 1772const char * 1773digi_errortxt(int id) 1774{ 1775 static const char *error_desc[] = { 1776 "silo overflow", 1777 "interrupt-level buffer overflow", 1778 "tty-level buffer overflow", 1779 }; 1780 1781 KASSERT(id >= 0 && id < sizeof(error_desc) / sizeof(error_desc[0]), 1782 ("Unexpected digi error id %d\n", id)); 1783 1784 return (error_desc[id]); 1785} 1786 1787int 1788digi_attach(struct digi_softc *sc) 1789{ 1790 sc->res.ctldev = make_dev(&digi_sw, 1791 (sc->res.unit << 16) | CTRL_DEV, UID_ROOT, GID_WHEEL, 1792 0600, "digi%r.ctl", sc->res.unit); 1793 1794 digi_loadmoduledata(sc); 1795 digi_init(sc); 1796 digi_freemoduledata(sc); 1797 1798 return (0); 1799} 1800 1801static int 1802digi_inuse(struct digi_softc *sc) 1803{ 1804 int i; 1805 1806 for (i = 0; i < sc->numports; i++) 1807 if (sc->ttys[i].t_state & TS_ISOPEN) { 1808 DLOG(DIGIDB_INIT, (sc->dev, "port%d: busy\n", i)); 1809 return (1); 1810 } else if (sc->ports[i].wopeners || sc->ports[i].opencnt) { 1811 DLOG(DIGIDB_INIT, (sc->dev, "port%d: blocked in open\n", 1812 i)); 1813 return (1); 1814 } 1815 return (0); 1816} 1817 1818static void 1819digi_free_state(struct digi_softc *sc) 1820{ 1821 int d, i; 1822 1823 /* Blow it all away */ 1824 1825 for (i = 0; i < sc->numports; i++) 1826 for (d = 0; d < 6; d++) 1827 destroy_dev(sc->ports[i].dev[d]); 1828 1829 untimeout(digi_poll, sc, sc->callout); 1830 callout_handle_init(&sc->callout); 1831 untimeout(digi_int_test, sc, sc->inttest); 1832 callout_handle_init(&sc->inttest); 1833 1834 bus_teardown_intr(sc->dev, sc->res.irq, sc->res.irqHandler); 1835#ifdef DIGI_INTERRUPT 1836 if (sc->res.irq != NULL) { 1837 bus_release_resource(dev, SYS_RES_IRQ, sc->res.irqrid, 1838 sc->res.irq); 1839 sc->res.irq = NULL; 1840 } 1841#endif 1842 if (sc->numports) { 1843 KASSERT(sc->ports, ("digi%d: Lost my ports ?", sc->res.unit)); 1844 KASSERT(sc->ttys, ("digi%d: Lost my ttys ?", sc->res.unit)); 1845 free(sc->ports, M_TTYS); 1846 sc->ports = NULL; 1847 free(sc->ttys, M_TTYS); 1848 sc->ttys = NULL; 1849 sc->numports = 0; 1850 } 1851 1852 sc->status = DIGI_STATUS_NOTINIT; 1853} 1854 1855int 1856digi_detach(device_t dev) 1857{ 1858 struct digi_softc *sc = device_get_softc(dev); 1859 1860 DLOG(DIGIDB_INIT, (sc->dev, "detaching\n")); 1861 1862 /* If we're INIT'd, numports must be 0 */ 1863 KASSERT(sc->numports == 0 || sc->status != DIGI_STATUS_NOTINIT, 1864 ("digi%d: numports(%d) & status(%d) are out of sync", 1865 sc->res.unit, sc->numports, (int)sc->status)); 1866 1867 if (digi_inuse(sc)) 1868 return (EBUSY); 1869 1870 digi_free_state(sc); 1871 1872 destroy_dev(makedev(CDEV_MAJOR, 1873 (sc->res.unit << 16) | CTRL_DEV)); 1874 1875 if (sc->res.mem != NULL) { 1876 bus_release_resource(dev, SYS_RES_MEMORY, sc->res.mrid, 1877 sc->res.mem); 1878 sc->res.mem = NULL; 1879 } 1880 if (sc->res.io != NULL) { 1881 bus_release_resource(dev, SYS_RES_IOPORT, sc->res.iorid, 1882 sc->res.io); 1883 sc->res.io = NULL; 1884 } 1885 1886 return (0); 1887} 1888 1889int 1890digi_shutdown(device_t dev) 1891{ 1892 return (0); 1893} 1894