File:
[DragonFly] /
src /
sys /
i386 /
gnu /
isa /
Attic /
dgb.c
Revision
1.10:
download - view:
text,
annotated -
select for diffs
Thu May 13 23:49:23 2004 UTC (9 years ago) by
dillon
Branches:
MAIN
CVS tags:
HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).
d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device. It was never
used for that purpose.
d_clone will be more fully implemented as work continues. We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads. This is something we will be needing later
on.
1: /*-
2: * dgb.c $FreeBSD: src/sys/gnu/i386/isa/dgb.c,v 1.56.2.1 2001/02/26 04:23:09 jlemon Exp $
3: * dgb.c $DragonFly: src/sys/i386/gnu/isa/dgb.c,v 1.10 2004/05/13 23:49:23 dillon Exp $
4: *
5: * Digiboard driver.
6: *
7: * Stage 1. "Better than nothing".
8: * Stage 2. "Gee, it works!".
9: *
10: * Based on sio driver by Bruce Evans and on Linux driver by Troy
11: * De Jongh <troyd@digibd.com> or <troyd@skypoint.com>
12: * which is under GNU General Public License version 2 so this driver
13: * is forced to be under GPL 2 too.
14: *
15: * Written by Serge Babkin,
16: * Joint Stock Commercial Bank "Chelindbank"
17: * (Chelyabinsk, Russia)
18: * babkin@hq.icb.chel.su
19: *
20: * Assorted hacks to make it more functional and working under 3.0-current.
21: * Fixed broken routines to prevent processes hanging on closed (thanks
22: * to Bruce for his patience and assistance). Thanks also to Maxim Bolotin
23: * <max@run.net> for his patches which did most of the work to get this
24: * running under 2.2/3.0-current.
25: * Implemented ioctls: TIOCMSDTRWAIT, TIOCMGDTRWAIT, TIOCTIMESTAMP &
26: * TIOCDCDTIMESTAMP.
27: * Sysctl debug flag is now a bitflag, to filter noise during debugging.
28: * David L. Nugent <davidn@blaze.net.au>
29: */
30:
31: #include "opt_compat.h"
32: #include "opt_dgb.h"
33:
34: #include "use_dgb.h"
35:
36: /* Helg: i.e.25 times per sec board will be polled */
37: #define POLLSPERSEC 25
38: /* How many charactes can we write to input tty rawq */
39: #define DGB_IBUFSIZE (TTYHOG-100)
40:
41: /* the overall number of ports controlled by this driver */
42:
43: #ifndef NDGBPORTS
44: # define NDGBPORTS (NDGB*16)
45: #endif
46:
47: #include <sys/param.h>
48: #include <sys/systm.h>
49: #include <sys/tty.h>
50: #include <sys/proc.h>
51: #include <sys/conf.h>
52: #include <sys/dkstat.h>
53: #include <sys/fcntl.h>
54: #include <sys/kernel.h>
55: #include <sys/sysctl.h>
56:
57: #include <machine/clock.h>
58:
59: #include <vm/vm.h>
60: #include <vm/pmap.h>
61:
62: #include <bus/isa/i386/isa_device.h>
63:
64: #include "dgbios.h"
65: #include "dgfep.h"
66:
67: #define DGB_DEBUG /* Enable debugging info via sysctl */
68: #include "dgreg.h"
69:
70: #define CALLOUT_MASK 0x80
71: #define CONTROL_MASK 0x60
72: #define CONTROL_INIT_STATE 0x20
73: #define CONTROL_LOCK_STATE 0x40
74: #define UNIT_MASK 0x30000
75: #define PORT_MASK 0x1F
76: #define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
77: #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
78: #define MINOR_TO_UNIT(mynor) (((mynor) & UNIT_MASK)>>16)
79: #define MINOR_TO_PORT(mynor) ((mynor) & PORT_MASK)
80:
81: /* types. XXX - should be elsewhere */
82: typedef u_char bool_t; /* boolean */
83:
84: /* digiboard port structure */
85: struct dgb_p {
86: bool_t status;
87:
88: u_char unit; /* board unit number */
89: u_char pnum; /* port number */
90: u_char omodem; /* FEP output modem status */
91: u_char imodem; /* FEP input modem status */
92: u_char modemfake; /* Modem values to be forced */
93: u_char modem; /* Force values */
94: u_char hflow;
95: u_char dsr;
96: u_char dcd;
97: u_char stopc;
98: u_char startc;
99: u_char stopca;
100: u_char startca;
101: u_char fepstopc;
102: u_char fepstartc;
103: u_char fepstopca;
104: u_char fepstartca;
105: u_char txwin;
106: u_char rxwin;
107: ushort fepiflag;
108: ushort fepcflag;
109: ushort fepoflag;
110: ushort txbufhead;
111: ushort txbufsize;
112: ushort rxbufhead;
113: ushort rxbufsize;
114: int close_delay;
115: int count;
116: int blocked_open;
117: int event;
118: int asyncflags;
119: u_long statusflags;
120: u_char *txptr;
121: u_char *rxptr;
122: volatile struct board_chan *brdchan;
123: struct tty *tty;
124:
125: bool_t active_out; /* nonzero if the callout device is open */
126: u_int wopeners; /* # processes waiting for DCD in open() */
127:
128: /* Initial state. */
129: struct termios it_in; /* should be in struct tty */
130: struct termios it_out;
131:
132: /* Lock state. */
133: struct termios lt_in; /* should be in struct tty */
134: struct termios lt_out;
135:
136: bool_t do_timestamp;
137: bool_t do_dcd_timestamp;
138: struct timeval timestamp;
139: struct timeval dcd_timestamp;
140:
141: /* flags of state, are used in sleep() too */
142: u_char closing; /* port is being closed now */
143: u_char draining; /* port is being drained now */
144: u_char used; /* port is being used now */
145: u_char mustdrain; /* data must be waited to drain in dgbparam() */
146: };
147:
148: /* Digiboard per-board structure */
149: struct dgb_softc {
150: /* struct board_info */
151: u_char status; /* status: DISABLED/ENABLED */
152: u_char unit; /* unit number */
153: u_char type; /* type of card: PCXE, PCXI, PCXEVE */
154: u_char altpin; /* do we need alternate pin setting ? */
155: int numports; /* number of ports on card */
156: int port; /* I/O port */
157: u_char *vmem; /* virtual memory address */
158: long pmem; /* physical memory address */
159: int mem_seg; /* internal memory segment */
160: struct dgb_p *ports; /* pointer to array of port descriptors */
161: struct tty *ttys; /* pointer to array of TTY structures */
162: volatile struct global_data *mailbox;
163: };
164:
165:
166: static struct dgb_softc dgb_softc[NDGB];
167: static struct dgb_p dgb_ports[NDGBPORTS];
168: static struct tty dgb_tty[NDGBPORTS];
169:
170: /*
171: * The public functions in the com module ought to be declared in a com-driver
172: * system header.
173: */
174:
175: /* Interrupt handling entry points. */
176: static void dgbpoll (void *unit_c);
177:
178: /* Device switch entry points. */
179: #define dgbreset noreset
180: #define dgbmmap nommap
181: #define dgbstrategy nostrategy
182:
183: static int dgbattach (struct isa_device *dev);
184: static int dgbprobe (struct isa_device *dev);
185:
186: static void fepcmd(struct dgb_p *port, unsigned cmd, unsigned op1, unsigned op2,
187: unsigned ncmds, unsigned bytecmd);
188:
189: static void dgbstart (struct tty *tp);
190: static void dgbstop (struct tty *tp, int rw);
191: static int dgbparam (struct tty *tp, struct termios *t);
192: static void dgbhardclose (struct dgb_p *port);
193: static void dgb_drain_or_flush (struct dgb_p *port);
194: static int dgbdrain (struct dgb_p *port);
195: static void dgb_pause (void *chan);
196: static void wakeflush (void *p);
197: static void disc_optim (struct tty *tp, struct termios *t);
198:
199:
200: struct isa_driver dgbdriver = {
201: dgbprobe, dgbattach, "dgb",0
202: };
203:
204: static d_open_t dgbopen;
205: static d_close_t dgbclose;
206: static d_ioctl_t dgbioctl;
207:
208: #define CDEV_MAJOR 58
209: static struct cdevsw dgb_cdevsw = {
210: /* name */ "dgb",
211: /* maj */ CDEV_MAJOR,
212: /* flags */ D_TTY | D_KQFILTER,
213: /* port */ NULL,
214: /* clone */ NULL,
215:
216: /* open */ dgbopen,
217: /* close */ dgbclose,
218: /* read */ ttyread,
219: /* write */ ttywrite,
220: /* ioctl */ dgbioctl,
221: /* poll */ ttypoll,
222: /* mmap */ nommap,
223: /* strategy */ nostrategy,
224: /* dump */ nodump,
225: /* psize */ nopsize,
226: /* kqfilter */ ttykqfilter
227: };
228:
229: static speed_t dgbdefaultrate = TTYDEF_SPEED;
230:
231: static struct speedtab dgbspeedtab[] = {
232: { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
233: { 50, FEP_B50 },
234: { 75, FEP_B75 },
235: { 110, FEP_B110 },
236: { 134, FEP_B134 },
237: { 150, FEP_B150 },
238: { 200, FEP_B200 },
239: { 300, FEP_B300 },
240: { 600, FEP_B600 },
241: { 1200, FEP_B1200 },
242: { 1800, FEP_B1800 },
243: { 2400, FEP_B2400 },
244: { 4800, FEP_B4800 },
245: { 9600, FEP_B9600 },
246: { 19200, FEP_B19200 },
247: { 38400, FEP_B38400 },
248: { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
249: { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
250: { -1, -1 }
251: };
252:
253: static struct dbgflagtbl
254: {
255: tcflag_t in_mask;
256: tcflag_t in_val;
257: tcflag_t out_val;
258: } dgb_cflags[] =
259: {
260: { PARODD, PARODD, FEP_PARODD },
261: { PARENB, PARENB, FEP_PARENB },
262: { CSTOPB, CSTOPB, FEP_CSTOPB },
263: { CSIZE, CS5, FEP_CS6 },
264: { CSIZE, CS6, FEP_CS6 },
265: { CSIZE, CS7, FEP_CS7 },
266: { CSIZE, CS8, FEP_CS8 },
267: { CLOCAL, CLOCAL, FEP_CLOCAL },
268: { (tcflag_t)-1 }
269: }, dgb_iflags[] =
270: {
271: { IGNBRK, IGNBRK, FEP_IGNBRK },
272: { BRKINT, BRKINT, FEP_BRKINT },
273: { IGNPAR, IGNPAR, FEP_IGNPAR },
274: { PARMRK, PARMRK, FEP_PARMRK },
275: { INPCK, INPCK, FEP_INPCK },
276: { ISTRIP, ISTRIP, FEP_ISTRIP },
277: { IXON, IXON, FEP_IXON },
278: { IXOFF, IXOFF, FEP_IXOFF },
279: { IXANY, IXANY, FEP_IXANY },
280: { (tcflag_t)-1 }
281: }, dgb_flow[] =
282: {
283: { CRTSCTS, CRTSCTS, CTS|RTS },
284: { CRTSCTS, CCTS_OFLOW, CTS },
285: { CRTSCTS, CRTS_IFLOW, RTS },
286: { (tcflag_t)-1 }
287: };
288:
289: /* xlat bsd termios flags to dgb sys-v style */
290: static tcflag_t
291: dgbflags(struct dbgflagtbl *tbl, tcflag_t input)
292: {
293: tcflag_t output = 0;
294: int i;
295:
296: for (i=0; tbl[i].in_mask != (tcflag_t)-1; i++)
297: {
298: if ((input & tbl[i].in_mask) == tbl[i].in_val)
299: output |= tbl[i].out_val;
300: }
301: return output;
302: }
303:
304: #ifdef DGB_DEBUG
305: static int dgbdebug=0;
306: SYSCTL_INT(_debug, OID_AUTO, dgb_debug, CTLFLAG_RW, &dgbdebug, 0, "");
307: #endif
308:
309: static __inline int setwin (struct dgb_softc *sc, unsigned addr);
310: static __inline int setinitwin (struct dgb_softc *sc, unsigned addr);
311: static __inline void hidewin (struct dgb_softc *sc);
312: static __inline void towin (struct dgb_softc *sc, int win);
313:
314: /*Helg: to allow recursive dgb...() calls */
315: typedef struct
316: { /* If we were called and don't want to disturb we need: */
317: int port; /* write to this port */
318: u_char data; /* this data on exit */
319: /* or DATA_WINOFF to close memory window on entry */
320: } BoardMemWinState; /* so several channels and even boards can coexist */
321: #define DATA_WINOFF 0
322: static BoardMemWinState bmws;
323:
324: /* return current memory window state and close window */
325: static BoardMemWinState
326: bmws_get(void)
327: {
328: BoardMemWinState bmwsRet=bmws;
329: if(bmws.data!=DATA_WINOFF)
330: outb(bmws.port, bmws.data=DATA_WINOFF);
331: return bmwsRet;
332: }
333:
334: /* restore memory window state */
335: static void
336: bmws_set(BoardMemWinState ws)
337: {
338: if(ws.data != bmws.data || ws.port!=bmws.port ) {
339: if(bmws.data!=DATA_WINOFF)
340: outb(bmws.port,DATA_WINOFF);
341: if(ws.data!=DATA_WINOFF)
342: outb(ws.port, ws.data);
343: bmws=ws;
344: }
345: }
346:
347: static __inline int
348: setwin(sc,addr)
349: struct dgb_softc *sc;
350: unsigned int addr;
351: {
352: if(sc->type==PCXEVE) {
353: outb(bmws.port=sc->port+1, bmws.data=FEPWIN|(addr>>13));
354: DPRINT3(DB_WIN,"dgb%d: switched to window 0x%x\n",sc->unit,addr>>13);
355: return (addr & 0x1FFF);
356: } else {
357: outb(bmws.port=sc->port,bmws.data=FEPMEM);
358: return addr;
359: }
360: }
361:
362: static __inline int
363: setinitwin(sc,addr)
364: struct dgb_softc *sc;
365: unsigned int addr;
366: {
367: if(sc->type==PCXEVE) {
368: outb(bmws.port=sc->port+1, bmws.data=FEPWIN|(addr>>13));
369: DPRINT3(DB_WIN,"dgb%d: switched to window 0x%x\n",sc->unit,addr>>13);
370: return (addr & 0x1FFF);
371: } else {
372: outb(bmws.port=sc->port,bmws.data=inb(sc->port)|FEPMEM);
373: return addr;
374: }
375: }
376:
377: static __inline void
378: hidewin(sc)
379: struct dgb_softc *sc;
380: {
381: bmws.data=0;
382: if(sc->type==PCXEVE)
383: outb(bmws.port=sc->port+1, bmws.data);
384: else
385: outb(bmws.port=sc->port, bmws.data);
386: }
387:
388: static __inline void
389: towin(sc,win)
390: struct dgb_softc *sc;
391: int win;
392: {
393: if(sc->type==PCXEVE) {
394: outb(bmws.port=sc->port+1, bmws.data=win);
395: } else {
396: outb(bmws.port=sc->port,bmws.data=FEPMEM);
397: }
398: }
399:
400: static int
401: dgbprobe(dev)
402: struct isa_device *dev;
403: {
404: struct dgb_softc *sc= &dgb_softc[dev->id_unit];
405: int i, v;
406: u_long win_size; /* size of vizible memory window */
407: int unit=dev->id_unit;
408: static int once;
409:
410: if (!once++)
411: cdevsw_add(&dgb_cdevsw);
412: sc->unit=dev->id_unit;
413: sc->port=dev->id_iobase;
414:
415: if(dev->id_flags & DGBFLAG_ALTPIN)
416: sc->altpin=1;
417: else
418: sc->altpin=0;
419:
420: /* left 24 bits only (ISA address) */
421: sc->pmem=((intptr_t)(void *)dev->id_maddr & 0xFFFFFF);
422:
423: DPRINT4(DB_INFO,"dgb%d: port 0x%x mem 0x%lx\n",unit,sc->port,sc->pmem);
424:
425: outb(sc->port, FEPRST);
426: sc->status=DISABLED;
427:
428: for(i=0; i< 1000; i++) {
429: DELAY(1);
430: if( (inb(sc->port) & FEPMASK) == FEPRST ) {
431: sc->status=ENABLED;
432: DPRINT3(DB_EXCEPT,"dgb%d: got reset after %d us\n",unit,i);
433: break;
434: }
435: }
436:
437: if(sc->status!=ENABLED) {
438: DPRINT2(DB_EXCEPT,"dgb%d: failed to respond\n",dev->id_unit);
439: return 0;
440: }
441:
442: /* check type of card and get internal memory characteristics */
443:
444: v=inb(sc->port);
445:
446: if( v & 0x1 ) {
447: switch( v&0x30 ) {
448: case 0:
449: sc->mem_seg=0xF000;
450: win_size=0x10000;
451: printf("dgb%d: PC/Xi 64K\n",dev->id_unit);
452: break;
453: case 0x10:
454: sc->mem_seg=0xE000;
455: win_size=0x20000;
456: printf("dgb%d: PC/Xi 128K\n",dev->id_unit);
457: break;
458: case 0x20:
459: sc->mem_seg=0xC000;
460: win_size=0x40000;
461: printf("dgb%d: PC/Xi 256K\n",dev->id_unit);
462: break;
463: default: /* case 0x30: */
464: sc->mem_seg=0x8000;
465: win_size=0x80000;
466: printf("dgb%d: PC/Xi 512K\n",dev->id_unit);
467: break;
468: }
469: sc->type=PCXI;
470: } else {
471: outb(sc->port, 1);
472: v=inb(sc->port);
473:
474: if( v & 0x1 ) {
475: printf("dgb%d: PC/Xm isn't supported\n",dev->id_unit);
476: sc->status=DISABLED;
477: return 0;
478: }
479:
480: sc->mem_seg=0xF000;
481:
482: if(dev->id_flags==DGBFLAG_NOWIN || ( v&0xC0 )==0) {
483: win_size=0x10000;
484: printf("dgb%d: PC/Xe 64K\n",dev->id_unit);
485: sc->type=PCXE;
486: } else {
487: win_size=0x2000;
488: printf("dgb%d: PC/Xe 64/8K (windowed)\n",dev->id_unit);
489: sc->type=PCXEVE;
490: if((u_long)sc->pmem & ~0xFFE000) {
491: printf("dgb%d: warning: address 0x%lx truncated to 0x%lx\n",
492: dev->id_unit, sc->pmem,
493: sc->pmem & 0xFFE000);
494:
495: dev->id_maddr= (u_char *)(void *)(intptr_t)( sc->pmem & 0xFFE000 );
496: }
497: }
498: }
499:
500: /* save size of vizible memory segment */
501: dev->id_msize=win_size;
502:
503: /* map memory */
504: dev->id_maddr=sc->vmem=pmap_mapdev(sc->pmem,dev->id_msize);
505:
506: outb(sc->port, FEPCLR); /* drop RESET */
507: hidewin(sc); /* Helg: to set initial bmws state */
508:
509: return 4; /* we need I/O space of 4 ports */
510: }
511:
512: static int
513: dgbattach(dev)
514: struct isa_device *dev;
515: {
516: int unit=dev->id_unit;
517: struct dgb_softc *sc= &dgb_softc[dev->id_unit];
518: int i, t;
519: u_char volatile *mem;
520: u_char volatile *ptr;
521: int addr;
522: struct dgb_p *port;
523: volatile struct board_chan *bc;
524: int shrinkmem;
525: int nfails;
526: const volatile ushort *pstat;
527: int lowwater;
528: static int nports=0;
529: char suffix;
530:
531: if(sc->status!=ENABLED) {
532: DPRINT2(DB_EXCEPT,"dbg%d: try to attach a disabled card\n",unit);
533: return 0;
534: }
535:
536: mem=sc->vmem;
537:
538: DPRINT3(DB_INFO,"dgb%d: internal memory segment 0x%x\n",unit,sc->mem_seg);
539:
540: outb(sc->port, FEPRST); DELAY(1);
541:
542: for(i=0; (inb(sc->port) & FEPMASK) != FEPRST ; i++) {
543: if(i>10000) {
544: printf("dgb%d: 1st reset failed\n",dev->id_unit);
545: sc->status=DISABLED;
546: hidewin(sc);
547: return 0;
548: }
549: DELAY(1);
550: }
551:
552: DPRINT3(DB_INFO,"dgb%d: got reset after %d us\n",unit,i);
553:
554: /* for PCXEVE set up interrupt and base address */
555:
556: if(sc->type==PCXEVE) {
557: t=(((u_long)sc->pmem>>8) & 0xFFE0) | 0x10 /* enable windowing */;
558: /* IRQ isn't used */
559: outb(sc->port+2,t & 0xFF);
560: outb(sc->port+3,t>>8);
561: } else if(sc->type==PCXE) {
562: t=(((u_long)sc->pmem>>8) & 0xFFE0) /* disable windowing */;
563: outb(sc->port+2,t & 0xFF);
564: outb(sc->port+3,t>>8);
565: }
566:
567:
568: if(sc->type==PCXI || sc->type==PCXE) {
569: outb(sc->port, FEPRST|FEPMEM); DELAY(1);
570:
571: for(i=0; (inb(sc->port) & FEPMASK) != (FEPRST|FEPMEM) ; i++) {
572: if(i>10000) {
573: printf("dgb%d: 2nd reset failed\n",dev->id_unit);
574: sc->status=DISABLED;
575: hidewin(sc);
576: return 0;
577: }
578: DELAY(1);
579: }
580:
581: DPRINT3(DB_INFO,"dgb%d: got memory after %d us\n",unit,i);
582: }
583:
584: mem=sc->vmem;
585:
586: /* very short memory test */
587:
588: addr=setinitwin(sc,BOTWIN);
589: *(u_long volatile *)(mem+addr) = 0xA55A3CC3;
590: if(*(u_long volatile *)(mem+addr)!=0xA55A3CC3) {
591: printf("dgb%d: 1st memory test failed\n",dev->id_unit);
592: sc->status=DISABLED;
593: hidewin(sc);
594: return 0;
595: }
596:
597: addr=setinitwin(sc,TOPWIN);
598: *(u_long volatile *)(mem+addr) = 0x5AA5C33C;
599: if(*(u_long volatile *)(mem+addr)!=0x5AA5C33C) {
600: printf("dgb%d: 2nd memory test failed\n",dev->id_unit);
601: sc->status=DISABLED;
602: hidewin(sc);
603: return 0;
604: }
605:
606: addr=setinitwin(sc,BIOSCODE+((0xF000-sc->mem_seg)<<4));
607: *(u_long volatile *)(mem+addr) = 0x5AA5C33C;
608: if(*(u_long volatile *)(mem+addr)!=0x5AA5C33C) {
609: printf("dgb%d: 3rd (BIOS) memory test failed\n",dev->id_unit);
610: }
611:
612: addr=setinitwin(sc,MISCGLOBAL);
613: for(i=0; i<16; i++) {
614: mem[addr+i]=0;
615: }
616:
617: if(sc->type==PCXI || sc->type==PCXE) {
618:
619: addr=BIOSCODE+((0xF000-sc->mem_seg)<<4);
620:
621: DPRINT3(DB_INFO,"dgb%d: BIOS local address=0x%x\n",unit,addr);
622:
623: ptr= mem+addr;
624:
625: for(i=0; i<pcxx_nbios; i++, ptr++)
626: *ptr = pcxx_bios[i];
627:
628: ptr= mem+addr;
629:
630: nfails=0;
631: for(i=0; i<pcxx_nbios; i++, ptr++)
632: if( *ptr != pcxx_bios[i] ) {
633: DPRINT5(DB_EXCEPT,"dgb%d: wrong code in BIOS at addr 0x%x : \
634: 0x%x instead of 0x%x\n", unit, ptr-(mem+addr), *ptr, pcxx_bios[i] );
635:
636: if(++nfails>=5) {
637: printf("dgb%d: 4th memory test (BIOS load) fails\n",unit);
638: break;
639: }
640: }
641:
642: outb(sc->port,FEPMEM);
643:
644: for(i=0; (inb(sc->port) & FEPMASK) != FEPMEM ; i++) {
645: if(i>10000) {
646: printf("dgb%d: BIOS start failed\n",dev->id_unit);
647: sc->status=DISABLED;
648: hidewin(sc);
649: return 0;
650: }
651: DELAY(1);
652: }
653:
654: DPRINT3(DB_INFO,"dgb%d: reset dropped after %d us\n",unit,i);
655:
656: for(i=0; i<200000; i++) {
657: if( *((ushort volatile *)(mem+MISCGLOBAL)) == *((ushort *)"GD") )
658: goto load_fep;
659: DELAY(1);
660: }
661: printf("dgb%d: BIOS download failed\n",dev->id_unit);
662: DPRINT4(DB_EXCEPT,"dgb%d: code=0x%x must be 0x%x\n",
663: dev->id_unit,
664: *((ushort volatile *)(mem+MISCGLOBAL)),
665: *((ushort *)"GD"));
666:
667: sc->status=DISABLED;
668: hidewin(sc);
669: return 0;
670: }
671:
672: if(sc->type==PCXEVE) {
673: /* set window 7 */
674: outb(sc->port+1,0xFF);
675:
676: ptr= mem+(BIOSCODE & 0x1FFF);
677:
678: for(i=0; i<pcxx_nbios; i++)
679: *ptr++ = pcxx_bios[i];
680:
681: ptr= mem+(BIOSCODE & 0x1FFF);
682:
683: nfails=0;
684: for(i=0; i<pcxx_nbios; i++, ptr++)
685: if( *ptr != pcxx_bios[i] ) {
686: DPRINT5(DB_EXCEPT,"dgb%d: wrong code in BIOS at addr 0x%x : \
687: 0x%x instead of 0x%x\n", unit, ptr-(mem+addr), *ptr, pcxx_bios[i] );
688:
689: if(++nfails>=5) {
690: printf("dgb%d: 4th memory test (BIOS load) fails\n",unit);
691: break;
692: }
693: }
694:
695: outb(sc->port,FEPCLR);
696:
697: setwin(sc,0);
698:
699: for(i=0; (inb(sc->port) & FEPMASK) != FEPCLR ; i++) {
700: if(i>10000) {
701: printf("dgb%d: BIOS start failed\n",dev->id_unit);
702: sc->status=DISABLED;
703: hidewin(sc);
704: return 0;
705: }
706: DELAY(1);
707: }
708:
709: DPRINT3(DB_INFO,"dgb%d: reset dropped after %d us\n",unit,i);
710:
711: addr=setwin(sc,MISCGLOBAL);
712:
713: for(i=0; i<200000; i++) {
714: if(*(ushort volatile *)(mem+addr)== *(ushort *)"GD")
715: goto load_fep;
716: DELAY(1);
717: }
718: printf("dgb%d: BIOS download failed\n",dev->id_unit);
719: DPRINT5(DB_EXCEPT,"dgb%d: Error#(0x%x,0x%x) code=0x%x\n",
720: dev->id_unit,
721: *(ushort volatile *)(mem+0xC12),
722: *(ushort volatile *)(mem+0xC14),
723: *(ushort volatile *)(mem+MISCGLOBAL));
724:
725: sc->status=DISABLED;
726: hidewin(sc);
727: return 0;
728: }
729:
730: load_fep:
731: DPRINT2(DB_INFO,"dgb%d: BIOS loaded\n",dev->id_unit);
732:
733: addr=setwin(sc,FEPCODE);
734:
735: ptr= mem+addr;
736:
737: for(i=0; i<pcxx_ncook; i++)
738: *ptr++ = pcxx_cook[i];
739:
740: addr=setwin(sc,MBOX);
741: *(ushort volatile *)(mem+addr+ 0)=2;
742: *(ushort volatile *)(mem+addr+ 2)=sc->mem_seg+FEPCODESEG;
743: *(ushort volatile *)(mem+addr+ 4)=0;
744: *(ushort volatile *)(mem+addr+ 6)=FEPCODESEG;
745: *(ushort volatile *)(mem+addr+ 8)=0;
746: *(ushort volatile *)(mem+addr+10)=pcxx_ncook;
747:
748: outb(sc->port,FEPMEM|FEPINT); /* send interrupt to BIOS */
749: outb(sc->port,FEPMEM);
750:
751: for(i=0; *(ushort volatile *)(mem+addr)!=0; i++) {
752: if(i>200000) {
753: printf("dgb%d: FEP code download failed\n",unit);
754: DPRINT3(DB_EXCEPT,"dgb%d: code=0x%x must be 0\n", unit,
755: *(ushort volatile *)(mem+addr));
756: sc->status=DISABLED;
757: hidewin(sc);
758: return 0;
759: }
760: }
761:
762: DPRINT2(DB_INFO,"dgb%d: FEP code loaded\n",unit);
763:
764: *(ushort volatile *)(mem+setwin(sc,FEPSTAT))=0;
765: addr=setwin(sc,MBOX);
766: *(ushort volatile *)(mem+addr+0)=1;
767: *(ushort volatile *)(mem+addr+2)=FEPCODESEG;
768: *(ushort volatile *)(mem+addr+4)=0x4;
769:
770: outb(sc->port,FEPINT); /* send interrupt to BIOS */
771: outb(sc->port,FEPCLR);
772:
773: addr=setwin(sc,FEPSTAT);
774: for(i=0; *(ushort volatile *)(mem+addr)!= *(ushort *)"OS"; i++) {
775: if(i>200000) {
776: printf("dgb%d: FEP/OS start failed\n",dev->id_unit);
777: sc->status=DISABLED;
778: hidewin(sc);
779: return 0;
780: }
781: }
782:
783: DPRINT2(DB_INFO,"dgb%d: FEP/OS started\n",dev->id_unit);
784:
785: sc->numports= *(ushort volatile *)(mem+setwin(sc,NPORT));
786:
787: printf("dgb%d: %d ports\n",unit,sc->numports);
788:
789: if(sc->numports > MAX_DGB_PORTS) {
790: printf("dgb%d: too many ports\n",unit);
791: sc->status=DISABLED;
792: hidewin(sc);
793: return 0;
794: }
795:
796: if(nports+sc->numports>NDGBPORTS) {
797: printf("dgb%d: only %d ports are usable\n", unit, NDGBPORTS-nports);
798: sc->numports=NDGBPORTS-nports;
799: }
800:
801: /* allocate port and tty structures */
802: sc->ports=&dgb_ports[nports];
803: sc->ttys=&dgb_tty[nports];
804: nports+=sc->numports;
805:
806: addr=setwin(sc,PORTBASE);
807: pstat=(const ushort volatile *)(mem+addr);
808:
809: for(i=0; i<sc->numports && pstat[i]; i++)
810: if(pstat[i])
811: sc->ports[i].status=ENABLED;
812: else {
813: sc->ports[i].status=DISABLED;
814: printf("dgb%d: port%d is broken\n", unit, i);
815: }
816:
817: /* We should now init per-port structures */
818: bc=(volatile struct board_chan *)(mem + CHANSTRUCT);
819: sc->mailbox=(volatile struct global_data *)(mem + FEP_GLOBAL);
820:
821: if(sc->numports<3)
822: shrinkmem=1;
823: else
824: shrinkmem=0;
825:
826: for(i=0; i<sc->numports; i++, bc++) {
827: port= &sc->ports[i];
828:
829: port->tty=&sc->ttys[i];
830: port->unit=unit;
831:
832: port->brdchan=bc;
833:
834: if(sc->altpin) {
835: port->dsr=CD;
836: port->dcd=DSR;
837: } else {
838: port->dcd=CD;
839: port->dsr=DSR;
840: }
841:
842: port->pnum=i;
843:
844: if(shrinkmem) {
845: DPRINT2(DB_INFO,"dgb%d: shrinking memory\n",unit);
846: fepcmd(port, SETBUFFER, 32, 0, 0, 0);
847: shrinkmem=0;
848: }
849:
850: if(sc->type!=PCXEVE) {
851: port->txptr=mem+((bc->tseg-sc->mem_seg)<<4);
852: port->rxptr=mem+((bc->rseg-sc->mem_seg)<<4);
853: port->txwin=port->rxwin=0;
854: } else {
855: port->txptr=mem+( ((bc->tseg-sc->mem_seg)<<4) & 0x1FFF );
856: port->rxptr=mem+( ((bc->rseg-sc->mem_seg)<<4) & 0x1FFF );
857: port->txwin=FEPWIN | ((bc->tseg-sc->mem_seg)>>9);
858: port->rxwin=FEPWIN | ((bc->rseg-sc->mem_seg)>>9);
859: }
860:
861: port->txbufhead=0;
862: port->rxbufhead=0;
863: port->txbufsize=bc->tmax+1;
864: port->rxbufsize=bc->rmax+1;
865:
866: lowwater= (port->txbufsize>=2000) ? 1024 : (port->txbufsize/2);
867: setwin(sc,0);
868: fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
869: fepcmd(port, SRXLWATER, port->rxbufsize/4, 0, 10, 0);
870: fepcmd(port, SRXHWATER, 3*port->rxbufsize/4, 0, 10, 0);
871:
872: bc->edelay=100;
873: bc->idata=1;
874:
875: port->startc=bc->startc;
876: port->startca=bc->startca;
877: port->stopc=bc->stopc;
878: port->stopca=bc->stopca;
879:
880: /*port->close_delay=50;*/
881: port->close_delay=3 * hz;
882: port->do_timestamp=0;
883: port->do_dcd_timestamp=0;
884:
885: /*
886: * We don't use all the flags from <sys/ttydefaults.h> since they
887: * are only relevant for logins. It's important to have echo off
888: * initially so that the line doesn't start blathering before the
889: * echo flag can be turned off.
890: */
891: port->it_in.c_iflag = TTYDEF_IFLAG;
892: port->it_in.c_oflag = TTYDEF_OFLAG;
893: port->it_in.c_cflag = TTYDEF_CFLAG;
894: port->it_in.c_lflag = TTYDEF_LFLAG;
895: termioschars(&port->it_in);
896: port->it_in.c_ispeed = port->it_in.c_ospeed = dgbdefaultrate;
897: port->it_out = port->it_in;
898: /* MAX_DGB_PORTS is 32 => [0-9a-v] */
899: suffix = i < 10 ? '0' + i : 'a' + i - 10;
900: make_dev(&dgb_cdevsw, (unit*32)+i,
901: UID_ROOT, GID_WHEEL, 0600, "ttyD%d%c", unit, suffix);
902:
903: make_dev(&dgb_cdevsw, (unit*32)+i+32,
904: UID_ROOT, GID_WHEEL, 0600, "ttyiD%d%c", unit, suffix);
905:
906: make_dev(&dgb_cdevsw, (unit*32)+i+64,
907: UID_ROOT, GID_WHEEL, 0600, "ttylD%d%c", unit, suffix);
908:
909: make_dev(&dgb_cdevsw, (unit*32)+i+128,
910: UID_UUCP, GID_DIALER, 0660, "cuaD%d%c", unit, suffix);
911:
912: make_dev(&dgb_cdevsw, (unit*32)+i+160,
913: UID_UUCP, GID_DIALER, 0660, "cuaiD%d%c", unit, suffix);
914:
915: make_dev(&dgb_cdevsw, (unit*32)+i+192,
916: UID_UUCP, GID_DIALER, 0660, "cualD%d%c", unit, suffix);
917: }
918:
919: hidewin(sc);
920:
921: /* register the polling function */
922: timeout(dgbpoll, (void *)unit, hz/POLLSPERSEC);
923:
924: return 1;
925: }
926:
927: /* ARGSUSED */
928: static int
929: dgbopen(dev_t dev, int flag, int mode, struct thread *td)
930: {
931: struct dgb_softc *sc;
932: struct tty *tp;
933: int unit;
934: int mynor;
935: int pnum;
936: struct dgb_p *port;
937: int s,cs;
938: int error;
939: volatile struct board_chan *bc;
940:
941: error=0;
942:
943: mynor=minor(dev);
944: unit=MINOR_TO_UNIT(mynor);
945: pnum=MINOR_TO_PORT(mynor);
946:
947: if(unit >= NDGB) {
948: DPRINT2(DB_EXCEPT,"dgb%d: try to open a nonexisting card\n",unit);
949: return ENXIO;
950: }
951:
952: sc=&dgb_softc[unit];
953:
954: if(sc->status!=ENABLED) {
955: DPRINT2(DB_EXCEPT,"dgb%d: try to open a disabled card\n",unit);
956: return ENXIO;
957: }
958:
959: if(pnum>=sc->numports) {
960: DPRINT3(DB_EXCEPT,"dgb%d: try to open non-existing port %d\n",unit,pnum);
961: return ENXIO;
962: }
963:
964: if(mynor & CONTROL_MASK)
965: return 0;
966:
967: tp=&sc->ttys[pnum];
968: dev->si_tty = tp;
969: port=&sc->ports[pnum];
970: bc=port->brdchan;
971:
972: open_top:
973:
974: s=spltty();
975:
976: while(port->closing) {
977: error=tsleep(&port->closing, PCATCH, "dgocl", 0);
978:
979: if(error) {
980: DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgocl) error=%d\n",unit,pnum,error);
981: goto out;
982: }
983: }
984:
985: if (tp->t_state & TS_ISOPEN) {
986: /*
987: * The device is open, so everything has been initialized.
988: * Handle conflicts.
989: */
990: if (mynor & CALLOUT_MASK) {
991: if (!port->active_out) {
992: error = EBUSY;
993: DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error);
994: goto out;
995: }
996: } else {
997: if (port->active_out) {
998: if (flag & O_NONBLOCK) {
999: error = EBUSY;
1000: DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error);
1001: goto out;
1002: }
1003: error = tsleep(&port->active_out,
1004: PCATCH, "dgbi", 0);
1005: if (error != 0) {
1006: DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgbi) error=%d\n",
1007: unit,pnum,error);
1008: goto out;
1009: }
1010: splx(s);
1011: goto open_top;
1012: }
1013: }
1014: if (tp->t_state & TS_XCLUDE && suser(td)) {
1015: error = EBUSY;
1016: goto out;
1017: }
1018: } else {
1019: /*
1020: * The device isn't open, so there are no conflicts.
1021: * Initialize it. Initialization is done twice in many
1022: * cases: to preempt sleeping callin opens if we are
1023: * callout, and to complete a callin open after DCD rises.
1024: */
1025: tp->t_oproc=dgbstart;
1026: tp->t_param=dgbparam;
1027: tp->t_stop=dgbstop;
1028: tp->t_dev=dev;
1029: tp->t_termios= (mynor & CALLOUT_MASK) ?
1030: port->it_out :
1031: port->it_in;
1032:
1033: cs=splclock();
1034: setwin(sc,0);
1035: port->imodem=bc->mstat;
1036: bc->rout=bc->rin; /* clear input queue */
1037: bc->idata=1;
1038: #ifdef PRINT_BUFSIZE
1039: printf("dgb buffers tx=%x:%x rx=%x:%x\n",bc->tseg,bc->tmax,bc->rseg,bc->rmax);
1040: #endif
1041:
1042: hidewin(sc);
1043: splx(cs);
1044:
1045: port->wopeners++;
1046: error=dgbparam(tp, &tp->t_termios);
1047: port->wopeners--;
1048:
1049: if(error!=0) {
1050: DPRINT4(DB_OPEN,"dgb%d: port%d: dgbparam error=%d\n",unit,pnum,error);
1051: goto out;
1052: }
1053:
1054: /* handle fake DCD for callout devices */
1055: /* and initial DCD */
1056:
1057: if( (port->imodem & port->dcd) || mynor & CALLOUT_MASK )
1058: linesw[tp->t_line].l_modem(tp,1);
1059:
1060: }
1061:
1062: /*
1063: * Wait for DCD if necessary.
1064: */
1065: if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1066: && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1067: ++port->wopeners;
1068: error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1069: --port->wopeners;
1070: if (error != 0) {
1071: DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgdcd) error=%d\n",unit,pnum,error);
1072: goto out;
1073: }
1074: splx(s);
1075: goto open_top;
1076: }
1077: error = linesw[tp->t_line].l_open(dev, tp);
1078: disc_optim(tp,&tp->t_termios);
1079: DPRINT4(DB_OPEN,"dgb%d: port%d: l_open error=%d\n",unit,pnum,error);
1080:
1081: if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1082: port->active_out = TRUE;
1083:
1084: port->used=1;
1085:
1086: /* If any port is open (i.e. the open() call is completed for it)
1087: * the device is busy
1088: */
1089:
1090: out:
1091: disc_optim(tp,&tp->t_termios);
1092: splx(s);
1093:
1094: if( !(tp->t_state & TS_ISOPEN) && port->wopeners==0 )
1095: dgbhardclose(port);
1096:
1097: DPRINT4(DB_OPEN,"dgb%d: port%d: open() returns %d\n",unit,pnum,error);
1098:
1099: return error;
1100: }
1101:
1102: /*ARGSUSED*/
1103: static int
1104: dgbclose(dev_t dev, int flag, int mode, struct thread *td)
1105: {
1106: struct tty *tp;
1107: int unit, pnum;
1108: struct dgb_softc *sc;
1109: struct dgb_p *port;
1110: int mynor;
1111: int s;
1112: int i;
1113:
1114: mynor=minor(dev);
1115: if(mynor & CONTROL_MASK)
1116: return 0;
1117: unit=MINOR_TO_UNIT(mynor);
1118: pnum=MINOR_TO_PORT(mynor);
1119:
1120: sc=&dgb_softc[unit];
1121: tp=&sc->ttys[pnum];
1122: port=sc->ports+pnum;
1123:
1124: DPRINT3(DB_CLOSE,"dgb%d: port%d: closing\n",unit,pnum);
1125:
1126: DPRINT3(DB_CLOSE,"dgb%d: port%d: draining port\n",unit,pnum);
1127: dgb_drain_or_flush(port);
1128:
1129: s=spltty();
1130:
1131: port->closing=1;
1132: DPRINT3(DB_CLOSE,"dgb%d: port%d: closing line disc\n",unit,pnum);
1133: linesw[tp->t_line].l_close(tp,flag);
1134: disc_optim(tp,&tp->t_termios);
1135:
1136: DPRINT3(DB_CLOSE,"dgb%d: port%d: hard closing\n",unit,pnum);
1137: dgbhardclose(port);
1138: DPRINT3(DB_CLOSE,"dgb%d: port%d: closing tty\n",unit,pnum);
1139: ttyclose(tp);
1140: port->closing=0;
1141: wakeup(&port->closing);
1142: port->used=0;
1143:
1144: /* mark the card idle when all ports are closed */
1145:
1146: for(i=0; i<sc->numports; i++)
1147: if(sc->ports[i].used)
1148: break;
1149:
1150: splx(s);
1151:
1152: DPRINT3(DB_CLOSE,"dgb%d: port%d: closed\n",unit,pnum);
1153:
1154: wakeup(TSA_CARR_ON(tp));
1155: wakeup(&port->active_out);
1156: port->active_out=0;
1157:
1158: DPRINT3(DB_CLOSE,"dgb%d: port%d: close exit\n",unit,pnum);
1159:
1160: return 0;
1161: }
1162:
1163: static void
1164: dgbhardclose(port)
1165: struct dgb_p *port;
1166: {
1167: struct dgb_softc *sc=&dgb_softc[port->unit];
1168: volatile struct board_chan *bc=port->brdchan;
1169: int cs;
1170:
1171: cs=splclock();
1172: port->do_timestamp = 0;
1173: setwin(sc,0);
1174:
1175: bc->idata=0; bc->iempty=0; bc->ilow=0;
1176: if(port->tty->t_cflag & HUPCL) {
1177: port->omodem &= ~(RTS|DTR);
1178: fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1179: }
1180:
1181: hidewin(sc);
1182: splx(cs);
1183:
1184: timeout(dgb_pause, &port->brdchan, hz/2);
1185: tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1186: }
1187:
1188: static void
1189: dgb_pause(chan)
1190: void *chan;
1191: {
1192: wakeup((caddr_t)chan);
1193: }
1194:
1195: static void
1196: dgbpoll(unit_c)
1197: void *unit_c;
1198: {
1199: int unit=(int)unit_c;
1200: int pnum;
1201: struct dgb_p *port;
1202: struct dgb_softc *sc=&dgb_softc[unit];
1203: int head, tail;
1204: u_char *eventbuf;
1205: int event, mstat, lstat;
1206: volatile struct board_chan *bc;
1207: struct tty *tp;
1208: int rhead, rtail;
1209: int whead, wtail;
1210: int size;
1211: u_char *ptr;
1212: int ocount;
1213: int ibuf_full,obuf_full;
1214:
1215: BoardMemWinState ws=bmws_get();
1216:
1217: if(sc->status==DISABLED) {
1218: printf("dgb%d: polling of disabled board stopped\n",unit);
1219: return;
1220: }
1221:
1222: setwin(sc,0);
1223:
1224: head=sc->mailbox->ein;
1225: tail=sc->mailbox->eout;
1226:
1227: while(head!=tail) {
1228: if(head >= FEP_IMAX-FEP_ISTART
1229: || tail >= FEP_IMAX-FEP_ISTART
1230: || (head|tail) & 03 ) {
1231: printf("dgb%d: event queue's head or tail is wrong! hd=%d,tl=%d\n", unit,head,tail);
1232: break;
1233: }
1234:
1235: eventbuf=sc->vmem+tail+FEP_ISTART;
1236: pnum=eventbuf[0];
1237: event=eventbuf[1];
1238: mstat=eventbuf[2];
1239: lstat=eventbuf[3];
1240:
1241: port=&sc->ports[pnum];
1242: bc=port->brdchan;
1243: tp=&sc->ttys[pnum];
1244:
1245: if(pnum>=sc->numports || port->status==DISABLED) {
1246: printf("dgb%d: port%d: got event on nonexisting port\n",unit,pnum);
1247: } else if(port->used || port->wopeners>0 ) {
1248:
1249: int wrapmask=port->rxbufsize-1;
1250:
1251: if( !(event & ALL_IND) )
1252: printf("dgb%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1253: unit, pnum, event, mstat, lstat);
1254:
1255: if(event & DATA_IND) {
1256: DPRINT3(DB_DATA,"dgb%d: port%d: DATA_IND\n",unit,pnum);
1257:
1258: rhead=bc->rin & wrapmask;
1259: rtail=bc->rout & wrapmask;
1260:
1261: if( !(tp->t_cflag & CREAD) || !port->used ) {
1262: bc->rout=rhead;
1263: goto end_of_data;
1264: }
1265:
1266: if(bc->orun) {
1267: printf("dgb%d: port%d: overrun\n", unit, pnum);
1268: bc->orun=0;
1269: }
1270:
1271: if(!(tp->t_state & TS_ISOPEN))
1272: goto end_of_data;
1273:
1274: for(ibuf_full=FALSE;rhead!=rtail && !ibuf_full;) {
1275: DPRINT5(DB_RXDATA,"dgb%d: port%d: p rx head=%d tail=%d\n",
1276: unit,pnum,rhead,rtail);
1277:
1278: if(rhead>rtail)
1279: size=rhead-rtail;
1280: else
1281: size=port->rxbufsize-rtail;
1282:
1283: ptr=port->rxptr+rtail;
1284:
1285: /* Helg: */
1286: if( tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1287: size=DGB_IBUFSIZE-tp->t_rawq.c_cc;
1288: DPRINT1(DB_RXDATA,"*");
1289: ibuf_full=TRUE;
1290: }
1291:
1292: if(size) {
1293: if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1294: DPRINT1(DB_RXDATA,"!");
1295: towin(sc,port->rxwin);
1296: tk_nin += size;
1297: tk_rawcc += size;
1298: tp->t_rawcc += size;
1299: b_to_q(ptr,size,&tp->t_rawq);
1300: setwin(sc,0);
1301: } else {
1302: int i=size;
1303: unsigned char chr;
1304: do {
1305: towin(sc,port->rxwin);
1306: chr= *ptr++;
1307: hidewin(sc);
1308: (*linesw[tp->t_line].l_rint)(chr, tp);
1309: } while (--i > 0 );
1310: setwin(sc,0);
1311: }
1312: }
1313: rtail= (rtail + size) & wrapmask;
1314: bc->rout=rtail;
1315: rhead=bc->rin & wrapmask;
1316: hidewin(sc);
1317: ttwakeup(tp);
1318: setwin(sc,0);
1319: }
1320: end_of_data: ;
1321: }
1322:
1323: if(event & MODEMCHG_IND) {
1324: DPRINT3(DB_MODEM,"dgb%d: port%d: MODEMCHG_IND\n",unit,pnum);
1325: port->imodem=mstat;
1326: if(mstat & port->dcd) {
1327: hidewin(sc);
1328: linesw[tp->t_line].l_modem(tp,1);
1329: setwin(sc,0);
1330: wakeup(TSA_CARR_ON(tp));
1331: } else {
1332: hidewin(sc);
1333: linesw[tp->t_line].l_modem(tp,0);
1334: setwin(sc,0);
1335: if( port->draining) {
1336: port->draining=0;
1337: wakeup(&port->draining);
1338: }
1339: }
1340: }
1341:
1342: if(event & BREAK_IND) {
1343: if((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1344: DPRINT3(DB_BREAK,"dgb%d: port%d: BREAK_IND\n",unit,pnum);
1345: hidewin(sc);
1346: linesw[tp->t_line].l_rint(TTY_BI, tp);
1347: setwin(sc,0);
1348: }
1349: }
1350:
1351: /* Helg: with output flow control */
1352:
1353: if(event & (LOWTX_IND | EMPTYTX_IND) ) {
1354: DPRINT3(DB_TXDATA,"dgb%d: port%d: LOWTX_IND or EMPTYTX_IND\n",unit,pnum);
1355:
1356: if( (event & EMPTYTX_IND ) && tp->t_outq.c_cc==0
1357: && port->draining) {
1358: port->draining=0;
1359: wakeup(&port->draining);
1360: bc->ilow=0; bc->iempty=0;
1361: } else {
1362:
1363: int wrapmask=port->txbufsize-1;
1364:
1365: for(obuf_full=FALSE; tp->t_outq.c_cc!=0 && !obuf_full; ) {
1366: int s;
1367: /* add "last-minute" data to write buffer */
1368: if(!(tp->t_state & TS_BUSY)) {
1369: hidewin(sc);
1370: #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1371: ttwwakeup(tp);
1372: #else
1373: if(tp->t_outq.c_cc <= tp->t_lowat) {
1374: if(tp->t_state & TS_ASLEEP) {
1375: tp->t_state &= ~TS_ASLEEP;
1376: wakeup(TSA_OLOWAT(tp));
1377: }
1378: /* selwakeup(&tp->t_wsel); */
1379: }
1380: #endif
1381: setwin(sc,0);
1382: }
1383: s=spltty();
1384:
1385: whead=bc->tin & wrapmask;
1386: wtail=bc->tout & wrapmask;
1387:
1388: if(whead<wtail)
1389: size=wtail-whead-1;
1390: else {
1391: size=port->txbufsize-whead;
1392: if(wtail==0)
1393: size--;
1394: }
1395:
1396: if(size==0) {
1397: DPRINT5(DB_WR,"dgb: head=%d tail=%d size=%d full=%d\n",
1398: whead,wtail,size,obuf_full);
1399: bc->iempty=1; bc->ilow=1;
1400: obuf_full=TRUE;
1401: splx(s);
1402: break;
1403: }
1404:
1405: towin(sc,port->txwin);
1406:
1407: ocount=q_to_b(&tp->t_outq, port->txptr+whead, size);
1408: whead+=ocount;
1409:
1410: setwin(sc,0);
1411: bc->tin=whead;
1412: bc->tin=whead & wrapmask;
1413: splx(s);
1414: }
1415:
1416: if(obuf_full) {
1417: DPRINT1(DB_WR," +BUSY\n");
1418: tp->t_state|=TS_BUSY;
1419: } else {
1420: DPRINT1(DB_WR," -BUSY\n");
1421: hidewin(sc);
1422: #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1423: /* should clear TS_BUSY before ttwwakeup */
1424: if(tp->t_state & TS_BUSY) {
1425: tp->t_state &= ~TS_BUSY;
1426: linesw[tp->t_line].l_start(tp);
1427: ttwwakeup(tp);
1428: }
1429: #else
1430: if(tp->t_state & TS_ASLEEP) {
1431: tp->t_state &= ~TS_ASLEEP;
1432: wakeup(TSA_OLOWAT(tp));
1433: }
1434: tp->t_state &= ~TS_BUSY;
1435: #endif
1436: setwin(sc,0);
1437: }
1438: }
1439: }
1440: bc->idata=1; /* require event on incoming data */
1441:
1442: } else {
1443: bc=port->brdchan;
1444: DPRINT4(DB_EXCEPT,"dgb%d: port%d: got event 0x%x on closed port\n",
1445: unit,pnum,event);
1446: bc->rout=bc->rin;
1447: bc->idata=bc->iempty=bc->ilow=0;
1448: }
1449:
1450: tail= (tail+4) & (FEP_IMAX-FEP_ISTART-4);
1451: }
1452:
1453: sc->mailbox->eout=tail;
1454: bmws_set(ws);
1455:
1456: timeout(dgbpoll, unit_c, hz/POLLSPERSEC);
1457: }
1458:
1459: static int
1460: dgbioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1461: {
1462: struct dgb_softc *sc;
1463: int unit, pnum;
1464: struct dgb_p *port;
1465: int mynor;
1466: struct tty *tp;
1467: volatile struct board_chan *bc;
1468: int error;
1469: int s,cs;
1470: int tiocm_xxx;
1471:
1472: #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1473: u_long oldcmd;
1474: struct termios term;
1475: #endif
1476:
1477: BoardMemWinState ws=bmws_get();
1478:
1479: mynor=minor(dev);
1480: unit=MINOR_TO_UNIT(mynor);
1481: pnum=MINOR_TO_PORT(mynor);
1482:
1483: sc=&dgb_softc[unit];
1484: port=&sc->ports[pnum];
1485: tp=&sc->ttys[pnum];
1486: bc=port->brdchan;
1487:
1488: if (mynor & CONTROL_MASK) {
1489: struct termios *ct;
1490:
1491: switch (mynor & CONTROL_MASK) {
1492: case CONTROL_INIT_STATE:
1493: ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1494: break;
1495: case CONTROL_LOCK_STATE:
1496: ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1497: break;
1498: default:
1499: return (ENODEV); /* /dev/nodev */
1500: }
1501: switch (cmd) {
1502: case TIOCSETA:
1503: error = suser(td);
1504: if (error != 0)
1505: return (error);
1506: *ct = *(struct termios *)data;
1507: return (0);
1508: case TIOCGETA:
1509: *(struct termios *)data = *ct;
1510: return (0);
1511: case TIOCGETD:
1512: *(int *)data = TTYDISC;
1513: return (0);
1514: case TIOCGWINSZ:
1515: bzero(data, sizeof(struct winsize));
1516: return (0);
1517: default:
1518: return (ENOTTY);
1519: }
1520: }
1521:
1522: #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1523: term = tp->t_termios;
1524: if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1525: DPRINT6(DB_PARAM,"dgb%d: port%d: dgbioctl-ISNOW c=0x%x i=0x%x l=0x%x\n",unit,pnum,term.c_cflag,term.c_iflag,term.c_lflag);
1526: }
1527: oldcmd = cmd;
1528: error = ttsetcompat(tp, &cmd, data, &term);
1529: if (error != 0)
1530: return (error);
1531: if (cmd != oldcmd)
1532: data = (caddr_t)&term;
1533: #endif
1534:
1535: if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1536: int cc;
1537: struct termios *dt = (struct termios *)data;
1538: struct termios *lt = mynor & CALLOUT_MASK
1539: ? &port->lt_out : &port->lt_in;
1540:
1541: DPRINT6(DB_PARAM,"dgb%d: port%d: dgbioctl-TOSET c=0x%x i=0x%x l=0x%x\n",unit,pnum,dt->c_cflag,dt->c_iflag,dt->c_lflag);
1542: dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1543: | (dt->c_iflag & ~lt->c_iflag);
1544: dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1545: | (dt->c_oflag & ~lt->c_oflag);
1546: dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1547: | (dt->c_cflag & ~lt->c_cflag);
1548: dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1549: | (dt->c_lflag & ~lt->c_lflag);
1550: for (cc = 0; cc < NCCS; ++cc)
1551: if (lt->c_cc[cc] != 0)
1552: dt->c_cc[cc] = tp->t_cc[cc];
1553: if (lt->c_ispeed != 0)
1554: dt->c_ispeed = tp->t_ispeed;
1555: if (lt->c_ospeed != 0)
1556: dt->c_ospeed = tp->t_ospeed;
1557: }
1558:
1559: if(cmd==TIOCSTOP) {
1560: cs=splclock();
1561: setwin(sc,0);
1562: fepcmd(port, PAUSETX, 0, 0, 0, 0);
1563: bmws_set(ws);
1564: splx(cs);
1565: return 0;
1566: } else if(cmd==TIOCSTART) {
1567: cs=splclock();
1568: setwin(sc,0);
1569: fepcmd(port, RESUMETX, 0, 0, 0, 0);
1570: bmws_set(ws);
1571: splx(cs);
1572: return 0;
1573: }
1574:
1575: if(cmd==TIOCSETAW || cmd==TIOCSETAF)
1576: port->mustdrain=1;
1577:
1578: error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, td);
1579: if (error != ENOIOCTL)
1580: return error;
1581: s = spltty();
1582: error = ttioctl(tp, cmd, data, flag);
1583: disc_optim(tp,&tp->t_termios);
1584: port->mustdrain=0;
1585: if (error != ENOIOCTL) {
1586: splx(s);
1587: if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1588: DPRINT6(DB_PARAM,"dgb%d: port%d: dgbioctl-RES c=0x%x i=0x%x l=0x%x\n",unit,pnum,tp->t_cflag,tp->t_iflag,tp->t_lflag);
1589: }
1590: return error;
1591: }
1592:
1593: switch (cmd) {
1594: case TIOCSBRK:
1595: /* Helg: commented */
1596: /* error=dgbdrain(port);*/
1597:
1598: if(error!=0) {
1599: splx(s);
1600: return error;
1601: }
1602:
1603: cs=splclock();
1604: setwin(sc,0);
1605:
1606: /* now it sends 250 millisecond break because I don't know */
1607: /* how to send an infinite break */
1608:
1609: fepcmd(port, SENDBREAK, 250, 0, 10, 0);
1610: hidewin(sc);
1611: splx(cs);
1612: break;
1613: case TIOCCBRK:
1614: /* now it's empty */
1615: break;
1616: case TIOCSDTR:
1617: DPRINT3(DB_MODEM,"dgb%d: port%d: set DTR\n",unit,pnum);
1618: port->omodem |= DTR;
1619: cs=splclock();
1620: setwin(sc,0);
1621: fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1622:
1623: if( !(bc->mstat & DTR) ) {
1624: DPRINT3(DB_MODEM,"dgb%d: port%d: DTR is off\n",unit,pnum);
1625: }
1626:
1627: hidewin(sc);
1628: splx(cs);
1629: break;
1630: case TIOCCDTR:
1631: DPRINT3(DB_MODEM,"dgb%d: port%d: reset DTR\n",unit,pnum);
1632: port->omodem &= ~DTR;
1633: cs=splclock();
1634: setwin(sc,0);
1635: fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1636:
1637: if( bc->mstat & DTR ) {
1638: DPRINT3(DB_MODEM,"dgb%d: port%d: DTR is on\n",unit,pnum);
1639: }
1640:
1641: hidewin(sc);
1642: splx(cs);
1643: break;
1644: case TIOCMSET:
1645: if(*(int *)data & TIOCM_DTR)
1646: port->omodem |=DTR;
1647: else
1648: port->omodem &=~DTR;
1649:
1650: if(*(int *)data & TIOCM_RTS)
1651: port->omodem |=RTS;
1652: else
1653: port->omodem &=~RTS;
1654:
1655: cs=splclock();
1656: setwin(sc,0);
1657: fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1658: hidewin(sc);
1659: splx(cs);
1660: break;
1661: case TIOCMBIS:
1662: if(*(int *)data & TIOCM_DTR)
1663: port->omodem |=DTR;
1664:
1665: if(*(int *)data & TIOCM_RTS)
1666: port->omodem |=RTS;
1667:
1668: cs=splclock();
1669: setwin(sc,0);
1670: fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1671: hidewin(sc);
1672: splx(cs);
1673: break;
1674: case TIOCMBIC:
1675: if(*(int *)data & TIOCM_DTR)
1676: port->omodem &=~DTR;
1677:
1678: if(*(int *)data & TIOCM_RTS)
1679: port->omodem &=~RTS;
1680:
1681: cs=splclock();
1682: setwin(sc,0);
1683: fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1684: hidewin(sc);
1685: splx(cs);
1686: break;
1687: case TIOCMGET:
1688: setwin(sc,0);
1689: port->imodem=bc->mstat;
1690: hidewin(sc);
1691:
1692: tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1693:
1694: DPRINT3(DB_MODEM,"dgb%d: port%d: modem stat -- ",unit,pnum);
1695:
1696: if (port->imodem & DTR) {
1697: DPRINT1(DB_MODEM,"DTR ");
1698: tiocm_xxx |= TIOCM_DTR;
1699: }
1700: if (port->imodem & RTS) {
1701: DPRINT1(DB_MODEM,"RTS ");
1702: tiocm_xxx |= TIOCM_RTS;
1703: }
1704: if (port->imodem & CTS) {
1705: DPRINT1(DB_MODEM,"CTS ");
1706: tiocm_xxx |= TIOCM_CTS;
1707: }
1708: if (port->imodem & port->dcd) {
1709: DPRINT1(DB_MODEM,"DCD ");
1710: tiocm_xxx |= TIOCM_CD;
1711: }
1712: if (port->imodem & port->dsr) {
1713: DPRINT1(DB_MODEM,"DSR ");
1714: tiocm_xxx |= TIOCM_DSR;
1715: }
1716: if (port->imodem & RI) {
1717: DPRINT1(DB_MODEM,"RI ");
1718: tiocm_xxx |= TIOCM_RI;
1719: }
1720: *(int *)data = tiocm_xxx;
1721: DPRINT1(DB_MODEM,"--\n");
1722: break;
1723: case TIOCMSDTRWAIT:
1724: /* must be root since the wait applies to following logins */
1725: error = suser(td);
1726: if (error != 0) {
1727: splx(s);
1728: return (error);
1729: }
1730: port->close_delay = *(int *)data * hz / 100;
1731: break;
1732: case TIOCMGDTRWAIT:
1733: *(int *)data = port->close_delay * 100 / hz;
1734: break;
1735: case TIOCTIMESTAMP:
1736: port->do_timestamp = TRUE;
1737: *(struct timeval *)data = port->timestamp;
1738: break;
1739: case TIOCDCDTIMESTAMP:
1740: port->do_dcd_timestamp = TRUE;
1741: *(struct timeval *)data = port->dcd_timestamp;
1742: break;
1743: default:
1744: bmws_set(ws);
1745: splx(s);
1746: return ENOTTY;
1747: }
1748: bmws_set(ws);
1749: splx(s);
1750:
1751: return 0;
1752: }
1753:
1754: static void
1755: wakeflush(p)
1756: void *p;
1757: {
1758: struct dgb_p *port=p;
1759:
1760: wakeup(&port->draining);
1761: }
1762:
1763: /* wait for the output to drain */
1764:
1765: static int
1766: dgbdrain(port)
1767: struct dgb_p *port;
1768: {
1769: struct dgb_softc *sc=&dgb_softc[port->unit];
1770: volatile struct board_chan *bc=port->brdchan;
1771: int error;
1772: int head, tail;
1773:
1774: BoardMemWinState ws=bmws_get();
1775:
1776: setwin(sc,0);
1777:
1778: bc->iempty=1;
1779: tail=bc->tout;
1780: head=bc->tin;
1781:
1782: while(tail!=head) {
1783: DPRINT5(DB_WR,"dgb%d: port%d: drain: head=%d tail=%d\n",
1784: port->unit, port->pnum, head, tail);
1785:
1786: hidewin(sc);
1787: port->draining=1;
1788: timeout(wakeflush,port, hz);
1789: error=tsleep(&port->draining, PCATCH, "dgdrn", 0);
1790: port->draining=0;
1791: setwin(sc,0);
1792:
1793: if (error != 0) {
1794: DPRINT4(DB_WR,"dgb%d: port%d: tsleep(dgdrn) error=%d\n",
1795: port->unit,port->pnum,error);
1796:
1797: bc->iempty=0;
1798: bmws_set(ws);
1799: return error;
1800: }
1801:
1802: tail=bc->tout;
1803: head=bc->tin;
1804: }
1805: DPRINT5(DB_WR,"dgb%d: port%d: drain: head=%d tail=%d\n",
1806: port->unit, port->pnum, head, tail);
1807: bmws_set(ws);
1808: return 0;
1809: }
1810:
1811: /* wait for the output to drain */
1812: /* or simply clear the buffer it it's stopped */
1813:
1814: static void
1815: dgb_drain_or_flush(port)
1816: struct dgb_p *port;
1817: {
1818: struct tty *tp=port->tty;
1819: struct dgb_softc *sc=&dgb_softc[port->unit];
1820: volatile struct board_chan *bc=port->brdchan;
1821: int error;
1822: int lasttail;
1823: int head, tail;
1824:
1825: setwin(sc,0);
1826:
1827: lasttail=-1;
1828: bc->iempty=1;
1829: tail=bc->tout;
1830: head=bc->tin;
1831:
1832: while(tail!=head /* && tail!=lasttail */ ) {
1833: DPRINT5(DB_WR,"dgb%d: port%d: flush: head=%d tail=%d\n",
1834: port->unit, port->pnum, head, tail);
1835:
1836: /* if there is no carrier simply clean the buffer */
1837: if( !(tp->t_state & TS_CARR_ON) ) {
1838: bc->tout=bc->tin=0;
1839: bc->iempty=0;
1840: hidewin(sc);
1841: return;
1842: }
1843:
1844: hidewin(sc);
1845: port->draining=1;
1846: timeout(wakeflush,port, hz);
1847: error=tsleep(&port->draining, PCATCH, "dgfls", 0);
1848: port->draining=0;
1849: setwin(sc,0);
1850:
1851: if (error != 0) {
1852: DPRINT4(DB_WR,"dgb%d: port%d: tsleep(dgfls) error=%d\n",
1853: port->unit,port->pnum,error);
1854:
1855: /* silently clean the buffer */
1856:
1857: bc->tout=bc->tin=0;
1858: bc->iempty=0;
1859: hidewin(sc);
1860: return;
1861: }
1862:
1863: lasttail=tail;
1864: tail=bc->tout;
1865: head=bc->tin;
1866: }
1867: hidewin(sc);
1868: DPRINT5(DB_WR,"dgb%d: port%d: flush: head=%d tail=%d\n",
1869: port->unit, port->pnum, head, tail);
1870: }
1871:
1872: static int
1873: dgbparam(tp, t)
1874: struct tty *tp;
1875: struct termios *t;
1876: {
1877: int unit=MINOR_TO_UNIT(minor(tp->t_dev));
1878: int pnum=MINOR_TO_PORT(minor(tp->t_dev));
1879: struct dgb_softc *sc=&dgb_softc[unit];
1880: struct dgb_p *port=&sc->ports[pnum];
1881: volatile struct board_chan *bc=port->brdchan;
1882: int cflag;
1883: int head;
1884: int mval;
1885: int iflag;
1886: int hflow;
1887: int cs;
1888:
1889: BoardMemWinState ws=bmws_get();
1890:
1891: DPRINT6(DB_PARAM,"dgb%d: port%d: dgbparm c=0x%x i=0x%x l=0x%x\n",unit,pnum,t->c_cflag,t->c_iflag,t->c_lflag);
1892:
1893: if(port->mustdrain) {
1894: DPRINT3(DB_PARAM,"dgb%d: port%d: must call dgbdrain()\n",unit,pnum);
1895: dgbdrain(port);
1896: }
1897:
1898: cflag=ttspeedtab(t->c_ospeed, dgbspeedtab);
1899:
1900: if (t->c_ispeed == 0)
1901: t->c_ispeed = t->c_ospeed;
1902:
1903: if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1904: DPRINT4(DB_PARAM,"dgb%d: port%d: invalid cflag=0%o\n",unit,pnum,cflag);
1905: return (EINVAL);
1906: }
1907:
1908: cs=splclock();
1909: setwin(sc,0);
1910:
1911: if(cflag==0) { /* hangup */
1912: DPRINT3(DB_PARAM,"dgb%d: port%d: hangup\n",unit,pnum);
1913: head=bc->rin;
1914: bc->rout=head;
1915: head=bc->tin;
1916: fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1917: mval= port->omodem & ~(DTR|RTS);
1918: } else {
1919: cflag |= dgbflags(dgb_cflags, t->c_cflag);
1920:
1921: if(cflag!=port->fepcflag) {
1922: port->fepcflag=cflag;
1923: DPRINT5(DB_PARAM,"dgb%d: port%d: set cflag=0x%x c=0x%x\n",
1924: unit,pnum,cflag,t->c_cflag&~CRTSCTS);
1925: fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1926: }
1927: mval= port->omodem | (DTR|RTS);
1928: }
1929:
1930: iflag=dgbflags(dgb_iflags, t->c_iflag);
1931: if(iflag!=port->fepiflag) {
1932: port->fepiflag=iflag;
1933: DPRINT5(DB_PARAM,"dgb%d: port%d: set iflag=0x%x c=0x%x\n",unit,pnum,iflag,t->c_iflag);
1934: fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1935: }
1936:
1937: bc->mint=port->dcd;
1938:
1939: hflow=dgbflags(dgb_flow, t->c_cflag);
1940: if(hflow!=port->hflow) {
1941: port->hflow=hflow;
1942: DPRINT5(DB_PARAM,"dgb%d: port%d: set hflow=0x%x f=0x%x\n",unit,pnum,hflow,t->c_cflag&CRTSCTS);
1943: fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1944: }
1945:
1946: if(port->omodem != mval) {
1947: DPRINT5(DB_PARAM,"dgb%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1948: unit,pnum,mval,port->omodem);
1949: port->omodem=mval;
1950: fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1951: }
1952:
1953: if(port->fepstartc!=t->c_cc[VSTART] || port->fepstopc!=t->c_cc[VSTOP]) {
1954: DPRINT5(DB_PARAM,"dgb%d: port%d: set startc=%d, stopc=%d\n",unit,pnum,t->c_cc[VSTART],t->c_cc[VSTOP]);
1955: port->fepstartc=t->c_cc[VSTART];
1956: port->fepstopc=t->c_cc[VSTOP];
1957: fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1958: }
1959:
1960: bmws_set(ws);
1961: splx(cs);
1962:
1963: return 0;
1964:
1965: }
1966:
1967: static void
1968: dgbstart(tp)
1969: struct tty *tp;
1970: {
1971: int unit;
1972: int pnum;
1973: struct dgb_p *port;
1974: struct dgb_softc *sc;
1975: volatile struct board_chan *bc;
1976: int head, tail;
1977: int size, ocount;
1978: int s;
1979: int wmask;
1980:
1981: BoardMemWinState ws=bmws_get();
1982:
1983: unit=MINOR_TO_UNIT(minor(tp->t_dev));
1984: pnum=MINOR_TO_PORT(minor(tp->t_dev));
1985: sc=&dgb_softc[unit];
1986: port=&sc->ports[pnum];
1987: bc=port->brdchan;
1988:
1989: wmask=port->txbufsize-1;
1990:
1991: s=spltty();
1992:
1993: while( tp->t_outq.c_cc!=0 ) {
1994: int cs;
1995: #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1996: ttwwakeup(tp);
1997: #else
1998: if(tp->t_outq.c_cc <= tp->t_lowat) {
1999: if(tp->t_state & TS_ASLEEP) {
2000: tp->t_state &= ~TS_ASLEEP;
2001: wakeup(TSA_OLOWAT(tp));
2002: }
2003: /*selwakeup(&tp->t_wsel);*/
2004: }
2005: #endif
2006: cs=splclock();
2007: setwin(sc,0);
2008:
2009: head=bc->tin & wmask;
2010:
2011: do { tail=bc->tout; } while (tail != bc->tout);
2012: tail=bc->tout & wmask;
2013:
2014: DPRINT5(DB_WR,"dgb%d: port%d: s tx head=%d tail=%d\n",unit,pnum,head,tail);
2015:
2016: #ifdef LEAVE_FREE_CHARS
2017: if(tail>head) {
2018: size=tail-head-LEAVE_FREE_CHARS;
2019: if (size <0)
2020: size=0;
2021: } else {
2022: size=port->txbufsize-head;
2023: if(tail+port->txbufsize < head)
2024: size=0;
2025: }
2026: }
2027: #else
2028: if(tail>head)
2029: size=tail-head-1;
2030: else {
2031: size=port->txbufsize-head/*-1*/;
2032: if(tail==0)
2033: size--;
2034: }
2035: #endif
2036:
2037: if(size==0) {
2038: bc->iempty=1; bc->ilow=1;
2039: splx(cs);
2040: bmws_set(ws);
2041: tp->t_state|=TS_BUSY;
2042: splx(s);
2043: return;
2044: }
2045:
2046: towin(sc,port->txwin);
2047:
2048: ocount=q_to_b(&tp->t_outq, port->txptr+head, size);
2049: head+=ocount;
2050: if(head>=port->txbufsize)
2051: head-=port->txbufsize;
2052:
2053: setwin(sc,0);
2054: bc->tin=head;
2055:
2056: DPRINT5(DB_WR,"dgb%d: port%d: tx avail=%d count=%d\n",unit,pnum,size,ocount);
2057: hidewin(sc);
2058: splx(cs);
2059: }
2060:
2061: bmws_set(ws);
2062: splx(s);
2063:
2064: #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2065: if(tp->t_state & TS_BUSY) {
2066: tp->t_state&=~TS_BUSY;
2067: linesw[tp->t_line].l_start(tp);
2068: ttwwakeup(tp);
2069: }
2070: #else
2071: if(tp->t_state & TS_ASLEEP) {
2072: tp->t_state &= ~TS_ASLEEP;
2073: wakeup(TSA_OLOWAT(tp));
2074: }
2075: tp->t_state&=~TS_BUSY;
2076: #endif
2077: }
2078:
2079: void
2080: dgbstop(tp, rw)
2081: struct tty *tp;
2082: int rw;
2083: {
2084: int unit;
2085: int pnum;
2086: struct dgb_p *port;
2087: struct dgb_softc *sc;
2088: volatile struct board_chan *bc;
2089: int s;
2090:
2091: BoardMemWinState ws=bmws_get();
2092:
2093: unit=MINOR_TO_UNIT(minor(tp->t_dev));
2094: pnum=MINOR_TO_PORT(minor(tp->t_dev));
2095:
2096: sc=&dgb_softc[unit];
2097: port=&sc->ports[pnum];
2098: bc=port->brdchan;
2099:
2100: DPRINT3(DB_WR,"dgb%d: port%d: stop\n",port->unit, port->pnum);
2101:
2102: s = spltty();
2103: setwin(sc,0);
2104:
2105: if (rw & FWRITE) {
2106: /* clear output queue */
2107: bc->tout=bc->tin=0;
2108: bc->ilow=0;bc->iempty=0;
2109: }
2110: if (rw & FREAD) {
2111: /* clear input queue */
2112: bc->rout=bc->rin;
2113: bc->idata=1;
2114: }
2115: hidewin(sc);
2116: bmws_set(ws);
2117: splx(s);
2118: dgbstart(tp);
2119: }
2120:
2121: static void
2122: fepcmd(port, cmd, op1, op2, ncmds, bytecmd)
2123: struct dgb_p *port;
2124: unsigned cmd, op1, op2, ncmds, bytecmd;
2125: {
2126: struct dgb_softc *sc=&dgb_softc[port->unit];
2127: u_char *mem=sc->vmem;
2128: unsigned tail, head;
2129: int count, n;
2130:
2131: if(port->status==DISABLED) {
2132: printf("dgb%d: port%d: FEP command on disabled port\n",
2133: port->unit, port->pnum);
2134: return;
2135: }
2136:
2137: /* setwin(sc,0); Require this to be set by caller */
2138: head=sc->mailbox->cin;
2139:
2140: if(head>=(FEP_CMAX-FEP_CSTART) || (head & 3)) {
2141: printf("dgb%d: port%d: wrong pointer head of command queue : 0x%x\n",
2142: port->unit, port->pnum, head);
2143: return;
2144: }
2145:
2146: mem[head+FEP_CSTART+0]=cmd;
2147: mem[head+FEP_CSTART+1]=port->pnum;
2148: if(bytecmd) {
2149: mem[head+FEP_CSTART+2]=op1;
2150: mem[head+FEP_CSTART+3]=op2;
2151: } else {
2152: mem[head+FEP_CSTART+2]=op1&0xff;
2153: mem[head+FEP_CSTART+3]=(op1>>8)&0xff;
2154: }
2155:
2156: DPRINT7(DB_FEP,"dgb%d: port%d: %s cmd=0x%x op1=0x%x op2=0x%x\n", port->unit, port->pnum,
2157: (bytecmd)?"byte":"word", cmd, mem[head+FEP_CSTART+2], mem[head+FEP_CSTART+3]);
2158:
2159: head=(head+4) & (FEP_CMAX-FEP_CSTART-4);
2160: sc->mailbox->cin=head;
2161:
2162: count=FEPTIMEOUT;
2163:
2164: while (count-- != 0) {
2165: head=sc->mailbox->cin;
2166: tail=sc->mailbox->cout;
2167:
2168: n = (head-tail) & (FEP_CMAX-FEP_CSTART-4);
2169: if(n <= ncmds * (sizeof(ushort)*4))
2170: return;
2171: }
2172: printf("dgb%d(%d): timeout on FEP cmd=0x%x\n", port->unit, port->pnum, cmd);
2173: }
2174:
2175: static void
2176: disc_optim(tp, t)
2177: struct tty *tp;
2178: struct termios *t;
2179: {
2180: if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2181: && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2182: && (!(t->c_iflag & PARMRK)
2183: || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2184: && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2185: && linesw[tp->t_line].l_rint == ttyinput)
2186: tp->t_state |= TS_CAN_BYPASS_L_RINT;
2187: else
2188: tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2189: }