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