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