This source file includes following definitions.
- memwinon
- memwinoff
- globalwinon
- rxwinon
- txwinon
- memoff
- assertgwinon
- assertmemoff
- pcxe_sched_event
- pcxx_error
- pcxx_waitcarrier
- pcxe_open
- shutdown
- pcxe_close
- pcxe_hangup
- pcxe_write
- pcxe_put_char
- pcxe_write_room
- pcxe_chars_in_buffer
- pcxe_flush_buffer
- pcxe_flush_chars
- pcxe_init
- pcxxpoll
- doevent
- pcxxdelay
- fepcmd
- termios2digi_c
- termios2digi_i
- termios2digi_h
- pcxxparam
- receive_data
- pcxe_ioctl
- pcxe_set_termios
- do_pcxe_bh
- do_softint
- pcxe_stop
- pcxe_throttle
- pcxe_unthrottle
- pcxe_start
- digi_send_break
- setup_empty_event
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 #undef SPEED_HACK
32
33
34
35
36
37
38
39 #include <linux/mm.h>
40 #include <linux/ioport.h>
41 #include <linux/errno.h>
42 #include <linux/signal.h>
43 #include <linux/sched.h>
44 #include <linux/timer.h>
45 #include <linux/interrupt.h>
46 #include <linux/tty.h>
47 #include <linux/tty_flip.h>
48 #include <linux/major.h>
49 #include <linux/string.h>
50 #include <linux/fcntl.h>
51 #include <linux/ptrace.h>
52 #include <linux/major.h>
53 #include <linux/delay.h>
54 #include <linux/serial.h>
55 #include <linux/tty_driver.h>
56 #include <linux/malloc.h>
57
58 #include <asm/system.h>
59 #include <asm/io.h>
60 #include <asm/segment.h>
61 #include <asm/bitops.h>
62
63 #define VERSION "1.5.4"
64
65
66
67 #include "digi.h"
68 #include "fep.h"
69 #include "pcxx.h"
70 #include "digi_fep.h"
71 #include "digi_bios.h"
72 #include "pcxxconfig.h"
73
74 #define DIGIMAJOR 30
75 #define DIGICUMAJOR 31
76
77 #define MAXPORTS 16
78 #define NBDEVS (NUMCARDS * MAXPORTS)
79 #define PORTNUM(x) ((x)->dev % MAXPORTS)
80 #define LINENUM(x) (MINOR((x)->device) - (x)->driver.minor_start)
81
82 int pcxx_ncook=sizeof(pcxx_cook);
83 int pcxx_nbios=sizeof(pcxx_bios);
84
85 struct channel digi_channels[NBDEVS];
86
87 #define MIN(a,b) ((a) < (b) ? (a) : (b))
88 #define pcxxassert(x, msg) if(!(x)) pcxx_error(__LINE__, msg)
89
90 #define FEPTIMEOUT 200000
91 #define SERIAL_TYPE_NORMAL 1
92 #define SERIAL_TYPE_CALLOUT 2
93 #define PCXE_EVENT_HANGUP 1
94
95 struct tty_driver pcxe_driver;
96 struct tty_driver pcxe_callout;
97 static int pcxe_refcount;
98
99 DECLARE_TASK_QUEUE(tq_pcxx);
100 static struct tty_struct *pcxe_table[NBDEVS];
101 static struct termios *pcxe_termios[NBDEVS];
102 static struct termios *pcxe_termios_locked[NBDEVS];
103
104 static void pcxxpoll(void);
105 static void pcxxdelay(int);
106 static void fepcmd(struct channel *, int, int, int, int, int);
107 static void pcxe_put_char(struct tty_struct *, unsigned char);
108 static void pcxe_flush_chars(struct tty_struct *);
109 static void pcxx_error(int, char *);
110 static void pcxe_close(struct tty_struct *, struct file *);
111 static int pcxe_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
112 static void pcxe_set_termios(struct tty_struct *, struct termios *);
113 static int pcxe_write(struct tty_struct *, int, const unsigned char *, int);
114 static int pcxe_write_room(struct tty_struct *);
115 static int pcxe_chars_in_buffer(struct tty_struct *);
116 static void pcxe_flush_buffer(struct tty_struct *);
117 static void doevent(int);
118 static void receive_data(struct channel *);
119 static void pcxxparam(struct tty_struct *, struct channel *ch);
120 static void do_softint(void *);
121 static inline void pcxe_sched_event(struct channel *, int);
122 static void do_pcxe_bh(void);
123 static void pcxe_start(struct tty_struct *);
124 static void pcxe_stop(struct tty_struct *);
125 static void pcxe_throttle(struct tty_struct *);
126 static void pcxe_unthrottle(struct tty_struct *);
127 static void digi_send_break(struct channel *ch, int msec);
128 static void shutdown(struct channel *);
129 static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
130 static inline void memwinon(struct board_info *b, unsigned int win);
131 static inline void memwinoff(struct board_info *b, unsigned int win);
132 static inline void globalwinon(struct channel *ch);
133 static inline void rxwinon(struct channel *ch);
134 static inline void txwinon(struct channel *ch);
135 static inline void memoff(struct channel *ch);
136 static inline void assertgwinon(struct channel *ch);
137 static inline void assertmemoff(struct channel *ch);
138
139 #define TZ_BUFSZ 4096
140
141 static inline struct channel *chan(register struct tty_struct *tty)
142 {
143 if (tty) {
144 register struct channel *ch=(struct channel *)tty->driver_data;
145 if ((ch >= &digi_channels[0]) && (ch < &digi_channels[NBDEVS])) {
146 if (ch->magic==PCXX_MAGIC)
147 return ch;
148 }
149 }
150 return NULL;
151 }
152
153
154 static inline void memwinon(struct board_info *b, unsigned int win)
155 {
156 if(b->type == PCXEVE)
157 outb_p(FEPWIN|win, b->port+1);
158 else
159 outb_p(inb(b->port)|FEPMEM, b->port);
160 }
161
162 static inline void memwinoff(struct board_info *b, unsigned int win)
163 {
164 outb_p(inb(b->port)&~FEPMEM, b->port);
165 if(b->type == PCXEVE)
166 outb_p(0, b->port + 1);
167 }
168
169 static inline void globalwinon(struct channel *ch)
170 {
171 if(ch->board->type == PCXEVE)
172 outb_p(FEPWIN, ch->board->port+1);
173 else
174 outb_p(FEPMEM, ch->board->port);
175 }
176
177 static inline void rxwinon(struct channel *ch)
178 {
179 if(ch->rxwin == 0)
180 outb_p(FEPMEM, ch->board->port);
181 else
182 outb_p(ch->rxwin, ch->board->port+1);
183 }
184
185 static inline void txwinon(struct channel *ch)
186 {
187 if(ch->txwin == 0)
188 outb_p(FEPMEM, ch->board->port);
189 else
190 outb_p(ch->txwin, ch->board->port+1);
191 }
192
193 static inline void memoff(struct channel *ch)
194 {
195 outb_p(0, ch->board->port);
196 if(ch->board->type == PCXEVE)
197 outb_p(0, ch->board->port+1);
198 }
199
200 static inline void assertgwinon(struct channel *ch)
201 {
202 if(ch->board->type != PCXEVE)
203 pcxxassert(inb(ch->board->port) & FEPMEM, "Global memory off");
204 }
205
206 static inline void assertmemoff(struct channel *ch)
207 {
208 if(ch->board->type != PCXEVE)
209 pcxxassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
210 }
211
212 static inline void pcxe_sched_event(struct channel *info, int event)
213 {
214 info->event |= 1 << event;
215 queue_task_irq_off(&info->tqueue, &tq_pcxx);
216 mark_bh(DIGI_BH);
217 }
218
219 static void pcxx_error(int line, char *msg)
220 {
221 printk("pcxx_error (DigiBoard): line=%d %s\n", line, msg);
222 }
223
224 static int pcxx_waitcarrier(struct tty_struct *tty,struct file *filp,struct channel *info)
225 {
226 struct wait_queue wait = { current, NULL };
227 int retval = 0;
228 int do_clocal = 0;
229
230 if (info->asyncflags & ASYNC_CALLOUT_ACTIVE) {
231 if (info->normal_termios.c_cflag & CLOCAL)
232 do_clocal = 1;
233 } else {
234 if (tty->termios->c_cflag & CLOCAL)
235 do_clocal = 1;
236 }
237
238
239
240
241
242 retval = 0;
243 add_wait_queue(&info->open_wait, &wait);
244 info->count--;
245 info->blocked_open++;
246
247 for (;;) {
248 cli();
249 if ((info->asyncflags & ASYNC_CALLOUT_ACTIVE) == 0) {
250 globalwinon(info);
251 info->omodem |= DTR|RTS;
252 fepcmd(info, SETMODEM, DTR|RTS, 0, 10, 1);
253 memoff(info);
254 }
255 sti();
256 current->state = TASK_INTERRUPTIBLE;
257 if(tty_hung_up_p(filp) || (info->asyncflags & ASYNC_INITIALIZED) == 0) {
258 if(info->asyncflags & ASYNC_HUP_NOTIFY)
259 retval = -EAGAIN;
260 else
261 retval = -ERESTARTSYS;
262 break;
263 }
264 if ((info->asyncflags & ASYNC_CALLOUT_ACTIVE) == 0 &&
265 (info->asyncflags & ASYNC_CLOSING) == 0 &&
266 (do_clocal || (info->imodem & info->dcd)))
267 break;
268 if(current->signal & ~current->blocked) {
269 retval = -ERESTARTSYS;
270 break;
271 }
272 schedule();
273 }
274 current->state = TASK_RUNNING;
275 remove_wait_queue(&info->open_wait, &wait);
276
277 if(!tty_hung_up_p(filp))
278 info->count++;
279 info->blocked_open--;
280
281 return retval;
282 }
283
284
285
286 int pcxe_open(struct tty_struct *tty, struct file * filp)
287 {
288 volatile struct board_chan *bc;
289 struct channel *ch;
290 unsigned long flags;
291 int line;
292 int boardnum;
293 int retval;
294
295 line = MINOR(tty->device) - tty->driver.minor_start;
296 if(line < 0 || line >= NBDEVS) {
297 printk("line out of range in pcxe_open\n");
298 tty->driver_data = NULL;
299 return(-ENODEV);
300 }
301
302 boardnum = line / 16;
303 if(boardnum >= NUMCARDS || boards[boardnum].status == DISABLED ||
304 (line % MAXPORTS) >= boards[boardnum].numports) {
305 tty->driver_data = NULL;
306 return(-ENODEV);
307 }
308
309 ch = &digi_channels[line];
310
311 if(ch->brdchan == 0) {
312 tty->driver_data = NULL;
313 return(-ENODEV);
314 }
315
316
317
318
319
320 if(ch->asyncflags & ASYNC_CLOSING) {
321 interruptible_sleep_on(&ch->close_wait);
322 if(ch->asyncflags & ASYNC_HUP_NOTIFY)
323 return -EAGAIN;
324 else
325 return -ERESTARTSYS;
326 }
327
328 save_flags(flags);
329 cli();
330 ch->count++;
331 tty->driver_data = ch;
332 ch->tty = tty;
333
334 if ((ch->asyncflags & ASYNC_INITIALIZED) == 0) {
335 unsigned int head;
336
337 globalwinon(ch);
338 ch->statusflags = 0;
339 bc=ch->brdchan;
340 ch->imodem = bc->mstat;
341 head = bc->rin;
342 bc->rout = head;
343 ch->tty = tty;
344 pcxxparam(tty,ch);
345 ch->imodem = bc->mstat;
346 bc->idata = 1;
347 ch->omodem = DTR|RTS;
348 fepcmd(ch, SETMODEM, DTR|RTS, 0, 10, 1);
349 memoff(ch);
350 ch->asyncflags |= ASYNC_INITIALIZED;
351 }
352 restore_flags(flags);
353
354 if(ch->asyncflags & ASYNC_CLOSING) {
355 interruptible_sleep_on(&ch->close_wait);
356 if(ch->asyncflags & ASYNC_HUP_NOTIFY)
357 return -EAGAIN;
358 else
359 return -ERESTARTSYS;
360 }
361
362
363
364
365 if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
366 if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
367 return -EBUSY;
368 if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) {
369 if ((ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&
370 (ch->session != current->session))
371 return -EBUSY;
372 if((ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&
373 (ch->pgrp != current->pgrp))
374 return -EBUSY;
375 }
376 ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;
377 }
378 else {
379 if (filp->f_flags & O_NONBLOCK) {
380 if(ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
381 return -EBUSY;
382 }
383 else {
384 if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0)
385 return retval;
386 }
387 ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
388 }
389
390 save_flags(flags);
391 cli();
392 if((ch->count == 1) && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) {
393 if(tty->driver.subtype == SERIAL_TYPE_NORMAL)
394 *tty->termios = ch->normal_termios;
395 else
396 *tty->termios = ch->callout_termios;
397 globalwinon(ch);
398 pcxxparam(tty,ch);
399 memoff(ch);
400 }
401
402 ch->session = current->session;
403 ch->pgrp = current->pgrp;
404 restore_flags(flags);
405 return 0;
406 }
407
408 static void shutdown(struct channel *info)
409 {
410 unsigned long flags;
411 volatile struct board_chan *bc;
412 struct tty_struct *tty;
413
414 if (!(info->asyncflags & ASYNC_INITIALIZED))
415 return;
416
417 save_flags(flags);
418 cli();
419 globalwinon(info);
420
421 bc = info->brdchan;
422 if(bc)
423 bc->idata = 0;
424
425 tty = info->tty;
426
427
428
429
430 if(tty->termios->c_cflag & HUPCL) {
431 info->omodem &= ~(RTS|DTR);
432 fepcmd(info, SETMODEM, 0, DTR|RTS, 10, 1);
433 }
434
435 memoff(info);
436 info->asyncflags &= ~ASYNC_INITIALIZED;
437 restore_flags(flags);
438 }
439
440
441 static void pcxe_close(struct tty_struct * tty, struct file * filp)
442 {
443 struct channel *info;
444
445 if ((info=chan(tty))!=NULL) {
446 unsigned long flags;
447 save_flags(flags);
448 cli();
449
450 if(tty_hung_up_p(filp)) {
451 restore_flags(flags);
452 return;
453 }
454 if (info->count-- > 1) {
455 restore_flags(flags);
456 return;
457 }
458 if (info->count < 0) {
459 info->count = 0;
460 }
461
462 info->asyncflags |= ASYNC_CLOSING;
463
464
465
466
467
468 if(info->asyncflags & ASYNC_NORMAL_ACTIVE)
469 info->normal_termios = *tty->termios;
470 if(info->asyncflags & ASYNC_CALLOUT_ACTIVE)
471 info->callout_termios = *tty->termios;
472 tty->closing = 1;
473 if(info->asyncflags & ASYNC_INITIALIZED) {
474 setup_empty_event(tty,info);
475 tty_wait_until_sent(tty, 3000);
476 }
477
478 if(tty->driver.flush_buffer)
479 tty->driver.flush_buffer(tty);
480 if(tty->ldisc.flush_buffer)
481 tty->ldisc.flush_buffer(tty);
482 shutdown(info);
483 tty->closing = 0;
484 info->event = 0;
485 info->tty = NULL;
486 if(tty->ldisc.num != ldiscs[N_TTY].num) {
487 if(tty->ldisc.close)
488 (tty->ldisc.close)(tty);
489 tty->ldisc = ldiscs[N_TTY];
490 tty->termios->c_line = N_TTY;
491 if(tty->ldisc.open)
492 (tty->ldisc.open)(tty);
493 }
494 if(info->blocked_open) {
495 if(info->close_delay) {
496 current->state = TASK_INTERRUPTIBLE;
497 current->timeout = jiffies + info->close_delay;
498 schedule();
499 }
500 wake_up_interruptible(&info->open_wait);
501 }
502 info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|
503 ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
504 wake_up_interruptible(&info->close_wait);
505 restore_flags(flags);
506 }
507 }
508
509
510 void pcxe_hangup(struct tty_struct *tty)
511 {
512 struct channel *ch;
513
514 if ((ch=chan(tty))!=NULL) {
515 unsigned long flags;
516
517 save_flags(flags);
518 cli();
519 shutdown(ch);
520 ch->event = 0;
521 ch->count = 0;
522 ch->tty = NULL;
523 ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
524 wake_up_interruptible(&ch->open_wait);
525 restore_flags(flags);
526 }
527 }
528
529
530
531 static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
532 {
533 struct channel *ch;
534 volatile struct board_chan *bc;
535 int total, remain, size, stlen;
536 unsigned int head, tail;
537 unsigned long flags;
538
539
540
541 if ((ch=chan(tty))==NULL)
542 return 0;
543
544 bc = ch->brdchan;
545 size = ch->txbufsize;
546
547 if (from_user) {
548
549 save_flags(flags);
550 cli();
551 globalwinon(ch);
552 head = bc->tin & (size - 1);
553 tail = bc->tout;
554 if (tail != bc->tout)
555 tail = bc->tout;
556 tail &= (size - 1);
557 stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
558 count = MIN(stlen, count);
559 if (count) {
560 if (verify_area(VERIFY_READ, (char*)buf, count))
561 count=0;
562 else memcpy_fromfs(ch->tmp_buf, buf, count);
563 }
564 buf = ch->tmp_buf;
565 memoff(ch);
566 restore_flags(flags);
567 }
568
569
570
571
572
573 total = 0;
574 save_flags(flags);
575 cli();
576 globalwinon(ch);
577 head = bc->tin & (size - 1);
578 tail = bc->tout;
579 if (tail != bc->tout)
580 tail = bc->tout;
581 tail &= (size - 1);
582 if (head >= tail) {
583 remain = size - (head - tail) - 1;
584 stlen = size - head;
585 }
586 else {
587 remain = tail - head - 1;
588 stlen = remain;
589 }
590 count = MIN(remain, count);
591
592 txwinon(ch);
593 while (count > 0) {
594 stlen = MIN(count, stlen);
595 memcpy(ch->txptr + head, buf, stlen);
596 buf += stlen;
597 count -= stlen;
598 total += stlen;
599 head += stlen;
600 if (head >= size) {
601 head = 0;
602 stlen = tail;
603 }
604 }
605 ch->statusflags |= TXBUSY;
606 globalwinon(ch);
607 bc->tin = head;
608 if ((ch->statusflags & LOWWAIT) == 0) {
609 ch->statusflags |= LOWWAIT;
610 bc->ilow = 1;
611 }
612 memoff(ch);
613 restore_flags(flags);
614
615 return(total);
616 }
617
618
619 static void pcxe_put_char(struct tty_struct *tty, unsigned char c)
620 {
621 pcxe_write(tty, 0, &c, 1);
622 return;
623 }
624
625
626 static int pcxe_write_room(struct tty_struct *tty)
627 {
628 struct channel *ch;
629 int remain;
630
631 remain = 0;
632 if ((ch=chan(tty))!=NULL) {
633 volatile struct board_chan *bc;
634 unsigned int head, tail;
635 unsigned long flags;
636
637 save_flags(flags);
638 cli();
639 globalwinon(ch);
640
641 bc = ch->brdchan;
642 head = bc->tin & (ch->txbufsize - 1);
643 tail = bc->tout;
644 if (tail != bc->tout)
645 tail = bc->tout;
646 tail &= (ch->txbufsize - 1);
647
648 if((remain = tail - head - 1) < 0 )
649 remain += ch->txbufsize;
650
651 if (remain && (ch->statusflags & LOWWAIT) == 0) {
652 ch->statusflags |= LOWWAIT;
653 bc->ilow = 1;
654 }
655 memoff(ch);
656 restore_flags(flags);
657 }
658
659 return remain;
660 }
661
662
663 static int pcxe_chars_in_buffer(struct tty_struct *tty)
664 {
665 int chars;
666 unsigned int ctail, head, tail;
667 int remain;
668 unsigned long flags;
669 struct channel *ch;
670 volatile struct board_chan *bc;
671
672 if ((ch=chan(tty))==NULL)
673 return(0);
674
675 save_flags(flags);
676 cli();
677 globalwinon(ch);
678
679 bc = ch->brdchan;
680 tail = bc->tout;
681 head = bc->tin;
682 ctail = ch->mailbox->cout;
683 if(tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
684 chars = 0;
685 else {
686 head = bc->tin & (ch->txbufsize - 1);
687 tail &= (ch->txbufsize - 1);
688 if((remain = tail - head - 1) < 0 )
689 remain += ch->txbufsize;
690
691 chars = (int)(ch->txbufsize - remain);
692
693
694
695
696
697 if(!(ch->statusflags & EMPTYWAIT))
698 setup_empty_event(tty,ch);
699 }
700
701 memoff(ch);
702 restore_flags(flags);
703
704 return(chars);
705 }
706
707
708 static void pcxe_flush_buffer(struct tty_struct *tty)
709 {
710 unsigned int tail;
711 volatile struct board_chan *bc;
712 struct channel *ch;
713 unsigned long flags;
714
715 if ((ch=chan(tty))==NULL)
716 return;
717
718 save_flags(flags);
719 cli();
720
721 globalwinon(ch);
722 bc = ch->brdchan;
723 tail = bc->tout;
724 fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
725
726 memoff(ch);
727 restore_flags(flags);
728
729 wake_up_interruptible(&tty->write_wait);
730 if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
731 (tty->ldisc.write_wakeup)(tty);
732 }
733
734 static void pcxe_flush_chars(struct tty_struct *tty)
735 {
736 struct channel * ch;
737
738 if ((ch=chan(tty))!=NULL) {
739 unsigned long flags;
740
741 save_flags(flags);
742 cli();
743 if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
744 setup_empty_event(tty,ch);
745 restore_flags(flags);
746 }
747 }
748
749
750 int pcxe_init(void)
751 {
752 ulong flags, save_loops_per_sec, memory_seg=0, memory_size;
753 int lowwater, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
754 unchar *fepos, *memaddr, *bios, v;
755 volatile struct global_data *gd;
756 struct board_info *bd;
757 volatile struct board_chan *bc;
758 struct channel *ch;
759
760 init_bh(DIGI_BH,do_pcxe_bh);
761 enable_bh(DIGI_BH);
762
763 timer_table[DIGI_TIMER].fn = pcxxpoll;
764 timer_table[DIGI_TIMER].expires = 0;
765
766 memset(&pcxe_driver, 0, sizeof(struct tty_driver));
767 pcxe_driver.magic = TTY_DRIVER_MAGIC;
768 pcxe_driver.name = "ttyd";
769 pcxe_driver.major = DIGIMAJOR;
770 pcxe_driver.minor_start = 0;
771 pcxe_driver.num = NBDEVS;
772 pcxe_driver.type = TTY_DRIVER_TYPE_SERIAL;
773 pcxe_driver.subtype = SERIAL_TYPE_NORMAL;
774 pcxe_driver.init_termios = tty_std_termios;
775 pcxe_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
776 pcxe_driver.flags = TTY_DRIVER_REAL_RAW;
777 pcxe_driver.refcount = &pcxe_refcount;
778 pcxe_driver.table = pcxe_table;
779 pcxe_driver.termios = pcxe_termios;
780 pcxe_driver.termios_locked = pcxe_termios_locked;
781
782 pcxe_driver.open = pcxe_open;
783 pcxe_driver.close = pcxe_close;
784 pcxe_driver.write = pcxe_write;
785 pcxe_driver.put_char = pcxe_put_char;
786 pcxe_driver.flush_chars = pcxe_flush_chars;
787 pcxe_driver.write_room = pcxe_write_room;
788 pcxe_driver.chars_in_buffer = pcxe_chars_in_buffer;
789 pcxe_driver.flush_buffer = pcxe_flush_buffer;
790 pcxe_driver.ioctl = pcxe_ioctl;
791 pcxe_driver.throttle = pcxe_throttle;
792 pcxe_driver.unthrottle = pcxe_unthrottle;
793 pcxe_driver.set_termios = pcxe_set_termios;
794 pcxe_driver.stop = pcxe_stop;
795 pcxe_driver.start = pcxe_start;
796 pcxe_driver.hangup = pcxe_hangup;
797
798 pcxe_callout = pcxe_driver;
799 pcxe_callout.name = "ttyD";
800 pcxe_callout.major = DIGICUMAJOR;
801 pcxe_callout.subtype = SERIAL_TYPE_CALLOUT;
802 pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
803
804
805
806
807
808 save_loops_per_sec = loops_per_sec;
809 loops_per_sec = 13L*500000L;
810
811 save_flags(flags);
812 cli();
813
814 for(crd=0; crd < NUMCARDS; crd++) {
815 bd = &boards[crd];
816 outb(FEPRST, bd->port);
817 pcxxdelay(1);
818
819 for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
820 if(i > 1000) {
821 printk("Board not found at port 0x%x! Check switch settings.\n",
822 bd->port);
823 bd->status = DISABLED;
824 break;
825 }
826 pcxxdelay(1);
827 }
828 if(bd->status == DISABLED)
829 continue;
830
831 v = inb(bd->port);
832
833 if((v & 0x1) == 0x1) {
834 if((v & 0x30) == 0) {
835 memory_seg = 0xf000;
836 memory_size = 0x10000;
837 }
838
839 if((v & 0x30) == 0x10) {
840 memory_seg = 0xe000;
841 memory_size = 0x20000;
842 }
843
844 if((v & 0x30) == 0x20) {
845 memory_seg = 0xc000;
846 memory_size = 0x40000;
847 }
848
849 if((v & 0x30) == 0x30) {
850 memory_seg = 0x8000;
851 memory_size = 0x80000;
852 }
853 bd->type = PCXI;
854 } else {
855 if((v & 0x1) == 0x1) {
856 bd->status = DISABLED;
857 printk("PC/Xm at 0x%x not supported!!\n", bd->port);
858 continue;
859 } else {
860 if(v & 0xC0) {
861 topwin = 0x1f00L;
862 outb((((ulong)bd->membase>>8) & 0xe0) | 0x10, bd->port+2);
863 outb(((ulong)bd->membase>>16) & 0xff, bd->port+3);
864 bd->type = PCXEVE;
865 } else {
866 bd->type = PCXE;
867 }
868
869 memory_seg = 0xf000;
870 memory_size = 0x10000;
871 }
872 }
873
874 memaddr = (unchar *) bd->membase;
875
876 outb(FEPRST|FEPMEM, bd->port);
877
878 for(i=0; (inb(bd->port) & FEPMASK) != (FEPRST|FEPMEM); i++) {
879 if(i > 10000) {
880 printk("%s not resetting at port 0x%x! Check switch settings.\n",
881 board_desc[bd->type], bd->port);
882 bd->status = DISABLED;
883 break;
884 }
885 pcxxdelay(1);
886 }
887 if(bd->status == DISABLED)
888 continue;
889
890 memwinon(bd,0);
891 *(ulong *)(memaddr + botwin) = 0xa55a3cc3;
892 *(ulong *)(memaddr + topwin) = 0x5aa5c33c;
893
894 if(*(ulong *)(memaddr + botwin) != 0xa55a3cc3 ||
895 *(ulong *)(memaddr + topwin) != 0x5aa5c33c) {
896 printk("Failed memory test at %lx for %s at port %x, check switch settings.\n",
897 bd->membase, board_desc[bd->type], bd->port);
898 bd->status = DISABLED;
899 continue;
900 }
901
902 for(i=0; i < 16; i++) {
903 memaddr[MISCGLOBAL+i] = 0;
904 }
905
906 if(bd->type == PCXI || bd->type == PCXE) {
907 bios = memaddr + BIOSCODE + ((0xf000 - memory_seg) << 4);
908
909 memcpy(bios, pcxx_bios, pcxx_nbios);
910
911 outb(FEPMEM, bd->port);
912
913 for(i=0; i <= 10000; i++) {
914 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
915 goto load_fep;
916 }
917 pcxxdelay(1);
918 }
919
920 printk("BIOS download failed on the %s at 0x%x!\n",
921 board_desc[bd->type], bd->port);
922 bd->status = DISABLED;
923 continue;
924 }
925
926 if(bd->type == PCXEVE) {
927 bios = memaddr + (BIOSCODE & 0x1fff);
928 memwinon(bd,0xff);
929
930 memcpy(bios, pcxx_bios, pcxx_nbios);
931
932 outb(FEPCLR, bd->port);
933 memwinon(bd,0);
934
935 for(i=0; i <= 10000; i++) {
936 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
937 goto load_fep;
938 }
939 pcxxdelay(1);
940 }
941
942 printk("BIOS download failed on the %s at 0x%x!\n",
943 board_desc[bd->type], bd->port);
944 bd->status = DISABLED;
945 continue;
946 }
947
948 load_fep:
949 fepos = memaddr + FEPCODE;
950 if(bd->type == PCXEVE)
951 fepos = memaddr + (FEPCODE & 0x1fff);
952
953 memwinon(bd, (FEPCODE >> 13));
954 memcpy(fepos, pcxx_cook, pcxx_ncook);
955 memwinon(bd, 0);
956
957 *(ushort *)((ulong)memaddr + MBOX + 0) = 2;
958 *(ushort *)((ulong)memaddr + MBOX + 2) = memory_seg + FEPCODESEG;
959 *(ushort *)((ulong)memaddr + MBOX + 4) = 0;
960 *(ushort *)((ulong)memaddr + MBOX + 6) = FEPCODESEG;
961 *(ushort *)((ulong)memaddr + MBOX + 8) = 0;
962 *(ushort *)((ulong)memaddr + MBOX + 10) = pcxx_ncook;
963
964 outb(FEPMEM|FEPINT, bd->port);
965 outb(FEPMEM, bd->port);
966
967 for(i=0; *(ushort *)((ulong)memaddr + MBOX); i++) {
968 if(i > 2000) {
969 printk("Command failed for the %s at 0x%x!\n",
970 board_desc[bd->type], bd->port);
971 bd->status = DISABLED;
972 break;
973 }
974 pcxxdelay(1);
975 }
976
977 if(bd->status == DISABLED)
978 continue;
979
980 *(ushort *)(memaddr + FEPSTAT) = 0;
981 *(ushort *)(memaddr + MBOX + 0) = 1;
982 *(ushort *)(memaddr + MBOX + 2) = FEPCODESEG;
983 *(ushort *)(memaddr + MBOX + 4) = 0x4L;
984
985 outb(FEPINT, bd->port);
986 outb(FEPCLR, bd->port);
987 memwinon(bd, 0);
988
989 for(i=0; *(ushort *)((ulong)memaddr + FEPSTAT) != *(ushort *)"OS"; i++) {
990 if(i > 10000) {
991 printk("FEP/OS download failed on the %s at 0x%x!\n",
992 board_desc[bd->type], bd->port);
993 bd->status = DISABLED;
994 break;
995 }
996 pcxxdelay(1);
997 }
998 if(bd->status == DISABLED)
999 continue;
1000
1001 ch = &digi_channels[MAXPORTS * crd];
1002 pcxxassert(ch <= &digi_channels[NBDEVS-1], "ch out of range");
1003
1004 bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
1005 gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
1006
1007 if((bd->type == PCXEVE) && (*(ushort *)((ulong)memaddr+NPORT) < 3))
1008 shrinkmem = 1;
1009
1010 request_region(bd->port, 4, "PC/Xx");
1011
1012 for(i=0; i < bd->numports; i++, ch++, bc++) {
1013 if(((ushort *)((ulong)memaddr + PORTBASE))[i] == 0) {
1014 ch->brdchan = 0;
1015 continue;
1016 }
1017 ch->brdchan = bc;
1018 ch->mailbox = gd;
1019 ch->tqueue.routine = do_softint;
1020 ch->tqueue.data = ch;
1021 ch->board = &boards[crd];
1022 #ifdef DEFAULT_HW_FLOW
1023 ch->digiext.digi_flags = RTSPACE|CTSPACE;
1024 #endif
1025 if(boards[crd].altpin) {
1026 ch->dsr = CD;
1027 ch->dcd = DSR;
1028 ch->digiext.digi_flags |= DIGI_ALTPIN;
1029 } else {
1030 ch->dcd = CD;
1031 ch->dsr = DSR;
1032 }
1033
1034 ch->magic = PCXX_MAGIC;
1035 ch->boardnum = crd;
1036 ch->channelnum = i;
1037
1038 ch->dev = (MAXPORTS * crd) + i;
1039 ch->tty = 0;
1040
1041 if(shrinkmem) {
1042 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1043 shrinkmem = 0;
1044 }
1045
1046 if(bd->type != PCXEVE) {
1047 ch->txptr = memaddr+((bc->tseg-memory_seg) << 4);
1048 ch->rxptr = memaddr+((bc->rseg-memory_seg) << 4);
1049 ch->txwin = ch->rxwin = 0;
1050 } else {
1051 ch->txptr = memaddr+(((bc->tseg-memory_seg) << 4) & 0x1fff);
1052 ch->txwin = FEPWIN | ((bc->tseg-memory_seg) >> 9);
1053 ch->rxptr = memaddr+(((bc->rseg-memory_seg) << 4) & 0x1fff);
1054 ch->rxwin = FEPWIN | ((bc->rseg-memory_seg) >>9 );
1055 }
1056
1057 ch->txbufsize = bc->tmax + 1;
1058 ch->rxbufsize = bc->rmax + 1;
1059
1060 ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
1061
1062 lowwater = ch->txbufsize >= 2000 ? 1024 : ch->txbufsize/2;
1063 fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1064 fepcmd(ch, SRXLWATER, ch->rxbufsize/4, 0, 10, 0);
1065 fepcmd(ch, SRXHWATER, 3 * ch->rxbufsize/4, 0, 10, 0);
1066
1067 bc->edelay = 100;
1068 bc->idata = 1;
1069
1070 ch->startc = bc->startc;
1071 ch->stopc = bc->stopc;
1072 ch->startca = bc->startca;
1073 ch->stopca = bc->stopca;
1074
1075 ch->fepcflag = 0;
1076 ch->fepiflag = 0;
1077 ch->fepoflag = 0;
1078 ch->fepstartc = 0;
1079 ch->fepstopc = 0;
1080 ch->fepstartca = 0;
1081 ch->fepstopca = 0;
1082
1083 ch->close_delay = 50;
1084 ch->count = 0;
1085 ch->blocked_open = 0;
1086 ch->callout_termios = pcxe_callout.init_termios;
1087 ch->normal_termios = pcxe_driver.init_termios;
1088 ch->open_wait = 0;
1089 ch->close_wait = 0;
1090 }
1091
1092 printk("DigiBoard PC/Xx Driver V%s: %s I/O=0x%x Mem=0x%lx Ports=%d\n",
1093 VERSION, board_desc[bd->type], bd->port, bd->membase, bd->numports);
1094
1095 memwinoff(bd, 0);
1096 }
1097
1098 if(tty_register_driver(&pcxe_driver))
1099 panic("Couldn't register PC/Xe driver");
1100
1101 if(tty_register_driver(&pcxe_callout))
1102 panic("Couldn't register PC/Xe callout");
1103
1104
1105 loops_per_sec = save_loops_per_sec;
1106
1107
1108
1109
1110 timer_active |= 1 << DIGI_TIMER;
1111 restore_flags(flags);
1112
1113 return 0;
1114 }
1115
1116
1117 static void pcxxpoll(void)
1118 {
1119 unsigned long flags;
1120 int crd;
1121 volatile unsigned int head, tail;
1122 struct channel *ch;
1123 struct board_info *bd;
1124
1125 save_flags(flags);
1126 cli();
1127
1128 for(crd=0; crd < NUMCARDS; crd++) {
1129 bd = &boards[crd];
1130 ch = &digi_channels[MAXPORTS*crd];
1131
1132 if(bd->status == DISABLED)
1133 continue;
1134
1135 assertmemoff(ch);
1136
1137 globalwinon(ch);
1138 head = ch->mailbox->ein;
1139 tail = ch->mailbox->eout;
1140
1141 if(head != tail)
1142 doevent(crd);
1143
1144 memoff(ch);
1145 }
1146
1147 timer_table[DIGI_TIMER].fn = pcxxpoll;
1148 timer_table[DIGI_TIMER].expires = jiffies + HZ/25;
1149 timer_active |= 1 << DIGI_TIMER;
1150 restore_flags(flags);
1151 }
1152
1153 static void doevent(int crd)
1154 {
1155 volatile struct board_info *bd;
1156 static struct tty_struct *tty;
1157 volatile struct board_chan *bc;
1158 volatile unchar *eventbuf;
1159 volatile unsigned int head;
1160 volatile unsigned int tail;
1161 struct channel *ch;
1162 struct channel *chan0;
1163 int channel, event, mstat, lstat;
1164
1165 bd = &boards[crd];
1166
1167 chan0 = &digi_channels[MAXPORTS * crd];
1168 pcxxassert(chan0 <= &digi_channels[NBDEVS-1], "ch out of range");
1169
1170 assertgwinon(chan0);
1171
1172 while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) {
1173 assertgwinon(chan0);
1174 eventbuf = (volatile unchar *)bd->membase + tail + ISTART;
1175 channel = eventbuf[0];
1176 event = eventbuf[1];
1177 mstat = eventbuf[2];
1178 lstat = eventbuf[3];
1179
1180 ch=chan0+channel;
1181
1182 if ((unsigned)channel >= bd->numports || !ch) {
1183 printk("physmem=%lx, tail=%x, head=%x\n", bd->membase, tail, head);
1184 printk("doevent(%x) channel %x, event %x, mstat %x, lstat %x\n",
1185 crd, (unsigned)channel, event, (unsigned)mstat, lstat);
1186 if(channel >= bd->numports)
1187 ch = chan0;
1188 bc = ch->brdchan;
1189 goto next;
1190 }
1191 if ((bc = ch->brdchan) == NULL)
1192 goto next;
1193
1194 if (event & DATA_IND) {
1195 receive_data(ch);
1196 assertgwinon(ch);
1197 }
1198
1199 if (event & MODEMCHG_IND) {
1200 ch->imodem = mstat;
1201 if (ch->asyncflags & (ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE)) {
1202 if (ch->asyncflags & ASYNC_CHECK_CD) {
1203 if (mstat & ch->dcd) {
1204 wake_up_interruptible(&ch->open_wait);
1205 } else {
1206 pcxe_sched_event(ch, PCXE_EVENT_HANGUP);
1207 }
1208 }
1209 }
1210 }
1211
1212 tty = ch->tty;
1213
1214 if (tty) {
1215
1216 if (event & BREAK_IND) {
1217 tty->flip.count++;
1218 *tty->flip.flag_buf_ptr++ = TTY_BREAK;
1219 *tty->flip.char_buf_ptr++ = 0;
1220 #if 0
1221 if (ch->asyncflags & ASYNC_SAK)
1222 do_SAK(tty);
1223 #endif
1224 tty_schedule_flip(tty);
1225 }
1226
1227 if (event & LOWTX_IND) {
1228 if (ch->statusflags & LOWWAIT) {
1229 ch->statusflags &= ~LOWWAIT;
1230 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1231 tty->ldisc.write_wakeup)
1232 (tty->ldisc.write_wakeup)(tty);
1233 wake_up_interruptible(&tty->write_wait);
1234 }
1235 }
1236
1237 if (event & EMPTYTX_IND) {
1238 ch->statusflags &= ~TXBUSY;
1239 if (ch->statusflags & EMPTYWAIT) {
1240 ch->statusflags &= ~EMPTYWAIT;
1241 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1242 tty->ldisc.write_wakeup)
1243 (tty->ldisc.write_wakeup)(tty);
1244 wake_up_interruptible(&tty->write_wait);
1245 }
1246 }
1247 }
1248
1249 next:
1250 globalwinon(ch);
1251 if(!bc) printk("bc == NULL in doevent!\n");
1252 else bc->idata = 1;
1253
1254 chan0->mailbox->eout = (tail+4) & (IMAX-ISTART-4);
1255 globalwinon(chan0);
1256 }
1257
1258 }
1259
1260
1261
1262
1263
1264 static void pcxxdelay(int msec)
1265 {
1266 while(msec-- > 0)
1267 __delay(loops_per_sec/1000);
1268 }
1269
1270
1271 static void
1272 fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
1273 int bytecmd)
1274 {
1275 unchar *memaddr;
1276 unsigned int head, tail;
1277 long count;
1278 int n;
1279
1280 if(ch->board->status == DISABLED)
1281 return;
1282
1283 assertgwinon(ch);
1284
1285 memaddr = (unchar *)ch->board->membase;
1286 head = ch->mailbox->cin;
1287
1288 if(head >= (CMAX-CSTART) || (head & 03)) {
1289 printk("line %d: Out of range, cmd=%x, head=%x\n", __LINE__, cmd, head);
1290 return;
1291 }
1292
1293 if(bytecmd) {
1294 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1295 *(unchar *)(memaddr+head+CSTART+1) = PORTNUM(ch);
1296 *(unchar *)(memaddr+head+CSTART+2) = word_or_byte;
1297 *(unchar *)(memaddr+head+CSTART+3) = byte2;
1298 } else {
1299 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1300 *(unchar *)(memaddr+head+CSTART+1) = PORTNUM(ch);
1301 *(ushort*)(memaddr+head+CSTART+2) = word_or_byte;
1302 }
1303
1304 head = (head+4) & (CMAX-CSTART-4);
1305 ch->mailbox->cin = head;
1306
1307 count = FEPTIMEOUT;
1308
1309 while(1) {
1310 count--;
1311 if(count == 0) {
1312 printk("Fep not responding in fepcmd()\n");
1313 return;
1314 }
1315
1316 head = ch->mailbox->cin;
1317 tail = ch->mailbox->cout;
1318
1319 n = (head-tail) & (CMAX-CSTART-4);
1320
1321 if(n <= ncmds * (sizeof(short)*4))
1322 break;
1323 }
1324 }
1325
1326
1327 static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
1328 {
1329 unsigned res = 0;
1330 #ifdef SPEED_HACK
1331
1332 if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;
1333 if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;
1334 #endif
1335 if (cflag & CBAUDEX)
1336 {
1337 ch->digiext.digi_flags |= DIGI_FAST;
1338 res |= FEP_HUPCL;
1339
1340
1341
1342
1343
1344 if (cflag & B115200) res|=1;
1345 }
1346 else ch->digiext.digi_flags &= ~DIGI_FAST;
1347 res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE);
1348 return res;
1349 }
1350
1351 static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
1352 {
1353 unsigned res = iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|IXON|IXANY|IXOFF);
1354
1355 if(ch->digiext.digi_flags & DIGI_AIXON)
1356 res |= IAIXON;
1357 return res;
1358 }
1359
1360 static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
1361 {
1362 unsigned res = 0;
1363
1364 if(cflag & CRTSCTS) {
1365 ch->digiext.digi_flags |= (RTSPACE|CTSPACE);
1366 res |= (CTS | RTS);
1367 }
1368 if(ch->digiext.digi_flags & RTSPACE)
1369 res |= RTS;
1370 if(ch->digiext.digi_flags & DTRPACE)
1371 res |= DTR;
1372 if(ch->digiext.digi_flags & CTSPACE)
1373 res |= CTS;
1374 if(ch->digiext.digi_flags & DSRPACE)
1375 res |= ch->dsr;
1376 if(ch->digiext.digi_flags & DCDPACE)
1377 res |= ch->dcd;
1378
1379 if (res & RTS)
1380 ch->digiext.digi_flags |= RTSPACE;
1381 if (res & CTS)
1382 ch->digiext.digi_flags |= CTSPACE;
1383
1384 return res;
1385 }
1386
1387 static void pcxxparam(struct tty_struct *tty, struct channel *ch)
1388 {
1389 volatile struct board_chan *bc;
1390 unsigned int head;
1391 unsigned mval, hflow, cflag, iflag;
1392 struct termios *ts;
1393
1394 bc = ch->brdchan;
1395 assertgwinon(ch);
1396 ts = tty->termios;
1397
1398 if((ts->c_cflag & CBAUD) == 0) {
1399 head = bc->rin;
1400 bc->rout = head;
1401 head = bc->tin;
1402 fepcmd(ch, STOUT, (unsigned) head, 0, 0, 0);
1403 mval = 0;
1404 } else {
1405
1406 cflag = termios2digi_c(ch, ts->c_cflag);
1407
1408 if(cflag != ch->fepcflag) {
1409 ch->fepcflag = cflag;
1410 fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1411 }
1412
1413 if(cflag & CLOCAL)
1414 ch->asyncflags &= ~ASYNC_CHECK_CD;
1415 else {
1416 ch->asyncflags |= ASYNC_CHECK_CD;
1417 }
1418
1419 mval = DTR | RTS;
1420 }
1421
1422 iflag = termios2digi_i(ch, ts->c_iflag);
1423
1424 if(iflag != ch->fepiflag) {
1425 ch->fepiflag = iflag;
1426 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1427 }
1428
1429 bc->mint = ch->dcd;
1430 if((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1431 if(ch->digiext.digi_flags & DIGI_FORCEDCD)
1432 bc->mint = 0;
1433
1434 ch->imodem = bc->mstat;
1435
1436 hflow = termios2digi_h(ch, ts->c_cflag);
1437
1438 if(hflow != ch->hflow) {
1439 ch->hflow = hflow;
1440 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1441 }
1442
1443
1444
1445 if(ch->omodem != mval) {
1446 ch->omodem = mval;
1447 fepcmd(ch, SETMODEM, mval, RTS|DTR, 0, 1);
1448 }
1449
1450 if(ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
1451 ch->fepstartc = ch->startc;
1452 ch->fepstopc = ch->stopc;
1453 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1454 }
1455
1456 if(ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
1457 ch->fepstartca = ch->startca;
1458 ch->fepstopca = ch->stopca;
1459 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1460 }
1461 }
1462
1463
1464 static void receive_data(struct channel *ch)
1465 {
1466 volatile struct board_chan *bc;
1467 struct tty_struct *tty;
1468 unsigned int tail, head, wrapmask;
1469 int n;
1470 int piece;
1471 struct termios *ts=0;
1472 unchar *rptr;
1473 int rc;
1474 int wrapgap;
1475
1476 globalwinon(ch);
1477
1478 if (ch->statusflags & RXSTOPPED)
1479 return;
1480
1481 tty = ch->tty;
1482 if(tty)
1483 ts = tty->termios;
1484
1485 bc = ch->brdchan;
1486
1487 if(!bc) {
1488 printk("bc is NULL in receive_data!\n");
1489 return;
1490 }
1491
1492 wrapmask = ch->rxbufsize - 1;
1493
1494 head = bc->rin;
1495 head &= wrapmask;
1496 tail = bc->rout & wrapmask;
1497
1498 n = (head-tail) & wrapmask;
1499
1500 if(n == 0)
1501 return;
1502
1503
1504
1505
1506 if(!tty || !ts || !(ts->c_cflag & CREAD)) {
1507 bc->rout = head;
1508 return;
1509 }
1510
1511 if(tty->flip.count == TTY_FLIPBUF_SIZE) {
1512
1513 return;
1514 }
1515
1516 if(bc->orun) {
1517 bc->orun = 0;
1518 printk("overrun! DigiBoard device minor=%d\n",MINOR(tty->device));
1519 }
1520
1521 rxwinon(ch);
1522 rptr = tty->flip.char_buf_ptr;
1523 rc = tty->flip.count;
1524 while(n > 0) {
1525 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
1526 piece = (wrapgap < n) ? wrapgap : n;
1527
1528
1529
1530
1531
1532 if ((rc + piece) > TTY_FLIPBUF_SIZE)
1533 piece = TTY_FLIPBUF_SIZE - rc;
1534
1535 if (piece == 0)
1536 break;
1537
1538 memcpy(rptr, ch->rxptr + tail, piece);
1539 rptr += piece;
1540 rc += piece;
1541 tail = (tail + piece) & wrapmask;
1542 n -= piece;
1543 }
1544 tty->flip.count = rc;
1545 tty->flip.char_buf_ptr = rptr;
1546 globalwinon(ch);
1547 bc->rout = tail;
1548
1549
1550 tty_schedule_flip(ch->tty);
1551 return;
1552 }
1553
1554
1555 static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
1556 unsigned int cmd, unsigned long arg)
1557 {
1558 int error;
1559 struct channel *ch = (struct channel *) tty->driver_data;
1560 volatile struct board_chan *bc;
1561 int retval;
1562 unsigned int mflag, mstat;
1563 unsigned char startc, stopc;
1564 unsigned long flags;
1565 digiflow_t dflow;
1566
1567 if(ch)
1568 bc = ch->brdchan;
1569 else {
1570 printk("ch is NULL in pcxe_ioctl!\n");
1571 return(-EINVAL);
1572 }
1573
1574 save_flags(flags);
1575
1576 switch(cmd) {
1577 case TCSBRK:
1578 retval = tty_check_change(tty);
1579 if(retval)
1580 return retval;
1581 setup_empty_event(tty,ch);
1582 tty_wait_until_sent(tty, 0);
1583 if(!arg)
1584 digi_send_break(ch, HZ/4);
1585 return 0;
1586
1587 case TCSBRKP:
1588 retval = tty_check_change(tty);
1589 if(retval)
1590 return retval;
1591 setup_empty_event(tty,ch);
1592 tty_wait_until_sent(tty, 0);
1593 digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
1594 return 0;
1595
1596 case TIOCGSOFTCAR:
1597 error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
1598 if(error)
1599 return error;
1600 put_fs_long(C_CLOCAL(tty) ? 1 : 0,
1601 (unsigned long *) arg);
1602 return 0;
1603
1604 case TIOCSSOFTCAR:
1605 arg = get_fs_long((unsigned long *) arg);
1606 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
1607 return 0;
1608
1609 case TIOCMODG:
1610 case TIOCMGET:
1611 mflag = 0;
1612
1613 cli();
1614 globalwinon(ch);
1615 mstat = bc->mstat;
1616 memoff(ch);
1617 restore_flags(flags);
1618
1619 if(mstat & DTR)
1620 mflag |= TIOCM_DTR;
1621 if(mstat & RTS)
1622 mflag |= TIOCM_RTS;
1623 if(mstat & CTS)
1624 mflag |= TIOCM_CTS;
1625 if(mstat & ch->dsr)
1626 mflag |= TIOCM_DSR;
1627 if(mstat & RI)
1628 mflag |= TIOCM_RI;
1629 if(mstat & ch->dcd)
1630 mflag |= TIOCM_CD;
1631
1632 error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
1633 if(error)
1634 return error;
1635 put_fs_long(mflag, (unsigned long *) arg);
1636 break;
1637
1638 case TIOCMBIS:
1639 case TIOCMBIC:
1640 case TIOCMODS:
1641 case TIOCMSET:
1642 mstat = get_fs_long((unsigned long *) arg);
1643
1644 mflag = 0;
1645 if(mstat & TIOCM_DTR)
1646 mflag |= DTR;
1647 if(mstat & TIOCM_RTS)
1648 mflag |= RTS;
1649
1650 switch(cmd) {
1651 case TIOCMODS:
1652 case TIOCMSET:
1653 ch->modemfake = DTR|RTS;
1654 ch->modem = mflag;
1655 break;
1656
1657 case TIOCMBIS:
1658 ch->modemfake |= mflag;
1659 ch->modem |= mflag;
1660 break;
1661
1662 case TIOCMBIC:
1663 ch->modemfake |= mflag;
1664 ch->modem &= ~mflag;
1665 break;
1666 }
1667
1668 cli();
1669 globalwinon(ch);
1670 pcxxparam(tty,ch);
1671 memoff(ch);
1672 restore_flags(flags);
1673 break;
1674
1675 case TIOCSDTR:
1676 cli();
1677 ch->omodem |= DTR;
1678 globalwinon(ch);
1679 fepcmd(ch, SETMODEM, DTR, 0, 10, 1);
1680 memoff(ch);
1681 restore_flags(flags);
1682 break;
1683
1684 case TIOCCDTR:
1685 ch->omodem &= ~DTR;
1686 cli();
1687 globalwinon(ch);
1688 fepcmd(ch, SETMODEM, 0, DTR, 10, 1);
1689 memoff(ch);
1690 restore_flags(flags);
1691 break;
1692
1693 case DIGI_GETA:
1694 if((error=verify_area(VERIFY_WRITE, (char*)arg, sizeof(digi_t))))
1695 return(error);
1696
1697 memcpy_tofs((char*)arg, &ch->digiext, sizeof(digi_t));
1698 break;
1699
1700 case DIGI_SETAW:
1701 case DIGI_SETAF:
1702 if(cmd == DIGI_SETAW) {
1703 setup_empty_event(tty,ch);
1704 tty_wait_until_sent(tty, 0);
1705 }
1706 else {
1707 if(tty->ldisc.flush_buffer)
1708 tty->ldisc.flush_buffer(tty);
1709 }
1710
1711
1712
1713 case DIGI_SETA:
1714 if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(digi_t))))
1715 return(error);
1716
1717 memcpy_fromfs(&ch->digiext, (char*)arg, sizeof(digi_t));
1718 #ifdef DEBUG_IOCTL
1719 printk("ioctl(DIGI_SETA): flags = %x\n", ch->digiext.digi_flags);
1720 #endif
1721
1722 if(ch->digiext.digi_flags & DIGI_ALTPIN) {
1723 ch->dcd = DSR;
1724 ch->dsr = CD;
1725 } else {
1726 ch->dcd = CD;
1727 ch->dsr = DSR;
1728 }
1729
1730 cli();
1731 globalwinon(ch);
1732 pcxxparam(tty,ch);
1733 memoff(ch);
1734 restore_flags(flags);
1735 break;
1736
1737 case DIGI_GETFLOW:
1738 case DIGI_GETAFLOW:
1739 cli();
1740 globalwinon(ch);
1741 if(cmd == DIGI_GETFLOW) {
1742 dflow.startc = bc->startc;
1743 dflow.stopc = bc->stopc;
1744 } else {
1745 dflow.startc = bc->startca;
1746 dflow.stopc = bc->stopca;
1747 }
1748 memoff(ch);
1749 restore_flags(flags);
1750
1751 if((error=verify_area(VERIFY_WRITE, (char*)arg,sizeof(dflow))))
1752 return(error);
1753
1754 memcpy_tofs((char*)arg, &dflow, sizeof(dflow));
1755 break;
1756
1757 case DIGI_SETAFLOW:
1758 case DIGI_SETFLOW:
1759 if(cmd == DIGI_SETFLOW) {
1760 startc = ch->startc;
1761 stopc = ch->stopc;
1762 } else {
1763 startc = ch->startca;
1764 stopc = ch->stopca;
1765 }
1766
1767 if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(dflow))))
1768 return(error);
1769
1770 memcpy_fromfs(&dflow, (char*)arg, sizeof(dflow));
1771
1772 if(dflow.startc != startc || dflow.stopc != stopc) {
1773 cli();
1774 globalwinon(ch);
1775
1776 if(cmd == DIGI_SETFLOW) {
1777 ch->fepstartc = ch->startc = dflow.startc;
1778 ch->fepstopc = ch->stopc = dflow.stopc;
1779 fepcmd(ch,SONOFFC,ch->fepstartc,ch->fepstopc,0, 1);
1780 } else {
1781 ch->fepstartca = ch->startca = dflow.startc;
1782 ch->fepstopca = ch->stopca = dflow.stopc;
1783 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1784 }
1785
1786 if(ch->statusflags & TXSTOPPED)
1787 pcxe_start(tty);
1788
1789 memoff(ch);
1790 restore_flags(flags);
1791 }
1792 break;
1793
1794 default:
1795 return -ENOIOCTLCMD;
1796 }
1797
1798 return 0;
1799 }
1800
1801 static void pcxe_set_termios(struct tty_struct *tty, struct termios *old_termios)
1802 {
1803 struct channel *info;
1804
1805 if ((info=chan(tty))!=NULL) {
1806 unsigned long flags;
1807 save_flags(flags);
1808 cli();
1809 globalwinon(info);
1810 pcxxparam(tty,info);
1811 memoff(info);
1812
1813 if ((old_termios->c_cflag & CRTSCTS) &&
1814 ((tty->termios->c_cflag & CRTSCTS) == 0))
1815 tty->hw_stopped = 0;
1816 if(!(old_termios->c_cflag & CLOCAL) &&
1817 (tty->termios->c_cflag & CLOCAL))
1818 wake_up_interruptible(&info->open_wait);
1819 restore_flags(flags);
1820 }
1821 }
1822
1823
1824 static void do_pcxe_bh(void)
1825 {
1826 run_task_queue(&tq_pcxx);
1827 }
1828
1829
1830 static void do_softint(void *private_)
1831 {
1832 struct channel *info = (struct channel *) private_;
1833
1834 if(info && info->magic == PCXX_MAGIC) {
1835 struct tty_struct *tty = info->tty;
1836 if (tty && tty->driver_data) {
1837 if(clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
1838 tty_hangup(tty);
1839 wake_up_interruptible(&info->open_wait);
1840 info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
1841 }
1842 }
1843 }
1844 }
1845
1846
1847 static void pcxe_stop(struct tty_struct *tty)
1848 {
1849 struct channel *info;
1850
1851 if ((info=chan(tty))!=NULL) {
1852 unsigned long flags;
1853 save_flags(flags);
1854 cli();
1855 if ((info->statusflags & TXSTOPPED) == 0) {
1856 globalwinon(info);
1857 fepcmd(info, PAUSETX, 0, 0, 0, 0);
1858 info->statusflags |= TXSTOPPED;
1859 memoff(info);
1860 }
1861 restore_flags(flags);
1862 }
1863 }
1864
1865 static void pcxe_throttle(struct tty_struct * tty)
1866 {
1867 struct channel *info;
1868
1869 if ((info=chan(tty))!=NULL) {
1870 unsigned long flags;
1871 save_flags(flags);
1872 cli();
1873 if ((info->statusflags & RXSTOPPED) == 0) {
1874 globalwinon(info);
1875 fepcmd(info, PAUSERX, 0, 0, 0, 0);
1876 info->statusflags |= RXSTOPPED;
1877 memoff(info);
1878 }
1879 restore_flags(flags);
1880 }
1881 }
1882
1883 static void pcxe_unthrottle(struct tty_struct *tty)
1884 {
1885 struct channel *info;
1886
1887 if ((info=chan(tty)) != NULL) {
1888 unsigned long flags;
1889
1890
1891 save_flags(flags);
1892 cli();
1893 if(info->statusflags & RXSTOPPED) {
1894 volatile struct board_chan *bc;
1895 globalwinon(info);
1896 bc = info->brdchan;
1897 fepcmd(info, RESUMERX, 0, 0, 0, 0);
1898 info->statusflags &= ~RXSTOPPED;
1899 memoff(info);
1900 }
1901 restore_flags(flags);
1902 }
1903 }
1904
1905
1906 static void pcxe_start(struct tty_struct *tty)
1907 {
1908 struct channel *info;
1909
1910 if ((info=chan(tty))!=NULL) {
1911 unsigned long flags;
1912
1913 save_flags(flags);
1914 cli();
1915
1916 if(info->statusflags & TXSTOPPED) {
1917 volatile struct board_chan *bc;
1918 globalwinon(info);
1919 bc = info->brdchan;
1920 if(info->statusflags & LOWWAIT)
1921 bc->ilow = 1;
1922 fepcmd(info, RESUMETX, 0, 0, 0, 0);
1923 info->statusflags &= ~TXSTOPPED;
1924 memoff(info);
1925 }
1926 restore_flags(flags);
1927 }
1928 }
1929
1930
1931 void digi_send_break(struct channel *ch, int msec)
1932 {
1933 unsigned long flags;
1934
1935 save_flags(flags);
1936 cli();
1937 globalwinon(ch);
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947 fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
1948 memoff(ch);
1949
1950 restore_flags(flags);
1951 }
1952
1953 static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
1954 {
1955 volatile struct board_chan *bc;
1956 unsigned long flags;
1957
1958 save_flags(flags);
1959 cli();
1960 globalwinon(ch);
1961 ch->statusflags |= EMPTYWAIT;
1962 bc = ch->brdchan;
1963 bc->iempty = 1;
1964 memoff(ch);
1965 restore_flags(flags);
1966 }
1967