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