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