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