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