vserver 1.9.5.x5
[linux-2.6.git] / drivers / char / pcxx.c
1 /*
2  *  linux/drivers/char/pcxx.c
3  * 
4  *  Written by Troy De Jongh, November, 1994
5  *
6  *  Copyright (C) 1994,1995 Troy De Jongh
7  *  This software may be used and distributed according to the terms 
8  *  of the GNU General Public License.
9  *
10  *  This driver is for the DigiBoard PC/Xe and PC/Xi line of products.
11  *
12  *  This driver does NOT support DigiBoard's fastcook FEP option and
13  *  does not support the transparent print (i.e. digiprint) option.
14  *
15  * This Driver is currently maintained by Christoph Lameter (christoph@lameter.com)
16  *
17  * Please contact digi for support issues at digilnux@dgii.com.
18  * Some more information can be found at
19  * http://lameter.com/digi.
20  *
21  *  1.5.2 Fall 1995 Bug fixes by David Nugent
22  *  1.5.3 March 9, 1996 Christoph Lameter: Fixed 115.2K Support. Memory
23  *              allocation harmonized with 1.3.X Series.
24  *  1.5.4 March 30, 1996 Christoph Lameter: Fixup for 1.3.81. Use init_bh
25  *              instead of direct assignment to kernel arrays.
26  *  1.5.5 April 5, 1996 Major device numbers corrected.
27  *              Mike McLagan<mike.mclagan@linux.org>: Add setup
28  *              variable handling, instead of using the old pcxxconfig.h
29  *  1.5.6 April 16, 1996 Christoph Lameter: Pointer cleanup, macro cleanup.
30  *              Call out devices changed to /dev/cudxx.
31  *  1.5.7 July 22, 1996 Martin Mares: CLOCAL fix, pcxe_table clearing.
32  *              David Nugent: Bug in pcxe_open.
33  *              Brian J. Murrell: Modem Control fixes, Majors correctly assigned
34  *  1.6.1 April 6, 1997 Bernhard Kaindl: fixed virtual memory access for 2.1
35  *              i386-kernels and use on other archtitectures, Allowing use
36  *              as module, added module parameters, added switch to enable
37  *              verbose messages to assist user during card configuration.
38  *              Currently only tested on a PC/Xi card, but should work on Xe
39  *              and Xeve also.
40  *  1.6.2 August, 7, 2000: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
41  *              get rid of panics, release previously allocated resources
42  *  1.6.3 August, 23, 2000: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
43  *              cleaned up wrt verify_area.
44  *              Christoph Lameter: Update documentation, email addresses
45  *              and URLs. Remove some obsolete code.
46  *
47  */
48
49 #include <linux/module.h>
50 #include <linux/mm.h>
51 #include <linux/ioport.h>
52 #include <linux/errno.h>
53 #include <linux/signal.h>
54 #include <linux/sched.h>
55 #include <linux/timer.h>
56 #include <linux/interrupt.h>
57 #include <linux/tty.h>
58 #include <linux/tty_flip.h>
59 #include <linux/major.h>
60 #include <linux/string.h>
61 #include <linux/fcntl.h>
62 #include <linux/ptrace.h>
63 #include <linux/delay.h>
64 #include <linux/serial.h>
65 #include <linux/tty_driver.h>
66 #include <linux/slab.h>
67 #include <linux/init.h>
68 #include <linux/bitops.h>
69
70 #ifndef MODULE
71 #include <linux/ctype.h> /* We only need it for parsing the "digi="-line */
72 #endif
73
74 #include <asm/system.h>
75 #include <asm/io.h>
76 #include <asm/uaccess.h>
77 #include <asm/semaphore.h>
78
79 #define VERSION         "1.6.3"
80
81 #include "digi.h"
82 #include "fep.h"
83 #include "pcxx.h"
84 #include "digi_fep.h"
85 #include "digi_bios.h"
86
87 /*
88  * Define one default setting if no digi= config line is used.
89  * Default is altpin = disabled, 16 ports, I/O 200h, Memory 0D0000h
90  */
91 static struct board_info boards[MAX_DIGI_BOARDS] = { {
92 /* Board is enabled       */    ENABLED,
93 /* Type is auto-detected  */    0,
94 /* altping is disabled    */    DISABLED,
95 /* number of ports = 16   */    16,
96 /* io address is 0x200    */    0x200,
97 /* card memory at 0xd0000 */    0xd0000,
98 /* first minor device no. */    0
99 } };
100  
101 static int verbose = 0;
102 static int debug   = 0;
103
104 #ifdef MODULE
105 /* Variables for insmod */
106 static int io[]           = {0, 0, 0, 0};
107 static int membase[]      = {0, 0, 0, 0};
108 static int memsize[]      = {0, 0, 0, 0};
109 static int altpin[]       = {0, 0, 0, 0};
110 static int numports[]     = {0, 0, 0, 0};
111
112 MODULE_AUTHOR("Bernhard Kaindl");
113 MODULE_DESCRIPTION("Digiboard PC/X{i,e,eve} driver");
114 MODULE_LICENSE("GPL");
115 module_param(verbose,     bool, 0644);
116 module_param(debug,       bool, 0644);
117 module_param_array(io,          int, NULL, 0);
118 module_param_array(membase,     int, NULL, 0);
119 module_param_array(memsize,     int, NULL, 0);
120 module_param_array(altpin,      int, NULL, 0);
121 module_param_array(numports,    int, NULL, 0);
122
123 #endif /* MODULE */
124
125 static int numcards = 1;
126 static int nbdevs = 0;
127  
128 static struct channel    *digi_channels;
129  
130 int pcxx_ncook=sizeof(pcxx_cook);
131 int pcxx_nbios=sizeof(pcxx_bios);
132
133 #define pcxxassert(x, msg)  if(!(x)) pcxx_error(__LINE__, msg)
134
135 #define FEPTIMEOUT 200000  
136 #define SERIAL_TYPE_NORMAL      1
137 #define PCXE_EVENT_HANGUP   1
138
139 static struct tty_driver *pcxe_driver;
140
141 static struct timer_list pcxx_timer;
142
143 static void pcxxpoll(unsigned long dummy);
144 static void fepcmd(struct channel *, int, int, int, int, int);
145 static void pcxe_put_char(struct tty_struct *, unsigned char);
146 static void pcxe_flush_chars(struct tty_struct *);
147 static void pcxx_error(int, char *);
148 static void pcxe_close(struct tty_struct *, struct file *);
149 static int pcxe_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
150 static void pcxe_set_termios(struct tty_struct *, struct termios *);
151 static int pcxe_write(struct tty_struct *, const unsigned char *, int);
152 static int pcxe_write_room(struct tty_struct *);
153 static int pcxe_chars_in_buffer(struct tty_struct *);
154 static void pcxe_flush_buffer(struct tty_struct *);
155 static void doevent(int);
156 static void receive_data(struct channel *);
157 static void pcxxparam(struct tty_struct *, struct channel *ch);
158 static void do_softint(void *);
159 static inline void pcxe_sched_event(struct channel *, int);
160 static void pcxe_start(struct tty_struct *);
161 static void pcxe_stop(struct tty_struct *);
162 static void pcxe_throttle(struct tty_struct *);
163 static void pcxe_unthrottle(struct tty_struct *);
164 static void digi_send_break(struct channel *ch, int msec);
165 static void shutdown(struct channel *);
166 static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
167 static inline void memwinon(struct board_info *b, unsigned int win);
168 static inline void memwinoff(struct board_info *b, unsigned int win);
169 static inline void globalwinon(struct channel *ch);
170 static inline void rxwinon(struct channel *ch);
171 static inline void txwinon(struct channel *ch);
172 static inline void memoff(struct channel *ch);
173 static inline void assertgwinon(struct channel *ch);
174 static inline void assertmemoff(struct channel *ch);
175 static int pcxe_tiocmget(struct tty_struct *tty, struct file *file);
176 static int pcxe_tiocmset(struct tty_struct *tty, struct file *file,
177                          unsigned int set, unsigned int clear);
178
179 #define TZ_BUFSZ 4096
180
181 /* function definitions */
182
183 /*****************************************************************************/
184
185 static void cleanup_board_resources(void)
186 {
187         int crd, i;
188         struct board_info *bd;
189         struct channel *ch;
190
191         for(crd = 0; crd < numcards; crd++) {
192                 bd = &boards[crd];
193                 ch = digi_channels + bd->first_minor;
194
195                 if (bd->region)
196                         release_region(bd->port, 4);
197
198                 for(i = 0; i < bd->numports; i++, ch++)
199                         if (ch->tmp_buf)
200                                 kfree(ch->tmp_buf);
201         }
202 }
203
204 static void __exit pcxe_cleanup(void)
205 {
206
207         unsigned long   flags;
208         int e1;
209
210         printk(KERN_NOTICE "Unloading PC/Xx version %s\n", VERSION);
211
212         save_flags(flags);
213         cli();
214         del_timer_sync(&pcxx_timer);
215
216         if ((e1 = tty_unregister_driver(pcxe_driver)))
217                 printk("SERIAL: failed to unregister serial driver (%d)\n", e1);
218
219         put_tty_driver(pcxe_driver);
220         cleanup_board_resources();
221         kfree(digi_channels);
222         restore_flags(flags);
223 }
224
225 static inline struct channel *chan(register struct tty_struct *tty)
226 {
227         if (tty) {
228                 register struct channel *ch=(struct channel *)tty->driver_data;
229                 if (ch >= digi_channels && ch < digi_channels+nbdevs) {
230                         if (ch->magic==PCXX_MAGIC)
231                                 return ch;
232                 }
233         }
234         return NULL;
235 }
236
237 /* These inline routines are to turn board memory on and off */
238 static inline void memwinon(struct board_info *b, unsigned int win)
239 {
240         if(b->type == PCXEVE)
241                 outb_p(FEPWIN|win, b->port+1);
242         else
243                 outb_p(inb(b->port)|FEPMEM, b->port);
244 }
245
246 static inline void memwinoff(struct board_info *b, unsigned int win)
247 {
248         outb_p(inb(b->port)&~FEPMEM, b->port);
249         if(b->type == PCXEVE)
250                 outb_p(0, b->port + 1);
251 }
252
253 static inline void globalwinon(struct channel *ch)
254 {
255         if(ch->board->type == PCXEVE)
256                 outb_p(FEPWIN, ch->board->port+1);
257         else
258                 outb_p(FEPMEM, ch->board->port);
259 }
260
261 static inline void rxwinon(struct channel *ch)
262 {
263         if(ch->rxwin == 0)
264                 outb_p(FEPMEM, ch->board->port);
265         else 
266                 outb_p(ch->rxwin, ch->board->port+1);
267 }
268
269 static inline void txwinon(struct channel *ch)
270 {
271         if(ch->txwin == 0)
272                 outb_p(FEPMEM, ch->board->port);
273         else
274                 outb_p(ch->txwin, ch->board->port+1);
275 }
276
277 static inline void memoff(struct channel *ch)
278 {
279         outb_p(0, ch->board->port);
280         if(ch->board->type == PCXEVE)
281                 outb_p(0, ch->board->port+1);
282 }
283
284 static inline void assertgwinon(struct channel *ch)
285 {
286         if(ch->board->type != PCXEVE)
287                 pcxxassert(inb(ch->board->port) & FEPMEM, "Global memory off");
288 }
289
290 static inline void assertmemoff(struct channel *ch)
291 {
292         if(ch->board->type != PCXEVE)
293                 pcxxassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
294 }
295
296 static inline void pcxe_sched_event(struct channel *info, int event)
297 {
298         info->event |= 1 << event;
299         schedule_work(&info->tqueue);
300 }
301
302 static void pcxx_error(int line, char *msg)
303 {
304         printk("pcxx_error (DigiBoard): line=%d %s\n", line, msg);
305 }
306
307 static int pcxx_waitcarrier(struct tty_struct *tty,struct file *filp,struct channel *info)
308 {
309         DECLARE_WAITQUEUE(wait, current);
310         int     retval = 0;
311         int     do_clocal = 0;
312
313         if (tty->termios->c_cflag & CLOCAL)
314                 do_clocal = 1;
315
316         /*
317          * Block waiting for the carrier detect and the line to become free
318          */
319
320         retval = 0;
321         add_wait_queue(&info->open_wait, &wait);
322         info->count--;
323         info->blocked_open++;
324
325         for (;;) {
326                 cli();
327                 globalwinon(info);
328                 info->omodem |= DTR|RTS;
329                 fepcmd(info, SETMODEM, DTR|RTS, 0, 10, 1);
330                 memoff(info);
331                 sti();
332                 set_current_state(TASK_INTERRUPTIBLE);
333                 if(tty_hung_up_p(filp) || (info->asyncflags & ASYNC_INITIALIZED) == 0) {
334                         if(info->asyncflags & ASYNC_HUP_NOTIFY)
335                                 retval = -EAGAIN;
336                         else
337                                 retval = -ERESTARTSYS;  
338                         break;
339                 }
340                 if ((info->asyncflags & ASYNC_CLOSING) == 0 &&
341                         (do_clocal || (info->imodem & info->dcd)))
342                         break;
343                 if(signal_pending(current)) {
344                         retval = -ERESTARTSYS;
345                         break;
346                 }
347                 schedule();
348         }
349         current->state = TASK_RUNNING;
350         remove_wait_queue(&info->open_wait, &wait);
351
352         if(!tty_hung_up_p(filp))
353                 info->count++;
354         info->blocked_open--;
355
356         return retval;
357 }       
358
359
360 int pcxe_open(struct tty_struct *tty, struct file * filp)
361 {
362         volatile struct board_chan *bc;
363         struct channel *ch;
364         unsigned long flags;
365         int line;
366         int boardnum;
367         int retval;
368
369         line = tty->index;
370
371         if(line < 0 || line >= nbdevs) {
372                 printk("line out of range in pcxe_open\n");
373                 tty->driver_data = NULL;
374                 return(-ENODEV);
375         }
376
377         for(boardnum=0;boardnum<numcards;boardnum++)
378                 if ((line >= boards[boardnum].first_minor) && 
379                         (line < boards[boardnum].first_minor + boards[boardnum].numports))
380                 break;
381
382         if(boardnum >= numcards || boards[boardnum].status == DISABLED ||
383                 (line - boards[boardnum].first_minor) >= boards[boardnum].numports) {
384                 tty->driver_data = NULL;   /* Mark this device as 'down' */
385                 return(-ENODEV);
386         }
387
388         ch = digi_channels+line;
389
390         if(ch->brdchan == 0) {
391                 tty->driver_data = NULL;
392                 return(-ENODEV);
393         }
394
395         /*
396          * If the device is in the middle of being closed, then block
397          * until it's done, and then try again.
398          */
399         if(ch->asyncflags & ASYNC_CLOSING) {
400                 interruptible_sleep_on(&ch->close_wait);
401                 if(ch->asyncflags & ASYNC_HUP_NOTIFY)
402                         return -EAGAIN;
403                 else
404                         return -ERESTARTSYS;
405         }
406
407         save_flags(flags);
408         cli();
409         ch->count++;
410         tty->driver_data = ch;
411         ch->tty = tty;
412
413         if ((ch->asyncflags & ASYNC_INITIALIZED) == 0) {
414                 unsigned int head;
415
416                 globalwinon(ch);
417                 ch->statusflags = 0;
418                 bc=ch->brdchan;
419                 ch->imodem = bc->mstat;
420                 head = bc->rin;
421                 bc->rout = head;
422                 ch->tty = tty;
423                 pcxxparam(tty,ch);
424                 ch->imodem = bc->mstat;
425                 bc->idata = 1;
426                 ch->omodem = DTR|RTS;
427                 fepcmd(ch, SETMODEM, DTR|RTS, 0, 10, 1);
428                 memoff(ch);
429                 ch->asyncflags |= ASYNC_INITIALIZED;
430         }
431         restore_flags(flags);
432
433         if(ch->asyncflags & ASYNC_CLOSING) {
434                 interruptible_sleep_on(&ch->close_wait);
435                 if(ch->asyncflags & ASYNC_HUP_NOTIFY)
436                         return -EAGAIN;
437                 else
438                         return -ERESTARTSYS;
439         }
440
441         if (!(filp->f_flags & O_NONBLOCK)) {
442                 /* this has to be set in order for the "block until
443                  * CD" code to work correctly.  i'm not sure under
444                  * what circumstances asyncflags should be set to
445                  * ASYNC_NORMAL_ACTIVE though
446                  * brian@ilinx.com
447                  */
448                 ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
449                 if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0)
450                         return retval;
451         }
452         ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
453         
454         return 0;
455
456
457 static void shutdown(struct channel *info)
458 {
459         unsigned long flags;
460         volatile struct board_chan *bc;
461         struct tty_struct *tty;
462
463         if (!(info->asyncflags & ASYNC_INITIALIZED)) 
464                 return;
465
466         save_flags(flags);
467         cli();
468         globalwinon(info);
469
470         bc = info->brdchan;
471         if(bc)
472                 bc->idata = 0;
473
474         tty = info->tty;
475
476         /*
477          * If we're a modem control device and HUPCL is on, drop RTS & DTR.
478          */
479         if(tty->termios->c_cflag & HUPCL) {
480                 info->omodem &= ~(RTS|DTR);
481                 fepcmd(info, SETMODEM, 0, DTR|RTS, 10, 1);
482         }
483
484         memoff(info);
485         info->asyncflags &= ~ASYNC_INITIALIZED;
486         restore_flags(flags);
487 }
488
489
490 static void pcxe_close(struct tty_struct * tty, struct file * filp)
491 {
492         struct channel *info;
493
494         if ((info=chan(tty))!=NULL) {
495                 unsigned long flags;
496                 save_flags(flags);
497                 cli();
498
499                 if(tty_hung_up_p(filp)) {
500                         /* flag that somebody is done with this module */
501                         restore_flags(flags);
502                         return;
503                 }
504                 /* this check is in serial.c, it won't hurt to do it here too */
505                 if ((tty->count == 1) && (info->count != 1)) {
506                         /*
507                          * Uh, oh.  tty->count is 1, which means that the tty
508                          * structure will be freed.  Info->count should always
509                          * be one in these conditions.  If it's greater than
510                          * one, we've got real problems, since it means the
511                          * serial port won't be shutdown.
512                          */
513                         printk("pcxe_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count);
514                         info->count = 1;
515                 }
516                 if (info->count-- > 1) {
517                         restore_flags(flags);
518                         return;
519                 }
520                 if (info->count < 0) {
521                         info->count = 0;
522                 }
523
524                 info->asyncflags |= ASYNC_CLOSING;
525         
526                 tty->closing = 1;
527                 if(info->asyncflags & ASYNC_INITIALIZED) {
528                         setup_empty_event(tty,info);            
529                         tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
530                 }
531         
532                 if(tty->driver->flush_buffer)
533                         tty->driver->flush_buffer(tty);
534                 tty_ldisc_flush(tty);
535                 shutdown(info);
536                 tty->closing = 0;
537                 info->event = 0;
538                 info->tty = NULL;
539                 if(info->blocked_open) {
540                         if(info->close_delay) {
541                                 msleep_interruptible(jiffies_to_msecs(info->close_delay));
542                         }
543                         wake_up_interruptible(&info->open_wait);
544                 }
545                 info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
546                 wake_up_interruptible(&info->close_wait);
547                 restore_flags(flags);
548         }
549 }
550
551
552 void pcxe_hangup(struct tty_struct *tty)
553 {
554         struct channel *ch;
555
556         if ((ch=chan(tty))!=NULL) {
557                 unsigned long flags;
558
559                 save_flags(flags);
560                 cli();
561                 shutdown(ch);
562                 ch->event = 0;
563                 ch->count = 0;
564                 ch->tty = NULL;
565                 ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
566                 wake_up_interruptible(&ch->open_wait);
567                 restore_flags(flags);
568         }
569 }
570
571
572
573 static int pcxe_write(struct tty_struct * tty, const unsigned char *buf, int count)
574 {
575         struct channel *ch;
576         volatile struct board_chan *bc;
577         int total, remain, size, stlen;
578         unsigned int head, tail;
579         unsigned long flags;
580         /* printk("Entering pcxe_write()\n"); */
581
582         if ((ch=chan(tty))==NULL)
583                 return 0;
584
585         bc = ch->brdchan;
586         size = ch->txbufsize;
587
588         /*
589          * All data is now local
590          */
591
592         total = 0;
593         save_flags(flags);
594         cli();
595         globalwinon(ch);
596         head = bc->tin & (size - 1);
597         tail = bc->tout;
598         if (tail != bc->tout)
599                 tail = bc->tout;
600         tail &= (size - 1);
601         if (head >= tail) {
602                 remain = size - (head - tail) - 1;
603                 stlen = size - head;
604         }
605         else {
606                 remain = tail - head - 1;
607                 stlen = remain;
608         }
609         count = min(remain, count);
610
611         txwinon(ch);
612         while (count > 0) {
613                 stlen = min(count, stlen);
614                 memcpy(ch->txptr + head, buf, stlen);
615                 buf += stlen;
616                 count -= stlen;
617                 total += stlen;
618                 head += stlen;
619                 if (head >= size) {
620                         head = 0;
621                         stlen = tail;
622                 }
623         }
624         ch->statusflags |= TXBUSY;
625         globalwinon(ch);
626         bc->tin = head;
627         if ((ch->statusflags & LOWWAIT) == 0) {
628                 ch->statusflags |= LOWWAIT;
629                 bc->ilow = 1;
630         }
631         memoff(ch);
632         restore_flags(flags);
633         
634         return(total);
635 }
636
637
638 static void pcxe_put_char(struct tty_struct *tty, unsigned char c)
639 {
640         pcxe_write(tty, &c, 1);
641         return;
642 }
643
644
645 static int pcxe_write_room(struct tty_struct *tty)
646 {
647         struct channel *ch;
648         int remain;
649
650         remain = 0;
651         if ((ch=chan(tty))!=NULL) {
652                 volatile struct board_chan *bc;
653                 unsigned int head, tail;
654                 unsigned long flags;
655
656                 save_flags(flags);
657                 cli();
658                 globalwinon(ch);
659
660                 bc = ch->brdchan;
661                 head = bc->tin & (ch->txbufsize - 1);
662                 tail = bc->tout;
663                 if (tail != bc->tout)
664                         tail = bc->tout;
665                 tail &= (ch->txbufsize - 1);
666
667                 if((remain = tail - head - 1) < 0 )
668                         remain += ch->txbufsize;
669
670                 if (remain && (ch->statusflags & LOWWAIT) == 0) {
671                         ch->statusflags |= LOWWAIT;
672                         bc->ilow = 1;
673                 }
674                 memoff(ch);
675                 restore_flags(flags);
676         }
677
678         return remain;
679 }
680
681
682 static int pcxe_chars_in_buffer(struct tty_struct *tty)
683 {
684         int chars;
685         unsigned int ctail, head, tail;
686         int remain;
687         unsigned long flags;
688         struct channel *ch;
689         volatile struct board_chan *bc;
690
691         if ((ch=chan(tty))==NULL)
692                 return(0);
693
694         save_flags(flags);
695         cli();
696         globalwinon(ch);
697
698         bc = ch->brdchan;
699         tail = bc->tout;
700         head = bc->tin;
701         ctail = ch->mailbox->cout;
702         if(tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
703                 chars = 0;
704         else {
705                 head = bc->tin & (ch->txbufsize - 1);
706                 tail &= (ch->txbufsize - 1);
707                 if((remain = tail - head - 1) < 0 )
708                         remain += ch->txbufsize;
709
710                 chars = (int)(ch->txbufsize - remain);
711
712                 /* 
713                  * Make it possible to wakeup anything waiting for output
714                  * in tty_ioctl.c, etc.
715                  */
716                 if(!(ch->statusflags & EMPTYWAIT))
717                         setup_empty_event(tty,ch);
718         }
719
720         memoff(ch);
721         restore_flags(flags);
722
723         return(chars);
724 }
725
726
727 static void pcxe_flush_buffer(struct tty_struct *tty)
728 {
729         unsigned int tail;
730         volatile struct board_chan *bc;
731         struct channel *ch;
732         unsigned long flags;
733
734         if ((ch=chan(tty))==NULL)
735                 return;
736
737         save_flags(flags);
738         cli();
739
740         globalwinon(ch);
741         bc = ch->brdchan;
742         tail = bc->tout;
743         fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
744
745         memoff(ch);
746         restore_flags(flags);
747
748         tty_wakeup(tty);
749 }
750
751 static void pcxe_flush_chars(struct tty_struct *tty)
752 {
753         struct channel * ch;
754
755         if ((ch=chan(tty))!=NULL) {
756                 unsigned long flags;
757
758                 save_flags(flags);
759                 cli();
760                 if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
761                         setup_empty_event(tty,ch);
762                 restore_flags(flags);
763         }
764 }
765
766 #ifndef MODULE
767
768 /*
769  * Driver setup function when linked into the kernel to optionally parse multible
770  * "digi="-lines and initialize the driver at boot time. No probing.
771  */
772 void __init pcxx_setup(char *str, int *ints)
773 {
774
775         struct board_info board;
776         int               i, j, last;
777         char              *temp, *t2;
778         unsigned          len;
779
780         numcards=0;
781
782         memset(&board, 0, sizeof(board));
783
784         for(last=0,i=1;i<=ints[0];i++)
785                 switch(i)
786                 {
787                         case 1:
788                                 board.status = ints[i];
789                                 last = i;
790                                 break;
791
792                         case 2:
793                                 board.type = ints[i];
794                                 last = i;
795                                 break;
796
797                         case 3:
798                                 board.altpin = ints[i];
799                                 last = i;
800                                 break;
801
802                         case 4:
803                                 board.numports = ints[i];
804                                 last = i;
805                                 break;
806
807                         case 5:
808                                 board.port = ints[i];
809                                 last = i;
810                                 break;
811
812                         case 6:
813                                 board.membase = ints[i];
814                                 last = i;
815                                 break;
816
817                         default:
818                                 printk("PC/Xx: Too many integer parms\n");
819                                 return;
820                 }
821
822         while (str && *str) 
823         {
824                 /* find the next comma or terminator */
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 io port address %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         /* I should REALLY validate the stuff here */
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         /* keep track of my initial minor number */
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         /* yeha!  string parameter was successful! */
955         numcards++;
956 }
957 #endif
958
959 static struct tty_operations pcxe_ops = {
960         .open = pcxe_open,
961         .close = pcxe_close,
962         .write = pcxe_write,
963         .put_char = pcxe_put_char,
964         .flush_chars = pcxe_flush_chars,
965         .write_room = pcxe_write_room,
966         .chars_in_buffer = pcxe_chars_in_buffer,
967         .flush_buffer = pcxe_flush_buffer,
968         .ioctl = pcxe_ioctl,
969         .throttle = pcxe_throttle,
970         .unthrottle = pcxe_unthrottle,
971         .set_termios = pcxe_set_termios,
972         .stop = pcxe_stop,
973         .start = pcxe_start,
974         .hangup = pcxe_hangup,
975         .tiocmget = pcxe_tiocmget,
976         .tiocmset = pcxe_tiocmset,
977 };
978
979 /*
980  * function to initialize the driver with the given parameters, which are either
981  * the default values from this file or the parameters given at boot.
982  */
983 static int __init pcxe_init(void)
984 {
985         ulong memory_seg=0, memory_size=0;
986         int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
987         int ret = -ENOMEM;
988         unchar *fepos, *memaddr, *bios, v;
989         volatile struct global_data *gd;
990         volatile struct board_chan *bc;
991         struct board_info *bd;
992         struct channel *ch;
993
994         printk(KERN_NOTICE "Digiboard PC/X{i,e,eve} driver v%s\n", VERSION);
995
996 #ifdef MODULE
997         for (i = 0; i < MAX_DIGI_BOARDS; i++) {
998                 if (io[i]) {
999                         numcards = 0;
1000                         break;
1001                 }
1002         }
1003         if (numcards == 0) {
1004                 int first_minor = 0;
1005
1006                 for (i = 0; i < MAX_DIGI_BOARDS; i++) {
1007                         if (io[i] == 0) {
1008                                 boards[i].port    = 0;
1009                                 boards[i].status  = DISABLED;
1010                         }
1011                         else {
1012                                 boards[i].port         = (ushort)io[i];
1013                                 boards[i].status       = ENABLED;
1014                                 boards[i].first_minor  = first_minor;
1015                                 numcards=i+1;
1016                         }
1017                         if (membase[i])
1018                                 boards[i].membase = (ulong)membase[i];
1019                         else
1020                                 boards[i].membase = 0xD0000;
1021
1022                         if (memsize[i])
1023                                 boards[i].memsize = (ulong)(memsize[i] * 1024);
1024                         else
1025                                 boards[i].memsize = 0;
1026
1027                         if (altpin[i])
1028                                 boards[i].altpin  = ON;
1029                         else
1030                                 boards[i].altpin  = OFF;
1031
1032                         if (numports[i])
1033                                 boards[i].numports  = (ushort)numports[i];
1034                         else
1035                                 boards[i].numports  = 16;
1036
1037                         boards[i].region = NULL;
1038                         first_minor += boards[i].numports;
1039                 }
1040         }
1041 #endif
1042
1043         if (numcards <= 0)
1044         {
1045                 printk("PC/Xx: No cards configured, driver not active.\n");
1046                 return -EIO;
1047         }
1048 #if 1
1049         if (debug)
1050             for (i = 0; i < numcards; i++) {
1051                     printk("Card %d:status=%d, port=0x%x, membase=0x%lx, memsize=0x%lx, altpin=%d, numports=%d, first_minor=%d\n",
1052                             i+1,
1053                             boards[i].status,
1054                             boards[i].port,
1055                             boards[i].membase,
1056                             boards[i].memsize,
1057                             boards[i].altpin,
1058                             boards[i].numports,
1059                             boards[i].first_minor);
1060             }
1061 #endif
1062
1063         for (i=0;i<numcards;i++)
1064                 nbdevs += boards[i].numports;
1065
1066         if (nbdevs <= 0)
1067         {
1068                 printk("PC/Xx: No devices activated, driver not active.\n");
1069                 return -EIO;
1070         }
1071
1072         pcxe_driver = alloc_tty_driver(nbdevs);
1073         if (!pcxe_driver)
1074                 return -ENOMEM;
1075
1076         /*
1077          * this turns out to be more memory efficient, as there are no 
1078          * unused spaces.
1079          */
1080         digi_channels = kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL);
1081         if (!digi_channels) {
1082                 printk(KERN_ERR "Unable to allocate digi_channel struct\n");
1083                 put_tty_driver(pcxe_driver);
1084                 return -ENOMEM;
1085         }
1086         memset(digi_channels, 0, sizeof(struct channel) * nbdevs);
1087
1088         init_timer(&pcxx_timer);
1089         pcxx_timer.function = pcxxpoll;
1090
1091         pcxe_driver->owner = THIS_MODULE;
1092         pcxe_driver->name = "ttyD";
1093         pcxe_driver->devfs_name = "pcxe/";
1094         pcxe_driver->major = DIGI_MAJOR; 
1095         pcxe_driver->minor_start = 0;
1096         pcxe_driver->type = TTY_DRIVER_TYPE_SERIAL;
1097         pcxe_driver->subtype = SERIAL_TYPE_NORMAL;
1098         pcxe_driver->init_termios = tty_std_termios;
1099         pcxe_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
1100         pcxe_driver->flags = TTY_DRIVER_REAL_RAW;
1101         tty_set_operations(pcxe_driver, &pcxe_ops);
1102
1103         for(crd=0; crd < numcards; crd++) {
1104                 bd = &boards[crd];
1105                 outb(FEPRST, bd->port);
1106                 mdelay(1);
1107
1108                 for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
1109                         if(i > 100) {
1110                                 printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n",
1111                                         bd->port);
1112                                 bd->status = DISABLED;
1113                                 break;
1114                         }
1115 #ifdef MODULE
1116                         schedule();
1117 #endif
1118                         mdelay(10);
1119                 }
1120                 if(bd->status == DISABLED)
1121                         continue;
1122
1123                 v = inb(bd->port);
1124
1125                 if((v & 0x1) == 0x1) {
1126                         if((v & 0x30) == 0) {        /* PC/Xi 64K card */
1127                                 memory_seg = 0xf000;
1128                                 memory_size = 0x10000;
1129                         } 
1130
1131                         if((v & 0x30) == 0x10) {     /* PC/Xi 128K card */
1132                                 memory_seg = 0xe000;
1133                                 memory_size = 0x20000;
1134                         }
1135                         
1136                         if((v & 0x30) == 0x20) {     /* PC/Xi 256K card */
1137                                 memory_seg = 0xc000;
1138                                 memory_size = 0x40000;
1139                         }
1140
1141                         if((v & 0x30) == 0x30) {     /* PC/Xi 512K card */
1142                                 memory_seg = 0x8000;
1143                                 memory_size = 0x80000;
1144                         }
1145                         bd->type = PCXI;
1146                 } else {
1147                         if((v & 0x1) == 0x1) {
1148                                 bd->status = DISABLED;   /* PC/Xm unsupported card */
1149                                 printk("PC/Xx: PC/Xm at 0x%x not supported!!\n", bd->port);
1150                                 continue;
1151                         } else {
1152                                 if(v & 0xC0) {    
1153                                         topwin = 0x1f00L;
1154                                         outb((((ulong)bd->membase>>8) & 0xe0) | 0x10, bd->port+2);
1155                                         outb(((ulong)bd->membase>>16) & 0xff, bd->port+3);
1156                                         bd->type = PCXEVE; /* PC/Xe 8K card */
1157                                 } else { 
1158                                         bd->type = PCXE;    /* PC/Xe 64K card */
1159                                 }
1160                                         
1161                                 memory_seg = 0xf000;
1162                                 memory_size = 0x10000;
1163                         }
1164                 }
1165                 if (verbose)
1166                         printk("Configuring card %d as a %s %ldK card. io=0x%x, mem=%lx-%lx\n",
1167                                 crd+1, board_desc[bd->type], memory_size/1024,
1168                                 bd->port,bd->membase,bd->membase+memory_size-1);
1169
1170                 if (boards[crd].memsize == 0)
1171                         boards[crd].memsize = memory_size;
1172                 else
1173                         if (boards[crd].memsize != memory_size) {
1174                             printk("PC/Xx: memory size mismatch:supplied=%lx(%ldK) probed=%ld(%ldK)\n",
1175                                     boards[crd].memsize, boards[crd].memsize / 1024,
1176                                     memory_size, memory_size / 1024);
1177                             continue;
1178                         }
1179
1180                 memaddr = (unchar *)phys_to_virt(bd->membase);
1181
1182                 if (verbose)
1183                         printk("Resetting board and testing memory access:");
1184
1185                 outb(FEPRST|FEPMEM, bd->port);
1186
1187                 for(i=0; (inb(bd->port) & FEPMASK) != (FEPRST|FEPMEM); i++) {
1188                         if(i > 1000) {
1189                                 printk("\nPC/Xx: %s not resetting at port 0x%x! Check switch settings.\n",
1190                                         board_desc[bd->type], bd->port);
1191                                 bd->status = DISABLED;
1192                                 break;
1193                         }
1194 #ifdef MODULE
1195                         schedule();
1196 #endif
1197                         mdelay(1);
1198                 }
1199                 if(bd->status == DISABLED)
1200                         continue;
1201
1202                 memwinon(bd,0);
1203                 *(ulong *)(memaddr + botwin) = 0xa55a3cc3;
1204                 *(ulong *)(memaddr + topwin) = 0x5aa5c33c;
1205
1206                 if(*(ulong *)(memaddr + botwin) != 0xa55a3cc3 ||
1207                                         *(ulong *)(memaddr + topwin) != 0x5aa5c33c) {
1208                         printk("PC/Xx: Failed memory test at %lx for %s at port %x, check switch settings.\n",
1209                                 bd->membase, board_desc[bd->type], bd->port);
1210                         bd->status = DISABLED;
1211                         continue;
1212                 }
1213                 if (verbose)
1214                         printk(" done.\n");
1215
1216                 for(i=0; i < 16; i++) {
1217                         memaddr[MISCGLOBAL+i] = 0;
1218                 }
1219
1220                 if(bd->type == PCXI || bd->type == PCXE) {
1221                         bios = memaddr + BIOSCODE + ((0xf000 - memory_seg) << 4);
1222
1223                         if (verbose)
1224                                 printk("Downloading BIOS to 0x%lx:", virt_to_phys(bios));
1225
1226                         memcpy(bios, pcxx_bios, pcxx_nbios);
1227
1228                         if (verbose)
1229                                 printk(" done.\n");
1230
1231                         outb(FEPMEM, bd->port);
1232
1233                         if (verbose)
1234                                 printk("Waiting for BIOS to become ready");
1235
1236                         for(i=1; i <= 30; i++) {
1237                                 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
1238                                         goto load_fep;
1239                                 }
1240                                 if (verbose) {
1241                                         printk(".");
1242                                         if (i % 50 == 0)
1243                                                 printk("\n");
1244                                 }
1245 #ifdef MODULE
1246                                 schedule();
1247 #endif
1248                                 mdelay(50);
1249                         }
1250
1251                         printk("\nPC/Xx: BIOS download failed for board at 0x%x(addr=%lx-%lx)!\n",
1252                                                         bd->port, bd->membase, bd->membase+bd->memsize);
1253                         bd->status = DISABLED;
1254                         continue;
1255                 }
1256
1257                 if(bd->type == PCXEVE) {
1258                         bios = memaddr + (BIOSCODE & 0x1fff);
1259                         memwinon(bd,0xff);
1260                         
1261                         memcpy(bios, pcxx_bios, pcxx_nbios);
1262
1263                         outb(FEPCLR, bd->port);
1264                         memwinon(bd,0);
1265
1266                         for(i=0; i <= 1000; i++) {
1267                                 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
1268                                         goto load_fep;
1269                                 }
1270                                 if (verbose) {
1271                                         printk(".");
1272                                         if (i % 50 == 0)
1273                                                 printk("\n");
1274                                 }
1275 #ifdef MODULE
1276                                 schedule();
1277 #endif
1278                                 mdelay(10);
1279                         }
1280
1281                         printk("\nPC/Xx: BIOS download failed on the %s at 0x%x!\n",
1282                                 board_desc[bd->type], bd->port);
1283                         bd->status = DISABLED;
1284                         continue;
1285                 }
1286
1287 load_fep:
1288                 fepos = memaddr + FEPCODE;
1289                 if(bd->type == PCXEVE)
1290                         fepos = memaddr + (FEPCODE & 0x1fff);
1291
1292                 if (verbose)
1293                         printk(" ok.\nDownloading FEP/OS to 0x%lx:", virt_to_phys(fepos));
1294
1295                 memwinon(bd, (FEPCODE >> 13));
1296                 memcpy(fepos, pcxx_cook, pcxx_ncook);
1297                 memwinon(bd, 0);
1298
1299                 if (verbose)
1300                         printk(" done.\n");
1301
1302                 *(ushort *)((ulong)memaddr + MBOX +  0) = 2;
1303                 *(ushort *)((ulong)memaddr + MBOX +  2) = memory_seg + FEPCODESEG;
1304                 *(ushort *)((ulong)memaddr + MBOX +  4) = 0;
1305                 *(ushort *)((ulong)memaddr + MBOX +  6) = FEPCODESEG;
1306                 *(ushort *)((ulong)memaddr + MBOX +  8) = 0;
1307                 *(ushort *)((ulong)memaddr + MBOX + 10) = pcxx_ncook;
1308
1309                 outb(FEPMEM|FEPINT, bd->port);
1310                 outb(FEPMEM, bd->port);
1311
1312                 for(i=0; *(ushort *)((ulong)memaddr + MBOX); i++) {
1313                         if(i > 2000) {
1314                                 printk("PC/Xx: Command failed for the %s at 0x%x!\n",
1315                                         board_desc[bd->type], bd->port);
1316                                 bd->status = DISABLED;
1317                                 break;
1318                         }
1319 #ifdef MODULE
1320                         schedule();
1321 #endif
1322                         mdelay(1);
1323                 }
1324
1325                 if(bd->status == DISABLED)
1326                         continue;
1327
1328                 if (verbose)
1329                         printk("Waiting for FEP/OS to become ready");
1330
1331                 *(ushort *)(memaddr + FEPSTAT) = 0;
1332                 *(ushort *)(memaddr + MBOX + 0) = 1;
1333                 *(ushort *)(memaddr + MBOX + 2) = FEPCODESEG;
1334                 *(ushort *)(memaddr + MBOX + 4) = 0x4L;
1335
1336                 outb(FEPINT, bd->port);
1337                 outb(FEPCLR, bd->port);
1338                 memwinon(bd, 0);
1339
1340                 for(i=1; *(ushort *)((ulong)memaddr + FEPSTAT) != *(ushort *)"OS"; i++) {
1341                         if(i > 1000) {
1342                                 printk("\nPC/Xx: FEP/OS download failed on the %s at 0x%x!\n",
1343                                         board_desc[bd->type], bd->port);
1344                                 bd->status = DISABLED;
1345                                 break;
1346                         }
1347                         if (verbose) {
1348                                 printk(".");
1349                                 if (i % 50 == 0)
1350                                         printk("\n%5d",i/50);
1351                         }
1352 #ifdef MODULE
1353                         schedule();
1354 #endif
1355                         mdelay(1);
1356                 }
1357                 if(bd->status == DISABLED)
1358                         continue;
1359
1360                 if (verbose)
1361                         printk(" ok.\n");
1362
1363                 ch = digi_channels+bd->first_minor;
1364                 pcxxassert(ch < digi_channels+nbdevs, "ch out of range");
1365
1366                 bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
1367                 gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
1368
1369                 if((bd->type == PCXEVE) && (*(ushort *)((ulong)memaddr+NPORT) < 3))
1370                         shrinkmem = 1;
1371
1372                 bd->region = request_region(bd->port, 4, "PC/Xx");
1373
1374                 if (!bd->region) {
1375                         printk(KERN_ERR "I/O port 0x%x is already used\n", bd->port);
1376                         ret = -EBUSY;
1377                         goto cleanup_boards;
1378                 }
1379
1380                 for(i=0; i < bd->numports; i++, ch++, bc++) {
1381                         if(((ushort *)((ulong)memaddr + PORTBASE))[i] == 0) {
1382                                 ch->brdchan = 0;
1383                                 continue;
1384                         }
1385                         ch->brdchan = bc;
1386                         ch->mailbox = gd;
1387                         INIT_WORK(&ch->tqueue, do_softint, ch);
1388                         ch->board = &boards[crd];
1389 #ifdef DEFAULT_HW_FLOW
1390                         ch->digiext.digi_flags = RTSPACE|CTSPACE;
1391 #endif
1392                         if(boards[crd].altpin) {
1393                                 ch->dsr = CD;
1394                                 ch->dcd = DSR;
1395                                 ch->digiext.digi_flags |= DIGI_ALTPIN;
1396                         } else { 
1397                                 ch->dcd = CD;
1398                                 ch->dsr = DSR;
1399                         }
1400
1401                         ch->magic = PCXX_MAGIC;
1402                         ch->boardnum = crd;
1403                         ch->channelnum = i;
1404
1405                         ch->dev = bd->first_minor + i;
1406                         ch->tty = 0;
1407
1408                         if(shrinkmem) {
1409                                 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1410                                 shrinkmem = 0;
1411                         }
1412                         
1413                         if(bd->type != PCXEVE) {
1414                                 ch->txptr = memaddr+((bc->tseg-memory_seg) << 4);
1415                                 ch->rxptr = memaddr+((bc->rseg-memory_seg) << 4);
1416                                 ch->txwin = ch->rxwin = 0;
1417                         } else {
1418                                 ch->txptr = memaddr+(((bc->tseg-memory_seg) << 4) & 0x1fff);
1419                                 ch->txwin = FEPWIN | ((bc->tseg-memory_seg) >> 9);
1420                                 ch->rxptr = memaddr+(((bc->rseg-memory_seg) << 4) & 0x1fff);
1421                                 ch->rxwin = FEPWIN | ((bc->rseg-memory_seg) >>9 );
1422                         }
1423
1424                         ch->txbufsize = bc->tmax + 1;
1425                         ch->rxbufsize = bc->rmax + 1;
1426                         ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
1427                         init_MUTEX(&ch->tmp_buf_sem);
1428
1429                         if (!ch->tmp_buf) {
1430                                 printk(KERN_ERR "Unable to allocate memory for temp buffers\n");
1431                                 goto cleanup_boards;
1432                         }
1433
1434                         lowwater = ch->txbufsize >= 2000 ? 1024 : ch->txbufsize/2;
1435                         fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1436                         fepcmd(ch, SRXLWATER, ch->rxbufsize/4, 0, 10, 0);
1437                         fepcmd(ch, SRXHWATER, 3 * ch->rxbufsize/4, 0, 10, 0);
1438
1439                         bc->edelay = 100;
1440                         bc->idata = 1;
1441
1442                         ch->startc = bc->startc;
1443                         ch->stopc = bc->stopc;
1444                         ch->startca = bc->startca;
1445                         ch->stopca = bc->stopca;
1446
1447                         ch->fepcflag = 0;
1448                         ch->fepiflag = 0;
1449                         ch->fepoflag = 0;
1450                         ch->fepstartc = 0;
1451                         ch->fepstopc = 0;
1452                         ch->fepstartca = 0;
1453                         ch->fepstopca = 0;
1454
1455                         ch->close_delay = 50;
1456                         ch->count = 0;
1457                         ch->blocked_open = 0;
1458                         init_waitqueue_head(&ch->open_wait);
1459                         init_waitqueue_head(&ch->close_wait);
1460                         ch->asyncflags = 0;
1461                 }
1462
1463                 if (verbose)
1464                     printk("Card No. %d ready: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n", 
1465                             crd+1, board_desc[bd->type], board_mem[bd->type], bd->port, 
1466                             bd->membase, bd->numports);
1467                 else
1468                     printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n", 
1469                             board_desc[bd->type], board_mem[bd->type], bd->port, 
1470                             bd->membase, bd->numports);
1471
1472                 memwinoff(bd, 0);
1473                 enabled_cards++;
1474         }
1475
1476         if (enabled_cards <= 0) {
1477                 printk(KERN_NOTICE "PC/Xx: No cards enabled, no driver.\n");
1478                 ret = -EIO;
1479                 goto cleanup_boards;
1480         }
1481
1482         ret = tty_register_driver(pcxe_driver);
1483         if(ret) {
1484                 printk(KERN_ERR "Couldn't register PC/Xe driver\n");
1485                 goto cleanup_boards;
1486         }
1487
1488         /*
1489          * Start up the poller to check for events on all enabled boards
1490          */
1491         mod_timer(&pcxx_timer, HZ/25);
1492
1493         if (verbose)
1494                 printk(KERN_NOTICE "PC/Xx: Driver with %d card(s) ready.\n", enabled_cards);
1495
1496         return 0;
1497 cleanup_boards:
1498         cleanup_board_resources();
1499         kfree(digi_channels);
1500         put_tty_driver(pcxe_driver);
1501         return ret;
1502 }
1503
1504 module_init(pcxe_init)
1505 module_exit(pcxe_cleanup)
1506
1507 static void pcxxpoll(unsigned long dummy)
1508 {
1509         unsigned long flags;
1510         int crd;
1511         volatile unsigned int head, tail;
1512         struct channel *ch;
1513         struct board_info *bd;
1514
1515         save_flags(flags);
1516         cli();
1517
1518         for(crd=0; crd < numcards; crd++) {
1519                 bd = &boards[crd];
1520
1521                 ch = digi_channels+bd->first_minor;
1522
1523                 if(bd->status == DISABLED)
1524                         continue;
1525
1526                 assertmemoff(ch);
1527
1528                 globalwinon(ch);
1529                 head = ch->mailbox->ein;
1530                 tail = ch->mailbox->eout;
1531
1532                 if(head != tail)
1533                         doevent(crd);
1534
1535                 memoff(ch);
1536         }
1537
1538         mod_timer(&pcxx_timer, jiffies + HZ/25);
1539         restore_flags(flags);
1540 }
1541
1542 static void doevent(int crd)
1543 {
1544         volatile struct board_info *bd;
1545         static struct tty_struct *tty;
1546         volatile struct board_chan *bc;
1547         volatile unchar *eventbuf;
1548         volatile unsigned int head;
1549         volatile unsigned int tail;
1550         struct channel *ch;
1551         struct channel *chan0;
1552         int channel, event, mstat, lstat;
1553
1554         bd = &boards[crd];
1555
1556         chan0 = digi_channels+bd->first_minor;
1557         pcxxassert(chan0 < digi_channels+nbdevs, "ch out of range");
1558
1559
1560         assertgwinon(chan0);
1561
1562         while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) {
1563                 assertgwinon(chan0);
1564                 eventbuf = (volatile unchar *)phys_to_virt(bd->membase + tail + ISTART);
1565                 channel = eventbuf[0];
1566                 event = eventbuf[1];
1567                 mstat = eventbuf[2];
1568                 lstat = eventbuf[3];
1569
1570                 ch=chan0+channel;
1571
1572                 if ((unsigned)channel >= bd->numports || !ch) { 
1573                         printk("physmem=%lx, tail=%x, head=%x\n", bd->membase, tail, head);
1574                         printk("doevent(%x) channel %x, event %x, mstat %x, lstat %x\n",
1575                                         crd, (unsigned)channel, event, (unsigned)mstat, lstat);
1576                         if(channel >= bd->numports)
1577                                 ch = chan0;
1578                         bc = ch->brdchan;
1579                         goto next;
1580                 }
1581                 if ((bc = ch->brdchan) == NULL)
1582                         goto next;
1583
1584                 if (event & DATA_IND) {
1585                         receive_data(ch);
1586                         assertgwinon(ch);
1587                 }
1588
1589                 if (event & MODEMCHG_IND) {
1590                         ch->imodem = mstat;
1591                         if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) {
1592                                 if (ch->asyncflags & ASYNC_CHECK_CD) {
1593                                         if (mstat & ch->dcd) {
1594                                                 wake_up_interruptible(&ch->open_wait);
1595                                         } else {
1596                                                 pcxe_sched_event(ch, PCXE_EVENT_HANGUP);
1597                                         }
1598                                 }
1599                         }
1600                 }
1601
1602                 tty = ch->tty;
1603
1604                 if (tty) {
1605
1606                         if (event & BREAK_IND) {
1607                                 tty->flip.count++;
1608                                 *tty->flip.flag_buf_ptr++ = TTY_BREAK;
1609                                 *tty->flip.char_buf_ptr++ = 0;
1610 #if 0
1611                                 if (ch->asyncflags & ASYNC_SAK)
1612                                         do_SAK(tty);
1613 #endif
1614                                 tty_schedule_flip(tty); 
1615                         }
1616
1617                         if (event & LOWTX_IND) {
1618                                 if (ch->statusflags & LOWWAIT) {
1619                                         ch->statusflags &= ~LOWWAIT;
1620                                         tty_wakeup(tty);
1621                                 }
1622                         }
1623
1624                         if (event & EMPTYTX_IND) {
1625                                 ch->statusflags &= ~TXBUSY;
1626                                 if (ch->statusflags & EMPTYWAIT) {
1627                                         ch->statusflags &= ~EMPTYWAIT;
1628                                         tty_wakeup(tty);
1629                                 }
1630                         }
1631                 }
1632
1633         next:
1634                 globalwinon(ch);
1635                 if(!bc) printk("bc == NULL in doevent!\n");
1636                 else bc->idata = 1;
1637
1638                 chan0->mailbox->eout = (tail+4) & (IMAX-ISTART-4);
1639                 globalwinon(chan0);
1640         }
1641
1642 }
1643
1644
1645 static void 
1646 fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
1647                                                 int bytecmd)
1648 {
1649         unchar *memaddr;
1650         unsigned int head, tail;
1651         long count;
1652         int n;
1653
1654         if(ch->board->status == DISABLED)
1655                 return;
1656
1657         assertgwinon(ch);
1658
1659         memaddr = (unchar *)phys_to_virt(ch->board->membase);
1660         head = ch->mailbox->cin;
1661
1662         if(head >= (CMAX-CSTART) || (head & 03)) {
1663                 printk("line %d: Out of range, cmd=%x, head=%x\n", __LINE__, cmd, head);
1664                 return;
1665         }
1666
1667         if(bytecmd) {
1668                 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1669
1670                 *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
1671
1672                 *(unchar *)(memaddr+head+CSTART+2) = word_or_byte;
1673                 *(unchar *)(memaddr+head+CSTART+3) = byte2;
1674         } else {
1675                 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1676
1677                 *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
1678                 *(ushort*)(memaddr+head+CSTART+2) = word_or_byte;
1679         }
1680
1681         head = (head+4) & (CMAX-CSTART-4);
1682         ch->mailbox->cin = head;
1683
1684         count = FEPTIMEOUT;
1685
1686         while(1) {
1687                 count--;
1688                 if(count == 0) {
1689                         printk("Fep not responding in fepcmd()\n");
1690                         return;
1691                 }
1692
1693                 head = ch->mailbox->cin;
1694                 tail = ch->mailbox->cout;
1695
1696                 n = (head-tail) & (CMAX-CSTART-4);
1697
1698                 if(n <= ncmds * (sizeof(short)*4))
1699                         break;
1700                 /* Seems not to be good here: schedule(); */
1701         }
1702 }
1703
1704
1705 static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
1706 {
1707         unsigned res = 0;
1708         if (cflag & CBAUDEX)
1709         {
1710                 ch->digiext.digi_flags |= DIGI_FAST;
1711                 res |= FEP_HUPCL;
1712                 /* This gets strange but if we don't do this we will get 78600
1713                  * instead of 115200. 57600 is mapped to 50 baud yielding 57600 in
1714                  * FAST mode. 115200 is mapped to 75. We need to map it to 110 to
1715                  * do 115K
1716                  */
1717                 if (cflag & B115200) res|=1;
1718         }
1719         else ch->digiext.digi_flags &= ~DIGI_FAST;
1720         res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE | CLOCAL);
1721         return res;
1722 }
1723
1724 static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
1725 {
1726         unsigned res = iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|IXON|IXANY|IXOFF);
1727         
1728         if(ch->digiext.digi_flags & DIGI_AIXON)
1729                 res |= IAIXON;
1730         return res;
1731 }
1732
1733 static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
1734 {
1735         unsigned res = 0;
1736
1737         if(cflag & CRTSCTS) {
1738                 ch->digiext.digi_flags |= (RTSPACE|CTSPACE);
1739                 res |= (CTS | RTS);
1740         }
1741         if(ch->digiext.digi_flags & RTSPACE)
1742                 res |= RTS;
1743         if(ch->digiext.digi_flags & DTRPACE)
1744                 res |= DTR;
1745         if(ch->digiext.digi_flags & CTSPACE)
1746                 res |= CTS;
1747         if(ch->digiext.digi_flags & DSRPACE)
1748                 res |= ch->dsr;
1749         if(ch->digiext.digi_flags & DCDPACE)
1750                 res |= ch->dcd;
1751
1752         if (res & RTS)
1753                 ch->digiext.digi_flags |= RTSPACE;
1754         if (res & CTS)
1755                 ch->digiext.digi_flags |= CTSPACE;
1756
1757         return res;
1758 }
1759
1760 static void pcxxparam(struct tty_struct *tty, struct channel *ch)
1761 {
1762         volatile struct board_chan *bc;
1763         unsigned int head;
1764         unsigned mval, hflow, cflag, iflag;
1765         struct termios *ts;
1766
1767         bc = ch->brdchan;
1768         assertgwinon(ch);
1769         ts = tty->termios;
1770
1771         if((ts->c_cflag & CBAUD) == 0) {
1772                 head = bc->rin;
1773                 bc->rout = head;
1774                 head = bc->tin;
1775                 fepcmd(ch, STOUT, (unsigned) head, 0, 0, 0);
1776                 mval = 0;
1777         } else {
1778
1779                 cflag = termios2digi_c(ch, ts->c_cflag);
1780
1781                 if(cflag != ch->fepcflag) {
1782                         ch->fepcflag = cflag;
1783                         fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1784                 }
1785
1786                 if(cflag & CLOCAL)
1787                         ch->asyncflags &= ~ASYNC_CHECK_CD;
1788                 else {
1789                         ch->asyncflags |= ASYNC_CHECK_CD;
1790                 }
1791
1792                 mval = DTR | RTS;
1793         }
1794
1795         iflag = termios2digi_i(ch, ts->c_iflag);
1796
1797         if(iflag != ch->fepiflag) {
1798                 ch->fepiflag = iflag;
1799                 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1800         }
1801
1802         bc->mint = ch->dcd;
1803         if((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1804                 if(ch->digiext.digi_flags & DIGI_FORCEDCD)
1805                         bc->mint = 0;
1806
1807         ch->imodem = bc->mstat;
1808
1809         hflow = termios2digi_h(ch, ts->c_cflag);
1810
1811         if(hflow != ch->hflow) {
1812                 ch->hflow = hflow;
1813                 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1814         }
1815
1816         /* mval ^= ch->modemfake & (mval ^ ch->modem); */
1817
1818         if(ch->omodem != mval) {
1819                 ch->omodem = mval;
1820                 fepcmd(ch, SETMODEM, mval, RTS|DTR, 0, 1);
1821         }
1822
1823         if(ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
1824                 ch->fepstartc = ch->startc;
1825                 ch->fepstopc = ch->stopc;
1826                 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1827         }
1828
1829         if(ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
1830                 ch->fepstartca = ch->startca;
1831                 ch->fepstopca = ch->stopca;
1832                 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1833         }
1834 }
1835
1836
1837 static void receive_data(struct channel *ch)
1838 {
1839         volatile struct board_chan *bc;
1840         struct tty_struct *tty;
1841         unsigned int tail, head, wrapmask;
1842         int n;
1843         int piece;
1844         struct termios *ts=0;
1845         unchar *rptr;
1846         int rc;
1847         int wrapgap;
1848
1849     globalwinon(ch);
1850
1851         if (ch->statusflags & RXSTOPPED)
1852                 return;
1853
1854         tty = ch->tty;
1855         if(tty)
1856                 ts = tty->termios;
1857
1858         bc = ch->brdchan;
1859
1860         if(!bc) {
1861                 printk("bc is NULL in receive_data!\n");
1862                 return;
1863         }
1864
1865         wrapmask = ch->rxbufsize - 1;
1866
1867         head = bc->rin;
1868         head &= wrapmask;
1869         tail = bc->rout & wrapmask;
1870
1871         n = (head-tail) & wrapmask;
1872
1873         if(n == 0)
1874                 return;
1875
1876         /*
1877          * If CREAD bit is off or device not open, set TX tail to head
1878          */
1879         if(!tty || !ts || !(ts->c_cflag & CREAD)) {
1880                 bc->rout = head;
1881                 return;
1882         }
1883
1884         if(tty->flip.count == TTY_FLIPBUF_SIZE) {
1885                 /* printk("tty->flip.count = TTY_FLIPBUF_SIZE\n"); */
1886                 return;
1887         }
1888
1889         if(bc->orun) {
1890                 bc->orun = 0;
1891                 printk("overrun! DigiBoard device %s\n", tty->name);
1892         }
1893
1894         rxwinon(ch);
1895         rptr = tty->flip.char_buf_ptr;
1896         rc = tty->flip.count;
1897         while(n > 0) {
1898                 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
1899                 piece = (wrapgap < n) ? wrapgap : n;
1900
1901                 /*
1902                  * Make sure we don't overflow the buffer
1903                  */
1904
1905                 if ((rc + piece) > TTY_FLIPBUF_SIZE)
1906                         piece = TTY_FLIPBUF_SIZE - rc;
1907
1908                 if (piece == 0)
1909                         break;
1910
1911                 memcpy(rptr, ch->rxptr + tail, piece);
1912                 rptr += piece;
1913                 rc += piece;
1914                 tail = (tail + piece) & wrapmask;
1915                 n -= piece;
1916         }
1917         tty->flip.count = rc;
1918         tty->flip.char_buf_ptr = rptr;
1919     globalwinon(ch);
1920         bc->rout = tail;
1921
1922         /* Must be called with global data */
1923         tty_schedule_flip(ch->tty); 
1924         return;
1925 }
1926
1927
1928 static int pcxe_tiocmget(struct tty_struct *tty, struct file *file)
1929 {
1930         struct channel *ch = (struct channel *) tty->driver_data;
1931         volatile struct board_chan *bc;
1932         unsigned long flags;
1933         int mflag = 0;
1934         int mstat;
1935
1936         if(ch)
1937                 bc = ch->brdchan;
1938         else {
1939                 printk("ch is NULL in %s!\n", __FUNCTION__);
1940                 return(-EINVAL);
1941         }
1942
1943         save_flags(flags);
1944         cli();
1945         globalwinon(ch);
1946         mstat = bc->mstat;
1947         memoff(ch);
1948         restore_flags(flags);
1949
1950         if(mstat & DTR)
1951                 mflag |= TIOCM_DTR;
1952         if(mstat & RTS)
1953                 mflag |= TIOCM_RTS;
1954         if(mstat & CTS)
1955                 mflag |= TIOCM_CTS;
1956         if(mstat & ch->dsr)
1957                 mflag |= TIOCM_DSR;
1958         if(mstat & RI)
1959                 mflag |= TIOCM_RI;
1960         if(mstat & ch->dcd)
1961                 mflag |= TIOCM_CD;
1962
1963         return mflag;
1964 }
1965
1966
1967 static int pcxe_tiocmset(struct tty_struct *tty, struct file *file,
1968                          unsigned int set, unsigned int clear)
1969 {
1970         struct channel *ch = (struct channel *) tty->driver_data;
1971         volatile struct board_chan *bc;
1972         unsigned long flags;
1973
1974         if(ch)
1975                 bc = ch->brdchan;
1976         else {
1977                 printk("ch is NULL in %s!\n", __FUNCTION__);
1978                 return(-EINVAL);
1979         }
1980
1981         save_flags(flags);
1982         cli();
1983         /*
1984          * I think this modemfake stuff is broken.  It doesn't
1985          * correctly reflect the behaviour desired by the TIOCM*
1986          * ioctls.  Therefore this is probably broken.
1987          */
1988         if (set & TIOCM_DTR) {
1989                 ch->modemfake |= DTR;
1990                 ch->modem |= DTR;
1991         }
1992         if (set & TIOCM_RTS) {
1993                 ch->modemfake |= RTS;
1994                 ch->modem |= RTS;
1995         }
1996
1997         if (clear & TIOCM_DTR) {
1998                 ch->modemfake |= DTR;
1999                 ch->modem &= ~DTR;
2000         }
2001         if (clear & TIOCM_RTS) {
2002                 ch->modemfake |= RTS;
2003                 ch->modem &= ~RTS;
2004         }
2005         globalwinon(ch);
2006         pcxxparam(tty,ch);
2007         memoff(ch);
2008         restore_flags(flags);
2009         return 0;
2010 }
2011
2012
2013 static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
2014                     unsigned int cmd, unsigned long arg)
2015 {
2016         struct channel *ch = (struct channel *) tty->driver_data;
2017         volatile struct board_chan *bc;
2018         int retval;
2019         unsigned int mflag, mstat;
2020         unsigned char startc, stopc;
2021         unsigned long flags;
2022         digiflow_t dflow;
2023
2024         if(ch)
2025                 bc = ch->brdchan;
2026         else {
2027                 printk("ch is NULL in pcxe_ioctl!\n");
2028                 return(-EINVAL);
2029         }
2030
2031         save_flags(flags);
2032
2033         switch(cmd) {
2034                 case TCSBRK:    /* SVID version: non-zero arg --> no break */
2035                         retval = tty_check_change(tty);
2036                         if(retval)
2037                                 return retval;
2038                         setup_empty_event(tty,ch);              
2039                         tty_wait_until_sent(tty, 0);
2040                         if(!arg)
2041                                 digi_send_break(ch, HZ/4);    /* 1/4 second */
2042                         return 0;
2043
2044                 case TCSBRKP:   /* support for POSIX tcsendbreak() */
2045                         retval = tty_check_change(tty);
2046                         if(retval)
2047                                 return retval;
2048                         setup_empty_event(tty,ch);              
2049                         tty_wait_until_sent(tty, 0);
2050                         digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
2051                         return 0;
2052
2053                 case TIOCGSOFTCAR:
2054                         return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *)arg);
2055
2056                 case TIOCSSOFTCAR:
2057                         {
2058                             unsigned int value;
2059                             if (get_user(value, (unsigned int *) arg))
2060                                     return -EFAULT;
2061                             tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (value ? CLOCAL : 0));
2062                         }
2063                         return 0;
2064
2065                 case TIOCMODG:
2066                         mflag = pcxe_tiocmget(tty, file);
2067                         if (put_user(mflag, (unsigned int *) arg))
2068                                 return -EFAULT;
2069                         break;
2070
2071                 case TIOCMODS:
2072                         if (get_user(mstat, (unsigned int *) arg))
2073                                 return -EFAULT;
2074                         return pcxe_tiocmset(tty, file, mstat, ~mstat);
2075
2076                 case TIOCSDTR:
2077                         cli();
2078                         ch->omodem |= DTR;
2079                         globalwinon(ch);
2080                         fepcmd(ch, SETMODEM, DTR, 0, 10, 1);
2081                         memoff(ch);
2082                         restore_flags(flags);
2083                         break;
2084
2085                 case TIOCCDTR:
2086                         ch->omodem &= ~DTR;
2087                         cli();
2088                         globalwinon(ch);
2089                         fepcmd(ch, SETMODEM, 0, DTR, 10, 1);
2090                         memoff(ch);
2091                         restore_flags(flags);
2092                         break;
2093
2094                 case DIGI_GETA:
2095                         if (copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t)))
2096                                 return -EFAULT;
2097                         break;
2098
2099                 case DIGI_SETAW:
2100                 case DIGI_SETAF:
2101                         if(cmd == DIGI_SETAW) {
2102                                 setup_empty_event(tty,ch);              
2103                                 tty_wait_until_sent(tty, 0);
2104                         }
2105                         else {
2106                                 tty_ldisc_flush(tty);
2107                         }
2108
2109                         /* Fall Thru */
2110
2111                 case DIGI_SETA:
2112                         if (copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t)))
2113                                 return -EFAULT;
2114 #ifdef DEBUG_IOCTL
2115                         printk("ioctl(DIGI_SETA): flags = %x\n", ch->digiext.digi_flags);
2116 #endif
2117                         
2118                         if(ch->digiext.digi_flags & DIGI_ALTPIN) {
2119                                 ch->dcd = DSR;
2120                                 ch->dsr = CD;
2121                         } else {
2122                                 ch->dcd = CD;
2123                                 ch->dsr = DSR;
2124                         }
2125                 
2126                         cli();
2127                         globalwinon(ch);
2128                         pcxxparam(tty,ch);
2129                         memoff(ch);
2130                         restore_flags(flags);
2131                         break;
2132
2133                 case DIGI_GETFLOW:
2134                 case DIGI_GETAFLOW:
2135                         cli();  
2136                         globalwinon(ch);
2137                         if(cmd == DIGI_GETFLOW) {
2138                                 dflow.startc = bc->startc;
2139                                 dflow.stopc = bc->stopc;
2140                         } else {
2141                                 dflow.startc = bc->startca;
2142                                 dflow.stopc = bc->stopca;
2143                         }
2144                         memoff(ch);
2145                         restore_flags(flags);
2146
2147                         if (copy_to_user((char*)arg, &dflow, sizeof(dflow)))
2148                                 return -EFAULT;
2149                         break;
2150
2151                 case DIGI_SETAFLOW:
2152                 case DIGI_SETFLOW:
2153                         if(cmd == DIGI_SETFLOW) {
2154                                 startc = ch->startc;
2155                                 stopc = ch->stopc;
2156                         } else {
2157                                 startc = ch->startca;
2158                                 stopc = ch->stopca;
2159                         }
2160
2161                         if (copy_from_user(&dflow, (char*)arg, sizeof(dflow)))
2162                                 return -EFAULT;
2163
2164                         if(dflow.startc != startc || dflow.stopc != stopc) {
2165                                 cli();
2166                                 globalwinon(ch);
2167
2168                                 if(cmd == DIGI_SETFLOW) {
2169                                         ch->fepstartc = ch->startc = dflow.startc;
2170                                         ch->fepstopc = ch->stopc = dflow.stopc;
2171                                         fepcmd(ch,SONOFFC,ch->fepstartc,ch->fepstopc,0, 1);
2172                                 } else {
2173                                         ch->fepstartca = ch->startca = dflow.startc;
2174                                         ch->fepstopca  = ch->stopca = dflow.stopc;
2175                                         fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
2176                                 }
2177
2178                                 if(ch->statusflags & TXSTOPPED)
2179                                         pcxe_start(tty);
2180
2181                                 memoff(ch);
2182                                 restore_flags(flags);
2183                         }
2184                         break;
2185
2186                 default:
2187                         return -ENOIOCTLCMD;
2188         }
2189
2190         return 0;
2191 }
2192
2193 static void pcxe_set_termios(struct tty_struct *tty, struct termios *old_termios)
2194 {
2195         struct channel *info;
2196
2197         if ((info=chan(tty))!=NULL) {
2198                 unsigned long flags;
2199                 save_flags(flags);
2200                 cli();
2201                 globalwinon(info);
2202                 pcxxparam(tty,info);
2203                 memoff(info);
2204
2205                 if ((old_termios->c_cflag & CRTSCTS) &&
2206                         ((tty->termios->c_cflag & CRTSCTS) == 0))
2207                         tty->hw_stopped = 0;
2208                 if(!(old_termios->c_cflag & CLOCAL) &&
2209                         (tty->termios->c_cflag & CLOCAL))
2210                         wake_up_interruptible(&info->open_wait);
2211                 restore_flags(flags);
2212         }
2213 }
2214
2215
2216
2217 static void do_softint(void *private_)
2218 {
2219         struct channel *info = (struct channel *) private_;
2220         
2221         if(info && info->magic == PCXX_MAGIC) {
2222                 struct tty_struct *tty = info->tty;
2223                 if (tty && tty->driver_data) {
2224                         if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
2225                                 tty_hangup(tty);
2226                                 wake_up_interruptible(&info->open_wait);
2227                                 info->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
2228                         }
2229                 }
2230         }
2231 }
2232
2233
2234 static void pcxe_stop(struct tty_struct *tty)
2235 {
2236         struct channel *info;
2237
2238         if ((info=chan(tty))!=NULL) {
2239                 unsigned long flags;
2240                 save_flags(flags); 
2241                 cli();
2242                 if ((info->statusflags & TXSTOPPED) == 0) {
2243                         globalwinon(info);
2244                         fepcmd(info, PAUSETX, 0, 0, 0, 0);
2245                         info->statusflags |= TXSTOPPED;
2246                         memoff(info);
2247                 }
2248                 restore_flags(flags);
2249         }
2250 }
2251
2252 static void pcxe_throttle(struct tty_struct * tty)
2253 {
2254         struct channel *info;
2255
2256         if ((info=chan(tty))!=NULL) {
2257                 unsigned long flags;
2258                 save_flags(flags);
2259                 cli();
2260                 if ((info->statusflags & RXSTOPPED) == 0) {
2261                         globalwinon(info);
2262                         fepcmd(info, PAUSERX, 0, 0, 0, 0);
2263                         info->statusflags |= RXSTOPPED;
2264                         memoff(info);
2265                 }
2266                 restore_flags(flags);
2267         }
2268 }
2269
2270 static void pcxe_unthrottle(struct tty_struct *tty)
2271 {
2272         struct channel *info;
2273
2274         if ((info=chan(tty)) != NULL) {
2275                 unsigned long flags;
2276
2277                 /* Just in case output was resumed because of a change in Digi-flow */
2278                 save_flags(flags);
2279                 cli();
2280                 if(info->statusflags & RXSTOPPED) {
2281                         volatile struct board_chan *bc;
2282                         globalwinon(info);
2283                         bc = info->brdchan;
2284                         fepcmd(info, RESUMERX, 0, 0, 0, 0);
2285                         info->statusflags &= ~RXSTOPPED;
2286                         memoff(info);
2287                 }
2288                 restore_flags(flags);
2289         }
2290 }
2291
2292
2293 static void pcxe_start(struct tty_struct *tty)
2294 {
2295         struct channel *info;
2296
2297         if ((info=chan(tty))!=NULL) {
2298                 unsigned long flags;
2299
2300                 save_flags(flags);
2301                 cli();
2302                 /* Just in case output was resumed because of a change in Digi-flow */
2303                 if(info->statusflags & TXSTOPPED) {
2304                         volatile struct board_chan *bc;
2305                         globalwinon(info);
2306                         bc = info->brdchan;
2307                         if(info->statusflags & LOWWAIT)
2308                                 bc->ilow = 1;
2309                         fepcmd(info, RESUMETX, 0, 0, 0, 0);
2310                         info->statusflags &= ~TXSTOPPED;
2311                         memoff(info);
2312                 }
2313                 restore_flags(flags);
2314         }
2315 }
2316
2317
2318 void digi_send_break(struct channel *ch, int msec)
2319 {
2320         unsigned long flags;
2321
2322         save_flags(flags);
2323         cli();
2324         globalwinon(ch);
2325
2326         /* 
2327          * Maybe I should send an infinite break here, schedule() for
2328          * msec amount of time, and then stop the break.  This way,
2329          * the user can't screw up the FEP by causing digi_send_break()
2330          * to be called (i.e. via an ioctl()) more than once in msec amount 
2331          * of time.  Try this for now...
2332          */
2333
2334         fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2335         memoff(ch);
2336
2337         restore_flags(flags);
2338 }
2339
2340 static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
2341 {
2342         volatile struct board_chan *bc;
2343         unsigned long flags;
2344
2345         save_flags(flags);
2346         cli();
2347         globalwinon(ch);
2348         ch->statusflags |= EMPTYWAIT;
2349         bc = ch->brdchan;
2350         bc->iempty = 1;
2351         memoff(ch);
2352         restore_flags(flags);
2353 }