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