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