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