digi.c revision 83861
1270919Sjfv/*- 2270919Sjfv * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org> 3270631Sjfv * based on work by Slawa Olhovchenkov 4270631Sjfv * John Prince <johnp@knight-trosoft.com> 5270631Sjfv * Eric Hernes 6270631Sjfv * All rights reserved. 7270919Sjfv * 8270631Sjfv * Redistribution and use in source and binary forms, with or without 9270631Sjfv * modification, are permitted provided that the following conditions 10270631Sjfv * are met: 11270631Sjfv * 1. Redistributions of source code must retain the above copyright 12270631Sjfv * notice, this list of conditions and the following disclaimer. 13270631Sjfv * 2. Redistributions in binary form must reproduce the above copyright 14270631Sjfv * notice, this list of conditions and the following disclaimer in the 15270919Sjfv * documentation and/or other materials provided with the distribution. 16270631Sjfv * 17270631Sjfv * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18270631Sjfv * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19270631Sjfv * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20270631Sjfv * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21270631Sjfv * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22270631Sjfv * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23270631Sjfv * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24270919Sjfv * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25270919Sjfv * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26270919Sjfv * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27270919Sjfv * SUCH DAMAGE. 28270631Sjfv * 29270919Sjfv * $FreeBSD: head/sys/dev/digi/digi.c 83861 2001-09-23 20:03:40Z brian $ 30270919Sjfv */ 31270919Sjfv 32270631Sjfv/*- 33270631Sjfv * TODO: 34270631Sjfv * Figure out what the con bios stuff is supposed to do 35270631Sjfv * Test with *LOTS* more cards - I only have a PCI8r and an ISA Xem. 36270631Sjfv */ 37270919Sjfv 38270919Sjfv#include <sys/param.h> 39270631Sjfv#include <sys/systm.h> 40270631Sjfv#include <sys/proc.h> 41270631Sjfv#include <sys/conf.h> 42270631Sjfv#include <sys/linker.h> 43270631Sjfv#include <sys/kernel.h> 44270631Sjfv#include <sys/mbuf.h> 45270631Sjfv#include <sys/malloc.h> 46270631Sjfv#include <sys/tty.h> 47270631Sjfv#include <sys/syslog.h> 48270631Sjfv#include <sys/fcntl.h> 49270631Sjfv#include <sys/bus.h> 50270631Sjfv#include <sys/bus.h> 51270631Sjfv#include <machine/resource.h> 52270631Sjfv 53270631Sjfv#include <sys/digiio.h> 54270631Sjfv#include <dev/digi/digireg.h> 55270631Sjfv#include <dev/digi/digi.h> 56270631Sjfv#include <dev/digi/digi_mod.h> 57270631Sjfv#include <dev/digi/digi_pci.h> 58270631Sjfv 59270631Sjfv#define CDEV_MAJOR 162 60270919Sjfv 61270919Sjfv#define CTRL_DEV 0x800000 62270631Sjfv#define CALLOUT_MASK 0x400000 63270919Sjfv#define CONTROL_INIT_STATE 0x100000 64270919Sjfv#define CONTROL_LOCK_STATE 0x200000 65270919Sjfv#define CONTROL_MASK (CTRL_DEV|CONTROL_INIT_STATE|CONTROL_LOCK_STATE) 66270919Sjfv#define UNIT_MASK 0x030000 67270919Sjfv#define PORT_MASK 0x0000FF 68270919Sjfv#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev))) 69270631Sjfv#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK) 70270919Sjfv#define MINOR_TO_UNIT(mynor) (((mynor) & UNIT_MASK)>>16) 71270919Sjfv#define MINOR_TO_PORT(mynor) ((mynor) & PORT_MASK) 72270919Sjfv 73270919Sjfvstatic d_open_t digiopen; 74270919Sjfvstatic d_close_t digiclose; 75270919Sjfvstatic d_read_t digiread; 76270919Sjfvstatic d_write_t digiwrite; 77270919Sjfvstatic d_ioctl_t digiioctl; 78270919Sjfv 79270919Sjfvstatic void digistop(struct tty *tp, int rw); 80270919Sjfvstatic int digimctl(struct digi_p *port, int bits, int how); 81270919Sjfvstatic void digi_poll(void *ptr); 82270919Sjfvstatic void digi_freemoduledata(struct digi_softc *); 83270919Sjfvstatic void fepcmd(struct digi_p *port, int cmd, int op, int ncmds); 84270919Sjfvstatic void digistart(struct tty *tp); 85270631Sjfvstatic int digiparam(struct tty *tp, struct termios *t); 86270631Sjfvstatic void digihardclose(struct digi_p *port); 87270919Sjfvstatic void digi_intr(void *); 88270631Sjfvstatic int digi_init(struct digi_softc *_sc); 89270919Sjfvstatic int digi_loadmoduledata(struct digi_softc *); 90270919Sjfvstatic int digi_inuse(struct digi_softc *); 91270919Sjfvstatic void digi_free_state(struct digi_softc *); 92270919Sjfv 93270631Sjfv#define fepcmd_b(port, cmd, op1, op2, ncmds) \ 94270919Sjfv fepcmd(port, cmd, (op2 << 8) | op1, ncmds) 95270919Sjfv#define fepcmd_w fepcmd 96270631Sjfv 97270919Sjfv 98270919Sjfvstatic speed_t digidefaultrate = TTYDEF_SPEED; 99270631Sjfv 100270631Sjfvstruct con_bios { 101270631Sjfv struct con_bios *next; 102270631Sjfv u_char *bios; 103270631Sjfv size_t size; 104270631Sjfv}; 105270631Sjfv 106270631Sjfvstruct con_bios *con_bios_list; 107270631Sjfvdevclass_t digi_devclass; 108270631Sjfvstatic char driver_name[] = "digi"; 109270631Sjfvunsigned digi_debug = 0; 110270631Sjfv 111270631Sjfvstatic struct speedtab digispeedtab[] = { 112270631Sjfv { 0, 0}, /* old (sysV-like) Bx codes */ 113270631Sjfv { 50, 1}, 114270919Sjfv { 75, 2}, 115270919Sjfv { 110, 3}, 116270919Sjfv { 134, 4}, 117270631Sjfv { 150, 5}, 118270631Sjfv { 200, 6}, 119270631Sjfv { 300, 7}, 120270631Sjfv { 600, 8}, 121270631Sjfv { 1200, 9}, 122270631Sjfv { 1800, 10}, 123270631Sjfv { 2400, 11}, 124270631Sjfv { 4800, 12}, 125270631Sjfv { 9600, 13}, 126270631Sjfv { 19200, 14}, 127270631Sjfv { 38400, 15}, 128270631Sjfv { 57600, (02000 | 1)}, 129270631Sjfv { 76800, (02000 | 2)}, 130270631Sjfv { 115200, (02000 | 3)}, 131270631Sjfv { 230400, (02000 | 6)}, 132270631Sjfv { -1, -1} 133270631Sjfv}; 134270631Sjfv 135270631Sjfvconst struct digi_control_signals digi_xixe_signals = { 136270631Sjfv 0x02, 0x08, 0x10, 0x20, 0x40, 0x80 137270631Sjfv}; 138270631Sjfv 139270631Sjfvconst struct digi_control_signals digi_normal_signals = { 140270631Sjfv 0x02, 0x80, 0x20, 0x10, 0x40, 0x01 141270631Sjfv}; 142270631Sjfv 143270631Sjfvstatic struct cdevsw digi_sw = { 144270631Sjfv digiopen, /* open */ 145270919Sjfv digiclose, /* close */ 146270631Sjfv digiread, /* read */ 147270631Sjfv digiwrite, /* write */ 148270631Sjfv digiioctl, /* ioctl */ 149270631Sjfv ttypoll, /* poll */ 150270631Sjfv nommap, /* mmap */ 151270631Sjfv nostrategy, /* strategy */ 152270631Sjfv driver_name, /* name */ 153270631Sjfv CDEV_MAJOR, /* maj */ 154270631Sjfv nodump, /* dump */ 155270631Sjfv nopsize, /* psize */ 156270631Sjfv D_TTY | D_KQFILTER, /* flags */ 157270631Sjfv ttykqfilter /* bmaj */ 158270631Sjfv}; 159270631Sjfv 160270631Sjfvint 161270631Sjfvdigi_modhandler(module_t mod, int event, void *arg) 162270631Sjfv{ 163270631Sjfv static int ref = 0; 164270631Sjfv 165270631Sjfv switch (event) { 166270631Sjfv case MOD_LOAD: 167270631Sjfv if (ref++ == 0) 168270631Sjfv cdevsw_add(&digi_sw); 169270631Sjfv break; 170270631Sjfv 171270631Sjfv case MOD_UNLOAD: 172270631Sjfv if (--ref == 0) 173270631Sjfv cdevsw_remove(&digi_sw); 174270631Sjfv break; 175270631Sjfv } 176270631Sjfv 177270631Sjfv return (0); 178270631Sjfv} 179270631Sjfv 180270631Sjfvstatic void 181270631Sjfvdigi_poll(void *ptr) 182270631Sjfv{ 183270631Sjfv struct digi_softc *sc; 184270631Sjfv 185270631Sjfv sc = (struct digi_softc *)ptr; 186270631Sjfv callout_handle_init(&sc->callout); 187270631Sjfv digi_intr(sc); 188270631Sjfv sc->callout = timeout(digi_poll, sc, (hz >= 200) ? hz / 100 : 1); 189270631Sjfv} 190270631Sjfv 191270631Sjfvstatic void 192270631Sjfvdigi_int_test(void *v) 193270631Sjfv{ 194270631Sjfv struct digi_softc *sc = v; 195270631Sjfv 196270631Sjfv callout_handle_init(&sc->inttest); 197270631Sjfv#ifdef DIGI_INTERRUPT 198270631Sjfv if (sc->intr_timestamp.tv_sec || sc->intr_timestamp.tv_usec) { 199270631Sjfv /* interrupt OK! */ 200270631Sjfv return; 201270631Sjfv } 202270631Sjfv log(LOG_ERR, "digi%d: Interrupt didn't work, use polled mode\n", unit); 203270631Sjfv#endif 204270631Sjfv sc->callout = timeout(digi_poll, sc, (hz >= 200) ? hz / 100 : 1); 205270631Sjfv} 206270631Sjfv 207270631Sjfvstatic void 208270631Sjfvdigi_freemoduledata(struct digi_softc *sc) 209270631Sjfv{ 210270631Sjfv if (sc->fep.data != NULL) { 211270631Sjfv free(sc->fep.data, M_TTYS); 212270631Sjfv sc->fep.data = NULL; 213270631Sjfv } 214270631Sjfv if (sc->link.data != NULL) { 215270631Sjfv free(sc->link.data, M_TTYS); 216270631Sjfv sc->link.data = NULL; 217270631Sjfv } 218270631Sjfv if (sc->bios.data != NULL) { 219270631Sjfv free(sc->bios.data, M_TTYS); 220270631Sjfv sc->bios.data = NULL; 221270631Sjfv } 222270631Sjfv} 223270631Sjfv 224270631Sjfvstatic int 225270631Sjfvdigi_bcopy(const void *vfrom, void *vto, size_t sz) 226270631Sjfv{ 227270631Sjfv volatile const char *from = (volatile const char *)vfrom; 228270631Sjfv volatile char *to = (volatile char *)vto; 229270631Sjfv size_t i; 230270631Sjfv 231270631Sjfv for (i = 0; i < sz; i++) 232270631Sjfv *to++ = *from++; 233270631Sjfv 234270631Sjfv from = (const volatile char *)vfrom; 235270631Sjfv to = (volatile char *)vto; 236270631Sjfv for (i = 0; i < sz; i++) 237270631Sjfv if (*to++ != *from++) 238270631Sjfv return (0); 239270631Sjfv return (1); 240270631Sjfv} 241270631Sjfv 242270631Sjfvstatic int 243270631Sjfvdigi_init(struct digi_softc *sc) 244270631Sjfv{ 245270631Sjfv int i, cnt, resp; 246270631Sjfv u_char *ptr; 247270631Sjfv int lowwater; 248270631Sjfv struct digi_p *port; 249270631Sjfv volatile struct board_chan *bc; 250270631Sjfv 251270631Sjfv ptr = NULL; 252270631Sjfv 253270631Sjfv if (sc->status == DIGI_STATUS_DISABLED) { 254270631Sjfv log(LOG_ERR, "digi%d: Cannot init a disabled card\n", 255270631Sjfv sc->res.unit); 256270631Sjfv return (EIO); 257270631Sjfv } 258270631Sjfv if (sc->bios.data == NULL) { 259270631Sjfv log(LOG_ERR, "digi%d: Cannot init without BIOS\n", 260270631Sjfv sc->res.unit); 261270631Sjfv return (EIO); 262270631Sjfv } 263270631Sjfv#if 0 264270631Sjfv if (sc->link.data == NULL && sc->model >= PCCX) { 265270631Sjfv log(LOG_ERR, "digi%d: Cannot init without link info\n", 266270631Sjfv sc->res.unit); 267270631Sjfv return (EIO); 268270631Sjfv } 269270631Sjfv#endif 270270631Sjfv if (sc->fep.data == NULL) { 271270631Sjfv log(LOG_ERR, "digi%d: Cannot init without fep code\n", 272270631Sjfv sc->res.unit); 273270631Sjfv return (EIO); 274270631Sjfv } 275270631Sjfv sc->status = DIGI_STATUS_NOTINIT; 276270631Sjfv 277270631Sjfv if (sc->numports) { 278270631Sjfv /* 279270631Sjfv * We're re-initialising - maybe because someone's attached 280270919Sjfv * another port module. For now, we just re-initialise 281270631Sjfv * everything. 282270631Sjfv */ 283270631Sjfv if (digi_inuse(sc)) 284270631Sjfv return (EBUSY); 285270631Sjfv 286270631Sjfv digi_free_state(sc); 287270631Sjfv } 288270631Sjfv 289270631Sjfv ptr = sc->setwin(sc, MISCGLOBAL); 290270631Sjfv for (i = 0; i < 16; i += 2) 291270631Sjfv vW(ptr + i) = 0; 292270631Sjfv 293270631Sjfv switch (sc->model) { 294270631Sjfv case PCXEVE: 295270631Sjfv outb(sc->wport, 0xff); /* window 7 */ 296270631Sjfv ptr = sc->vmem + (BIOSCODE & 0x1fff); 297270631Sjfv 298270631Sjfv if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) { 299270631Sjfv device_printf(sc->dev, "BIOS upload failed\n"); 300270631Sjfv return (EIO); 301270631Sjfv } 302270631Sjfv 303270919Sjfv outb(sc->port, FEPCLR); 304270919Sjfv break; 305270631Sjfv 306270631Sjfv case PCXE: 307270631Sjfv case PCXI: 308270631Sjfv case PCCX: 309270631Sjfv ptr = sc->setwin(sc, BIOSCODE + ((0xf000 - sc->mem_seg) << 4)); 310270631Sjfv if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) { 311270631Sjfv device_printf(sc->dev, "BIOS upload failed\n"); 312270631Sjfv return (EIO); 313270631Sjfv } 314270631Sjfv break; 315270631Sjfv 316270919Sjfv case PCXEM: 317270919Sjfv case PCIEPCX: 318270631Sjfv case PCIXR: 319270919Sjfv if (sc->model == PCIXR) 320270919Sjfv PCIPORT = FEPRST; 321270919Sjfv else 322270631Sjfv outb(sc->port, FEPRST | FEPMEM); 323270919Sjfv 324270631Sjfv for (i = 0; ((sc->model == PCIXR ? PCIPORT : inb(sc->port)) & 325270631Sjfv FEPMASK) != FEPRST; i++) { 326270631Sjfv if (i > 1000) { 327270631Sjfv log(LOG_ERR, "digi%d: init reset failed\n", 328270631Sjfv sc->res.unit); 329270919Sjfv return (EIO); 330270919Sjfv } 331270919Sjfv tsleep(sc, PUSER | PCATCH, "digiinit0", 1); 332270919Sjfv } 333270919Sjfv DLOG(DIGIDB_INIT, (sc->dev, "Got init reset after %d us\n", i)); 334270631Sjfv 335270631Sjfv /* Now upload the BIOS */ 336270631Sjfv cnt = (sc->bios.size < sc->win_size - BIOSOFFSET) ? 337270631Sjfv sc->bios.size : sc->win_size - BIOSOFFSET; 338270631Sjfv 339270631Sjfv ptr = sc->setwin(sc, BIOSOFFSET); 340270631Sjfv if (!digi_bcopy(sc->bios.data, ptr, cnt)) { 341270919Sjfv device_printf(sc->dev, "BIOS upload (1) failed\n"); 342270919Sjfv return (EIO); 343270631Sjfv } 344270919Sjfv 345270919Sjfv if (cnt != sc->bios.size) { 346270631Sjfv /* and the second part */ 347270631Sjfv ptr = sc->setwin(sc, sc->win_size); 348270631Sjfv if (!digi_bcopy(sc->bios.data + cnt, ptr, 349270631Sjfv sc->bios.size - cnt)) { 350270631Sjfv device_printf(sc->dev, "BIOS upload failed\n"); 351270631Sjfv return (EIO); 352270631Sjfv } 353270631Sjfv } 354270631Sjfv 355270631Sjfv ptr = sc->setwin(sc, 0); 356270919Sjfv vW(ptr + 0) = 0x0401; 357270919Sjfv vW(ptr + 2) = 0x0bf0; 358270919Sjfv vW(ptr + 4) = 0x0000; 359270919Sjfv vW(ptr + 6) = 0x0000; 360270631Sjfv 361270631Sjfv break; 362270631Sjfv } 363270631Sjfv 364270631Sjfv DLOG(DIGIDB_INIT, (sc->dev, "BIOS uploaded\n")); 365270631Sjfv 366270631Sjfv ptr = sc->setwin(sc, MISCGLOBAL); 367270631Sjfv W(ptr) = 0; 368270631Sjfv 369270919Sjfv if (sc->model == PCIXR) { 370270919Sjfv PCIPORT = FEPCLR; 371270919Sjfv resp = FEPRST; 372270631Sjfv } else if (sc->model == PCXEVE) { 373270919Sjfv outb(sc->port, FEPCLR); 374270919Sjfv resp = FEPRST; 375270919Sjfv } else { 376270631Sjfv outb(sc->port, FEPCLR | FEPMEM); 377270919Sjfv resp = FEPRST | FEPMEM; 378270919Sjfv } 379270919Sjfv 380270631Sjfv for (i = 0; ((sc->model == PCIXR ? PCIPORT : inb(sc->port)) & FEPMASK) 381270919Sjfv == resp; i++) { 382270919Sjfv if (i > 1000) { 383270631Sjfv log(LOG_ERR, "digi%d: BIOS start failed\n", 384270919Sjfv sc->res.unit); 385270631Sjfv return (EIO); 386270631Sjfv } 387270631Sjfv tsleep(sc, PUSER | PCATCH, "digibios0", 1); 388270631Sjfv } 389270631Sjfv 390270631Sjfv DLOG(DIGIDB_INIT, (sc->dev, "BIOS started after %d us\n", i)); 391270631Sjfv 392270919Sjfv for (i = 0; vW(ptr) != *(u_short *)"GD"; i++) { 393270919Sjfv if (i > 2000) { 394270919Sjfv log(LOG_ERR, "digi%d: BIOS boot failed " 395270631Sjfv "(0x%02x != 0x%02x)\n", 396270631Sjfv sc->res.unit, vW(ptr), *(u_short *)"GD"); 397270631Sjfv return (EIO); 398270631Sjfv } 399270631Sjfv tsleep(sc, PUSER | PCATCH, "digibios1", 1); 400270919Sjfv } 401270919Sjfv 402270919Sjfv DLOG(DIGIDB_INIT, (sc->dev, "BIOS booted after %d iterations\n", i)); 403270919Sjfv 404270919Sjfv if (sc->link.data != NULL) { 405270919Sjfv DLOG(DIGIDB_INIT, (sc->dev, "Loading link data\n")); 406270919Sjfv ptr = sc->setwin(sc, 0xcd0); 407270631Sjfv digi_bcopy(sc->link.data, ptr, 21); /* XXX 21 ? */ 408270631Sjfv } 409270631Sjfv 410270631Sjfv /* load FEP/OS */ 411 412 switch (sc->model) { 413 case PCXE: 414 case PCXEVE: 415 case PCXI: 416 ptr = sc->setwin(sc, sc->model == PCXI ? 0x2000 : 0x0); 417 digi_bcopy(sc->fep.data, ptr, sc->fep.size); 418 419 /* A BIOS request to move our data to 0x2000 */ 420 ptr = sc->setwin(sc, MBOX); 421 vW(ptr + 0) = 2; 422 vW(ptr + 2) = sc->mem_seg + FEPCODESEG; 423 vW(ptr + 4) = 0; 424 vW(ptr + 6) = FEPCODESEG; 425 vW(ptr + 8) = 0; 426 vW(ptr + 10) = sc->fep.size; 427 428 /* Run the BIOS request */ 429 outb(sc->port, FEPREQ | FEPMEM); 430 outb(sc->port, FEPCLR | FEPMEM); 431 432 for (i = 0; W(ptr); i++) { 433 if (i > 10) { 434 log(LOG_ERR, "digi%d: FEP/OS move failed\n", 435 sc->res.unit); 436 sc->hidewin(sc); 437 return (EIO); 438 } 439 tsleep(sc, PUSER | PCATCH, "digifep0", 1); 440 } 441 DLOG(DIGIDB_INIT, 442 (sc->dev, "FEP/OS moved after %d iterations\n", i)); 443 444 /* Clear the confirm word */ 445 ptr = sc->setwin(sc, FEPSTAT); 446 vW(ptr + 0) = 0; 447 448 /* A BIOS request to execute the FEP/OS */ 449 ptr = sc->setwin(sc, MBOX); 450 vW(ptr + 0) = 0x01; 451 vW(ptr + 2) = FEPCODESEG; 452 vW(ptr + 4) = 0x04; 453 454 /* Run the BIOS request */ 455 outb(sc->port, FEPREQ); 456 outb(sc->port, FEPCLR); 457 458 ptr = sc->setwin(sc, FEPSTAT); 459 460 break; 461 462 case PCXEM: 463 case PCIEPCX: 464 case PCIXR: 465 DLOG(DIGIDB_INIT, (sc->dev, "Loading FEP/OS\n")); 466 467 cnt = (sc->fep.size < sc->win_size - BIOSOFFSET) ? 468 sc->fep.size : sc->win_size - BIOSOFFSET; 469 470 ptr = sc->setwin(sc, BIOSOFFSET); 471 digi_bcopy(sc->fep.data, ptr, cnt); 472 473 if (cnt != sc->fep.size) { 474 ptr = sc->setwin(sc, BIOSOFFSET + cnt); 475 digi_bcopy(sc->fep.data + cnt, ptr, 476 sc->fep.size - cnt); 477 } 478 479 DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS loaded\n")); 480 481 ptr = sc->setwin(sc, 0xc30); 482 W(ptr + 4) = 0x1004; 483 W(ptr + 6) = 0xbfc0; 484 W(ptr + 0) = 0x03; 485 W(ptr + 2) = 0x00; 486 487 /* Clear the confirm word */ 488 ptr = sc->setwin(sc, FEPSTAT); 489 W(ptr + 0) = 0; 490 491 if (sc->port) 492 outb(sc->port, 0); /* XXX necessary ? */ 493 494 break; 495 496 case PCCX: 497 ptr = sc->setwin(sc, 0xd000); 498 digi_bcopy(sc->fep.data, ptr, sc->fep.size); 499 500 /* A BIOS request to execute the FEP/OS */ 501 ptr = sc->setwin(sc, 0xc40); 502 W(ptr + 0) = 1; 503 W(ptr + 2) = FEPCODE >> 4; 504 W(ptr + 4) = 4; 505 506 /* Clear the confirm word */ 507 ptr = sc->setwin(sc, FEPSTAT); 508 W(ptr + 0) = 0; 509 510 /* Run the BIOS request */ 511 outb(sc->port, FEPREQ | FEPMEM); /* send interrupt to BIOS */ 512 outb(sc->port, FEPCLR | FEPMEM); 513 break; 514 } 515 516 /* Now wait 'till the FEP/OS has booted */ 517 for (i = 0; vW(ptr) != *(u_short *)"OS"; i++) { 518 if (i > 2000) { 519 log(LOG_ERR, "digi%d: FEP/OS start failed " 520 "(0x%02x != 0x%02x)\n", 521 sc->res.unit, vW(ptr), *(u_short *)"OS"); 522 sc->hidewin(sc); 523 return (EIO); 524 } 525 tsleep(sc, PUSER | PCATCH, "digifep1", 1); 526 } 527 528 DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS started after %d iterations\n", i)); 529 530 if (sc->model >= PCXEM) { 531 ptr = sc->setwin(sc, 0xe04); 532 vW(ptr) = 2; 533 ptr = sc->setwin(sc, 0xc02); 534 sc->numports = vW(ptr); 535 } else { 536 ptr = sc->setwin(sc, 0xc22); 537 sc->numports = vW(ptr); 538 } 539 540 if (sc->numports == 0) { 541 device_printf(sc->dev, "%s, 0 ports found\n", sc->name); 542 sc->hidewin(sc); 543 return (0); 544 } 545 546 if (sc->numports > 256) { 547 /* Our minor numbering scheme is broken for more than 256 */ 548 device_printf(sc->dev, "%s, 256 ports (%d ports found)\n", 549 sc->name, sc->numports); 550 sc->numports = 256; 551 } else 552 device_printf(sc->dev, "%s, %d ports found\n", sc->name, 553 sc->numports); 554 555 if (sc->ports) 556 free(sc->ports, M_TTYS); 557 sc->ports = malloc(sizeof(struct digi_p) * sc->numports, 558 M_TTYS, M_WAIT | M_ZERO); 559 560 if (sc->ttys) 561 free(sc->ttys, M_TTYS); 562 sc->ttys = malloc(sizeof(struct tty) * sc->numports, 563 M_TTYS, M_WAIT | M_ZERO); 564 565 /* 566 * XXX Should read port 0xc90 for an array of 2byte values, 1 per 567 * port. If the value is 0, the port is broken.... 568 */ 569 570 ptr = sc->setwin(sc, 0); 571 572 /* We should now init per-port structures */ 573 bc = (volatile struct board_chan *)(ptr + CHANSTRUCT); 574 sc->gdata = (volatile struct global_data *)(ptr + FEP_GLOBAL); 575 576 sc->memcmd = ptr + sc->gdata->cstart; 577 sc->memevent = ptr + sc->gdata->istart; 578 579 for (i = 0; i < sc->numports; i++, bc++) { 580 port = sc->ports + i; 581 port->pnum = i; 582 port->sc = sc; 583 port->status = ENABLED; 584 port->tp = sc->ttys + i; 585 port->bc = bc; 586 587 if (sc->model == PCXEVE) { 588 port->txbuf = ptr + 589 (((bc->tseg - sc->mem_seg) << 4) & 0x1fff); 590 port->rxbuf = ptr + 591 (((bc->rseg - sc->mem_seg) << 4) & 0x1fff); 592 port->txwin = FEPWIN | ((bc->tseg - sc->mem_seg) >> 9); 593 port->rxwin = FEPWIN | ((bc->rseg - sc->mem_seg) >> 9); 594 } else if (sc->model == PCXI || sc->model == PCXE) { 595 port->txbuf = ptr + ((bc->tseg - sc->mem_seg) << 4); 596 port->rxbuf = ptr + ((bc->rseg - sc->mem_seg) << 4); 597 port->txwin = port->rxwin = 0; 598 } else { 599 port->txbuf = ptr + 600 (((bc->tseg - sc->mem_seg) << 4) % sc->win_size); 601 port->rxbuf = ptr + 602 (((bc->rseg - sc->mem_seg) << 4) % sc->win_size); 603 port->txwin = FEPWIN | 604 (((bc->tseg - sc->mem_seg) << 4) / sc->win_size); 605 port->rxwin = FEPWIN | 606 (((bc->rseg - sc->mem_seg) << 4) / sc->win_size); 607 } 608 port->txbufsize = bc->tmax + 1; 609 port->rxbufsize = bc->rmax + 1; 610 611 lowwater = port->txbufsize >> 2; 612 if (lowwater > 1024) 613 lowwater = 1024; 614 sc->setwin(sc, 0); 615 fepcmd_w(port, STXLWATER, lowwater, 10); 616 fepcmd_w(port, SRXLWATER, port->rxbufsize >> 2, 10); 617 fepcmd_w(port, SRXHWATER, (3 * port->rxbufsize) >> 2, 10); 618 619 bc->edelay = 100; 620 port->dtr_wait = 3 * hz; 621 622 /* 623 * We don't use all the flags from <sys/ttydefaults.h> since 624 * they are only relevant for logins. It's important to have 625 * echo off initially so that the line doesn't start blathering 626 * before the echo flag can be turned off. 627 */ 628 port->it_in.c_iflag = 0; 629 port->it_in.c_oflag = 0; 630 port->it_in.c_cflag = TTYDEF_CFLAG; 631 port->it_in.c_lflag = 0; 632 termioschars(&port->it_in); 633 port->it_in.c_ispeed = port->it_in.c_ospeed = digidefaultrate; 634 port->it_out = port->it_in; 635 port->send_ring = 1; /* Default action on signal RI */ 636 637 port->dev[0] = make_dev(&digi_sw, (sc->res.unit << 16) + i, 638 UID_ROOT, GID_WHEEL, 0600, "ttyD%d.%d", sc->res.unit, i); 639 port->dev[1] = make_dev(&digi_sw, ((sc->res.unit << 16) + i) | 640 CONTROL_INIT_STATE, UID_ROOT, GID_WHEEL, 641 0600, "ttyiD%d.%d", sc->res.unit, i); 642 port->dev[2] = make_dev(&digi_sw, ((sc->res.unit << 16) + i) | 643 CONTROL_LOCK_STATE, UID_ROOT, GID_WHEEL, 644 0600, "ttylD%d.%d", sc->res.unit, i); 645 port->dev[3] = make_dev(&digi_sw, ((sc->res.unit << 16) + i) | 646 CALLOUT_MASK, UID_UUCP, GID_DIALER, 647 0660, "cuaD%d.%d", sc->res.unit, i); 648 port->dev[4] = make_dev(&digi_sw, ((sc->res.unit << 16) + i) | 649 CALLOUT_MASK | CONTROL_INIT_STATE, UID_UUCP, GID_DIALER, 650 0660, "cuaiD%d.%d", sc->res.unit, i); 651 port->dev[5] = make_dev(&digi_sw, ((sc->res.unit << 16) + i) | 652 CALLOUT_MASK | CONTROL_LOCK_STATE, UID_UUCP, GID_DIALER, 653 0660, "cualD%d.%d", sc->res.unit, i); 654 } 655 656 sc->hidewin(sc); 657 sc->inttest = timeout(digi_int_test, sc, hz); 658 /* fepcmd_w(&sc->ports[0], 0xff, 0, 0); */ 659 sc->status = DIGI_STATUS_ENABLED; 660 661 return (0); 662} 663 664static int 665digimctl(struct digi_p *port, int bits, int how) 666{ 667 int mstat; 668 669 if (how == DMGET) { 670 port->sc->setwin(port->sc, 0); 671 mstat = port->bc->mstat; 672 port->sc->hidewin(port->sc); 673 bits = TIOCM_LE; 674 if (mstat & port->sc->csigs->rts) 675 bits |= TIOCM_RTS; 676 if (mstat & port->cd) 677 bits |= TIOCM_CD; 678 if (mstat & port->dsr) 679 bits |= TIOCM_DSR; 680 if (mstat & port->sc->csigs->cts) 681 bits |= TIOCM_CTS; 682 if (mstat & port->sc->csigs->ri) 683 bits |= TIOCM_RI; 684 if (mstat & port->sc->csigs->dtr) 685 bits |= TIOCM_DTR; 686 return (bits); 687 } 688 689 /* Only DTR and RTS may be set */ 690 mstat = 0; 691 if (bits & TIOCM_DTR) 692 mstat |= port->sc->csigs->dtr; 693 if (bits & TIOCM_RTS) 694 mstat |= port->sc->csigs->rts; 695 696 switch (how) { 697 case DMSET: 698 fepcmd_b(port, SETMODEM, mstat, ~mstat, 0); 699 break; 700 case DMBIS: 701 fepcmd_b(port, SETMODEM, mstat, 0, 0); 702 break; 703 case DMBIC: 704 fepcmd_b(port, SETMODEM, 0, mstat, 0); 705 break; 706 } 707 708 return (0); 709} 710 711static void 712digi_disc_optim(struct tty *tp, struct termios *t, struct digi_p *port) 713{ 714 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP)) && 715 (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) && 716 (!(t->c_iflag & PARMRK) || 717 (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) && 718 !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) && 719 linesw[tp->t_line].l_rint == ttyinput) 720 tp->t_state |= TS_CAN_BYPASS_L_RINT; 721 else 722 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 723} 724 725int 726digiopen(dev_t dev, int flag, int mode, struct thread *td) 727{ 728 struct digi_softc *sc; 729 struct tty *tp; 730 int unit; 731 int pnum; 732 struct digi_p *port; 733 int s; 734 int error, mynor; 735 volatile struct board_chan *bc; 736 737 error = 0; 738 mynor = minor(dev); 739 unit = MINOR_TO_UNIT(minor(dev)); 740 pnum = MINOR_TO_PORT(minor(dev)); 741 742 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 743 if (!sc) 744 return (ENXIO); 745 746 if (sc->status != DIGI_STATUS_ENABLED) { 747 DLOG(DIGIDB_OPEN, (sc->dev, "Cannot open a disabled card\n")); 748 return (ENXIO); 749 } 750 if (pnum >= sc->numports) { 751 DLOG(DIGIDB_OPEN, (sc->dev, "port%d: Doesn't exist\n", pnum)); 752 return (ENXIO); 753 } 754 if (mynor & (CTRL_DEV | CONTROL_MASK)) { 755 sc->opencnt++; 756 return (0); 757 } 758 port = &sc->ports[pnum]; 759 tp = dev->si_tty = port->tp; 760 bc = port->bc; 761 762 s = spltty(); 763 764open_top: 765 while (port->status & DIGI_DTR_OFF) { 766 port->wopeners++; 767 error = tsleep(&port->dtr_wait, TTIPRI | PCATCH, "digidtr", 0); 768 port->wopeners--; 769 if (error) 770 goto out; 771 } 772 773 if (tp->t_state & TS_ISOPEN) { 774 /* 775 * The device is open, so everything has been initialized. 776 * Handle conflicts. 777 */ 778 if (mynor & CALLOUT_MASK) { 779 if (!port->active_out) { 780 error = EBUSY; 781 DLOG(DIGIDB_OPEN, (sc->dev, "port %d:" 782 " BUSY error = %d\n", pnum, error)); 783 goto out; 784 } 785 } else if (port->active_out) { 786 if (flag & O_NONBLOCK) { 787 error = EBUSY; 788 DLOG(DIGIDB_OPEN, (sc->dev, 789 "port %d: BUSY error = %d\n", pnum, error)); 790 goto out; 791 } 792 port->wopeners++; 793 error = tsleep(&port->active_out, TTIPRI | PCATCH, 794 "digibi", 0); 795 port->wopeners--; 796 if (error != 0) { 797 DLOG(DIGIDB_OPEN, (sc->dev, 798 "port %d: tsleep(digibi) error = %d\n", 799 pnum, error)); 800 goto out; 801 } 802 goto open_top; 803 } 804 if (tp->t_state & TS_XCLUDE && td->td_proc->p_ucred->cr_uid != 0) { 805 error = EBUSY; 806 goto out; 807 } 808 } else { 809 /* 810 * The device isn't open, so there are no conflicts. 811 * Initialize it. Initialization is done twice in many 812 * cases: to preempt sleeping callin opens if we are callout, 813 * and to complete a callin open after DCD rises. 814 */ 815 tp->t_oproc = digistart; 816 tp->t_param = digiparam; 817 tp->t_stop = digistop; 818 tp->t_dev = dev; 819 tp->t_termios = (mynor & CALLOUT_MASK) ? 820 port->it_out : port->it_in; 821 sc->setwin(sc, 0); 822 823 bc->rout = bc->rin; /* clear input queue */ 824 bc->idata = 1; 825 bc->iempty = 1; 826 bc->ilow = 1; 827 bc->mint = port->cd | port->sc->csigs->ri; 828 bc->tin = bc->tout; 829 if (port->ialtpin) { 830 port->cd = sc->csigs->dsr; 831 port->dsr = sc->csigs->cd; 832 } else { 833 port->cd = sc->csigs->cd; 834 port->dsr = sc->csigs->dsr; 835 } 836 port->wopeners++; /* XXX required ? */ 837 error = digiparam(tp, &tp->t_termios); 838 port->wopeners--; 839 840 if (error != 0) { 841 DLOG(DIGIDB_OPEN, (sc->dev, 842 "port %d: cxpparam error = %d\n", pnum, error)); 843 goto out; 844 } 845 ttsetwater(tp); 846 847 /* handle fake and initial DCD for callout devices */ 848 849 if (bc->mstat & port->cd || mynor & CALLOUT_MASK) 850 linesw[tp->t_line].l_modem(tp, 1); 851 } 852 853 /* Wait for DCD if necessary */ 854 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK) && 855 !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { 856 port->wopeners++; 857 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "digidcd", 0); 858 port->wopeners--; 859 if (error != 0) { 860 DLOG(DIGIDB_OPEN, (sc->dev, 861 "port %d: tsleep(digidcd) error = %d\n", 862 pnum, error)); 863 goto out; 864 } 865 goto open_top; 866 } 867 error = linesw[tp->t_line].l_open(dev, tp); 868 DLOG(DIGIDB_OPEN, (sc->dev, "port %d: l_open error = %d\n", 869 pnum, error)); 870 871 digi_disc_optim(tp, &tp->t_termios, port); 872 873 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK) 874 port->active_out = TRUE; 875 876 if (tp->t_state & TS_ISOPEN) 877 sc->opencnt++; 878out: 879 splx(s); 880 881 if (!(tp->t_state & TS_ISOPEN)) 882 digihardclose(port); 883 884 DLOG(DIGIDB_OPEN, (sc->dev, "port %d: open() returns %d\n", 885 pnum, error)); 886 887 return (error); 888} 889 890int 891digiclose(dev_t dev, int flag, int mode, struct thread *td) 892{ 893 int mynor; 894 struct tty *tp; 895 int unit, pnum; 896 struct digi_softc *sc; 897 struct digi_p *port; 898 int s; 899 900 mynor = minor(dev); 901 unit = MINOR_TO_UNIT(mynor); 902 pnum = MINOR_TO_PORT(mynor); 903 904 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 905 KASSERT(sc, ("digi%d: softc not allocated in digiclose\n", unit)); 906 907 if (mynor & (CTRL_DEV | CONTROL_MASK)) { 908 sc->opencnt--; 909 return (0); 910 } 911 912 port = sc->ports + pnum; 913 tp = port->tp; 914 915 DLOG(DIGIDB_CLOSE, (sc->dev, "port %d: closing\n", pnum)); 916 917 s = spltty(); 918 linesw[tp->t_line].l_close(tp, flag); 919 digi_disc_optim(tp, &tp->t_termios, port); 920 digistop(tp, FREAD | FWRITE); 921 digihardclose(port); 922 ttyclose(tp); 923 if (--sc->opencnt == 0) 924 splx(s); 925 return (0); 926} 927 928static void 929digidtrwakeup(void *chan) 930{ 931 struct digi_p *port = chan; 932 933 port->status &= ~DIGI_DTR_OFF; 934 wakeup(&port->dtr_wait); 935 port->wopeners--; 936} 937 938static void 939digihardclose(struct digi_p *port) 940{ 941 volatile struct board_chan *bc; 942 int s; 943 944 bc = port->bc; 945 946 s = spltty(); 947 port->sc->setwin(port->sc, 0); 948 bc->idata = 0; 949 bc->iempty = 0; 950 bc->ilow = 0; 951 bc->mint = 0; 952 if ((port->tp->t_cflag & HUPCL) || 953 (!port->active_out && !(bc->mstat & port->cd) && 954 !(port->it_in.c_cflag & CLOCAL)) || 955 !(port->tp->t_state & TS_ISOPEN)) { 956 digimctl(port, TIOCM_DTR | TIOCM_RTS, DMBIC); 957 if (port->dtr_wait != 0) { 958 /* Schedule a wakeup of any callin devices */ 959 port->wopeners++; 960 timeout(&digidtrwakeup, port, port->dtr_wait); 961 port->status |= DIGI_DTR_OFF; 962 } 963 } 964 port->active_out = FALSE; 965 wakeup(&port->active_out); 966 wakeup(TSA_CARR_ON(port->tp)); 967 splx(s); 968} 969 970int 971digiread(dev_t dev, struct uio *uio, int flag) 972{ 973 int mynor; 974 struct tty *tp; 975 int error, unit, pnum; 976 struct digi_softc *sc; 977 978 mynor = minor(dev); 979 if (mynor & CONTROL_MASK) 980 return (ENODEV); 981 982 unit = MINOR_TO_UNIT(mynor); 983 pnum = MINOR_TO_PORT(mynor); 984 985 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 986 KASSERT(sc, ("digi%d: softc not allocated in digiclose\n", unit)); 987 tp = &sc->ttys[pnum]; 988 989 error = linesw[tp->t_line].l_read(tp, uio, flag); 990 DLOG(DIGIDB_READ, (sc->dev, "port %d: read() returns %d\n", 991 pnum, error)); 992 993 return (error); 994} 995 996int 997digiwrite(dev_t dev, struct uio *uio, int flag) 998{ 999 int mynor; 1000 struct tty *tp; 1001 int error, unit, pnum; 1002 struct digi_softc *sc; 1003 1004 mynor = minor(dev); 1005 if (mynor & CONTROL_MASK) 1006 return (ENODEV); 1007 1008 unit = MINOR_TO_UNIT(mynor); 1009 pnum = MINOR_TO_PORT(mynor); 1010 1011 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 1012 KASSERT(sc, ("digi%d: softc not allocated in digiclose\n", unit)); 1013 tp = &sc->ttys[pnum]; 1014 1015 error = linesw[tp->t_line].l_write(tp, uio, flag); 1016 DLOG(DIGIDB_WRITE, (sc->dev, "port %d: write() returns %d\n", 1017 pnum, error)); 1018 1019 return (error); 1020} 1021 1022/* 1023 * Load module "digi_<mod>.ko" and look for a symbol called digi_mod_<mod>. 1024 * 1025 * Populate sc->bios, sc->fep, and sc->link from this data. 1026 * 1027 * sc->fep.data, sc->bios.data and sc->link.data are malloc()d according 1028 * to their respective sizes. 1029 * 1030 * The module is unloaded when we're done. 1031 */ 1032static int 1033digi_loadmoduledata(struct digi_softc *sc) 1034{ 1035 struct digi_mod *digi_mod; 1036 linker_file_t lf; 1037 char *modfile, *sym; 1038 caddr_t symptr; 1039 int modlen, res; 1040 1041 KASSERT(sc->bios.data == NULL, ("Uninitialised BIOS variable")); 1042 KASSERT(sc->fep.data == NULL, ("Uninitialised FEP variable")); 1043 KASSERT(sc->link.data == NULL, ("Uninitialised LINK variable")); 1044 KASSERT(sc->module != NULL, ("Uninitialised module name")); 1045 1046 modlen = strlen(sc->module); 1047 modfile = malloc(modlen + 6, M_TEMP, M_WAITOK); 1048 snprintf(modfile, modlen + 6, "digi_%s", sc->module); 1049 if ((res = linker_reference_module(modfile, &lf)) != 0) 1050 printf("%s: Failed %d to load module\n", modfile, res); 1051 free(modfile, M_TEMP); 1052 if (res != 0) 1053 return (res); 1054 1055 sym = malloc(modlen + 10, M_TEMP, M_WAITOK); 1056 snprintf(sym, modlen + 10, "digi_mod_%s", sc->module); 1057 if ((symptr = linker_file_lookup_symbol(lf, sym, 0)) == NULL) 1058 printf("digi_%s.ko: Symbol `%s' not found\n", sc->module, sym); 1059 free(sym, M_TEMP); 1060 1061 digi_mod = (struct digi_mod *)symptr; 1062 if (digi_mod->dm_version != DIGI_MOD_VERSION) { 1063 printf("digi_%s.ko: Invalid version %d (need %d)\n", 1064 sc->module, digi_mod->dm_version, DIGI_MOD_VERSION); 1065 linker_file_unload(lf); 1066 return (EINVAL); 1067 } 1068 1069 sc->bios.size = digi_mod->dm_bios.size; 1070 if (sc->bios.size != 0 && digi_mod->dm_bios.data != NULL) { 1071 sc->bios.data = malloc(sc->bios.size, M_TTYS, M_WAIT); 1072 bcopy(digi_mod->dm_bios.data, sc->bios.data, sc->bios.size); 1073 } 1074 1075 sc->fep.size = digi_mod->dm_fep.size; 1076 if (sc->fep.size != 0 && digi_mod->dm_fep.data != NULL) { 1077 sc->fep.data = malloc(sc->fep.size, M_TTYS, M_WAIT); 1078 bcopy(digi_mod->dm_fep.data, sc->fep.data, sc->fep.size); 1079 } 1080 1081 sc->link.size = digi_mod->dm_link.size; 1082 if (sc->link.size != 0 && digi_mod->dm_link.data != NULL) { 1083 sc->link.data = malloc(sc->link.size, M_TTYS, M_WAIT); 1084 bcopy(digi_mod->dm_link.data, sc->link.data, sc->link.size); 1085 } 1086 1087 linker_file_unload(lf); 1088 1089 return (0); 1090} 1091 1092static int 1093digiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 1094{ 1095 int unit, pnum, mynor, error, s; 1096 struct digi_softc *sc; 1097 struct digi_p *port; 1098 struct tty *tp; 1099#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1100 int oldcmd; 1101 struct termios term; 1102#endif 1103 1104 mynor = minor(dev); 1105 unit = MINOR_TO_UNIT(mynor); 1106 pnum = MINOR_TO_PORT(mynor); 1107 1108 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 1109 KASSERT(sc, ("digi%d: softc not allocated in digiioctl\n", unit)); 1110 1111 if (sc->status == DIGI_STATUS_DISABLED) 1112 return (ENXIO); 1113 1114 if (mynor & CTRL_DEV) { 1115 switch (cmd) { 1116 case DIGIIO_DEBUG: 1117#ifdef DEBUG 1118 digi_debug = *(int *)data; 1119 return (0); 1120#else 1121 device_printf(sc->dev, "DEBUG not defined\n"); 1122 return (ENXIO); 1123#endif 1124 case DIGIIO_REINIT: 1125 digi_loadmoduledata(sc); 1126 error = digi_init(sc); 1127 digi_freemoduledata(sc); 1128 return (error); 1129 1130 case DIGIIO_MODEL: 1131 *(enum digi_model *)data = sc->model; 1132 return (0); 1133 1134 case DIGIIO_IDENT: 1135 return (copyout(sc->name, *(char **)data, 1136 strlen(sc->name) + 1)); 1137 } 1138 } 1139 1140 if (pnum >= sc->numports) 1141 return (ENXIO); 1142 1143 port = sc->ports + pnum; 1144 if (!(port->status & ENABLED)) 1145 return (ENXIO); 1146 1147 tp = port->tp; 1148 1149 if (mynor & CONTROL_MASK) { 1150 struct termios *ct; 1151 1152 switch (mynor & CONTROL_MASK) { 1153 case CONTROL_INIT_STATE: 1154 ct = (mynor & CALLOUT_MASK) ? 1155 &port->it_out : &port->it_in; 1156 break; 1157 case CONTROL_LOCK_STATE: 1158 ct = (mynor & CALLOUT_MASK) ? 1159 &port->lt_out : &port->lt_in; 1160 break; 1161 default: 1162 return (ENODEV); /* /dev/nodev */ 1163 } 1164 1165 switch (cmd) { 1166 case TIOCSETA: 1167 error = suser_td(td); 1168 if (error != 0) 1169 return (error); 1170 *ct = *(struct termios *)data; 1171 return (0); 1172 1173 case TIOCGETA: 1174 *(struct termios *)data = *ct; 1175 return (0); 1176 1177 case TIOCGETD: 1178 *(int *)data = TTYDISC; 1179 return (0); 1180 1181 case TIOCGWINSZ: 1182 bzero(data, sizeof(struct winsize)); 1183 return (0); 1184 1185 case DIGIIO_GETALTPIN: 1186 switch (mynor & CONTROL_MASK) { 1187 case CONTROL_INIT_STATE: 1188 *(int *)data = port->ialtpin; 1189 break; 1190 1191 case CONTROL_LOCK_STATE: 1192 *(int *)data = port->laltpin; 1193 break; 1194 1195 default: 1196 panic("Confusion when re-testing minor"); 1197 return (ENODEV); 1198 } 1199 return (0); 1200 1201 case DIGIIO_SETALTPIN: 1202 switch (mynor & CONTROL_MASK) { 1203 case CONTROL_INIT_STATE: 1204 if (!port->laltpin) { 1205 port->ialtpin = !!*(int *)data; 1206 DLOG(DIGIDB_SET, (sc->dev, 1207 "port%d: initial ALTPIN %s\n", pnum, 1208 port->ialtpin ? "set" : "cleared")); 1209 } 1210 break; 1211 1212 case CONTROL_LOCK_STATE: 1213 port->laltpin = !!*(int *)data; 1214 DLOG(DIGIDB_SET, (sc->dev, 1215 "port%d: ALTPIN %slocked\n", 1216 pnum, port->laltpin ? "" : "un")); 1217 break; 1218 1219 default: 1220 panic("Confusion when re-testing minor"); 1221 return (ENODEV); 1222 } 1223 return (0); 1224 1225 default: 1226 return (ENOTTY); 1227 } 1228 } 1229 1230 switch (cmd) { 1231 case DIGIIO_GETALTPIN: 1232 *(int *)data = !!(port->dsr == sc->csigs->cd); 1233 return (0); 1234 1235 case DIGIIO_SETALTPIN: 1236 if (!port->laltpin) { 1237 if (*(int *)data) { 1238 DLOG(DIGIDB_SET, (sc->dev, 1239 "port%d: ALTPIN set\n", pnum)); 1240 port->cd = sc->csigs->dsr; 1241 port->dsr = sc->csigs->cd; 1242 } else { 1243 DLOG(DIGIDB_SET, (sc->dev, 1244 "port%d: ALTPIN cleared\n", pnum)); 1245 port->cd = sc->csigs->cd; 1246 port->dsr = sc->csigs->dsr; 1247 } 1248 } 1249 return (0); 1250 } 1251 1252 tp = port->tp; 1253#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1254 term = tp->t_termios; 1255 oldcmd = cmd; 1256 error = ttsetcompat(tp, &cmd, data, &term); 1257 if (error != 0) 1258 return (error); 1259 if (cmd != oldcmd) 1260 data = (caddr_t) & term; 1261#endif 1262 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 1263 int cc; 1264 struct termios *dt; 1265 struct termios *lt; 1266 1267 dt = (struct termios *)data; 1268 lt = (mynor & CALLOUT_MASK) ? &port->lt_out : &port->lt_in; 1269 1270 dt->c_iflag = 1271 (tp->t_iflag & lt->c_iflag) | (dt->c_iflag & ~lt->c_iflag); 1272 dt->c_oflag = 1273 (tp->t_oflag & lt->c_oflag) | (dt->c_oflag & ~lt->c_oflag); 1274 dt->c_cflag = 1275 (tp->t_cflag & lt->c_cflag) | (dt->c_cflag & ~lt->c_cflag); 1276 dt->c_lflag = 1277 (tp->t_lflag & lt->c_lflag) | (dt->c_lflag & ~lt->c_lflag); 1278 port->c_iflag = dt->c_iflag & (IXOFF | IXON | IXANY); 1279 dt->c_iflag &= ~(IXOFF | IXON | IXANY); 1280 for (cc = 0; cc < NCCS; ++cc) 1281 if (lt->c_cc[cc] != 0) 1282 dt->c_cc[cc] = tp->t_cc[cc]; 1283 if (lt->c_ispeed != 0) 1284 dt->c_ispeed = tp->t_ispeed; 1285 if (lt->c_ospeed != 0) 1286 dt->c_ospeed = tp->t_ospeed; 1287 } 1288 error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, td); 1289 if (error == 0 && cmd == TIOCGETA) 1290 ((struct termios *)data)->c_iflag |= port->c_iflag; 1291 1292 if (error >= 0 && error != ENOIOCTL) 1293 return (error); 1294 s = spltty(); 1295 error = ttioctl(tp, cmd, data, flag); 1296 if (error == 0 && cmd == TIOCGETA) 1297 ((struct termios *)data)->c_iflag |= port->c_iflag; 1298 1299 digi_disc_optim(tp, &tp->t_termios, port); 1300 if (error >= 0 && error != ENOIOCTL) { 1301 splx(s); 1302 return (error); 1303 } 1304 sc->setwin(sc, 0); 1305 switch (cmd) { 1306 case DIGIIO_RING: 1307 port->send_ring = *(u_char *)data; 1308 break; 1309 case TIOCSBRK: 1310 /* 1311 * now it sends 400 millisecond break because I don't know 1312 * how to send an infinite break 1313 */ 1314 fepcmd_w(port, SENDBREAK, 400, 10); 1315 break; 1316 case TIOCCBRK: 1317 /* now it's empty */ 1318 break; 1319 case TIOCSDTR: 1320 digimctl(port, TIOCM_DTR, DMBIS); 1321 break; 1322 case TIOCCDTR: 1323 digimctl(port, TIOCM_DTR, DMBIC); 1324 break; 1325 case TIOCMSET: 1326 digimctl(port, *(int *)data, DMSET); 1327 break; 1328 case TIOCMBIS: 1329 digimctl(port, *(int *)data, DMBIS); 1330 break; 1331 case TIOCMBIC: 1332 digimctl(port, *(int *)data, DMBIC); 1333 break; 1334 case TIOCMGET: 1335 *(int *)data = digimctl(port, 0, DMGET); 1336 break; 1337 case TIOCMSDTRWAIT: 1338 error = suser_td(td); 1339 if (error != 0) { 1340 splx(s); 1341 return (error); 1342 } 1343 port->dtr_wait = *(int *)data *hz / 100; 1344 1345 break; 1346 case TIOCMGDTRWAIT: 1347 *(int *)data = port->dtr_wait * 100 / hz; 1348 break; 1349#ifdef DIGI_INTERRUPT 1350 case TIOCTIMESTAMP: 1351 *(struct timeval *)data = sc->intr_timestamp; 1352 1353 break; 1354#endif 1355 default: 1356 splx(s); 1357 return (ENOTTY); 1358 } 1359 splx(s); 1360 return (0); 1361} 1362 1363static int 1364digiparam(struct tty *tp, struct termios *t) 1365{ 1366 int mynor; 1367 int unit; 1368 int pnum; 1369 struct digi_softc *sc; 1370 struct digi_p *port; 1371 int cflag; 1372 int iflag; 1373 int hflow; 1374 int s; 1375 int window; 1376 1377 mynor = minor(tp->t_dev); 1378 unit = MINOR_TO_UNIT(mynor); 1379 pnum = MINOR_TO_PORT(mynor); 1380 1381 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 1382 KASSERT(sc, ("digi%d: softc not allocated in digiparam\n", unit)); 1383 1384 port = &sc->ports[pnum]; 1385 1386 DLOG(DIGIDB_SET, (sc->dev, "port%d: setting parameters\n", pnum)); 1387 1388 if (t->c_ispeed == 0) 1389 t->c_ispeed = t->c_ospeed; 1390 1391 cflag = ttspeedtab(t->c_ospeed, digispeedtab); 1392 1393 if (cflag < 0 || (cflag > 0 && t->c_ispeed != t->c_ospeed)) 1394 return (EINVAL); 1395 1396 s = splclock(); 1397 1398 window = sc->window; 1399 sc->setwin(sc, 0); 1400 1401 if (cflag == 0) { /* hangup */ 1402 DLOG(DIGIDB_SET, (sc->dev, "port%d: hangup\n", pnum)); 1403 digimctl(port, TIOCM_DTR | TIOCM_RTS, DMBIC); 1404 } else { 1405 digimctl(port, TIOCM_DTR | TIOCM_RTS, DMBIS); 1406 1407 DLOG(DIGIDB_SET, (sc->dev, "port%d: CBAUD = %d\n", pnum, 1408 cflag)); 1409 1410#if 0 1411 /* convert flags to sysV-style values */ 1412 if (t->c_cflag & PARODD) 1413 cflag |= 0x0200; 1414 if (t->c_cflag & PARENB) 1415 cflag |= 0x0100; 1416 if (t->c_cflag & CSTOPB) 1417 cflag |= 0x0080; 1418#else 1419 /* convert flags to sysV-style values */ 1420 if (t->c_cflag & PARODD) 1421 cflag |= FEP_PARODD; 1422 if (t->c_cflag & PARENB) 1423 cflag |= FEP_PARENB; 1424 if (t->c_cflag & CSTOPB) 1425 cflag |= FEP_CSTOPB; 1426 if (t->c_cflag & CLOCAL) 1427 cflag |= FEP_CLOCAL; 1428#endif 1429 1430 cflag |= (t->c_cflag & CSIZE) >> 4; 1431 DLOG(DIGIDB_SET, (sc->dev, "port%d: CFLAG = 0x%x\n", pnum, 1432 cflag)); 1433 fepcmd_w(port, SETCFLAGS, (unsigned)cflag, 0); 1434 } 1435 1436 iflag = 1437 t->c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP); 1438 if (port->c_iflag & IXON) 1439 iflag |= 0x400; 1440 if (port->c_iflag & IXANY) 1441 iflag |= 0x800; 1442 if (port->c_iflag & IXOFF) 1443 iflag |= 0x1000; 1444 1445 DLOG(DIGIDB_SET, (sc->dev, "port%d: set iflag = 0x%x\n", pnum, iflag)); 1446 fepcmd_w(port, SETIFLAGS, (unsigned)iflag, 0); 1447 1448 hflow = 0; 1449 if (t->c_cflag & CDTR_IFLOW) 1450 hflow |= sc->csigs->dtr; 1451 if (t->c_cflag & CRTS_IFLOW) 1452 hflow |= sc->csigs->rts; 1453 if (t->c_cflag & CCTS_OFLOW) 1454 hflow |= sc->csigs->cts; 1455 if (t->c_cflag & CDSR_OFLOW) 1456 hflow |= port->dsr; 1457 if (t->c_cflag & CCAR_OFLOW) 1458 hflow |= port->cd; 1459 1460 DLOG(DIGIDB_SET, (sc->dev, "port%d: set hflow = 0x%x\n", pnum, hflow)); 1461 fepcmd_w(port, SETHFLOW, 0xff00 | (unsigned)hflow, 0); 1462 1463 DLOG(DIGIDB_SET, (sc->dev, "port%d: set startc(0x%x), stopc(0x%x)\n", 1464 pnum, t->c_cc[VSTART], t->c_cc[VSTOP])); 1465 fepcmd_b(port, SONOFFC, t->c_cc[VSTART], t->c_cc[VSTOP], 0); 1466 1467 if (sc->window != 0) 1468 sc->towin(sc, 0); 1469 if (window != 0) 1470 sc->towin(sc, window); 1471 splx(s); 1472 1473 return (0); 1474} 1475 1476static void 1477digi_intr(void *vp) 1478{ 1479 struct digi_p *port; 1480 char *cxcon; 1481 struct digi_softc *sc; 1482 int ehead, etail; 1483 volatile struct board_chan *bc; 1484 struct tty *tp; 1485 int head, tail; 1486 int wrapmask; 1487 int size, window; 1488 struct event { 1489 u_char pnum; 1490 u_char event; 1491 u_char mstat; 1492 u_char lstat; 1493 } event; 1494 1495 sc = vp; 1496 1497 if (sc->status != DIGI_STATUS_ENABLED) { 1498 DLOG(DIGIDB_IRQ, (sc->dev, "interrupt on disabled board !\n")); 1499 return; 1500 } 1501 1502#ifdef DIGI_INTERRUPT 1503 microtime(&sc->intr_timestamp); 1504#endif 1505 1506 window = sc->window; 1507 sc->setwin(sc, 0); 1508 1509 if (sc->model >= PCXEM && W(sc->vmem + 0xd00)) { 1510 struct con_bios *con = con_bios_list; 1511 register u_char *ptr; 1512 1513 ptr = sc->vmem + W(sc->vmem + 0xd00); 1514 while (con) { 1515 if (ptr[1] && W(ptr + 2) == W(con->bios + 2)) 1516 /* Not first block -- exact match */ 1517 break; 1518 1519 if (W(ptr + 4) >= W(con->bios + 4) && 1520 W(ptr + 4) <= W(con->bios + 6)) 1521 /* Initial search concetrator BIOS */ 1522 break; 1523 } 1524 1525 if (con == NULL) { 1526 log(LOG_ERR, "digi%d: wanted bios LREV = 0x%04x" 1527 " not found!\n", sc->res.unit, W(ptr + 4)); 1528 W(ptr + 10) = 0; 1529 W(sc->vmem + 0xd00) = 0; 1530 goto eoi; 1531 } 1532 cxcon = con->bios; 1533 W(ptr + 4) = W(cxcon + 4); 1534 W(ptr + 6) = W(cxcon + 6); 1535 if (ptr[1] == 0) 1536 W(ptr + 2) = W(cxcon + 2); 1537 W(ptr + 8) = (ptr[1] << 6) + W(cxcon + 8); 1538 size = W(cxcon + 10) - (ptr[1] << 10); 1539 if (size <= 0) { 1540 W(ptr + 8) = W(cxcon + 8); 1541 W(ptr + 10) = 0; 1542 } else { 1543 if (size > 1024) 1544 size = 1024; 1545 W(ptr + 10) = size; 1546 bcopy(cxcon + (ptr[1] << 10), ptr + 12, size); 1547 } 1548 W(sc->vmem + 0xd00) = 0; 1549 goto eoi; 1550 } 1551 1552 ehead = sc->gdata->ein; 1553 etail = sc->gdata->eout; 1554 if (ehead == etail) { 1555#ifdef DEBUG 1556 sc->intr_count++; 1557 if (sc->intr_count % 6000 == 0) { 1558 DLOG(DIGIDB_IRQ, (sc->dev, 1559 "6000 useless polls %x %x\n", ehead, etail)); 1560 sc->intr_count = 0; 1561 } 1562#endif 1563 goto eoi; 1564 } 1565 while (ehead != etail) { 1566 event = *(volatile struct event *)(sc->memevent + etail); 1567 1568 etail = (etail + 4) & sc->gdata->imax; 1569 1570 if (event.pnum >= sc->numports) { 1571 log(LOG_ERR, "digi%d: port %d: got event" 1572 " on nonexisting port\n", sc->res.unit, 1573 event.pnum); 1574 continue; 1575 } 1576 port = &sc->ports[event.pnum]; 1577 bc = port->bc; 1578 tp = port->tp; 1579 1580 if (!(tp->t_state & TS_ISOPEN) && !port->wopeners) { 1581 DLOG(DIGIDB_IRQ, (sc->dev, 1582 "port %d: event 0x%x on closed port\n", 1583 event.pnum, event.event)); 1584 bc->rout = bc->rin; 1585 bc->idata = 0; 1586 bc->iempty = 0; 1587 bc->ilow = 0; 1588 bc->mint = 0; 1589 continue; 1590 } 1591 if (event.event & ~ALL_IND) 1592 log(LOG_ERR, "digi%d: port%d: ? event 0x%x mstat 0x%x" 1593 " lstat 0x%x\n", sc->res.unit, event.pnum, 1594 event.event, event.mstat, event.lstat); 1595 1596 if (event.event & DATA_IND) { 1597 DLOG(DIGIDB_IRQ, (sc->dev, "port %d: DATA_IND\n", 1598 event.pnum)); 1599 wrapmask = port->rxbufsize - 1; 1600 head = bc->rin; 1601 tail = bc->rout; 1602 1603 size = 0; 1604 if (!(tp->t_state & TS_ISOPEN)) { 1605 bc->rout = head; 1606 goto end_of_data; 1607 } 1608 while (head != tail) { 1609 int top; 1610 1611 DLOG(DIGIDB_INT, (sc->dev, 1612 "port %d: p rx head = %d tail = %d\n", 1613 event.pnum, head, tail)); 1614 top = (head > tail) ? head : wrapmask + 1; 1615 sc->towin(sc, port->rxwin); 1616 size = top - tail; 1617 if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 1618 size = b_to_q((char *)port->rxbuf + 1619 tail, size, &tp->t_rawq); 1620 tail = top - size; 1621 ttwakeup(tp); 1622 } else for (; tail < top;) { 1623 linesw[tp->t_line]. 1624 l_rint(port->rxbuf[tail], tp); 1625 sc->towin(sc, port->rxwin); 1626 size--; 1627 tail++; 1628 if (tp->t_state & TS_TBLOCK) 1629 break; 1630 } 1631 tail &= wrapmask; 1632 sc->setwin(sc, 0); 1633 bc->rout = tail; 1634 head = bc->rin; 1635 if (size) 1636 break; 1637 } 1638 1639 if (bc->orun) { 1640 CE_RECORD(port, CE_OVERRUN); 1641 log(LOG_ERR, "digi%d: port%d: %s\n", 1642 sc->res.unit, event.pnum, 1643 digi_errortxt(CE_OVERRUN)); 1644 bc->orun = 0; 1645 } 1646end_of_data: 1647 if (size) { 1648 tp->t_state |= TS_TBLOCK; 1649 port->status |= PAUSE_RX; 1650 DLOG(DIGIDB_RX, (sc->dev, "port %d: pause RX\n", 1651 event.pnum)); 1652 } else { 1653 bc->idata = 1; 1654 } 1655 } 1656 1657 if (event.event & MODEMCHG_IND) { 1658 DLOG(DIGIDB_MODEM, (sc->dev, "port %d: MODEMCHG_IND\n", 1659 event.pnum)); 1660 1661 if ((event.mstat ^ event.lstat) & port->cd) { 1662 sc->hidewin(sc); 1663 linesw[tp->t_line].l_modem 1664 (tp, event.mstat & port->cd); 1665 sc->setwin(sc, 0); 1666 wakeup(TSA_CARR_ON(tp)); 1667 } 1668 1669 if (event.mstat & sc->csigs->ri) { 1670 DLOG(DIGIDB_RI, (sc->dev, "port %d: RING\n", 1671 event.pnum)); 1672 if (port->send_ring) { 1673 linesw[tp->t_line].l_rint('R', tp); 1674 linesw[tp->t_line].l_rint('I', tp); 1675 linesw[tp->t_line].l_rint('N', tp); 1676 linesw[tp->t_line].l_rint('G', tp); 1677 linesw[tp->t_line].l_rint('\r', tp); 1678 linesw[tp->t_line].l_rint('\n', tp); 1679 } 1680 } 1681 } 1682 if (event.event & BREAK_IND) { 1683 DLOG(DIGIDB_MODEM, (sc->dev, "port %d: BREAK_IND\n", 1684 event.pnum)); 1685 linesw[tp->t_line].l_rint(TTY_BI, tp); 1686 } 1687 if (event.event & (LOWTX_IND | EMPTYTX_IND)) { 1688 DLOG(DIGIDB_IRQ, (sc->dev, "port %d:%s%s\n", 1689 event.pnum, 1690 event.event & LOWTX_IND ? " LOWTX" : "", 1691 event.event & EMPTYTX_IND ? " EMPTYTX" : "")); 1692 (*linesw[tp->t_line].l_start)(tp); 1693 } 1694 } 1695 sc->gdata->eout = etail; 1696eoi: 1697 if (sc->window != 0) 1698 sc->towin(sc, 0); 1699 if (window != 0) 1700 sc->towin(sc, window); 1701} 1702 1703static void 1704digistart(struct tty *tp) 1705{ 1706 int unit; 1707 int pnum; 1708 struct digi_p *port; 1709 struct digi_softc *sc; 1710 volatile struct board_chan *bc; 1711 int head, tail; 1712 int size, ocount, totcnt = 0; 1713 int s; 1714 int wmask; 1715 1716 unit = MINOR_TO_UNIT(minor(tp->t_dev)); 1717 pnum = MINOR_TO_PORT(minor(tp->t_dev)); 1718 1719 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 1720 KASSERT(sc, ("digi%d: softc not allocated in digistart\n", unit)); 1721 1722 port = &sc->ports[pnum]; 1723 bc = port->bc; 1724 1725 wmask = port->txbufsize - 1; 1726 1727 s = spltty(); 1728 port->lcc = tp->t_outq.c_cc; 1729 sc->setwin(sc, 0); 1730 if (!(tp->t_state & TS_TBLOCK)) { 1731 if (port->status & PAUSE_RX) { 1732 DLOG(DIGIDB_RX, (sc->dev, "port %d: resume RX\n", 1733 pnum)); 1734 /* 1735 * CAREFUL - braces are needed here if the DLOG is 1736 * optimised out! 1737 */ 1738 } 1739 port->status &= ~PAUSE_RX; 1740 bc->idata = 1; 1741 } 1742 if (!(tp->t_state & TS_TTSTOP) && port->status & PAUSE_TX) { 1743 DLOG(DIGIDB_TX, (sc->dev, "port %d: resume TX\n", pnum)); 1744 port->status &= ~PAUSE_TX; 1745 fepcmd_w(port, RESUMETX, 0, 10); 1746 } 1747 if (tp->t_outq.c_cc == 0) 1748 tp->t_state &= ~TS_BUSY; 1749 else 1750 tp->t_state |= TS_BUSY; 1751 1752 head = bc->tin; 1753 while (tp->t_outq.c_cc != 0) { 1754 tail = bc->tout; 1755 DLOG(DIGIDB_INT, (sc->dev, "port%d: s tx head = %d tail = %d\n", 1756 pnum, head, tail)); 1757 1758 if (head < tail) 1759 size = tail - head - 1; 1760 else { 1761 size = port->txbufsize - head; 1762 if (tail == 0) 1763 size--; 1764 } 1765 1766 if (size == 0) 1767 break; 1768 sc->towin(sc, port->txwin); 1769 ocount = q_to_b(&tp->t_outq, port->txbuf + head, size); 1770 totcnt += ocount; 1771 head += ocount; 1772 head &= wmask; 1773 sc->setwin(sc, 0); 1774 bc->tin = head; 1775 bc->iempty = 1; 1776 bc->ilow = 1; 1777 } 1778 port->lostcc = tp->t_outq.c_cc; 1779 tail = bc->tout; 1780 if (head < tail) 1781 size = port->txbufsize - tail + head; 1782 else 1783 size = head - tail; 1784 1785 port->lbuf = size; 1786 DLOG(DIGIDB_INT, (sc->dev, "port%d: s total cnt = %d\n", pnum, totcnt)); 1787 ttwwakeup(tp); 1788 splx(s); 1789} 1790 1791static void 1792digistop(struct tty *tp, int rw) 1793{ 1794 struct digi_softc *sc; 1795 int unit; 1796 int pnum; 1797 struct digi_p *port; 1798 1799 unit = MINOR_TO_UNIT(minor(tp->t_dev)); 1800 pnum = MINOR_TO_PORT(minor(tp->t_dev)); 1801 1802 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit); 1803 KASSERT(sc, ("digi%d: softc not allocated in digistop\n", unit)); 1804 port = sc->ports + pnum; 1805 1806 DLOG(DIGIDB_TX, (sc->dev, "port %d: pause TX\n", pnum)); 1807 port->status |= PAUSE_TX; 1808 fepcmd_w(port, PAUSETX, 0, 10); 1809} 1810 1811static void 1812fepcmd(struct digi_p *port, int cmd, int op1, int ncmds) 1813{ 1814 u_char *mem; 1815 unsigned tail, head; 1816 int count, n; 1817 1818 mem = port->sc->memcmd; 1819 1820 port->sc->setwin(port->sc, 0); 1821 1822 head = port->sc->gdata->cin; 1823 mem[head + 0] = cmd; 1824 mem[head + 1] = port->pnum; 1825 *(ushort *)(mem + head + 2) = op1; 1826 1827 head = (head + 4) & port->sc->gdata->cmax; 1828 port->sc->gdata->cin = head; 1829 1830 for (count = FEPTIMEOUT; count > 0; count--) { 1831 head = port->sc->gdata->cin; 1832 tail = port->sc->gdata->cout; 1833 n = (head - tail) & port->sc->gdata->cmax; 1834 1835 if (n <= ncmds * sizeof(short) * 4) 1836 break; 1837 } 1838 if (count == 0) 1839 log(LOG_ERR, "digi%d: port%d: timeout on FEP command\n", 1840 port->sc->res.unit, port->pnum); 1841} 1842 1843const char * 1844digi_errortxt(int id) 1845{ 1846 static const char *error_desc[] = { 1847 "silo overflow", 1848 "interrupt-level buffer overflow", 1849 "tty-level buffer overflow", 1850 }; 1851 1852 KASSERT(id >= 0 && id < sizeof(error_desc) / sizeof(error_desc[0]), 1853 ("Unexpected digi error id %d\n", id)); 1854 1855 return (error_desc[id]); 1856} 1857 1858int 1859digi_attach(struct digi_softc *sc) 1860{ 1861 sc->res.ctldev = make_dev(&digi_sw, 1862 (sc->res.unit << 16) | CTRL_DEV, UID_ROOT, GID_WHEEL, 1863 0600, "digi%r.ctl", sc->res.unit); 1864 1865 digi_loadmoduledata(sc); 1866 digi_init(sc); 1867 digi_freemoduledata(sc); 1868 1869 return (0); 1870} 1871 1872static int 1873digi_inuse(struct digi_softc *sc) 1874{ 1875 int i; 1876 1877 for (i = 0; i < sc->numports; i++) 1878 if (sc->ttys[i].t_state & TS_ISOPEN) { 1879 DLOG(DIGIDB_INIT, (sc->dev, "port%d: busy\n", i)); 1880 return (1); 1881 } else if (sc->ports[i].wopeners || sc->ports[i].opencnt) { 1882 DLOG(DIGIDB_INIT, (sc->dev, "port%d: blocked in open\n", 1883 i)); 1884 return (1); 1885 } 1886 return (0); 1887} 1888 1889static void 1890digi_free_state(struct digi_softc *sc) 1891{ 1892 int d, i; 1893 1894 /* Blow it all away */ 1895 1896 for (i = 0; i < sc->numports; i++) 1897 for (d = 0; d < 6; d++) 1898 destroy_dev(sc->ports[i].dev[d]); 1899 1900 untimeout(digi_poll, sc, sc->callout); 1901 callout_handle_init(&sc->callout); 1902 untimeout(digi_int_test, sc, sc->inttest); 1903 callout_handle_init(&sc->inttest); 1904 1905 bus_teardown_intr(sc->dev, sc->res.irq, sc->res.irqHandler); 1906#ifdef DIGI_INTERRUPT 1907 if (sc->res.irq != NULL) { 1908 bus_release_resource(dev, SYS_RES_IRQ, sc->res.irqrid, 1909 sc->res.irq); 1910 sc->res.irq = NULL; 1911 } 1912#endif 1913 if (sc->numports) { 1914 KASSERT(sc->ports, ("digi%d: Lost my ports ?", sc->res.unit)); 1915 KASSERT(sc->ttys, ("digi%d: Lost my ttys ?", sc->res.unit)); 1916 free(sc->ports, M_TTYS); 1917 sc->ports = NULL; 1918 free(sc->ttys, M_TTYS); 1919 sc->ttys = NULL; 1920 sc->numports = 0; 1921 } 1922 1923 sc->status = DIGI_STATUS_NOTINIT; 1924} 1925 1926int 1927digi_detach(device_t dev) 1928{ 1929 struct digi_softc *sc = device_get_softc(dev); 1930 1931 DLOG(DIGIDB_INIT, (sc->dev, "detaching\n")); 1932 1933 /* If we're INIT'd, numports must be 0 */ 1934 KASSERT(sc->numports == 0 || sc->status != DIGI_STATUS_NOTINIT, 1935 ("digi%d: numports(%d) & status(%d) are out of sync", 1936 sc->res.unit, sc->numports, (int)sc->status)); 1937 1938 if (digi_inuse(sc)) 1939 return (EBUSY); 1940 1941 digi_free_state(sc); 1942 1943 destroy_dev(makedev(CDEV_MAJOR, 1944 (sc->res.unit << 16) | CTRL_DEV)); 1945 1946 if (sc->res.mem != NULL) { 1947 bus_release_resource(dev, SYS_RES_MEMORY, sc->res.mrid, 1948 sc->res.mem); 1949 sc->res.mem = NULL; 1950 } 1951 if (sc->res.io != NULL) { 1952 bus_release_resource(dev, SYS_RES_IOPORT, sc->res.iorid, 1953 sc->res.io); 1954 sc->res.io = NULL; 1955 } 1956 1957 return (0); 1958} 1959 1960int 1961digi_shutdown(device_t dev) 1962{ 1963 return (0); 1964} 1965