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