xref: /NextBSD/sys/dev/digi/digi.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
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$
30  */
31 
32 /*-
33  * TODO:
34  *	Figure out what the con bios stuff is supposed to do
35  *	Test with *LOTS* more cards - I only have a PCI8r and an ISA Xem.
36  */
37 
38 #include "opt_compat.h"
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/proc.h>
43 #include <sys/conf.h>
44 #include <sys/linker.h>
45 #include <sys/kernel.h>
46 #include <sys/mbuf.h>
47 #include <sys/malloc.h>
48 #include <sys/module.h>
49 #include <sys/tty.h>
50 #include <sys/syslog.h>
51 #include <sys/fcntl.h>
52 #include <sys/serial.h>
53 #include <sys/bus.h>
54 #include <machine/resource.h>
55 
56 #include <sys/digiio.h>
57 #include <dev/digi/digireg.h>
58 #include <dev/digi/digi.h>
59 #include <dev/digi/digi_mod.h>
60 #include <dev/digi/digi_pci.h>
61 
62 static t_open_t		digiopen;
63 static d_open_t		digicopen;
64 static d_close_t	digicclose;
65 static t_ioctl_t	digiioctl;
66 static d_ioctl_t	digisioctl;
67 static d_ioctl_t	digicioctl;
68 
69 static void	digistop(struct tty *tp, int rw);
70 static void	digibreak(struct tty *tp, int brk);
71 static int	digimodem(struct tty *tp, int sigon, int sigoff);
72 static void	digi_poll(void *ptr);
73 static void	digi_freemoduledata(struct digi_softc *);
74 static void	fepcmd(struct digi_p *port, int cmd, int op, int ncmds);
75 static void	digistart(struct tty *tp);
76 static int	digiparam(struct tty *tp, struct termios *t);
77 static void	digiclose(struct tty *tp);
78 static void	digi_intr(void *);
79 static int	digi_init(struct digi_softc *_sc);
80 static int	digi_loadmoduledata(struct digi_softc *);
81 static int	digi_inuse(struct digi_softc *);
82 static void	digi_free_state(struct digi_softc *);
83 
84 #define	fepcmd_b(port, cmd, op1, op2, ncmds) \
85 	fepcmd(port, cmd, (op2 << 8) | op1, ncmds)
86 #define	fepcmd_w	fepcmd
87 
88 struct con_bios {
89 	struct con_bios *next;
90 	u_char *bios;
91 	size_t size;
92 };
93 
94 static struct con_bios *con_bios_list;
95 devclass_t	 digi_devclass;
96 static char	 driver_name[] = "digi";
97 unsigned 	 digi_debug = 0;
98 
99 static struct speedtab digispeedtab[] = {
100 	{ 0,		0},			/* old (sysV-like) Bx codes */
101 	{ 50,		1},
102 	{ 75,		2},
103 	{ 110,		3},
104 	{ 134,		4},
105 	{ 150,		5},
106 	{ 200,		6},
107 	{ 300,		7},
108 	{ 600,		8},
109 	{ 1200,		9},
110 	{ 1800,		10},
111 	{ 2400,		11},
112 	{ 4800,		12},
113 	{ 9600,		13},
114 	{ 19200,	14},
115 	{ 38400,	15},
116 	{ 57600,	(02000 | 1)},
117 	{ 76800,	(02000 | 2)},
118 	{ 115200,	(02000 | 3)},
119 	{ 230400,	(02000 | 6)},
120 	{ -1,		-1}
121 };
122 
123 const struct digi_control_signals digi_xixe_signals = {
124 	0x02, 0x08, 0x10, 0x20, 0x40, 0x80
125 };
126 
127 const struct digi_control_signals digi_normal_signals = {
128 	0x02, 0x80, 0x20, 0x10, 0x40, 0x01
129 };
130 
131 static struct cdevsw digi_csw = {
132 	.d_version =	D_VERSION,
133 	.d_open =	digicopen,
134 	.d_close =	digicclose,
135 	.d_ioctl =	digicioctl,
136 	.d_name =	driver_name,
137 	.d_flags =	D_TTY | D_NEEDGIANT,
138 };
139 
140 static void
digi_poll(void * ptr)141 digi_poll(void *ptr)
142 {
143 	struct digi_softc *sc;
144 
145 	sc = (struct digi_softc *)ptr;
146 	callout_handle_init(&sc->callout);
147 	digi_intr(sc);
148 	sc->callout = timeout(digi_poll, sc, (hz >= 200) ? hz / 100 : 1);
149 }
150 
151 static void
digi_int_test(void * v)152 digi_int_test(void *v)
153 {
154 	struct digi_softc *sc = v;
155 
156 	callout_handle_init(&sc->inttest);
157 #ifdef DIGI_INTERRUPT
158 	if (sc->intr_timestamp.tv_sec || sc->intr_timestamp.tv_usec) {
159 		/* interrupt OK! */
160 		return;
161 	}
162 	log(LOG_ERR, "digi%d: Interrupt didn't work, use polled mode\n", unit);
163 #endif
164 	sc->callout = timeout(digi_poll, sc, (hz >= 200) ? hz / 100 : 1);
165 }
166 
167 static void
digi_freemoduledata(struct digi_softc * sc)168 digi_freemoduledata(struct digi_softc *sc)
169 {
170 	if (sc->fep.data != NULL) {
171 		free(sc->fep.data, M_TTYS);
172 		sc->fep.data = NULL;
173 	}
174 	if (sc->link.data != NULL) {
175 		free(sc->link.data, M_TTYS);
176 		sc->link.data = NULL;
177 	}
178 	if (sc->bios.data != NULL) {
179 		free(sc->bios.data, M_TTYS);
180 		sc->bios.data = NULL;
181 	}
182 }
183 
184 static int
digi_bcopy(const void * vfrom,void * vto,size_t sz)185 digi_bcopy(const void *vfrom, void *vto, size_t sz)
186 {
187 	volatile const char *from = (volatile const char *)vfrom;
188 	volatile char *to = (volatile char *)vto;
189 	size_t i;
190 
191 	for (i = 0; i < sz; i++)
192 		*to++ = *from++;
193 
194 	from = (const volatile char *)vfrom;
195 	to = (volatile char *)vto;
196 	for (i = 0; i < sz; i++)
197 		if (*to++ != *from++)
198 			return (0);
199 	return (1);
200 }
201 
202 void
digi_delay(struct digi_softc * sc,const char * txt,u_long timo)203 digi_delay(struct digi_softc *sc, const char *txt, u_long timo)
204 {
205 	if (cold)
206 		DELAY(timo * 1000000 / hz);
207 	else
208 		tsleep(sc, PUSER | PCATCH, txt, timo);
209 }
210 
211 static int
digi_init(struct digi_softc * sc)212 digi_init(struct digi_softc *sc)
213 {
214 	int i, cnt, resp;
215 	u_char *ptr;
216 	int lowwater;
217 	struct digi_p *port;
218 	volatile struct board_chan *bc;
219 	struct tty *tp;
220 
221 	ptr = NULL;
222 
223 	if (sc->status == DIGI_STATUS_DISABLED) {
224 		log(LOG_ERR, "digi%d: Cannot init a disabled card\n",
225 		    sc->res.unit);
226 		return (EIO);
227 	}
228 	if (sc->bios.data == NULL) {
229 		log(LOG_ERR, "digi%d: Cannot init without BIOS\n",
230 		    sc->res.unit);
231 		return (EIO);
232 	}
233 #if 0
234 	if (sc->link.data == NULL && sc->model >= PCCX) {
235 		log(LOG_ERR, "digi%d: Cannot init without link info\n",
236 		    sc->res.unit);
237 		return (EIO);
238 	}
239 #endif
240 	if (sc->fep.data == NULL) {
241 		log(LOG_ERR, "digi%d: Cannot init without fep code\n",
242 		    sc->res.unit);
243 		return (EIO);
244 	}
245 	sc->status = DIGI_STATUS_NOTINIT;
246 
247 	if (sc->numports) {
248 		/*
249 		 * We're re-initialising - maybe because someone's attached
250 		 * another port module.  For now, we just re-initialise
251 		 * everything.
252 		 */
253 		if (digi_inuse(sc))
254 			return (EBUSY);
255 
256 		digi_free_state(sc);
257 	}
258 
259 	ptr = sc->setwin(sc, MISCGLOBAL);
260 	for (i = 0; i < 16; i += 2)
261 		vW(ptr + i) = 0;
262 
263 	switch (sc->model) {
264 	case PCXEVE:
265 		outb(sc->wport, 0xff);		/* window 7 */
266 		ptr = sc->vmem + (BIOSCODE & 0x1fff);
267 
268 		if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) {
269 			device_printf(sc->dev, "BIOS upload failed\n");
270 			return (EIO);
271 		}
272 
273 		outb(sc->port, FEPCLR);
274 		break;
275 
276 	case PCXE:
277 	case PCXI:
278 	case PCCX:
279 		ptr = sc->setwin(sc, BIOSCODE + ((0xf000 - sc->mem_seg) << 4));
280 		if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) {
281 			device_printf(sc->dev, "BIOS upload failed\n");
282 			return (EIO);
283 		}
284 		break;
285 
286 	case PCXEM:
287 	case PCIEPCX:
288 	case PCIXR:
289 		if (sc->pcibus)
290 			PCIPORT = FEPRST;
291 		else
292 			outb(sc->port, FEPRST | FEPMEM);
293 
294 		for (i = 0; ((sc->pcibus ? PCIPORT : inb(sc->port)) &
295 		    FEPMASK) != FEPRST; i++) {
296 			if (i > hz) {
297 				log(LOG_ERR, "digi%d: %s init reset failed\n",
298 				    sc->res.unit, sc->name);
299 				return (EIO);
300 			}
301 			digi_delay(sc, "digiinit0", 5);
302 		}
303 		DLOG(DIGIDB_INIT, (sc->dev, "Got init reset after %d us\n", i));
304 
305 		/* Now upload the BIOS */
306 		cnt = (sc->bios.size < sc->win_size - BIOSOFFSET) ?
307 		    sc->bios.size : sc->win_size - BIOSOFFSET;
308 
309 		ptr = sc->setwin(sc, BIOSOFFSET);
310 		if (!digi_bcopy(sc->bios.data, ptr, cnt)) {
311 			device_printf(sc->dev, "BIOS upload (1) failed\n");
312 			return (EIO);
313 		}
314 
315 		if (cnt != sc->bios.size) {
316 			/* and the second part */
317 			ptr = sc->setwin(sc, sc->win_size);
318 			if (!digi_bcopy(sc->bios.data + cnt, ptr,
319 			    sc->bios.size - cnt)) {
320 				device_printf(sc->dev, "BIOS upload failed\n");
321 				return (EIO);
322 			}
323 		}
324 
325 		ptr = sc->setwin(sc, 0);
326 		vW(ptr + 0) = 0x0401;
327 		vW(ptr + 2) = 0x0bf0;
328 		vW(ptr + 4) = 0x0000;
329 		vW(ptr + 6) = 0x0000;
330 
331 		break;
332 	}
333 
334 	DLOG(DIGIDB_INIT, (sc->dev, "BIOS uploaded\n"));
335 
336 	ptr = sc->setwin(sc, MISCGLOBAL);
337 	W(ptr) = 0;
338 
339 	if (sc->pcibus) {
340 		PCIPORT = FEPCLR;
341 		resp = FEPRST;
342 	} else if (sc->model == PCXEVE) {
343 		outb(sc->port, FEPCLR);
344 		resp = FEPRST;
345 	} else {
346 		outb(sc->port, FEPCLR | FEPMEM);
347 		resp = FEPRST | FEPMEM;
348 	}
349 
350 	for (i = 0; ((sc->pcibus ? PCIPORT : inb(sc->port)) & FEPMASK)
351 	    == resp; i++) {
352 		if (i > hz) {
353 			log(LOG_ERR, "digi%d: BIOS start failed\n",
354 			    sc->res.unit);
355 			return (EIO);
356 		}
357 		digi_delay(sc, "digibios0", 5);
358 	}
359 
360 	DLOG(DIGIDB_INIT, (sc->dev, "BIOS started after %d us\n", i));
361 
362 	for (i = 0; vW(ptr) != *(u_short *)"GD"; i++) {
363 		if (i > 5*hz) {
364 			log(LOG_ERR, "digi%d: BIOS boot failed "
365 			    "(0x%02x != 0x%02x)\n",
366 			    sc->res.unit, vW(ptr), *(u_short *)"GD");
367 			return (EIO);
368 		}
369 		digi_delay(sc, "digibios1", 5);
370 	}
371 
372 	DLOG(DIGIDB_INIT, (sc->dev, "BIOS booted after %d iterations\n", i));
373 
374 	if (sc->link.data != NULL) {
375 		DLOG(DIGIDB_INIT, (sc->dev, "Loading link data\n"));
376 		ptr = sc->setwin(sc, 0xcd0);
377 		digi_bcopy(sc->link.data, ptr, 21);	/* XXX 21 ? */
378 	}
379 
380 	/* load FEP/OS */
381 
382 	switch (sc->model) {
383 	case PCXE:
384 	case PCXEVE:
385 	case PCXI:
386 		ptr = sc->setwin(sc, sc->model == PCXI ? 0x2000 : 0x0);
387 		digi_bcopy(sc->fep.data, ptr, sc->fep.size);
388 
389 		/* A BIOS request to move our data to 0x2000 */
390 		ptr = sc->setwin(sc, MBOX);
391 		vW(ptr + 0) = 2;
392 		vW(ptr + 2) = sc->mem_seg + FEPCODESEG;
393 		vW(ptr + 4) = 0;
394 		vW(ptr + 6) = FEPCODESEG;
395 		vW(ptr + 8) = 0;
396 		vW(ptr + 10) = sc->fep.size;
397 
398 		/* Run the BIOS request */
399 		outb(sc->port, FEPREQ | FEPMEM);
400 		outb(sc->port, FEPCLR | FEPMEM);
401 
402 		for (i = 0; W(ptr); i++) {
403 			if (i > hz) {
404 				log(LOG_ERR, "digi%d: FEP/OS move failed\n",
405 				    sc->res.unit);
406 				sc->hidewin(sc);
407 				return (EIO);
408 			}
409 			digi_delay(sc, "digifep0", 5);
410 		}
411 		DLOG(DIGIDB_INIT,
412 		    (sc->dev, "FEP/OS moved after %d iterations\n", i));
413 
414 		/* Clear the confirm word */
415 		ptr = sc->setwin(sc, FEPSTAT);
416 		vW(ptr + 0) = 0;
417 
418 		/* A BIOS request to execute the FEP/OS */
419 		ptr = sc->setwin(sc, MBOX);
420 		vW(ptr + 0) = 0x01;
421 		vW(ptr + 2) = FEPCODESEG;
422 		vW(ptr + 4) = 0x04;
423 
424 		/* Run the BIOS request */
425 		outb(sc->port, FEPREQ);
426 		outb(sc->port, FEPCLR);
427 
428 		ptr = sc->setwin(sc, FEPSTAT);
429 
430 		break;
431 
432 	case PCXEM:
433 	case PCIEPCX:
434 	case PCIXR:
435 		DLOG(DIGIDB_INIT, (sc->dev, "Loading FEP/OS\n"));
436 
437 		cnt = (sc->fep.size < sc->win_size - BIOSOFFSET) ?
438 		    sc->fep.size : sc->win_size - BIOSOFFSET;
439 
440 		ptr = sc->setwin(sc, BIOSOFFSET);
441 		digi_bcopy(sc->fep.data, ptr, cnt);
442 
443 		if (cnt != sc->fep.size) {
444 			ptr = sc->setwin(sc, BIOSOFFSET + cnt);
445 			digi_bcopy(sc->fep.data + cnt, ptr,
446 			    sc->fep.size - cnt);
447 		}
448 
449 		DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS loaded\n"));
450 
451 		ptr = sc->setwin(sc, 0xc30);
452 		W(ptr + 4) = 0x1004;
453 		W(ptr + 6) = 0xbfc0;
454 		W(ptr + 0) = 0x03;
455 		W(ptr + 2) = 0x00;
456 
457 		/* Clear the confirm word */
458 		ptr = sc->setwin(sc, FEPSTAT);
459 		W(ptr + 0) = 0;
460 
461 		if (sc->port)
462 			outb(sc->port, 0);		/* XXX necessary ? */
463 
464 		break;
465 
466 	case PCCX:
467 		ptr = sc->setwin(sc, 0xd000);
468 		digi_bcopy(sc->fep.data, ptr, sc->fep.size);
469 
470 		/* A BIOS request to execute the FEP/OS */
471 		ptr = sc->setwin(sc, 0xc40);
472 		W(ptr + 0) = 1;
473 		W(ptr + 2) = FEPCODE >> 4;
474 		W(ptr + 4) = 4;
475 
476 		/* Clear the confirm word */
477 		ptr = sc->setwin(sc, FEPSTAT);
478 		W(ptr + 0) = 0;
479 
480 		/* Run the BIOS request */
481 		outb(sc->port, FEPREQ | FEPMEM); /* send interrupt to BIOS */
482 		outb(sc->port, FEPCLR | FEPMEM);
483 		break;
484 	}
485 
486 	/* Now wait 'till the FEP/OS has booted */
487 	for (i = 0; vW(ptr) != *(u_short *)"OS"; i++) {
488 		if (i > 2*hz) {
489 			log(LOG_ERR, "digi%d: FEP/OS start failed "
490 			    "(0x%02x != 0x%02x)\n",
491 			    sc->res.unit, vW(ptr), *(u_short *)"OS");
492 			sc->hidewin(sc);
493 			return (EIO);
494 		}
495 		digi_delay(sc, "digifep1", 5);
496 	}
497 
498 	DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS started after %d iterations\n", i));
499 
500 	if (sc->model >= PCXEM) {
501 		ptr = sc->setwin(sc, 0xe04);
502 		vW(ptr) = 2;
503 		ptr = sc->setwin(sc, 0xc02);
504 		sc->numports = vW(ptr);
505 	} else {
506 		ptr = sc->setwin(sc, 0xc22);
507 		sc->numports = vW(ptr);
508 	}
509 
510 	if (sc->numports == 0) {
511 		device_printf(sc->dev, "%s, 0 ports found\n", sc->name);
512 		sc->hidewin(sc);
513 		return (0);
514 	}
515 
516 	device_printf(sc->dev, "%s, %d ports found\n", sc->name, sc->numports);
517 
518 	if (sc->ports)
519 		free(sc->ports, M_TTYS);
520 	sc->ports = malloc(sizeof(struct digi_p) * sc->numports,
521 	    M_TTYS, M_WAITOK | M_ZERO);
522 
523 	/*
524 	 * XXX Should read port 0xc90 for an array of 2byte values, 1 per
525 	 * port.  If the value is 0, the port is broken....
526 	 */
527 
528 	ptr = sc->setwin(sc, 0);
529 
530 	/* We should now init per-port structures */
531 	bc = (volatile struct board_chan *)(ptr + CHANSTRUCT);
532 	sc->gdata = (volatile struct global_data *)(ptr + FEP_GLOBAL);
533 
534 	sc->memcmd = ptr + sc->gdata->cstart;
535 	sc->memevent = ptr + sc->gdata->istart;
536 
537 	for (i = 0; i < sc->numports; i++, bc++) {
538 		port = sc->ports + i;
539 		port->pnum = i;
540 		port->sc = sc;
541 		port->status = ENABLED;
542 		port->bc = bc;
543 		tp = port->tp = ttyalloc();
544 		tp->t_oproc = digistart;
545 		tp->t_param = digiparam;
546 		tp->t_modem = digimodem;
547 		tp->t_break = digibreak;
548 		tp->t_stop = digistop;
549 		tp->t_cioctl = digisioctl;
550 		tp->t_ioctl = digiioctl;
551 		tp->t_open = digiopen;
552 		tp->t_close = digiclose;
553 		tp->t_sc = port;
554 
555 		if (sc->model == PCXEVE) {
556 			port->txbuf = ptr +
557 			    (((bc->tseg - sc->mem_seg) << 4) & 0x1fff);
558 			port->rxbuf = ptr +
559 			    (((bc->rseg - sc->mem_seg) << 4) & 0x1fff);
560 			port->txwin = FEPWIN | ((bc->tseg - sc->mem_seg) >> 9);
561 			port->rxwin = FEPWIN | ((bc->rseg - sc->mem_seg) >> 9);
562 		} else if (sc->model == PCXI || sc->model == PCXE) {
563 			port->txbuf = ptr + ((bc->tseg - sc->mem_seg) << 4);
564 			port->rxbuf = ptr + ((bc->rseg - sc->mem_seg) << 4);
565 			port->txwin = port->rxwin = 0;
566 		} else {
567 			port->txbuf = ptr +
568 			    (((bc->tseg - sc->mem_seg) << 4) % sc->win_size);
569 			port->rxbuf = ptr +
570 			    (((bc->rseg - sc->mem_seg) << 4) % sc->win_size);
571 			port->txwin = FEPWIN |
572 			    (((bc->tseg - sc->mem_seg) << 4) / sc->win_size);
573 			port->rxwin = FEPWIN |
574 			    (((bc->rseg - sc->mem_seg) << 4) / sc->win_size);
575 		}
576 		port->txbufsize = bc->tmax + 1;
577 		port->rxbufsize = bc->rmax + 1;
578 
579 		lowwater = port->txbufsize >> 2;
580 		if (lowwater > 1024)
581 			lowwater = 1024;
582 		sc->setwin(sc, 0);
583 		fepcmd_w(port, STXLWATER, lowwater, 10);
584 		fepcmd_w(port, SRXLWATER, port->rxbufsize >> 2, 10);
585 		fepcmd_w(port, SRXHWATER, (3 * port->rxbufsize) >> 2, 10);
586 
587 		bc->edelay = 100;
588 
589 		ttyinitmode(tp, 0, 0);
590 		port->send_ring = 1;	/* Default action on signal RI */
591 		ttycreate(tp, TS_CALLOUT, "D%r%r", sc->res.unit, i);
592 	}
593 
594 	sc->hidewin(sc);
595 	sc->inttest = timeout(digi_int_test, sc, hz);
596 	/* fepcmd_w(&sc->ports[0], 0xff, 0, 0); */
597 	sc->status = DIGI_STATUS_ENABLED;
598 
599 	return (0);
600 }
601 
602 static int
digimodem(struct tty * tp,int sigon,int sigoff)603 digimodem(struct tty *tp, int sigon, int sigoff)
604 {
605 	struct digi_softc *sc;
606 	struct digi_p *port;
607 	int bitand, bitor, mstat;
608 
609 	port = tp->t_sc;
610 	sc = port->sc;
611 
612 	if (sigon == 0 && sigoff == 0) {
613 		port->sc->setwin(port->sc, 0);
614 		mstat = port->bc->mstat;
615 		port->sc->hidewin(port->sc);
616 		if (mstat & port->sc->csigs->rts)
617 			sigon |= SER_RTS;
618 		if (mstat & port->cd)
619 			sigon |= SER_DCD;
620 		if (mstat & port->dsr)
621 			sigon |= SER_DSR;
622 		if (mstat & port->sc->csigs->cts)
623 			sigon |= SER_CTS;
624 		if (mstat & port->sc->csigs->ri)
625 			sigon |= SER_RI;
626 		if (mstat & port->sc->csigs->dtr)
627 			sigon |= SER_DTR;
628 		return (sigon);
629 	}
630 
631 	bitand = 0;
632 	bitor = 0;
633 
634 	if (sigoff & SER_DTR)
635 		bitand |= port->sc->csigs->dtr;
636 	if (sigoff & SER_RTS)
637 		bitand |= port->sc->csigs->rts;
638 	if (sigon & SER_DTR)
639 		bitor |= port->sc->csigs->dtr;
640 	if (sigon & SER_RTS)
641 		bitor |= port->sc->csigs->rts;
642 	fepcmd_b(port, SETMODEM, bitor, ~bitand, 0);
643 	return (0);
644 }
645 
646 static int
digicopen(struct cdev * dev,int flag,int mode,struct thread * td)647 digicopen(struct cdev *dev, int flag, int mode, struct thread *td)
648 {
649 	struct digi_softc *sc;
650 
651 	sc = dev->si_drv1;
652 	if (sc->status != DIGI_STATUS_ENABLED) {
653 		DLOG(DIGIDB_OPEN, (sc->dev, "Cannot open a disabled card\n"));
654 		return (ENXIO);
655 	}
656 	sc->opencnt++;
657 	return (0);
658 }
659 
660 static int
digiopen(struct tty * tp,struct cdev * dev)661 digiopen(struct tty *tp, struct cdev *dev)
662 {
663 	int error;
664 	struct digi_softc *sc;
665 	struct digi_p *port;
666 	volatile struct board_chan *bc;
667 
668 	port = tp->t_sc;
669 	sc = port->sc;
670 
671 	if (sc->status != DIGI_STATUS_ENABLED) {
672 		DLOG(DIGIDB_OPEN, (sc->dev, "Cannot open a disabled card\n"));
673 		return (ENXIO);
674 	}
675 	bc = port->bc;
676 
677 	/*
678 	 * The device isn't open, so there are no conflicts.
679 	 * Initialize it.  Initialization is done twice in many
680 	 * cases: to preempt sleeping callin opens if we are callout,
681 	 * and to complete a callin open after DCD rises.
682 	 */
683 	sc->setwin(sc, 0);
684 
685 	bc->rout = bc->rin;	/* clear input queue */
686 	bc->idata = 1;
687 	bc->iempty = 1;
688 	bc->ilow = 1;
689 	bc->mint = port->cd | port->sc->csigs->ri;
690 	bc->tin = bc->tout;
691 	if (port->ialtpin) {
692 		port->cd = sc->csigs->dsr;
693 		port->dsr = sc->csigs->cd;
694 	} else {
695 		port->cd = sc->csigs->cd;
696 		port->dsr = sc->csigs->dsr;
697 	}
698 	tp->t_wopeners++;			/* XXX required ? */
699 	error = digiparam(tp, &tp->t_termios);
700 	tp->t_wopeners--;
701 
702 	return (error);
703 }
704 
705 static int
digicclose(struct cdev * dev,int flag,int mode,struct thread * td)706 digicclose(struct cdev *dev, int flag, int mode, struct thread *td)
707 {
708 	struct digi_softc *sc;
709 
710 	sc = dev->si_drv1;
711 	sc->opencnt--;
712 	return (0);
713 }
714 
715 static void
digidtrwakeup(void * chan)716 digidtrwakeup(void *chan)
717 {
718 	struct digi_p *port = chan;
719 
720 	port->status &= ~DIGI_DTR_OFF;
721 	wakeup(&port->tp->t_dtr_wait);
722 	port->tp->t_wopeners--;
723 }
724 
725 static void
digiclose(struct tty * tp)726 digiclose(struct tty *tp)
727 {
728 	volatile struct board_chan *bc;
729 	struct digi_p *port;
730 	int s;
731 
732 	port = tp->t_sc;
733 	bc = port->bc;
734 
735 	s = spltty();
736 	port->sc->setwin(port->sc, 0);
737 	bc->idata = 0;
738 	bc->iempty = 0;
739 	bc->ilow = 0;
740 	bc->mint = 0;
741 	if ((tp->t_cflag & HUPCL) ||
742 	    (!tp->t_actout && !(bc->mstat & port->cd) &&
743 	    !(tp->t_init_in.c_cflag & CLOCAL)) ||
744 	    !(tp->t_state & TS_ISOPEN)) {
745 		digimodem(tp, 0, SER_DTR | SER_RTS);
746 		if (tp->t_dtr_wait != 0) {
747 			/* Schedule a wakeup of any callin devices */
748 			tp->t_wopeners++;
749 			timeout(&digidtrwakeup, port, tp->t_dtr_wait);
750 			port->status |= DIGI_DTR_OFF;
751 		}
752 	}
753 	tp->t_actout = FALSE;
754 	wakeup(&tp->t_actout);
755 	wakeup(TSA_CARR_ON(tp));
756 	splx(s);
757 }
758 
759 /*
760  * Load module "digi_<mod>.ko" and look for a symbol called digi_mod_<mod>.
761  *
762  * Populate sc->bios, sc->fep, and sc->link from this data.
763  *
764  * sc->fep.data, sc->bios.data and sc->link.data are malloc()d according
765  * to their respective sizes.
766  *
767  * The module is unloaded when we're done.
768  */
769 static int
digi_loadmoduledata(struct digi_softc * sc)770 digi_loadmoduledata(struct digi_softc *sc)
771 {
772 	struct digi_mod *digi_mod;
773 	linker_file_t lf;
774 	char *modfile, *sym;
775 	caddr_t symptr;
776 	int modlen, res;
777 
778 	KASSERT(sc->bios.data == NULL, ("Uninitialised BIOS variable"));
779 	KASSERT(sc->fep.data == NULL, ("Uninitialised FEP variable"));
780 	KASSERT(sc->link.data == NULL, ("Uninitialised LINK variable"));
781 	KASSERT(sc->module != NULL, ("Uninitialised module name"));
782 
783 	modlen = strlen(sc->module);
784 	modfile = malloc(modlen + 6, M_TEMP, M_WAITOK);
785 	snprintf(modfile, modlen + 6, "digi_%s", sc->module);
786 	if ((res = linker_reference_module(modfile, NULL, &lf)) != 0)
787 		printf("%s: Failed %d to autoload module\n", modfile, res);
788 	free(modfile, M_TEMP);
789 	if (res != 0)
790 		return (res);
791 
792 	sym = malloc(modlen + 10, M_TEMP, M_WAITOK);
793 	snprintf(sym, modlen + 10, "digi_mod_%s", sc->module);
794 	symptr = linker_file_lookup_symbol(lf, sym, 0);
795 	free(sym, M_TEMP);
796 	if (symptr == NULL) {
797 		printf("digi_%s.ko: Symbol `%s' not found\n", sc->module, sym);
798 		linker_release_module(NULL, NULL, lf);
799 		return (EINVAL);
800 	}
801 
802 	digi_mod = (struct digi_mod *)symptr;
803 	if (digi_mod->dm_version != DIGI_MOD_VERSION) {
804 		printf("digi_%s.ko: Invalid version %d (need %d)\n",
805 		    sc->module, digi_mod->dm_version, DIGI_MOD_VERSION);
806 		linker_release_module(NULL, NULL, lf);
807 		return (EINVAL);
808 	}
809 
810 	sc->bios.size = digi_mod->dm_bios.size;
811 	if (sc->bios.size != 0 && digi_mod->dm_bios.data != NULL) {
812 		sc->bios.data = malloc(sc->bios.size, M_TTYS, M_WAITOK);
813 		bcopy(digi_mod->dm_bios.data, sc->bios.data, sc->bios.size);
814 	}
815 
816 	sc->fep.size = digi_mod->dm_fep.size;
817 	if (sc->fep.size != 0 && digi_mod->dm_fep.data != NULL) {
818 		sc->fep.data = malloc(sc->fep.size, M_TTYS, M_WAITOK);
819 		bcopy(digi_mod->dm_fep.data, sc->fep.data, sc->fep.size);
820 	}
821 
822 	sc->link.size = digi_mod->dm_link.size;
823 	if (sc->link.size != 0 && digi_mod->dm_link.data != NULL) {
824 		sc->link.data = malloc(sc->link.size, M_TTYS, M_WAITOK);
825 		bcopy(digi_mod->dm_link.data, sc->link.data, sc->link.size);
826 	}
827 
828 	linker_release_module(NULL, NULL, lf);
829 
830 	return (0);
831 }
832 
833 static int
digisioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)834 digisioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
835 {
836 	struct digi_p *port;
837 	struct digi_softc *sc;
838 
839 	port = dev->si_drv1;
840 	sc = port->sc;
841 
842 	switch (cmd) {
843 	case DIGIIO_GETALTPIN:
844 		if (ISINIT(dev))
845 			*(int *)data = port->ialtpin;
846 		else if (ISLOCK(dev))
847 			*(int *)data = port->laltpin;
848 		else
849 			return (ENOTTY);
850 		break;
851 	case DIGIIO_SETALTPIN:
852 		if (ISINIT(dev)) {
853 			if (!port->laltpin) {
854 				port->ialtpin = !!*(int *)data;
855 				DLOG(DIGIDB_SET, (sc->dev,
856 				    "port%d: initial ALTPIN %s\n", port->pnum,
857 				    port->ialtpin ? "set" : "cleared"));
858 			}
859 		} else if (ISLOCK(dev)) {
860 			port->laltpin = !!*(int *)data;
861 			DLOG(DIGIDB_SET, (sc->dev,
862 			    "port%d: ALTPIN %slocked\n",
863 			    port->pnum, port->laltpin ? "" : "un"));
864 		} else
865 			return (ENOTTY);
866 		break;
867 	default:
868 		return (ENOTTY);
869 	}
870 	return (0);
871 }
872 
873 static int
digicioctl(struct cdev * dev,u_long cmd,caddr_t data,int flag,struct thread * td)874 digicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
875 {
876 	int error;
877 	struct digi_softc *sc;
878 
879 	sc = dev->si_drv1;
880 
881 	if (sc->status == DIGI_STATUS_DISABLED)
882 		return (ENXIO);
883 
884 	switch (cmd) {
885 	case DIGIIO_DEBUG:
886 #ifdef DEBUG
887 		digi_debug = *(int *)data;
888 		return (0);
889 #else
890 		device_printf(sc->dev, "DEBUG not defined\n");
891 		return (ENXIO);
892 #endif
893 	case DIGIIO_REINIT:
894 		digi_loadmoduledata(sc);
895 		error = digi_init(sc);
896 		digi_freemoduledata(sc);
897 		return (error);
898 
899 	case DIGIIO_MODEL:
900 		*(enum digi_model *)data = sc->model;
901 		return (0);
902 
903 	case DIGIIO_IDENT:
904 		return (copyout(sc->name, *(char **)data,
905 		    strlen(sc->name) + 1));
906 	default:
907 		return (ENOIOCTL);
908 	}
909 }
910 
911 static int
digiioctl(struct tty * tp,u_long cmd,void * data,int flag,struct thread * td)912 digiioctl(struct tty *tp, u_long cmd, void *data, int flag, struct thread *td)
913 {
914 	struct digi_softc *sc;
915 	struct digi_p *port;
916 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
917     defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
918 	int ival;
919 #endif
920 
921 	port = tp->t_sc;
922 	sc = port->sc;
923 	if (sc->status == DIGI_STATUS_DISABLED)
924 		return (ENXIO);
925 
926 	if (!(port->status & ENABLED))
927 		return (ENXIO);
928 
929 	switch (cmd) {
930 	case DIGIIO_GETALTPIN:
931 		*(int *)data = !!(port->dsr == sc->csigs->cd);
932 		return (0);
933 
934 	case DIGIIO_SETALTPIN:
935 		if (!port->laltpin) {
936 			if (*(int *)data) {
937 				DLOG(DIGIDB_SET, (sc->dev,
938 				    "port%d: ALTPIN set\n", port->pnum));
939 				port->cd = sc->csigs->dsr;
940 				port->dsr = sc->csigs->cd;
941 			} else {
942 				DLOG(DIGIDB_SET, (sc->dev,
943 				    "port%d: ALTPIN cleared\n", port->pnum));
944 				port->cd = sc->csigs->cd;
945 				port->dsr = sc->csigs->dsr;
946 			}
947 		}
948 		return (0);
949 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
950     defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
951 	case _IO('e', 'C'):
952 		ival = IOCPARM_IVAL(data);
953 		data = &ival;
954 		/* FALLTHROUGH */
955 #endif
956 	case DIGIIO_RING:
957 		port->send_ring = (u_char)*(int *)data;
958 		break;
959 	default:
960 		return (ENOTTY);
961 	}
962 	return (0);
963 }
964 
965 static void
digibreak(struct tty * tp,int brk)966 digibreak(struct tty *tp, int brk)
967 {
968 	struct digi_p *port;
969 
970 	port = tp->t_sc;
971 
972 	/*
973 	 * now it sends 400 millisecond break because I don't know
974 	 * how to send an infinite break
975 	 */
976 	if (brk)
977 		fepcmd_w(port, SENDBREAK, 400, 10);
978 }
979 
980 static int
digiparam(struct tty * tp,struct termios * t)981 digiparam(struct tty *tp, struct termios *t)
982 {
983 	struct digi_softc *sc;
984 	struct digi_p *port;
985 	int cflag;
986 	int iflag;
987 	int hflow;
988 	int s;
989 	int window;
990 
991 	port = tp->t_sc;
992 	sc = port->sc;
993 	DLOG(DIGIDB_SET, (sc->dev, "port%d: setting parameters\n", port->pnum));
994 
995 	if (t->c_ispeed == 0)
996 		t->c_ispeed = t->c_ospeed;
997 
998 	cflag = ttspeedtab(t->c_ospeed, digispeedtab);
999 
1000 	if (cflag < 0 || (cflag > 0 && t->c_ispeed != t->c_ospeed))
1001 		return (EINVAL);
1002 
1003 	s = splclock();
1004 
1005 	window = sc->window;
1006 	sc->setwin(sc, 0);
1007 
1008 	if (cflag == 0) {				/* hangup */
1009 		DLOG(DIGIDB_SET, (sc->dev, "port%d: hangup\n", port->pnum));
1010 		digimodem(port->tp, 0, SER_DTR | SER_RTS);
1011 	} else {
1012 		digimodem(port->tp, SER_DTR | SER_RTS, 0);
1013 
1014 		DLOG(DIGIDB_SET, (sc->dev, "port%d: CBAUD = %d\n", port->pnum,
1015 		    cflag));
1016 
1017 #if 0
1018 		/* convert flags to sysV-style values */
1019 		if (t->c_cflag & PARODD)
1020 			cflag |= 0x0200;
1021 		if (t->c_cflag & PARENB)
1022 			cflag |= 0x0100;
1023 		if (t->c_cflag & CSTOPB)
1024 			cflag |= 0x0080;
1025 #else
1026 		/* convert flags to sysV-style values */
1027 		if (t->c_cflag & PARODD)
1028 			cflag |= FEP_PARODD;
1029 		if (t->c_cflag & PARENB)
1030 			cflag |= FEP_PARENB;
1031 		if (t->c_cflag & CSTOPB)
1032 			cflag |= FEP_CSTOPB;
1033 		if (t->c_cflag & CLOCAL)
1034 			cflag |= FEP_CLOCAL;
1035 #endif
1036 
1037 		cflag |= (t->c_cflag & CSIZE) >> 4;
1038 		DLOG(DIGIDB_SET, (sc->dev, "port%d: CFLAG = 0x%x\n", port->pnum,
1039 		    cflag));
1040 		fepcmd_w(port, SETCFLAGS, (unsigned)cflag, 0);
1041 	}
1042 
1043 	iflag =
1044 	    t->c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP);
1045 	if (port->c_iflag & IXON)
1046 		iflag |= 0x400;
1047 	if (port->c_iflag & IXANY)
1048 		iflag |= 0x800;
1049 	if (port->c_iflag & IXOFF)
1050 		iflag |= 0x1000;
1051 
1052 	DLOG(DIGIDB_SET, (sc->dev, "port%d: set iflag = 0x%x\n", port->pnum, iflag));
1053 	fepcmd_w(port, SETIFLAGS, (unsigned)iflag, 0);
1054 
1055 	hflow = 0;
1056 	if (t->c_cflag & CDTR_IFLOW)
1057 		hflow |= sc->csigs->dtr;
1058 	if (t->c_cflag & CRTS_IFLOW)
1059 		hflow |= sc->csigs->rts;
1060 	if (t->c_cflag & CCTS_OFLOW)
1061 		hflow |= sc->csigs->cts;
1062 	if (t->c_cflag & CDSR_OFLOW)
1063 		hflow |= port->dsr;
1064 	if (t->c_cflag & CCAR_OFLOW)
1065 		hflow |= port->cd;
1066 
1067 	DLOG(DIGIDB_SET, (sc->dev, "port%d: set hflow = 0x%x\n", port->pnum, hflow));
1068 	fepcmd_w(port, SETHFLOW, 0xff00 | (unsigned)hflow, 0);
1069 
1070 	DLOG(DIGIDB_SET, (sc->dev, "port%d: set startc(0x%x), stopc(0x%x)\n",
1071 	    port->pnum, t->c_cc[VSTART], t->c_cc[VSTOP]));
1072 	fepcmd_b(port, SONOFFC, t->c_cc[VSTART], t->c_cc[VSTOP], 0);
1073 
1074 	if (sc->window != 0)
1075 		sc->towin(sc, 0);
1076 	if (window != 0)
1077 		sc->towin(sc, window);
1078 	splx(s);
1079 
1080 	return (0);
1081 }
1082 
1083 static void
digi_intr(void * vp)1084 digi_intr(void *vp)
1085 {
1086 	struct digi_p *port;
1087 	char *cxcon;
1088 	struct digi_softc *sc;
1089 	int ehead, etail;
1090 	volatile struct board_chan *bc;
1091 	struct tty *tp;
1092 	int head, tail;
1093 	int wrapmask;
1094 	int size, window;
1095 	struct event {
1096 		u_char pnum;
1097 		u_char event;
1098 		u_char mstat;
1099 		u_char lstat;
1100 	} event;
1101 
1102 	sc = vp;
1103 
1104 	if (sc->status != DIGI_STATUS_ENABLED) {
1105 		DLOG(DIGIDB_IRQ, (sc->dev, "interrupt on disabled board !\n"));
1106 		return;
1107 	}
1108 
1109 #ifdef DIGI_INTERRUPT
1110 	microtime(&sc->intr_timestamp);
1111 #endif
1112 
1113 	window = sc->window;
1114 	sc->setwin(sc, 0);
1115 
1116 	if (sc->model >= PCXEM && W(sc->vmem + 0xd00)) {
1117 		struct con_bios *con = con_bios_list;
1118 		register u_char *ptr;
1119 
1120 		ptr = sc->vmem + W(sc->vmem + 0xd00);
1121 		while (con) {
1122 			if (ptr[1] && W(ptr + 2) == W(con->bios + 2))
1123 				/* Not first block -- exact match */
1124 				break;
1125 
1126 			if (W(ptr + 4) >= W(con->bios + 4) &&
1127 			    W(ptr + 4) <= W(con->bios + 6))
1128 				/* Initial search concetrator BIOS */
1129 				break;
1130 		}
1131 
1132 		if (con == NULL) {
1133 			log(LOG_ERR, "digi%d: wanted bios LREV = 0x%04x"
1134 			    " not found!\n", sc->res.unit, W(ptr + 4));
1135 			W(ptr + 10) = 0;
1136 			W(sc->vmem + 0xd00) = 0;
1137 			goto eoi;
1138 		}
1139 		cxcon = con->bios;
1140 		W(ptr + 4) = W(cxcon + 4);
1141 		W(ptr + 6) = W(cxcon + 6);
1142 		if (ptr[1] == 0)
1143 			W(ptr + 2) = W(cxcon + 2);
1144 		W(ptr + 8) = (ptr[1] << 6) + W(cxcon + 8);
1145 		size = W(cxcon + 10) - (ptr[1] << 10);
1146 		if (size <= 0) {
1147 			W(ptr + 8) = W(cxcon + 8);
1148 			W(ptr + 10) = 0;
1149 		} else {
1150 			if (size > 1024)
1151 				size = 1024;
1152 			W(ptr + 10) = size;
1153 			bcopy(cxcon + (ptr[1] << 10), ptr + 12, size);
1154 		}
1155 		W(sc->vmem + 0xd00) = 0;
1156 		goto eoi;
1157 	}
1158 
1159 	ehead = sc->gdata->ein;
1160 	etail = sc->gdata->eout;
1161 	if (ehead == etail) {
1162 #ifdef DEBUG
1163 		sc->intr_count++;
1164 		if (sc->intr_count % 6000 == 0) {
1165 			DLOG(DIGIDB_IRQ, (sc->dev,
1166 			    "6000 useless polls %x %x\n", ehead, etail));
1167 			sc->intr_count = 0;
1168 		}
1169 #endif
1170 		goto eoi;
1171 	}
1172 	while (ehead != etail) {
1173 		event = *(volatile struct event *)(sc->memevent + etail);
1174 
1175 		etail = (etail + 4) & sc->gdata->imax;
1176 
1177 		if (event.pnum >= sc->numports) {
1178 			log(LOG_ERR, "digi%d: port %d: got event"
1179 			    " on nonexisting port\n", sc->res.unit,
1180 			    event.pnum);
1181 			continue;
1182 		}
1183 		port = &sc->ports[event.pnum];
1184 		bc = port->bc;
1185 		tp = port->tp;
1186 
1187 		if (!(tp->t_state & TS_ISOPEN) && !tp->t_wopeners) {
1188 			DLOG(DIGIDB_IRQ, (sc->dev,
1189 			    "port %d: event 0x%x on closed port\n",
1190 			    event.pnum, event.event));
1191 			bc->rout = bc->rin;
1192 			bc->idata = 0;
1193 			bc->iempty = 0;
1194 			bc->ilow = 0;
1195 			bc->mint = 0;
1196 			continue;
1197 		}
1198 		if (event.event & ~ALL_IND)
1199 			log(LOG_ERR, "digi%d: port%d: ? event 0x%x mstat 0x%x"
1200 			    " lstat 0x%x\n", sc->res.unit, event.pnum,
1201 			    event.event, event.mstat, event.lstat);
1202 
1203 		if (event.event & DATA_IND) {
1204 			DLOG(DIGIDB_IRQ, (sc->dev, "port %d: DATA_IND\n",
1205 			    event.pnum));
1206 			wrapmask = port->rxbufsize - 1;
1207 			head = bc->rin;
1208 			tail = bc->rout;
1209 
1210 			size = 0;
1211 			if (!(tp->t_state & TS_ISOPEN)) {
1212 				bc->rout = head;
1213 				goto end_of_data;
1214 			}
1215 			while (head != tail) {
1216 				int top;
1217 
1218 				DLOG(DIGIDB_INT, (sc->dev,
1219 				    "port %d: p rx head = %d tail = %d\n",
1220 				    event.pnum, head, tail));
1221 				top = (head > tail) ? head : wrapmask + 1;
1222 				sc->towin(sc, port->rxwin);
1223 				size = top - tail;
1224 				if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1225 					size = b_to_q((char *)port->rxbuf +
1226 					    tail, size, &tp->t_rawq);
1227 					tail = top - size;
1228 					ttwakeup(tp);
1229 				} else for (; tail < top;) {
1230 					ttyld_rint(tp, port->rxbuf[tail]);
1231 					sc->towin(sc, port->rxwin);
1232 					size--;
1233 					tail++;
1234 					if (tp->t_state & TS_TBLOCK)
1235 						break;
1236 				}
1237 				tail &= wrapmask;
1238 				sc->setwin(sc, 0);
1239 				bc->rout = tail;
1240 				head = bc->rin;
1241 				if (size)
1242 					break;
1243 			}
1244 
1245 			if (bc->orun) {
1246 				CE_RECORD(port, CE_OVERRUN);
1247 				log(LOG_ERR, "digi%d: port%d: %s\n",
1248 				    sc->res.unit, event.pnum,
1249 				    digi_errortxt(CE_OVERRUN));
1250 				bc->orun = 0;
1251 			}
1252 end_of_data:
1253 			if (size) {
1254 				tp->t_state |= TS_TBLOCK;
1255 				port->status |= PAUSE_RX;
1256 				DLOG(DIGIDB_RX, (sc->dev, "port %d: pause RX\n",
1257 				    event.pnum));
1258 			} else {
1259 				bc->idata = 1;
1260 			}
1261 		}
1262 
1263 		if (event.event & MODEMCHG_IND) {
1264 			DLOG(DIGIDB_MODEM, (sc->dev, "port %d: MODEMCHG_IND\n",
1265 			    event.pnum));
1266 
1267 			if ((event.mstat ^ event.lstat) & port->cd) {
1268 				sc->hidewin(sc);
1269 				ttyld_modem(tp, event.mstat & port->cd);
1270 				sc->setwin(sc, 0);
1271 				wakeup(TSA_CARR_ON(tp));
1272 			}
1273 
1274 			if (event.mstat & sc->csigs->ri) {
1275 				DLOG(DIGIDB_RI, (sc->dev, "port %d: RING\n",
1276 				    event.pnum));
1277 				if (port->send_ring) {
1278 					ttyld_rint(tp, 'R');
1279 					ttyld_rint(tp, 'I');
1280 					ttyld_rint(tp, 'N');
1281 					ttyld_rint(tp, 'G');
1282 					ttyld_rint(tp, '\r');
1283 					ttyld_rint(tp, '\n');
1284 				}
1285 			}
1286 		}
1287 		if (event.event & BREAK_IND) {
1288 			DLOG(DIGIDB_MODEM, (sc->dev, "port %d: BREAK_IND\n",
1289 			    event.pnum));
1290 			ttyld_rint(tp, TTY_BI);
1291 		}
1292 		if (event.event & (LOWTX_IND | EMPTYTX_IND)) {
1293 			DLOG(DIGIDB_IRQ, (sc->dev, "port %d:%s%s\n",
1294 			    event.pnum,
1295 			    event.event & LOWTX_IND ? " LOWTX" : "",
1296 			    event.event & EMPTYTX_IND ?  " EMPTYTX" : ""));
1297 			ttyld_start(tp);
1298 		}
1299 	}
1300 	sc->gdata->eout = etail;
1301 eoi:
1302 	if (sc->window != 0)
1303 		sc->towin(sc, 0);
1304 	if (window != 0)
1305 		sc->towin(sc, window);
1306 }
1307 
1308 static void
digistart(struct tty * tp)1309 digistart(struct tty *tp)
1310 {
1311 	struct digi_p *port;
1312 	struct digi_softc *sc;
1313 	volatile struct board_chan *bc;
1314 	int head, tail;
1315 	int size, ocount, totcnt = 0;
1316 	int s;
1317 	int wmask;
1318 
1319 	port = tp->t_sc;
1320 	sc = port->sc;
1321 	bc = port->bc;
1322 
1323 	wmask = port->txbufsize - 1;
1324 
1325 	s = spltty();
1326 	port->lcc = tp->t_outq.c_cc;
1327 	sc->setwin(sc, 0);
1328 	if (!(tp->t_state & TS_TBLOCK)) {
1329 		if (port->status & PAUSE_RX) {
1330 			DLOG(DIGIDB_RX, (sc->dev, "port %d: resume RX\n",
1331 			    port->pnum));
1332 			/*
1333 			 * CAREFUL - braces are needed here if the DLOG is
1334 			 * optimised out!
1335 			 */
1336 		}
1337 		port->status &= ~PAUSE_RX;
1338 		bc->idata = 1;
1339 	}
1340 	if (!(tp->t_state & TS_TTSTOP) && port->status & PAUSE_TX) {
1341 		DLOG(DIGIDB_TX, (sc->dev, "port %d: resume TX\n", port->pnum));
1342 		port->status &= ~PAUSE_TX;
1343 		fepcmd_w(port, RESUMETX, 0, 10);
1344 	}
1345 	if (tp->t_outq.c_cc == 0)
1346 		tp->t_state &= ~TS_BUSY;
1347 	else
1348 		tp->t_state |= TS_BUSY;
1349 
1350 	head = bc->tin;
1351 	while (tp->t_outq.c_cc != 0) {
1352 		tail = bc->tout;
1353 		DLOG(DIGIDB_INT, (sc->dev, "port%d: s tx head = %d tail = %d\n",
1354 		    port->pnum, head, tail));
1355 
1356 		if (head < tail)
1357 			size = tail - head - 1;
1358 		else {
1359 			size = port->txbufsize - head;
1360 			if (tail == 0)
1361 				size--;
1362 		}
1363 
1364 		if (size == 0)
1365 			break;
1366 		sc->towin(sc, port->txwin);
1367 		ocount = q_to_b(&tp->t_outq, port->txbuf + head, size);
1368 		totcnt += ocount;
1369 		head += ocount;
1370 		head &= wmask;
1371 		sc->setwin(sc, 0);
1372 		bc->tin = head;
1373 		bc->iempty = 1;
1374 		bc->ilow = 1;
1375 	}
1376 	port->lostcc = tp->t_outq.c_cc;
1377 	tail = bc->tout;
1378 	if (head < tail)
1379 		size = port->txbufsize - tail + head;
1380 	else
1381 		size = head - tail;
1382 
1383 	port->lbuf = size;
1384 	DLOG(DIGIDB_INT, (sc->dev, "port%d: s total cnt = %d\n", port->pnum, totcnt));
1385 	ttwwakeup(tp);
1386 	splx(s);
1387 }
1388 
1389 static void
digistop(struct tty * tp,int rw)1390 digistop(struct tty *tp, int rw)
1391 {
1392 	struct digi_softc *sc;
1393 	struct digi_p *port;
1394 
1395 	port = tp->t_sc;
1396 	sc = port->sc;
1397 
1398 	DLOG(DIGIDB_TX, (sc->dev, "port %d: pause TX\n", port->pnum));
1399 	port->status |= PAUSE_TX;
1400 	fepcmd_w(port, PAUSETX, 0, 10);
1401 }
1402 
1403 static void
fepcmd(struct digi_p * port,int cmd,int op1,int ncmds)1404 fepcmd(struct digi_p *port, int cmd, int op1, int ncmds)
1405 {
1406 	u_char *mem;
1407 	unsigned tail, head;
1408 	int count, n;
1409 
1410 	mem = port->sc->memcmd;
1411 
1412 	port->sc->setwin(port->sc, 0);
1413 
1414 	head = port->sc->gdata->cin;
1415 	mem[head + 0] = cmd;
1416 	mem[head + 1] = port->pnum;
1417 	*(u_short *)(mem + head + 2) = op1;
1418 
1419 	head = (head + 4) & port->sc->gdata->cmax;
1420 	port->sc->gdata->cin = head;
1421 
1422 	for (count = FEPTIMEOUT; count > 0; count--) {
1423 		head = port->sc->gdata->cin;
1424 		tail = port->sc->gdata->cout;
1425 		n = (head - tail) & port->sc->gdata->cmax;
1426 
1427 		if (n <= ncmds * sizeof(short) * 4)
1428 			break;
1429 	}
1430 	if (count == 0)
1431 		log(LOG_ERR, "digi%d: port%d: timeout on FEP command\n",
1432 		    port->sc->res.unit, port->pnum);
1433 }
1434 
1435 const char *
digi_errortxt(int id)1436 digi_errortxt(int id)
1437 {
1438 	static const char *error_desc[] = {
1439 		"silo overflow",
1440 		"interrupt-level buffer overflow",
1441 		"tty-level buffer overflow",
1442 	};
1443 
1444 	KASSERT(id >= 0 && id < sizeof(error_desc) / sizeof(error_desc[0]),
1445 	    ("Unexpected digi error id %d\n", id));
1446 
1447 	return (error_desc[id]);
1448 }
1449 
1450 int
digi_attach(struct digi_softc * sc)1451 digi_attach(struct digi_softc *sc)
1452 {
1453 	sc->res.ctldev = make_dev(&digi_csw,
1454 	    sc->res.unit << 16, UID_ROOT, GID_WHEEL,
1455 	    0600, "digi%r.ctl", sc->res.unit);
1456 	sc->res.ctldev->si_drv1 = sc;
1457 
1458 	digi_loadmoduledata(sc);
1459 	digi_init(sc);
1460 	digi_freemoduledata(sc);
1461 
1462 	return (0);
1463 }
1464 
1465 static int
digi_inuse(struct digi_softc * sc)1466 digi_inuse(struct digi_softc *sc)
1467 {
1468 	int i;
1469 	struct digi_p *port;
1470 
1471 	port = &sc->ports[0];
1472 	for (i = 0; i < sc->numports; i++, port++)
1473 		if (port->tp->t_state & TS_ISOPEN) {
1474 			DLOG(DIGIDB_INIT, (sc->dev, "port%d: busy\n", i));
1475 			return (1);
1476 		} else if (port->tp->t_wopeners || port->opencnt) {
1477 			DLOG(DIGIDB_INIT, (sc->dev, "port%d: blocked in open\n",
1478 			    i));
1479 			return (1);
1480 		}
1481 	return (0);
1482 }
1483 
1484 static void
digi_free_state(struct digi_softc * sc)1485 digi_free_state(struct digi_softc *sc)
1486 {
1487 	int i;
1488 
1489 	/* Blow it all away */
1490 
1491 	for (i = 0; i < sc->numports; i++)
1492 		ttygone(sc->ports[i].tp);
1493 
1494 	/* XXX: this might be better done as a ttypurge method */
1495 	untimeout(digi_poll, sc, sc->callout);
1496 	callout_handle_init(&sc->callout);
1497 	untimeout(digi_int_test, sc, sc->inttest);
1498 	callout_handle_init(&sc->inttest);
1499 
1500 	for (i = 0; i < sc->numports; i++)
1501 		ttyfree(sc->ports[i].tp);
1502 
1503 	bus_teardown_intr(sc->dev, sc->res.irq, sc->res.irqHandler);
1504 #ifdef DIGI_INTERRUPT
1505 	if (sc->res.irq != NULL) {
1506 		bus_release_resource(dev, SYS_RES_IRQ, sc->res.irqrid,
1507 		    sc->res.irq);
1508 		sc->res.irq = NULL;
1509 	}
1510 #endif
1511 	if (sc->numports) {
1512 		KASSERT(sc->ports, ("digi%d: Lost my ports ?", sc->res.unit));
1513 		free(sc->ports, M_TTYS);
1514 		sc->ports = NULL;
1515 		sc->numports = 0;
1516 	}
1517 
1518 	sc->status = DIGI_STATUS_NOTINIT;
1519 }
1520 
1521 int
digi_detach(device_t dev)1522 digi_detach(device_t dev)
1523 {
1524 	struct digi_softc *sc = device_get_softc(dev);
1525 
1526 	DLOG(DIGIDB_INIT, (sc->dev, "detaching\n"));
1527 
1528 	/* If we're INIT'd, numports must be 0 */
1529 	KASSERT(sc->numports == 0 || sc->status != DIGI_STATUS_NOTINIT,
1530 	    ("digi%d: numports(%d) & status(%d) are out of sync",
1531 	    sc->res.unit, sc->numports, (int)sc->status));
1532 
1533 	if (digi_inuse(sc))
1534 		return (EBUSY);
1535 
1536 	digi_free_state(sc);
1537 
1538 	destroy_dev(sc->res.ctldev);
1539 
1540 	if (sc->res.mem != NULL) {
1541 		bus_release_resource(dev, SYS_RES_MEMORY, sc->res.mrid,
1542 		    sc->res.mem);
1543 		sc->res.mem = NULL;
1544 	}
1545 	if (sc->res.io != NULL) {
1546 		bus_release_resource(dev, SYS_RES_IOPORT, sc->res.iorid,
1547 		    sc->res.io);
1548 		sc->res.io = NULL;
1549 	}
1550 
1551 	return (0);
1552 }
1553 
1554 int
digi_shutdown(device_t dev)1555 digi_shutdown(device_t dev)
1556 {
1557 	return (0);
1558 }
1559 
1560 MODULE_VERSION(digi, 1);
1561