kernel: Remove use of deprecated "%r" radix format.
[dragonfly.git] / sys / dev / serial / digi / digi.c
bloba99bddbcf385d7ba070a6ead256c969805898545
1 /*-
2 * (MPSAFE)
4 * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
5 * based on work by Slawa Olhovchenkov
6 * John Prince <johnp@knight-trosoft.com>
7 * Eric Hernes
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 * $FreeBSD: src/sys/dev/digi/digi.c,v 1.36 2003/09/26 09:05:57 phk Exp $
34 /*-
35 * TODO:
36 * Figure out what the con bios stuff is supposed to do
37 * Test with *LOTS* more cards - I only have a PCI8r and an ISA Xem.
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/proc.h>
43 #include <sys/priv.h>
44 #include <sys/conf.h>
45 #include <sys/linker.h>
46 #include <sys/kernel.h>
47 #include <sys/mbuf.h>
48 #include <sys/malloc.h>
49 #include <sys/tty.h>
50 #include <sys/syslog.h>
51 #include <sys/fcntl.h>
52 #include <sys/bus.h>
53 #include <sys/thread2.h>
55 #include <vm/vm.h>
56 #include <vm/pmap.h>
58 #include <dev/serial/digi/digiio.h>
59 #include <dev/serial/digi/digireg.h>
60 #include <dev/serial/digi/digi.h>
61 #include <dev/serial/digi/digi_pci.h>
62 #include <dev/serial/digi/digi_bios.h>
64 #define CTRL_DEV 0x800000
65 #define CALLOUT_MASK 0x400000
66 #define CONTROL_INIT_STATE 0x100000
67 #define CONTROL_LOCK_STATE 0x200000
68 #define CONTROL_MASK (CTRL_DEV|CONTROL_INIT_STATE|CONTROL_LOCK_STATE)
69 #define UNIT_MASK 0x030000
70 #define PORT_MASK 0x0000FF
71 #define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
72 #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
73 #define MINOR_TO_UNIT(mynor) (((mynor) & UNIT_MASK)>>16)
74 #define MINOR_TO_PORT(mynor) ((mynor) & PORT_MASK)
76 static d_open_t digiopen;
77 static d_close_t digiclose;
78 static d_read_t digiread;
79 static d_write_t digiwrite;
80 static d_ioctl_t digiioctl;
82 static void digistop(struct tty *tp, int rw);
83 static int digimctl(struct digi_p *port, int bits, int how);
84 static void digi_poll(void *ptr);
85 static void digi_freedata(struct digi_softc *);
86 static void fepcmd(struct digi_p *port, int cmd, int op, int ncmds);
87 static void digistart(struct tty *tp);
88 static int digiparam(struct tty *tp, struct termios *t);
89 static void digihardclose(struct digi_p *port);
90 static void digi_intr(void *);
91 static int digi_init(struct digi_softc *_sc);
92 static int digi_loaddata(struct digi_softc *);
93 static int digi_inuse(struct digi_softc *);
94 static void digi_free_state(struct digi_softc *);
96 #define fepcmd_b(port, cmd, op1, op2, ncmds) \
97 fepcmd(port, cmd, (op2 << 8) | op1, ncmds)
98 #define fepcmd_w fepcmd
101 static speed_t digidefaultrate = TTYDEF_SPEED;
103 struct con_bios {
104 struct con_bios *next;
105 u_char *bios;
106 size_t size;
109 static struct con_bios *con_bios_list;
110 devclass_t digi_devclass;
111 unsigned digi_debug = 0;
113 static struct speedtab digispeedtab[] = {
114 { 0, 0}, /* old (sysV-like) Bx codes */
115 { 50, 1},
116 { 75, 2},
117 { 110, 3},
118 { 134, 4},
119 { 150, 5},
120 { 200, 6},
121 { 300, 7},
122 { 600, 8},
123 { 1200, 9},
124 { 1800, 10},
125 { 2400, 11},
126 { 4800, 12},
127 { 9600, 13},
128 { 19200, 14},
129 { 38400, 15},
130 { 57600, (02000 | 1)},
131 { 76800, (02000 | 2)},
132 { 115200, (02000 | 3)},
133 { 230400, (02000 | 6)},
134 { -1, -1}
137 const struct digi_control_signals digi_xixe_signals = {
138 0x02, 0x08, 0x10, 0x20, 0x40, 0x80
141 const struct digi_control_signals digi_normal_signals = {
142 0x02, 0x80, 0x20, 0x10, 0x40, 0x01
145 static struct dev_ops digi_ops = {
146 { "dgm", 0, D_TTY },
147 .d_open = digiopen,
148 .d_close = digiclose,
149 .d_read = digiread,
150 .d_write = digiwrite,
151 .d_ioctl = digiioctl,
152 .d_kqfilter = ttykqfilter,
153 .d_revoke = ttyrevoke
156 static void
157 digi_poll(void *ptr)
159 struct digi_softc *sc;
161 sc = (struct digi_softc *)ptr;
162 callout_init_mp(&sc->callout);
163 digi_intr(sc);
164 callout_reset(&sc->callout, (hz >= 200) ? hz / 100 : 1, digi_poll, sc);
167 static void
168 digi_int_test(void *v)
170 struct digi_softc *sc = v;
172 callout_init_mp(&sc->inttest);
173 #ifdef DIGI_INTERRUPT
174 if (sc->intr_timestamp.tv_sec || sc->intr_timestamp.tv_usec) {
175 /* interrupt OK! */
176 return;
178 log(LOG_ERR, "digi%d: Interrupt didn't work, use polled mode\n", unit);
179 #endif
180 callout_reset(&sc->callout, (hz >= 200) ? hz / 100 : 1, digi_poll, sc);
183 static void
184 digi_freedata(struct digi_softc *sc)
186 if (sc->fep.data != NULL) {
187 kfree(sc->fep.data, M_TTYS);
188 sc->fep.data = NULL;
190 if (sc->link.data != NULL) {
191 kfree(sc->link.data, M_TTYS);
192 sc->link.data = NULL;
194 if (sc->bios.data != NULL) {
195 kfree(sc->bios.data, M_TTYS);
196 sc->bios.data = NULL;
200 static int
201 digi_bcopy(const void *vfrom, void *vto, size_t sz)
203 volatile const char *from = (volatile const char *)vfrom;
204 volatile char *to = (volatile char *)vto;
205 size_t i;
207 for (i = 0; i < sz; i++)
208 *to++ = *from++;
210 from = (const volatile char *)vfrom;
211 to = (volatile char *)vto;
212 for (i = 0; i < sz; i++)
213 if (*to++ != *from++)
214 return (0);
215 return (1);
218 void
219 digi_delay(struct digi_softc *sc, const char *txt, u_long timo)
221 if (cold)
222 DELAY(timo * 1000000 / hz);
223 else
224 tsleep(sc, PCATCH, txt, timo);
228 * NOTE: Must be called with tty_token held
230 static int
231 digi_init(struct digi_softc *sc)
233 int i, cnt, resp;
234 u_char *ptr;
235 int lowwater;
236 struct digi_p *port;
237 volatile struct board_chan *bc;
239 ASSERT_LWKT_TOKEN_HELD(&tty_token);
240 ptr = NULL;
242 if (sc->status == DIGI_STATUS_DISABLED) {
243 log(LOG_ERR, "digi%d: Cannot init a disabled card\n",
244 sc->res.unit);
245 return (EIO);
247 if (sc->bios.data == NULL) {
248 log(LOG_ERR, "digi%d: Cannot init without BIOS\n",
249 sc->res.unit);
250 return (EIO);
252 #if 0
253 if (sc->link.data == NULL && sc->model >= PCCX) {
254 log(LOG_ERR, "digi%d: Cannot init without link info\n",
255 sc->res.unit);
256 return (EIO);
258 #endif
259 if (sc->fep.data == NULL) {
260 log(LOG_ERR, "digi%d: Cannot init without fep code\n",
261 sc->res.unit);
262 return (EIO);
264 sc->status = DIGI_STATUS_NOTINIT;
266 if (sc->numports) {
268 * We're re-initialising - maybe because someone's attached
269 * another port module. For now, we just re-initialise
270 * everything.
272 if (digi_inuse(sc))
273 return (EBUSY);
275 digi_free_state(sc);
278 ptr = sc->setwin(sc, MISCGLOBAL);
279 for (i = 0; i < 16; i += 2)
280 vW(ptr + i) = 0;
282 switch (sc->model) {
283 case PCXEVE:
284 outb(sc->wport, 0xff); /* window 7 */
285 ptr = sc->vmem + (BIOSCODE & 0x1fff);
287 if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) {
288 device_printf(sc->dev, "BIOS upload failed\n");
289 return (EIO);
292 outb(sc->port, FEPCLR);
293 break;
295 case PCXE:
296 case PCXI:
297 case PCCX:
298 ptr = sc->setwin(sc, BIOSCODE + ((0xf000 - sc->mem_seg) << 4));
299 if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) {
300 device_printf(sc->dev, "BIOS upload failed\n");
301 return (EIO);
303 break;
305 case PCXEM:
306 case PCIEPCX:
307 case PCIXR:
308 if (sc->pcibus)
309 PCIPORT = FEPRST;
310 else
311 outb(sc->port, FEPRST | FEPMEM);
313 for (i = 0; ((sc->pcibus ? PCIPORT : inb(sc->port)) &
314 FEPMASK) != FEPRST; i++) {
315 if (i > hz) {
316 log(LOG_ERR, "digi%d: %s init reset failed\n",
317 sc->res.unit, sc->name);
318 return (EIO);
320 digi_delay(sc, "digiinit0", 5);
322 DLOG(DIGIDB_INIT, (sc->dev, "Got init reset after %d us\n", i));
324 /* Now upload the BIOS */
325 cnt = (sc->bios.size < sc->win_size - BIOSOFFSET) ?
326 sc->bios.size : sc->win_size - BIOSOFFSET;
328 ptr = sc->setwin(sc, BIOSOFFSET);
329 if (!digi_bcopy(sc->bios.data, ptr, cnt)) {
330 device_printf(sc->dev, "BIOS upload (1) failed\n");
331 return (EIO);
334 if (cnt != sc->bios.size) {
335 /* and the second part */
336 ptr = sc->setwin(sc, sc->win_size);
337 if (!digi_bcopy(sc->bios.data + cnt, ptr,
338 sc->bios.size - cnt)) {
339 device_printf(sc->dev, "BIOS upload failed\n");
340 return (EIO);
344 ptr = sc->setwin(sc, 0);
345 vW(ptr + 0) = 0x0401;
346 vW(ptr + 2) = 0x0bf0;
347 vW(ptr + 4) = 0x0000;
348 vW(ptr + 6) = 0x0000;
350 break;
353 DLOG(DIGIDB_INIT, (sc->dev, "BIOS uploaded\n"));
355 ptr = sc->setwin(sc, MISCGLOBAL);
356 W(ptr) = 0;
358 if (sc->pcibus) {
359 PCIPORT = FEPCLR;
360 resp = FEPRST;
361 } else if (sc->model == PCXEVE) {
362 outb(sc->port, FEPCLR);
363 resp = FEPRST;
364 } else {
365 outb(sc->port, FEPCLR | FEPMEM);
366 resp = FEPRST | FEPMEM;
369 for (i = 0; ((sc->pcibus ? PCIPORT : inb(sc->port)) & FEPMASK)
370 == resp; i++) {
371 if (i > hz) {
372 log(LOG_ERR, "digi%d: BIOS start failed\n",
373 sc->res.unit);
374 return (EIO);
376 digi_delay(sc, "digibios0", 5);
379 DLOG(DIGIDB_INIT, (sc->dev, "BIOS started after %d us\n", i));
381 for (i = 0; vW(ptr) != *(u_short *)"GD"; i++) {
382 if (i > 2*hz) {
383 log(LOG_ERR, "digi%d: BIOS boot failed "
384 "(0x%02x != 0x%02x)\n",
385 sc->res.unit, vW(ptr), *(u_short *)"GD");
386 return (EIO);
388 digi_delay(sc, "digibios1", 5);
391 DLOG(DIGIDB_INIT, (sc->dev, "BIOS booted after %d iterations\n", i));
393 if (sc->link.data != NULL) {
394 DLOG(DIGIDB_INIT, (sc->dev, "Loading link data\n"));
395 ptr = sc->setwin(sc, 0xcd0);
396 digi_bcopy(sc->link.data, ptr, 21); /* XXX 21 ? */
399 /* load FEP/OS */
401 switch (sc->model) {
402 case PCXE:
403 case PCXEVE:
404 case PCXI:
405 ptr = sc->setwin(sc, sc->model == PCXI ? 0x2000 : 0x0);
406 digi_bcopy(sc->fep.data, ptr, sc->fep.size);
408 /* A BIOS request to move our data to 0x2000 */
409 ptr = sc->setwin(sc, MBOX);
410 vW(ptr + 0) = 2;
411 vW(ptr + 2) = sc->mem_seg + FEPCODESEG;
412 vW(ptr + 4) = 0;
413 vW(ptr + 6) = FEPCODESEG;
414 vW(ptr + 8) = 0;
415 vW(ptr + 10) = sc->fep.size;
417 /* Run the BIOS request */
418 outb(sc->port, FEPREQ | FEPMEM);
419 outb(sc->port, FEPCLR | FEPMEM);
421 for (i = 0; W(ptr); i++) {
422 if (i > hz) {
423 log(LOG_ERR, "digi%d: FEP/OS move failed\n",
424 sc->res.unit);
425 sc->hidewin(sc);
426 return (EIO);
428 digi_delay(sc, "digifep0", 5);
430 DLOG(DIGIDB_INIT,
431 (sc->dev, "FEP/OS moved after %d iterations\n", i));
433 /* Clear the confirm word */
434 ptr = sc->setwin(sc, FEPSTAT);
435 vW(ptr + 0) = 0;
437 /* A BIOS request to execute the FEP/OS */
438 ptr = sc->setwin(sc, MBOX);
439 vW(ptr + 0) = 0x01;
440 vW(ptr + 2) = FEPCODESEG;
441 vW(ptr + 4) = 0x04;
443 /* Run the BIOS request */
444 outb(sc->port, FEPREQ);
445 outb(sc->port, FEPCLR);
447 ptr = sc->setwin(sc, FEPSTAT);
449 break;
451 case PCXEM:
452 case PCIEPCX:
453 case PCIXR:
454 DLOG(DIGIDB_INIT, (sc->dev, "Loading FEP/OS\n"));
456 cnt = (sc->fep.size < sc->win_size - BIOSOFFSET) ?
457 sc->fep.size : sc->win_size - BIOSOFFSET;
459 ptr = sc->setwin(sc, BIOSOFFSET);
460 digi_bcopy(sc->fep.data, ptr, cnt);
462 if (cnt != sc->fep.size) {
463 ptr = sc->setwin(sc, BIOSOFFSET + cnt);
464 digi_bcopy(sc->fep.data + cnt, ptr,
465 sc->fep.size - cnt);
468 DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS loaded\n"));
470 ptr = sc->setwin(sc, 0xc30);
471 W(ptr + 4) = 0x1004;
472 W(ptr + 6) = 0xbfc0;
473 W(ptr + 0) = 0x03;
474 W(ptr + 2) = 0x00;
476 /* Clear the confirm word */
477 ptr = sc->setwin(sc, FEPSTAT);
478 W(ptr + 0) = 0;
480 if (sc->port)
481 outb(sc->port, 0); /* XXX necessary ? */
483 break;
485 case PCCX:
486 ptr = sc->setwin(sc, 0xd000);
487 digi_bcopy(sc->fep.data, ptr, sc->fep.size);
489 /* A BIOS request to execute the FEP/OS */
490 ptr = sc->setwin(sc, 0xc40);
491 W(ptr + 0) = 1;
492 W(ptr + 2) = FEPCODE >> 4;
493 W(ptr + 4) = 4;
495 /* Clear the confirm word */
496 ptr = sc->setwin(sc, FEPSTAT);
497 W(ptr + 0) = 0;
499 /* Run the BIOS request */
500 outb(sc->port, FEPREQ | FEPMEM); /* send interrupt to BIOS */
501 outb(sc->port, FEPCLR | FEPMEM);
502 break;
505 /* Now wait 'till the FEP/OS has booted */
506 for (i = 0; vW(ptr) != *(u_short *)"OS"; i++) {
507 if (i > 2*hz) {
508 log(LOG_ERR, "digi%d: FEP/OS start failed "
509 "(0x%02x != 0x%02x)\n",
510 sc->res.unit, vW(ptr), *(u_short *)"OS");
511 sc->hidewin(sc);
512 return (EIO);
514 digi_delay(sc, "digifep1", 5);
517 DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS started after %d iterations\n", i));
519 if (sc->model >= PCXEM) {
520 ptr = sc->setwin(sc, 0xe04);
521 vW(ptr) = 2;
522 ptr = sc->setwin(sc, 0xc02);
523 sc->numports = vW(ptr);
524 } else {
525 ptr = sc->setwin(sc, 0xc22);
526 sc->numports = vW(ptr);
529 if (sc->numports == 0) {
530 device_printf(sc->dev, "%s, 0 ports found\n", sc->name);
531 sc->hidewin(sc);
532 return (0);
535 if (sc->numports > 256) {
536 /* Our minor numbering scheme is broken for more than 256 */
537 device_printf(sc->dev, "%s, 256 ports (%d ports found)\n",
538 sc->name, sc->numports);
539 sc->numports = 256;
540 } else
541 device_printf(sc->dev, "%s, %d ports found\n", sc->name,
542 sc->numports);
544 if (sc->ports)
545 kfree(sc->ports, M_TTYS);
546 sc->ports = kmalloc(sizeof(struct digi_p) * sc->numports,
547 M_TTYS, M_WAITOK | M_ZERO);
549 if (sc->ttys)
550 kfree(sc->ttys, M_TTYS);
551 sc->ttys = kmalloc(sizeof(struct tty) * sc->numports,
552 M_TTYS, M_WAITOK | M_ZERO);
555 * XXX Should read port 0xc90 for an array of 2byte values, 1 per
556 * port. If the value is 0, the port is broken....
559 ptr = sc->setwin(sc, 0);
561 /* We should now init per-port structures */
562 bc = (volatile struct board_chan *)(ptr + CHANSTRUCT);
563 sc->gdata = (volatile struct global_data *)(ptr + FEP_GLOBAL);
565 sc->memcmd = ptr + sc->gdata->cstart;
566 sc->memevent = ptr + sc->gdata->istart;
568 for (i = 0; i < sc->numports; i++, bc++) {
569 port = sc->ports + i;
570 port->pnum = i;
571 port->sc = sc;
572 port->status = ENABLED;
573 port->tp = sc->ttys + i;
574 port->bc = bc;
576 if (sc->model == PCXEVE) {
577 port->txbuf = ptr +
578 (((bc->tseg - sc->mem_seg) << 4) & 0x1fff);
579 port->rxbuf = ptr +
580 (((bc->rseg - sc->mem_seg) << 4) & 0x1fff);
581 port->txwin = FEPWIN | ((bc->tseg - sc->mem_seg) >> 9);
582 port->rxwin = FEPWIN | ((bc->rseg - sc->mem_seg) >> 9);
583 } else if (sc->model == PCXI || sc->model == PCXE) {
584 port->txbuf = ptr + ((bc->tseg - sc->mem_seg) << 4);
585 port->rxbuf = ptr + ((bc->rseg - sc->mem_seg) << 4);
586 port->txwin = port->rxwin = 0;
587 } else {
588 port->txbuf = ptr +
589 (((bc->tseg - sc->mem_seg) << 4) % sc->win_size);
590 port->rxbuf = ptr +
591 (((bc->rseg - sc->mem_seg) << 4) % sc->win_size);
592 port->txwin = FEPWIN |
593 (((bc->tseg - sc->mem_seg) << 4) / sc->win_size);
594 port->rxwin = FEPWIN |
595 (((bc->rseg - sc->mem_seg) << 4) / sc->win_size);
597 port->txbufsize = bc->tmax + 1;
598 port->rxbufsize = bc->rmax + 1;
600 lowwater = port->txbufsize >> 2;
601 if (lowwater > 1024)
602 lowwater = 1024;
603 sc->setwin(sc, 0);
604 fepcmd_w(port, STXLWATER, lowwater, 10);
605 fepcmd_w(port, SRXLWATER, port->rxbufsize >> 2, 10);
606 fepcmd_w(port, SRXHWATER, (3 * port->rxbufsize) >> 2, 10);
608 bc->edelay = 100;
609 port->dtr_wait = 3 * hz;
612 * We don't use all the flags from <sys/ttydefaults.h> since
613 * they are only relevant for logins. It's important to have
614 * echo off initially so that the line doesn't start blathering
615 * before the echo flag can be turned off.
617 port->it_in.c_iflag = 0;
618 port->it_in.c_oflag = 0;
619 port->it_in.c_cflag = TTYDEF_CFLAG;
620 port->it_in.c_lflag = 0;
621 termioschars(&port->it_in);
622 port->it_in.c_ispeed = port->it_in.c_ospeed = digidefaultrate;
623 port->it_out = port->it_in;
624 port->send_ring = 1; /* Default action on signal RI */
626 port->dev[0] = make_dev(&digi_ops, (sc->res.unit << 16) + i,
627 UID_ROOT, GID_WHEEL, 0600, "ttyD%d.%d", sc->res.unit, i);
628 port->dev[1] = make_dev(&digi_ops, ((sc->res.unit << 16) + i) |
629 CONTROL_INIT_STATE, UID_ROOT, GID_WHEEL,
630 0600, "ttyiD%d.%d", sc->res.unit, i);
631 port->dev[2] = make_dev(&digi_ops, ((sc->res.unit << 16) + i) |
632 CONTROL_LOCK_STATE, UID_ROOT, GID_WHEEL,
633 0600, "ttylD%d.%d", sc->res.unit, i);
634 port->dev[3] = make_dev(&digi_ops, ((sc->res.unit << 16) + i) |
635 CALLOUT_MASK, UID_UUCP, GID_DIALER,
636 0660, "cuaD%d.%d", sc->res.unit, i);
637 port->dev[4] = make_dev(&digi_ops, ((sc->res.unit << 16) + i) |
638 CALLOUT_MASK | CONTROL_INIT_STATE, UID_UUCP, GID_DIALER,
639 0660, "cuaiD%d.%d", sc->res.unit, i);
640 port->dev[5] = make_dev(&digi_ops, ((sc->res.unit << 16) + i) |
641 CALLOUT_MASK | CONTROL_LOCK_STATE, UID_UUCP, GID_DIALER,
642 0660, "cualD%d.%d", sc->res.unit, i);
645 sc->hidewin(sc);
646 callout_reset(&sc->inttest, hz, digi_int_test, sc);
647 /* fepcmd_w(&sc->ports[0], 0xff, 0, 0); */
648 sc->status = DIGI_STATUS_ENABLED;
650 return (0);
654 * NOTE: Must be called with tty_token held
656 static int
657 digimctl(struct digi_p *port, int bits, int how)
659 int mstat;
661 ASSERT_LWKT_TOKEN_HELD(&tty_token);
662 if (how == DMGET) {
663 port->sc->setwin(port->sc, 0);
664 mstat = port->bc->mstat;
665 port->sc->hidewin(port->sc);
666 bits = TIOCM_LE;
667 if (mstat & port->sc->csigs->rts)
668 bits |= TIOCM_RTS;
669 if (mstat & port->cd)
670 bits |= TIOCM_CD;
671 if (mstat & port->dsr)
672 bits |= TIOCM_DSR;
673 if (mstat & port->sc->csigs->cts)
674 bits |= TIOCM_CTS;
675 if (mstat & port->sc->csigs->ri)
676 bits |= TIOCM_RI;
677 if (mstat & port->sc->csigs->dtr)
678 bits |= TIOCM_DTR;
679 return (bits);
682 /* Only DTR and RTS may be set */
683 mstat = 0;
684 if (bits & TIOCM_DTR)
685 mstat |= port->sc->csigs->dtr;
686 if (bits & TIOCM_RTS)
687 mstat |= port->sc->csigs->rts;
689 switch (how) {
690 case DMSET:
691 fepcmd_b(port, SETMODEM, mstat, ~mstat, 0);
692 break;
693 case DMBIS:
694 fepcmd_b(port, SETMODEM, mstat, 0, 0);
695 break;
696 case DMBIC:
697 fepcmd_b(port, SETMODEM, 0, mstat, 0);
698 break;
701 return (0);
704 static void
705 digi_disc_optim(struct tty *tp, struct termios *t, struct digi_p *port)
707 lwkt_gettoken(&tty_token);
708 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP)) &&
709 (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) &&
710 (!(t->c_iflag & PARMRK) ||
711 (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) &&
712 !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) &&
713 linesw[tp->t_line].l_rint == ttyinput)
714 tp->t_state |= TS_CAN_BYPASS_L_RINT;
715 else
716 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
717 lwkt_reltoken(&tty_token);
720 static int
721 digiopen(struct dev_open_args *ap)
723 cdev_t dev = ap->a_head.a_dev;
724 struct digi_softc *sc;
725 struct tty *tp;
726 int unit;
727 int pnum;
728 struct digi_p *port;
729 int error, mynor;
730 volatile struct board_chan *bc;
732 error = 0;
733 mynor = minor(dev);
734 unit = MINOR_TO_UNIT(minor(dev));
735 pnum = MINOR_TO_PORT(minor(dev));
737 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit);
738 if (!sc)
739 return (ENXIO);
741 lwkt_gettoken(&tty_token);
742 if (sc->status != DIGI_STATUS_ENABLED) {
743 DLOG(DIGIDB_OPEN, (sc->dev, "Cannot open a disabled card\n"));
744 lwkt_reltoken(&tty_token);
745 return (ENXIO);
747 if (pnum >= sc->numports) {
748 DLOG(DIGIDB_OPEN, (sc->dev, "port%d: Doesn't exist\n", pnum));
749 lwkt_reltoken(&tty_token);
750 return (ENXIO);
752 if (mynor & (CTRL_DEV | CONTROL_MASK)) {
753 sc->opencnt++;
754 lwkt_reltoken(&tty_token);
755 return (0);
757 port = &sc->ports[pnum];
758 tp = dev->si_tty = port->tp;
759 bc = port->bc;
761 crit_enter();
763 open_top:
764 while (port->status & DIGI_DTR_OFF) {
765 port->wopeners++;
766 error = tsleep(&port->dtr_wait, PCATCH, "digidtr", 0);
767 port->wopeners--;
768 if (error)
769 goto out;
772 if (tp->t_state & TS_ISOPEN) {
774 * The device is open, so everything has been initialized.
775 * Handle conflicts.
777 if (mynor & CALLOUT_MASK) {
778 if (!port->active_out) {
779 error = EBUSY;
780 DLOG(DIGIDB_OPEN, (sc->dev, "port %d:"
781 " BUSY error = %d\n", pnum, error));
782 goto out;
784 } else if (port->active_out) {
785 if (ap->a_oflags & O_NONBLOCK) {
786 error = EBUSY;
787 DLOG(DIGIDB_OPEN, (sc->dev,
788 "port %d: BUSY error = %d\n", pnum, error));
789 goto out;
791 port->wopeners++;
792 error = tsleep(&port->active_out, PCATCH, "digibi", 0);
793 port->wopeners--;
794 if (error != 0) {
795 DLOG(DIGIDB_OPEN, (sc->dev,
796 "port %d: tsleep(digibi) error = %d\n",
797 pnum, error));
798 goto out;
800 goto open_top;
802 if (tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0) != 0) {
803 error = EBUSY;
804 goto out;
806 } else {
808 * The device isn't open, so there are no conflicts.
809 * Initialize it. Initialization is done twice in many
810 * cases: to preempt sleeping callin opens if we are callout,
811 * and to complete a callin open after DCD rises.
813 callout_init_mp(&port->wakeupco);
814 tp->t_oproc = digistart;
815 tp->t_param = digiparam;
816 tp->t_stop = digistop;
817 tp->t_dev = dev;
818 tp->t_termios = (mynor & CALLOUT_MASK) ?
819 port->it_out : port->it_in;
820 sc->setwin(sc, 0);
822 bc->rout = bc->rin; /* clear input queue */
823 bc->idata = 1;
824 bc->iempty = 1;
825 bc->ilow = 1;
826 bc->mint = port->cd | port->sc->csigs->ri;
827 bc->tin = bc->tout;
828 if (port->ialtpin) {
829 port->cd = sc->csigs->dsr;
830 port->dsr = sc->csigs->cd;
831 } else {
832 port->cd = sc->csigs->cd;
833 port->dsr = sc->csigs->dsr;
835 port->wopeners++; /* XXX required ? */
836 error = digiparam(tp, &tp->t_termios);
837 port->wopeners--;
839 if (error != 0) {
840 DLOG(DIGIDB_OPEN, (sc->dev,
841 "port %d: cxpparam error = %d\n", pnum, error));
842 goto out;
844 ttsetwater(tp);
846 /* handle fake and initial DCD for callout devices */
848 if (bc->mstat & port->cd || mynor & CALLOUT_MASK)
849 linesw[tp->t_line].l_modem(tp, 1);
852 /* Wait for DCD if necessary */
853 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK) &&
854 !(tp->t_cflag & CLOCAL) && !(ap->a_oflags & O_NONBLOCK)) {
855 port->wopeners++;
856 error = tsleep(TSA_CARR_ON(tp), PCATCH, "digidcd", 0);
857 port->wopeners--;
858 if (error != 0) {
859 DLOG(DIGIDB_OPEN, (sc->dev,
860 "port %d: tsleep(digidcd) error = %d\n",
861 pnum, error));
862 goto out;
864 goto open_top;
866 error = linesw[tp->t_line].l_open(dev, tp);
867 DLOG(DIGIDB_OPEN, (sc->dev, "port %d: l_open error = %d\n",
868 pnum, error));
870 digi_disc_optim(tp, &tp->t_termios, port);
872 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
873 port->active_out = TRUE;
875 if (tp->t_state & TS_ISOPEN)
876 sc->opencnt++;
877 out:
878 crit_exit();
880 if (!(tp->t_state & TS_ISOPEN))
881 digihardclose(port);
883 DLOG(DIGIDB_OPEN, (sc->dev, "port %d: open() returns %d\n",
884 pnum, error));
886 lwkt_reltoken(&tty_token);
887 return (error);
890 static int
891 digiclose(struct dev_close_args *ap)
893 cdev_t dev = ap->a_head.a_dev;
894 int mynor;
895 struct tty *tp;
896 int unit, pnum;
897 struct digi_softc *sc;
898 struct digi_p *port;
900 lwkt_gettoken(&tty_token);
901 mynor = minor(dev);
902 unit = MINOR_TO_UNIT(mynor);
903 pnum = MINOR_TO_PORT(mynor);
905 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit);
906 KASSERT(sc, ("digi%d: softc not allocated in digiclose", unit));
908 if (mynor & (CTRL_DEV | CONTROL_MASK)) {
909 sc->opencnt--;
910 lwkt_reltoken(&tty_token);
911 return (0);
914 port = sc->ports + pnum;
915 tp = port->tp;
917 DLOG(DIGIDB_CLOSE, (sc->dev, "port %d: closing\n", pnum));
919 crit_enter();
920 linesw[tp->t_line].l_close(tp, ap->a_fflag);
921 digi_disc_optim(tp, &tp->t_termios, port);
922 digistop(tp, FREAD | FWRITE);
923 digihardclose(port);
924 ttyclose(tp);
925 --sc->opencnt;
926 crit_exit();
927 lwkt_reltoken(&tty_token);
928 return (0);
931 static void
932 digidtrwakeup(void *chan)
934 struct digi_p *port = chan;
936 lwkt_gettoken(&tty_token);
937 port->status &= ~DIGI_DTR_OFF;
938 wakeup(&port->dtr_wait);
939 port->wopeners--;
940 lwkt_reltoken(&tty_token);
944 * NOTE: Must be called with tty_token held
946 static void
947 digihardclose(struct digi_p *port)
949 volatile struct board_chan *bc;
951 ASSERT_LWKT_TOKEN_HELD(&tty_token);
952 bc = port->bc;
954 crit_enter();
955 port->sc->setwin(port->sc, 0);
956 bc->idata = 0;
957 bc->iempty = 0;
958 bc->ilow = 0;
959 bc->mint = 0;
960 if ((port->tp->t_cflag & HUPCL) ||
961 (!port->active_out && !(bc->mstat & port->cd) &&
962 !(port->it_in.c_cflag & CLOCAL)) ||
963 !(port->tp->t_state & TS_ISOPEN)) {
964 digimctl(port, TIOCM_DTR | TIOCM_RTS, DMBIC);
965 if (port->dtr_wait != 0) {
966 /* Schedule a wakeup of any callin devices */
967 port->wopeners++;
968 callout_reset(&port->wakeupco, port->dtr_wait,
969 digidtrwakeup, port);
970 port->status |= DIGI_DTR_OFF;
973 port->active_out = FALSE;
974 wakeup(&port->active_out);
975 wakeup(TSA_CARR_ON(port->tp));
976 crit_exit();
979 static int
980 digiread(struct dev_read_args *ap)
982 cdev_t dev = ap->a_head.a_dev;
983 int mynor;
984 struct tty *tp;
985 int error, unit, pnum;
986 struct digi_softc *sc;
988 mynor = minor(dev);
989 if (mynor & CONTROL_MASK)
990 return (ENODEV);
992 lwkt_gettoken(&tty_token);
993 unit = MINOR_TO_UNIT(mynor);
994 pnum = MINOR_TO_PORT(mynor);
996 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit);
997 KASSERT(sc, ("digi%d: softc not allocated in digiclose", unit));
998 tp = &sc->ttys[pnum];
1000 error = linesw[tp->t_line].l_read(tp, ap->a_uio, ap->a_ioflag);
1001 DLOG(DIGIDB_READ, (sc->dev, "port %d: read() returns %d\n",
1002 pnum, error));
1004 lwkt_reltoken(&tty_token);
1005 return (error);
1008 static int
1009 digiwrite(struct dev_write_args *ap)
1011 cdev_t dev = ap->a_head.a_dev;
1012 int mynor;
1013 struct tty *tp;
1014 int error, unit, pnum;
1015 struct digi_softc *sc;
1017 mynor = minor(dev);
1018 if (mynor & CONTROL_MASK)
1019 return (ENODEV);
1021 lwkt_gettoken(&tty_token);
1022 unit = MINOR_TO_UNIT(mynor);
1023 pnum = MINOR_TO_PORT(mynor);
1025 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit);
1026 KASSERT(sc, ("digi%d: softc not allocated in digiclose", unit));
1027 tp = &sc->ttys[pnum];
1029 error = linesw[tp->t_line].l_write(tp, ap->a_uio, ap->a_ioflag);
1030 DLOG(DIGIDB_WRITE, (sc->dev, "port %d: write() returns %d\n",
1031 pnum, error));
1033 lwkt_reltoken(&tty_token);
1034 return (error);
1038 * Load module "digi_<mod>.ko" and look for a symbol called digi_mod_<mod>.
1040 * Populate sc->bios, sc->fep, and sc->link from this data.
1042 * sc->fep.data, sc->bios.data and sc->link.data are malloc()d according
1043 * to their respective sizes.
1045 * The module is unloaded when we're done.
1047 static int
1048 digi_loaddata(struct digi_softc *sc)
1050 struct digi_bios *bios;
1052 KASSERT(sc->bios.data == NULL, ("Uninitialised BIOS variable"));
1053 KASSERT(sc->fep.data == NULL, ("Uninitialised FEP variable"));
1054 KASSERT(sc->link.data == NULL, ("Uninitialised LINK variable"));
1055 KASSERT(sc->module != NULL, ("Uninitialised module name"));
1057 for (bios = digi_bioses; bios->model != NULL; bios++) {
1058 if (!strcmp(bios->model, sc->module))
1059 break;
1061 if (bios->model == NULL) {
1062 kprintf("digi.ko: driver %s not found", sc->module);
1063 return(EINVAL);
1066 sc->bios.size = bios->bios_size;
1067 if (sc->bios.size != 0 && bios->bios != NULL) {
1068 sc->bios.data = kmalloc(sc->bios.size, M_TTYS, M_WAITOK);
1069 bcopy(bios->bios, sc->bios.data, sc->bios.size);
1072 sc->fep.size = bios->fep_size;
1073 if (sc->fep.size != 0 && bios->fep != NULL) {
1074 sc->fep.data = kmalloc(sc->fep.size, M_TTYS, M_WAITOK);
1075 bcopy(bios->fep, sc->fep.data, sc->fep.size);
1078 return (0);
1081 static int
1082 digiioctl(struct dev_ioctl_args *ap)
1084 cdev_t dev = ap->a_head.a_dev;
1085 u_long cmd = ap->a_cmd;
1086 caddr_t data = ap->a_data;
1087 int unit, pnum, mynor, error, ret;
1088 struct digi_softc *sc;
1089 struct digi_p *port;
1090 struct tty *tp;
1092 mynor = minor(dev);
1093 unit = MINOR_TO_UNIT(mynor);
1094 pnum = MINOR_TO_PORT(mynor);
1096 lwkt_gettoken(&tty_token);
1097 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit);
1098 KASSERT(sc, ("digi%d: softc not allocated in digiioctl", unit));
1100 if (sc->status == DIGI_STATUS_DISABLED) {
1101 lwkt_reltoken(&tty_token);
1102 return (ENXIO);
1105 if (mynor & CTRL_DEV) {
1106 switch (cmd) {
1107 case DIGIIO_DEBUG:
1108 #ifdef DEBUG
1109 digi_debug = *(int *)data;
1110 lwkt_reltoken(&tty_token);
1111 return (0);
1112 #else
1113 device_printf(sc->dev, "DEBUG not defined\n");
1114 lwkt_reltoken(&tty_token);
1115 return (ENXIO);
1116 #endif
1117 case DIGIIO_REINIT:
1118 digi_loaddata(sc);
1119 error = digi_init(sc);
1120 digi_freedata(sc);
1121 lwkt_reltoken(&tty_token);
1122 return (error);
1124 case DIGIIO_MODEL:
1125 *(enum digi_model *)data = sc->model;
1126 lwkt_reltoken(&tty_token);
1127 return (0);
1129 case DIGIIO_IDENT:
1130 ret = copyout(sc->name, *(char **)data,
1131 strlen(sc->name) + 1);
1132 lwkt_reltoken(&tty_token);
1133 return ret;
1137 if (pnum >= sc->numports) {
1138 lwkt_reltoken(&tty_token);
1139 return (ENXIO);
1142 port = sc->ports + pnum;
1143 if (!(port->status & ENABLED)) {
1144 lwkt_reltoken(&tty_token);
1145 return (ENXIO);
1148 tp = port->tp;
1150 if (mynor & CONTROL_MASK) {
1151 struct termios *ct;
1153 switch (mynor & CONTROL_MASK) {
1154 case CONTROL_INIT_STATE:
1155 ct = (mynor & CALLOUT_MASK) ?
1156 &port->it_out : &port->it_in;
1157 break;
1158 case CONTROL_LOCK_STATE:
1159 ct = (mynor & CALLOUT_MASK) ?
1160 &port->lt_out : &port->lt_in;
1161 break;
1162 default:
1163 lwkt_reltoken(&tty_token);
1164 return (ENODEV); /* /dev/nodev */
1167 switch (cmd) {
1168 case TIOCSETA:
1169 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1170 if (error != 0) {
1171 lwkt_reltoken(&tty_token);
1172 return (error);
1174 *ct = *(struct termios *)data;
1175 lwkt_reltoken(&tty_token);
1176 return (0);
1178 case TIOCGETA:
1179 *(struct termios *)data = *ct;
1180 lwkt_reltoken(&tty_token);
1181 return (0);
1183 case TIOCGETD:
1184 *(int *)data = TTYDISC;
1185 lwkt_reltoken(&tty_token);
1186 return (0);
1188 case TIOCGWINSZ:
1189 bzero(data, sizeof(struct winsize));
1190 lwkt_reltoken(&tty_token);
1191 return (0);
1193 case DIGIIO_GETALTPIN:
1194 switch (mynor & CONTROL_MASK) {
1195 case CONTROL_INIT_STATE:
1196 *(int *)data = port->ialtpin;
1197 break;
1199 case CONTROL_LOCK_STATE:
1200 *(int *)data = port->laltpin;
1201 break;
1203 default:
1204 panic("Confusion when re-testing minor");
1205 lwkt_reltoken(&tty_token);
1206 return (ENODEV);
1208 lwkt_reltoken(&tty_token);
1209 return (0);
1211 case DIGIIO_SETALTPIN:
1212 switch (mynor & CONTROL_MASK) {
1213 case CONTROL_INIT_STATE:
1214 if (!port->laltpin) {
1215 port->ialtpin = !!*(int *)data;
1216 DLOG(DIGIDB_SET, (sc->dev,
1217 "port%d: initial ALTPIN %s\n", pnum,
1218 port->ialtpin ? "set" : "cleared"));
1220 break;
1222 case CONTROL_LOCK_STATE:
1223 port->laltpin = !!*(int *)data;
1224 DLOG(DIGIDB_SET, (sc->dev,
1225 "port%d: ALTPIN %slocked\n",
1226 pnum, port->laltpin ? "" : "un"));
1227 break;
1229 default:
1230 panic("Confusion when re-testing minor");
1231 lwkt_reltoken(&tty_token);
1232 return (ENODEV);
1234 lwkt_reltoken(&tty_token);
1235 return (0);
1237 default:
1238 lwkt_reltoken(&tty_token);
1239 return (ENOTTY);
1243 switch (cmd) {
1244 case DIGIIO_GETALTPIN:
1245 *(int *)data = !!(port->dsr == sc->csigs->cd);
1246 lwkt_reltoken(&tty_token);
1247 return (0);
1249 case DIGIIO_SETALTPIN:
1250 if (!port->laltpin) {
1251 if (*(int *)data) {
1252 DLOG(DIGIDB_SET, (sc->dev,
1253 "port%d: ALTPIN set\n", pnum));
1254 port->cd = sc->csigs->dsr;
1255 port->dsr = sc->csigs->cd;
1256 } else {
1257 DLOG(DIGIDB_SET, (sc->dev,
1258 "port%d: ALTPIN cleared\n", pnum));
1259 port->cd = sc->csigs->cd;
1260 port->dsr = sc->csigs->dsr;
1263 lwkt_reltoken(&tty_token);
1264 return (0);
1267 tp = port->tp;
1268 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1269 int cc;
1270 struct termios *dt;
1271 struct termios *lt;
1273 dt = (struct termios *)data;
1274 lt = (mynor & CALLOUT_MASK) ? &port->lt_out : &port->lt_in;
1276 dt->c_iflag =
1277 (tp->t_iflag & lt->c_iflag) | (dt->c_iflag & ~lt->c_iflag);
1278 dt->c_oflag =
1279 (tp->t_oflag & lt->c_oflag) | (dt->c_oflag & ~lt->c_oflag);
1280 dt->c_cflag =
1281 (tp->t_cflag & lt->c_cflag) | (dt->c_cflag & ~lt->c_cflag);
1282 dt->c_lflag =
1283 (tp->t_lflag & lt->c_lflag) | (dt->c_lflag & ~lt->c_lflag);
1284 port->c_iflag = dt->c_iflag & (IXOFF | IXON | IXANY);
1285 dt->c_iflag &= ~(IXOFF | IXON | IXANY);
1286 for (cc = 0; cc < NCCS; ++cc)
1287 if (lt->c_cc[cc] != 0)
1288 dt->c_cc[cc] = tp->t_cc[cc];
1289 if (lt->c_ispeed != 0)
1290 dt->c_ispeed = tp->t_ispeed;
1291 if (lt->c_ospeed != 0)
1292 dt->c_ospeed = tp->t_ospeed;
1294 error = linesw[tp->t_line].l_ioctl(tp, cmd, data,
1295 ap->a_fflag, ap->a_cred);
1296 if (error == 0 && cmd == TIOCGETA)
1297 ((struct termios *)data)->c_iflag |= port->c_iflag;
1299 if (error >= 0 && error != ENOIOCTL) {
1300 lwkt_reltoken(&tty_token);
1301 return (error);
1303 crit_enter();
1304 error = ttioctl(tp, cmd, data, ap->a_fflag);
1305 if (error == 0 && cmd == TIOCGETA)
1306 ((struct termios *)data)->c_iflag |= port->c_iflag;
1308 digi_disc_optim(tp, &tp->t_termios, port);
1309 if (error >= 0 && error != ENOIOCTL) {
1310 crit_exit();
1311 lwkt_reltoken(&tty_token);
1312 return (error);
1314 sc->setwin(sc, 0);
1315 switch (cmd) {
1316 case DIGIIO_RING:
1317 port->send_ring = *(u_char *)data;
1318 break;
1319 case TIOCSBRK:
1321 * now it sends 400 millisecond break because I don't know
1322 * how to send an infinite break
1324 fepcmd_w(port, SENDBREAK, 400, 10);
1325 break;
1326 case TIOCCBRK:
1327 /* now it's empty */
1328 break;
1329 case TIOCSDTR:
1330 digimctl(port, TIOCM_DTR, DMBIS);
1331 break;
1332 case TIOCCDTR:
1333 digimctl(port, TIOCM_DTR, DMBIC);
1334 break;
1335 case TIOCMSET:
1336 digimctl(port, *(int *)data, DMSET);
1337 break;
1338 case TIOCMBIS:
1339 digimctl(port, *(int *)data, DMBIS);
1340 break;
1341 case TIOCMBIC:
1342 digimctl(port, *(int *)data, DMBIC);
1343 break;
1344 case TIOCMGET:
1345 *(int *)data = digimctl(port, 0, DMGET);
1346 break;
1347 case TIOCMSDTRWAIT:
1348 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1349 if (error != 0) {
1350 crit_exit();
1351 lwkt_reltoken(&tty_token);
1352 return (error);
1354 port->dtr_wait = *(int *)data *hz / 100;
1356 break;
1357 case TIOCMGDTRWAIT:
1358 *(int *)data = port->dtr_wait * 100 / hz;
1359 break;
1360 #ifdef DIGI_INTERRUPT
1361 case TIOCTIMESTAMP:
1362 *(struct timeval *)data = sc->intr_timestamp;
1364 break;
1365 #endif
1366 default:
1367 crit_exit();
1368 lwkt_reltoken(&tty_token);
1369 return (ENOTTY);
1371 crit_exit();
1372 lwkt_reltoken(&tty_token);
1373 return (0);
1376 static int
1377 digiparam(struct tty *tp, struct termios *t)
1379 int mynor;
1380 int unit;
1381 int pnum;
1382 struct digi_softc *sc;
1383 struct digi_p *port;
1384 int cflag;
1385 int iflag;
1386 int hflow;
1387 int window;
1389 lwkt_gettoken(&tty_token);
1390 mynor = minor(tp->t_dev);
1391 unit = MINOR_TO_UNIT(mynor);
1392 pnum = MINOR_TO_PORT(mynor);
1394 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit);
1395 KASSERT(sc, ("digi%d: softc not allocated in digiparam", unit));
1397 port = &sc->ports[pnum];
1399 DLOG(DIGIDB_SET, (sc->dev, "port%d: setting parameters\n", pnum));
1401 if (t->c_ispeed == 0)
1402 t->c_ispeed = t->c_ospeed;
1404 cflag = ttspeedtab(t->c_ospeed, digispeedtab);
1406 if (cflag < 0 || (cflag > 0 && t->c_ispeed != t->c_ospeed)) {
1407 lwkt_reltoken(&tty_token);
1408 return (EINVAL);
1411 crit_enter();
1413 window = sc->window;
1414 sc->setwin(sc, 0);
1416 if (cflag == 0) { /* hangup */
1417 DLOG(DIGIDB_SET, (sc->dev, "port%d: hangup\n", pnum));
1418 digimctl(port, TIOCM_DTR | TIOCM_RTS, DMBIC);
1419 } else {
1420 digimctl(port, TIOCM_DTR | TIOCM_RTS, DMBIS);
1422 DLOG(DIGIDB_SET, (sc->dev, "port%d: CBAUD = %d\n", pnum,
1423 cflag));
1425 #if 0
1426 /* convert flags to sysV-style values */
1427 if (t->c_cflag & PARODD)
1428 cflag |= 0x0200;
1429 if (t->c_cflag & PARENB)
1430 cflag |= 0x0100;
1431 if (t->c_cflag & CSTOPB)
1432 cflag |= 0x0080;
1433 #else
1434 /* convert flags to sysV-style values */
1435 if (t->c_cflag & PARODD)
1436 cflag |= FEP_PARODD;
1437 if (t->c_cflag & PARENB)
1438 cflag |= FEP_PARENB;
1439 if (t->c_cflag & CSTOPB)
1440 cflag |= FEP_CSTOPB;
1441 if (t->c_cflag & CLOCAL)
1442 cflag |= FEP_CLOCAL;
1443 #endif
1445 cflag |= (t->c_cflag & CSIZE) >> 4;
1446 DLOG(DIGIDB_SET, (sc->dev, "port%d: CFLAG = 0x%x\n", pnum,
1447 cflag));
1448 fepcmd_w(port, SETCFLAGS, (unsigned)cflag, 0);
1451 iflag =
1452 t->c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP);
1453 if (port->c_iflag & IXON)
1454 iflag |= 0x400;
1455 if (port->c_iflag & IXANY)
1456 iflag |= 0x800;
1457 if (port->c_iflag & IXOFF)
1458 iflag |= 0x1000;
1460 DLOG(DIGIDB_SET, (sc->dev, "port%d: set iflag = 0x%x\n", pnum, iflag));
1461 fepcmd_w(port, SETIFLAGS, (unsigned)iflag, 0);
1463 hflow = 0;
1464 if (t->c_cflag & CDTR_IFLOW)
1465 hflow |= sc->csigs->dtr;
1466 if (t->c_cflag & CRTS_IFLOW)
1467 hflow |= sc->csigs->rts;
1468 if (t->c_cflag & CCTS_OFLOW)
1469 hflow |= sc->csigs->cts;
1470 if (t->c_cflag & CDSR_OFLOW)
1471 hflow |= port->dsr;
1472 if (t->c_cflag & CCAR_OFLOW)
1473 hflow |= port->cd;
1475 DLOG(DIGIDB_SET, (sc->dev, "port%d: set hflow = 0x%x\n", pnum, hflow));
1476 fepcmd_w(port, SETHFLOW, 0xff00 | (unsigned)hflow, 0);
1478 DLOG(DIGIDB_SET, (sc->dev, "port%d: set startc(0x%x), stopc(0x%x)\n",
1479 pnum, t->c_cc[VSTART], t->c_cc[VSTOP]));
1480 fepcmd_b(port, SONOFFC, t->c_cc[VSTART], t->c_cc[VSTOP], 0);
1482 if (sc->window != 0)
1483 sc->towin(sc, 0);
1484 if (window != 0)
1485 sc->towin(sc, window);
1486 crit_exit();
1488 lwkt_reltoken(&tty_token);
1489 return (0);
1492 static void
1493 digi_intr(void *vp)
1495 struct digi_p *port;
1496 char *cxcon;
1497 struct digi_softc *sc;
1498 int ehead, etail;
1499 volatile struct board_chan *bc;
1500 struct tty *tp;
1501 int head, tail;
1502 int wrapmask;
1503 int size, window;
1504 struct event {
1505 u_char pnum;
1506 u_char event;
1507 u_char mstat;
1508 u_char lstat;
1509 } event;
1511 lwkt_gettoken(&tty_token);
1512 sc = vp;
1514 if (sc->status != DIGI_STATUS_ENABLED) {
1515 DLOG(DIGIDB_IRQ, (sc->dev, "interrupt on disabled board !\n"));
1516 lwkt_reltoken(&tty_token);
1517 return;
1520 #ifdef DIGI_INTERRUPT
1521 microtime(&sc->intr_timestamp);
1522 #endif
1524 window = sc->window;
1525 sc->setwin(sc, 0);
1527 if (sc->model >= PCXEM && W(sc->vmem + 0xd00)) {
1528 struct con_bios *con = con_bios_list;
1529 u_char *ptr;
1531 ptr = sc->vmem + W(sc->vmem + 0xd00);
1532 while (con) {
1533 if (ptr[1] && W(ptr + 2) == W(con->bios + 2))
1534 /* Not first block -- exact match */
1535 break;
1537 if (W(ptr + 4) >= W(con->bios + 4) &&
1538 W(ptr + 4) <= W(con->bios + 6))
1539 /* Initial search concetrator BIOS */
1540 break;
1543 if (con == NULL) {
1544 log(LOG_ERR, "digi%d: wanted bios LREV = 0x%04x"
1545 " not found!\n", sc->res.unit, W(ptr + 4));
1546 W(ptr + 10) = 0;
1547 W(sc->vmem + 0xd00) = 0;
1548 goto eoi;
1550 cxcon = con->bios;
1551 W(ptr + 4) = W(cxcon + 4);
1552 W(ptr + 6) = W(cxcon + 6);
1553 if (ptr[1] == 0)
1554 W(ptr + 2) = W(cxcon + 2);
1555 W(ptr + 8) = (ptr[1] << 6) + W(cxcon + 8);
1556 size = W(cxcon + 10) - (ptr[1] << 10);
1557 if (size <= 0) {
1558 W(ptr + 8) = W(cxcon + 8);
1559 W(ptr + 10) = 0;
1560 } else {
1561 if (size > 1024)
1562 size = 1024;
1563 W(ptr + 10) = size;
1564 bcopy(cxcon + (ptr[1] << 10), ptr + 12, size);
1566 W(sc->vmem + 0xd00) = 0;
1567 goto eoi;
1570 ehead = sc->gdata->ein;
1571 etail = sc->gdata->eout;
1572 if (ehead == etail) {
1573 #ifdef DEBUG
1574 sc->intr_count++;
1575 if (sc->intr_count % 6000 == 0) {
1576 DLOG(DIGIDB_IRQ, (sc->dev,
1577 "6000 useless polls %x %x\n", ehead, etail));
1578 sc->intr_count = 0;
1580 #endif
1581 goto eoi;
1583 while (ehead != etail) {
1584 event = *(volatile struct event *)(sc->memevent + etail);
1586 etail = (etail + 4) & sc->gdata->imax;
1588 if (event.pnum >= sc->numports) {
1589 log(LOG_ERR, "digi%d: port %d: got event"
1590 " on nonexisting port\n", sc->res.unit,
1591 event.pnum);
1592 continue;
1594 port = &sc->ports[event.pnum];
1595 bc = port->bc;
1596 tp = port->tp;
1598 if (!(tp->t_state & TS_ISOPEN) && !port->wopeners) {
1599 DLOG(DIGIDB_IRQ, (sc->dev,
1600 "port %d: event 0x%x on closed port\n",
1601 event.pnum, event.event));
1602 bc->rout = bc->rin;
1603 bc->idata = 0;
1604 bc->iempty = 0;
1605 bc->ilow = 0;
1606 bc->mint = 0;
1607 continue;
1609 if (event.event & ~ALL_IND)
1610 log(LOG_ERR, "digi%d: port%d: ? event 0x%x mstat 0x%x"
1611 " lstat 0x%x\n", sc->res.unit, event.pnum,
1612 event.event, event.mstat, event.lstat);
1614 if (event.event & DATA_IND) {
1615 DLOG(DIGIDB_IRQ, (sc->dev, "port %d: DATA_IND\n",
1616 event.pnum));
1617 wrapmask = port->rxbufsize - 1;
1618 head = bc->rin;
1619 tail = bc->rout;
1621 size = 0;
1622 if (!(tp->t_state & TS_ISOPEN)) {
1623 bc->rout = head;
1624 goto end_of_data;
1626 while (head != tail) {
1627 int top;
1629 DLOG(DIGIDB_INT, (sc->dev,
1630 "port %d: p rx head = %d tail = %d\n",
1631 event.pnum, head, tail));
1632 top = (head > tail) ? head : wrapmask + 1;
1633 sc->towin(sc, port->rxwin);
1634 size = top - tail;
1635 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1636 size = b_to_q((char *)port->rxbuf +
1637 tail, size, &tp->t_rawq);
1638 tail = top - size;
1639 ttwakeup(tp);
1640 } else for (; tail < top;) {
1641 linesw[tp->t_line].
1642 l_rint(port->rxbuf[tail], tp);
1643 sc->towin(sc, port->rxwin);
1644 size--;
1645 tail++;
1646 if (tp->t_state & TS_TBLOCK)
1647 break;
1649 tail &= wrapmask;
1650 sc->setwin(sc, 0);
1651 bc->rout = tail;
1652 head = bc->rin;
1653 if (size)
1654 break;
1657 if (bc->orun) {
1658 CE_RECORD(port, CE_OVERRUN);
1659 log(LOG_ERR, "digi%d: port%d: %s\n",
1660 sc->res.unit, event.pnum,
1661 digi_errortxt(CE_OVERRUN));
1662 bc->orun = 0;
1664 end_of_data:
1665 if (size) {
1666 tp->t_state |= TS_TBLOCK;
1667 port->status |= PAUSE_RX;
1668 DLOG(DIGIDB_RX, (sc->dev, "port %d: pause RX\n",
1669 event.pnum));
1670 } else {
1671 bc->idata = 1;
1675 if (event.event & MODEMCHG_IND) {
1676 DLOG(DIGIDB_MODEM, (sc->dev, "port %d: MODEMCHG_IND\n",
1677 event.pnum));
1679 if ((event.mstat ^ event.lstat) & port->cd) {
1680 sc->hidewin(sc);
1681 linesw[tp->t_line].l_modem
1682 (tp, event.mstat & port->cd);
1683 sc->setwin(sc, 0);
1684 wakeup(TSA_CARR_ON(tp));
1687 if (event.mstat & sc->csigs->ri) {
1688 DLOG(DIGIDB_RI, (sc->dev, "port %d: RING\n",
1689 event.pnum));
1690 if (port->send_ring) {
1691 linesw[tp->t_line].l_rint('R', tp);
1692 linesw[tp->t_line].l_rint('I', tp);
1693 linesw[tp->t_line].l_rint('N', tp);
1694 linesw[tp->t_line].l_rint('G', tp);
1695 linesw[tp->t_line].l_rint('\r', tp);
1696 linesw[tp->t_line].l_rint('\n', tp);
1700 if (event.event & BREAK_IND) {
1701 DLOG(DIGIDB_MODEM, (sc->dev, "port %d: BREAK_IND\n",
1702 event.pnum));
1703 linesw[tp->t_line].l_rint(TTY_BI, tp);
1705 if (event.event & (LOWTX_IND | EMPTYTX_IND)) {
1706 DLOG(DIGIDB_IRQ, (sc->dev, "port %d:%s%s\n",
1707 event.pnum,
1708 event.event & LOWTX_IND ? " LOWTX" : "",
1709 event.event & EMPTYTX_IND ? " EMPTYTX" : ""));
1710 (*linesw[tp->t_line].l_start)(tp);
1713 sc->gdata->eout = etail;
1714 eoi:
1715 if (sc->window != 0)
1716 sc->towin(sc, 0);
1717 if (window != 0)
1718 sc->towin(sc, window);
1719 lwkt_reltoken(&tty_token);
1722 static void
1723 digistart(struct tty *tp)
1725 int unit;
1726 int pnum;
1727 struct digi_p *port;
1728 struct digi_softc *sc;
1729 volatile struct board_chan *bc;
1730 int head, tail;
1731 int size, ocount, totcnt = 0;
1732 int wmask;
1734 lwkt_gettoken(&tty_token);
1735 unit = MINOR_TO_UNIT(minor(tp->t_dev));
1736 pnum = MINOR_TO_PORT(minor(tp->t_dev));
1738 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit);
1739 KASSERT(sc, ("digi%d: softc not allocated in digistart", unit));
1741 port = &sc->ports[pnum];
1742 bc = port->bc;
1744 wmask = port->txbufsize - 1;
1746 crit_enter();
1747 port->lcc = tp->t_outq.c_cc;
1748 sc->setwin(sc, 0);
1749 if (!(tp->t_state & TS_TBLOCK)) {
1750 if (port->status & PAUSE_RX) {
1751 DLOG(DIGIDB_RX, (sc->dev, "port %d: resume RX\n",
1752 pnum));
1754 * CAREFUL - braces are needed here if the DLOG is
1755 * optimised out!
1758 port->status &= ~PAUSE_RX;
1759 bc->idata = 1;
1761 if (!(tp->t_state & TS_TTSTOP) && port->status & PAUSE_TX) {
1762 DLOG(DIGIDB_TX, (sc->dev, "port %d: resume TX\n", pnum));
1763 port->status &= ~PAUSE_TX;
1764 fepcmd_w(port, RESUMETX, 0, 10);
1766 if (tp->t_outq.c_cc == 0)
1767 tp->t_state &= ~TS_BUSY;
1768 else
1769 tp->t_state |= TS_BUSY;
1771 head = bc->tin;
1772 while (tp->t_outq.c_cc != 0) {
1773 tail = bc->tout;
1774 DLOG(DIGIDB_INT, (sc->dev, "port%d: s tx head = %d tail = %d\n",
1775 pnum, head, tail));
1777 if (head < tail)
1778 size = tail - head - 1;
1779 else {
1780 size = port->txbufsize - head;
1781 if (tail == 0)
1782 size--;
1785 if (size == 0)
1786 break;
1787 sc->towin(sc, port->txwin);
1788 ocount = q_to_b(&tp->t_outq, port->txbuf + head, size);
1789 totcnt += ocount;
1790 head += ocount;
1791 head &= wmask;
1792 sc->setwin(sc, 0);
1793 bc->tin = head;
1794 bc->iempty = 1;
1795 bc->ilow = 1;
1797 port->lostcc = tp->t_outq.c_cc;
1798 tail = bc->tout;
1799 if (head < tail)
1800 size = port->txbufsize - tail + head;
1801 else
1802 size = head - tail;
1804 port->lbuf = size;
1805 DLOG(DIGIDB_INT, (sc->dev, "port%d: s total cnt = %d\n", pnum, totcnt));
1806 ttwwakeup(tp);
1807 crit_exit();
1808 lwkt_reltoken(&tty_token);
1811 static void
1812 digistop(struct tty *tp, int rw)
1814 struct digi_softc *sc;
1815 int unit;
1816 int pnum;
1817 struct digi_p *port;
1819 lwkt_gettoken(&tty_token);
1820 unit = MINOR_TO_UNIT(minor(tp->t_dev));
1821 pnum = MINOR_TO_PORT(minor(tp->t_dev));
1823 sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit);
1824 KASSERT(sc, ("digi%d: softc not allocated in digistop", unit));
1825 port = sc->ports + pnum;
1827 DLOG(DIGIDB_TX, (sc->dev, "port %d: pause TX\n", pnum));
1828 port->status |= PAUSE_TX;
1829 fepcmd_w(port, PAUSETX, 0, 10);
1830 lwkt_reltoken(&tty_token);
1834 * NOTE: Must be called with tty_token held
1836 static void
1837 fepcmd(struct digi_p *port, int cmd, int op1, int ncmds)
1839 u_char *mem;
1840 unsigned tail, head;
1841 int count, n;
1843 ASSERT_LWKT_TOKEN_HELD(&tty_token);
1844 mem = port->sc->memcmd;
1846 port->sc->setwin(port->sc, 0);
1848 head = port->sc->gdata->cin;
1849 mem[head + 0] = cmd;
1850 mem[head + 1] = port->pnum;
1851 *(u_short *)(mem + head + 2) = op1;
1853 head = (head + 4) & port->sc->gdata->cmax;
1854 port->sc->gdata->cin = head;
1856 for (count = FEPTIMEOUT; count > 0; count--) {
1857 head = port->sc->gdata->cin;
1858 tail = port->sc->gdata->cout;
1859 n = (head - tail) & port->sc->gdata->cmax;
1861 if (n <= ncmds * sizeof(short) * 4)
1862 break;
1864 if (count == 0)
1865 log(LOG_ERR, "digi%d: port%d: timeout on FEP command\n",
1866 port->sc->res.unit, port->pnum);
1869 const char *
1870 digi_errortxt(int id)
1872 static const char *error_desc[] = {
1873 "silo overflow",
1874 "interrupt-level buffer overflow",
1875 "tty-level buffer overflow",
1878 KASSERT(id >= 0 && id < NELEM(error_desc),
1879 ("Unexpected digi error id %d\n", id));
1881 return (error_desc[id]);
1885 digi_attach(struct digi_softc *sc)
1887 char tbuf[MAKEDEV_MINNBUF];
1889 lwkt_gettoken(&tty_token);
1890 sc->res.ctldev = make_dev(&digi_ops,
1891 (sc->res.unit << 16) | CTRL_DEV, UID_ROOT, GID_WHEEL,
1892 0600, "digi%s.ctl", makedev_unit_b32(tbuf, sc->res.unit));
1894 digi_loaddata(sc);
1895 digi_init(sc);
1896 digi_freedata(sc);
1898 lwkt_reltoken(&tty_token);
1899 return (0);
1903 * NOTE: Must be called with tty_token held
1905 static int
1906 digi_inuse(struct digi_softc *sc)
1908 int i;
1910 ASSERT_LWKT_TOKEN_HELD(&tty_token);
1911 for (i = 0; i < sc->numports; i++)
1912 if (sc->ttys[i].t_state & TS_ISOPEN) {
1913 DLOG(DIGIDB_INIT, (sc->dev, "port%d: busy\n", i));
1914 return (1);
1915 } else if (sc->ports[i].wopeners || sc->ports[i].opencnt) {
1916 DLOG(DIGIDB_INIT, (sc->dev, "port%d: blocked in open\n",
1917 i));
1918 return (1);
1920 return (0);
1924 * NOTE: Must be called with tty_token held
1926 static void
1927 digi_free_state(struct digi_softc *sc)
1929 int d, i;
1931 ASSERT_LWKT_TOKEN_HELD(&tty_token);
1932 /* Blow it all away */
1934 for (i = 0; i < sc->numports; i++)
1935 for (d = 0; d < 6; d++)
1936 destroy_dev(sc->ports[i].dev[d]);
1938 callout_stop(&sc->callout);
1939 callout_stop(&sc->inttest);
1941 bus_teardown_intr(sc->dev, sc->res.irq, sc->res.irqHandler);
1942 #ifdef DIGI_INTERRUPT
1943 if (sc->res.irq != NULL) {
1944 bus_release_resource(dev, SYS_RES_IRQ, sc->res.irqrid,
1945 sc->res.irq);
1946 sc->res.irq = NULL;
1948 #endif
1949 if (sc->numports) {
1950 KASSERT(sc->ports, ("digi%d: Lost my ports ?", sc->res.unit));
1951 KASSERT(sc->ttys, ("digi%d: Lost my ttys ?", sc->res.unit));
1952 kfree(sc->ports, M_TTYS);
1953 sc->ports = NULL;
1954 kfree(sc->ttys, M_TTYS);
1955 sc->ttys = NULL;
1956 sc->numports = 0;
1959 sc->status = DIGI_STATUS_NOTINIT;
1963 digi_detach(device_t dev)
1965 struct digi_softc *sc = device_get_softc(dev);
1967 lwkt_gettoken(&tty_token);
1968 DLOG(DIGIDB_INIT, (sc->dev, "detaching\n"));
1970 /* If we're INIT'd, numports must be 0 */
1971 KASSERT(sc->numports == 0 || sc->status != DIGI_STATUS_NOTINIT,
1972 ("digi%d: numports(%d) & status(%d) are out of sync",
1973 sc->res.unit, sc->numports, (int)sc->status));
1975 if (digi_inuse(sc)) {
1976 lwkt_reltoken(&tty_token);
1977 return (EBUSY);
1980 digi_free_state(sc);
1982 destroy_dev(sc->res.ctldev);
1984 if (sc->res.mem != NULL) {
1985 bus_release_resource(dev, SYS_RES_MEMORY, sc->res.mrid,
1986 sc->res.mem);
1987 sc->res.mem = NULL;
1989 if (sc->res.io != NULL) {
1990 bus_release_resource(dev, SYS_RES_IOPORT, sc->res.iorid,
1991 sc->res.io);
1992 sc->res.io = NULL;
1994 if (sc->msize) {
1995 pmap_unmapdev((vm_offset_t)sc->vmem, sc->msize);
1996 sc->msize = 0;
1999 lwkt_reltoken(&tty_token);
2000 return (0);
2004 digi_shutdown(device_t dev)
2006 return (0);
2009 MODULE_VERSION(digi, 1);