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