vserver 1.9.3
[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
69 #ifndef MODULE
70 #include <linux/ctype.h> /* We only need it for parsing the "digi="-line */
71 #endif
72
73 #include <asm/system.h>
74 #include <asm/io.h>
75 #include <asm/uaccess.h>
76 #include <asm/bitops.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_PARM(verbose,     "i");
116 MODULE_PARM(debug,       "i");
117 MODULE_PARM(io,          "1-4i");
118 MODULE_PARM(membase,     "1-4i");
119 MODULE_PARM(memsize,     "1-4i");
120 MODULE_PARM(altpin,      "1-4i");
121 MODULE_PARM(numports,    "1-4i");
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 *, int, 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                                 current->state = TASK_INTERRUPTIBLE;
542                                 schedule_timeout(info->close_delay);
543                         }
544                         wake_up_interruptible(&info->open_wait);
545                 }
546                 info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
547                 wake_up_interruptible(&info->close_wait);
548                 restore_flags(flags);
549         }
550 }
551
552
553 void pcxe_hangup(struct tty_struct *tty)
554 {
555         struct channel *ch;
556
557         if ((ch=chan(tty))!=NULL) {
558                 unsigned long flags;
559
560                 save_flags(flags);
561                 cli();
562                 shutdown(ch);
563                 ch->event = 0;
564                 ch->count = 0;
565                 ch->tty = NULL;
566                 ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
567                 wake_up_interruptible(&ch->open_wait);
568                 restore_flags(flags);
569         }
570 }
571
572
573
574 static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
575 {
576         struct channel *ch;
577         volatile struct board_chan *bc;
578         int total, remain, size, stlen;
579         unsigned int head, tail;
580         unsigned long flags;
581         /* printk("Entering pcxe_write()\n"); */
582
583         if ((ch=chan(tty))==NULL)
584                 return 0;
585
586         bc = ch->brdchan;
587         size = ch->txbufsize;
588
589         if (from_user) {
590
591                 down(&ch->tmp_buf_sem);
592                 save_flags(flags);
593                 cli();
594                 globalwinon(ch);
595                 head = bc->tin & (size - 1);
596                 /* It seems to be necessary to make sure that the value is stable here somehow
597                    This is a rather odd pice of code here. */
598                 do
599                 {
600                         tail = bc->tout;
601                 } while (tail != bc->tout);
602                 
603                 tail &= (size - 1);
604                 stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
605                 count = min(stlen, count);
606                 memoff(ch);
607                 restore_flags(flags);
608
609                 if (count)
610                         if (copy_from_user(ch->tmp_buf, buf, count))
611                                 count = 0;
612
613                 buf = ch->tmp_buf;
614         }
615
616         /*
617          * All data is now local
618          */
619
620         total = 0;
621         save_flags(flags);
622         cli();
623         globalwinon(ch);
624         head = bc->tin & (size - 1);
625         tail = bc->tout;
626         if (tail != bc->tout)
627                 tail = bc->tout;
628         tail &= (size - 1);
629         if (head >= tail) {
630                 remain = size - (head - tail) - 1;
631                 stlen = size - head;
632         }
633         else {
634                 remain = tail - head - 1;
635                 stlen = remain;
636         }
637         count = min(remain, count);
638
639         txwinon(ch);
640         while (count > 0) {
641                 stlen = min(count, stlen);
642                 memcpy(ch->txptr + head, buf, stlen);
643                 buf += stlen;
644                 count -= stlen;
645                 total += stlen;
646                 head += stlen;
647                 if (head >= size) {
648                         head = 0;
649                         stlen = tail;
650                 }
651         }
652         ch->statusflags |= TXBUSY;
653         globalwinon(ch);
654         bc->tin = head;
655         if ((ch->statusflags & LOWWAIT) == 0) {
656                 ch->statusflags |= LOWWAIT;
657                 bc->ilow = 1;
658         }
659         memoff(ch);
660         restore_flags(flags);
661         
662         if(from_user)
663                 up(&ch->tmp_buf_sem);
664
665         return(total);
666 }
667
668
669 static void pcxe_put_char(struct tty_struct *tty, unsigned char c)
670 {
671         pcxe_write(tty, 0, &c, 1);
672         return;
673 }
674
675
676 static int pcxe_write_room(struct tty_struct *tty)
677 {
678         struct channel *ch;
679         int remain;
680
681         remain = 0;
682         if ((ch=chan(tty))!=NULL) {
683                 volatile struct board_chan *bc;
684                 unsigned int head, tail;
685                 unsigned long flags;
686
687                 save_flags(flags);
688                 cli();
689                 globalwinon(ch);
690
691                 bc = ch->brdchan;
692                 head = bc->tin & (ch->txbufsize - 1);
693                 tail = bc->tout;
694                 if (tail != bc->tout)
695                         tail = bc->tout;
696                 tail &= (ch->txbufsize - 1);
697
698                 if((remain = tail - head - 1) < 0 )
699                         remain += ch->txbufsize;
700
701                 if (remain && (ch->statusflags & LOWWAIT) == 0) {
702                         ch->statusflags |= LOWWAIT;
703                         bc->ilow = 1;
704                 }
705                 memoff(ch);
706                 restore_flags(flags);
707         }
708
709         return remain;
710 }
711
712
713 static int pcxe_chars_in_buffer(struct tty_struct *tty)
714 {
715         int chars;
716         unsigned int ctail, head, tail;
717         int remain;
718         unsigned long flags;
719         struct channel *ch;
720         volatile struct board_chan *bc;
721
722         if ((ch=chan(tty))==NULL)
723                 return(0);
724
725         save_flags(flags);
726         cli();
727         globalwinon(ch);
728
729         bc = ch->brdchan;
730         tail = bc->tout;
731         head = bc->tin;
732         ctail = ch->mailbox->cout;
733         if(tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
734                 chars = 0;
735         else {
736                 head = bc->tin & (ch->txbufsize - 1);
737                 tail &= (ch->txbufsize - 1);
738                 if((remain = tail - head - 1) < 0 )
739                         remain += ch->txbufsize;
740
741                 chars = (int)(ch->txbufsize - remain);
742
743                 /* 
744                  * Make it possible to wakeup anything waiting for output
745                  * in tty_ioctl.c, etc.
746                  */
747                 if(!(ch->statusflags & EMPTYWAIT))
748                         setup_empty_event(tty,ch);
749         }
750
751         memoff(ch);
752         restore_flags(flags);
753
754         return(chars);
755 }
756
757
758 static void pcxe_flush_buffer(struct tty_struct *tty)
759 {
760         unsigned int tail;
761         volatile struct board_chan *bc;
762         struct channel *ch;
763         unsigned long flags;
764
765         if ((ch=chan(tty))==NULL)
766                 return;
767
768         save_flags(flags);
769         cli();
770
771         globalwinon(ch);
772         bc = ch->brdchan;
773         tail = bc->tout;
774         fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
775
776         memoff(ch);
777         restore_flags(flags);
778
779         tty_wakeup(tty);
780 }
781
782 static void pcxe_flush_chars(struct tty_struct *tty)
783 {
784         struct channel * ch;
785
786         if ((ch=chan(tty))!=NULL) {
787                 unsigned long flags;
788
789                 save_flags(flags);
790                 cli();
791                 if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
792                         setup_empty_event(tty,ch);
793                 restore_flags(flags);
794         }
795 }
796
797 #ifndef MODULE
798
799 /*
800  * Driver setup function when linked into the kernel to optionally parse multible
801  * "digi="-lines and initialize the driver at boot time. No probing.
802  */
803 void __init pcxx_setup(char *str, int *ints)
804 {
805
806         struct board_info board;
807         int               i, j, last;
808         char              *temp, *t2;
809         unsigned          len;
810
811         numcards=0;
812
813         memset(&board, 0, sizeof(board));
814
815         for(last=0,i=1;i<=ints[0];i++)
816                 switch(i)
817                 {
818                         case 1:
819                                 board.status = ints[i];
820                                 last = i;
821                                 break;
822
823                         case 2:
824                                 board.type = ints[i];
825                                 last = i;
826                                 break;
827
828                         case 3:
829                                 board.altpin = ints[i];
830                                 last = i;
831                                 break;
832
833                         case 4:
834                                 board.numports = ints[i];
835                                 last = i;
836                                 break;
837
838                         case 5:
839                                 board.port = ints[i];
840                                 last = i;
841                                 break;
842
843                         case 6:
844                                 board.membase = ints[i];
845                                 last = i;
846                                 break;
847
848                         default:
849                                 printk("PC/Xx: Too many integer parms\n");
850                                 return;
851                 }
852
853         while (str && *str) 
854         {
855                 /* find the next comma or terminator */
856                 temp = str;
857                 while (*temp && (*temp != ','))
858                         temp++;
859
860                 if (!*temp)
861                         temp = NULL;
862                 else
863                         *temp++ = 0;
864
865                 i = last + 1;
866
867                 switch(i)
868                 {
869                         case 1:
870                                 len = strlen(str);
871                                 if (strncmp("Disable", str, len) == 0) 
872                                         board.status = 0;
873                                 else
874                                         if (strncmp("Enable", str, len) == 0)
875                                                 board.status = 1;
876                                         else
877                                         {
878                                                 printk("PC/Xx: Invalid status %s\n", str);
879                                                 return;
880                                         }
881                                 last = i;
882                                 break;
883
884                         case 2:
885                                 for(j=0;j<PCXX_NUM_TYPES;j++)
886                                         if (strcmp(board_desc[j], str) == 0)
887                                                 break;
888
889                                 if (i<PCXX_NUM_TYPES) 
890                                         board.type = j;
891                                 else
892                                 {
893                                         printk("PC/Xx: Invalid board name: %s\n", str);
894                                         return;
895                                 }
896                                 last = i;
897                                 break;
898
899                         case 3:
900                                 len = strlen(str);
901                                 if (strncmp("Disable", str, len) == 0) 
902                                         board.altpin = 0;
903                                 else
904                                         if (strncmp("Enable", str, len) == 0)
905                                                 board.altpin = 1;
906                                         else
907                                         {
908                                                 printk("PC/Xx: Invalid altpin %s\n", str);
909                                                 return;
910                                         }
911                                 last = i;
912                                 break;
913
914                         case 4:
915                                 t2 = str;
916                                 while (isdigit(*t2))
917                                         t2++;
918
919                                 if (*t2)
920                                 {
921                                         printk("PC/Xx: Invalid port count %s\n", str);
922                                         return;
923                                 }
924
925                                 board.numports = simple_strtoul(str, NULL, 0);
926                                 last = i;
927                                 break;
928
929                         case 5:
930                                 t2 = str;
931                                 while (isxdigit(*t2))
932                                         t2++;
933
934                                 if (*t2)
935                                 {
936                                         printk("PC/Xx: Invalid io port address %s\n", str);
937                                         return;
938                                 }
939
940                                 board.port = simple_strtoul(str, NULL, 16);
941                                 last = i;
942                                 break;
943
944                         case 6:
945                                 t2 = str;
946                                 while (isxdigit(*t2))
947                                         t2++;
948
949                                 if (*t2)
950                                 {
951                                         printk("PC/Xx: Invalid memory base %s\n", str);
952                                         return;
953                                 }
954
955                                 board.membase = simple_strtoul(str, NULL, 16);
956                                 last = i;
957                                 break;
958
959                         default:
960                                 printk("PC/Xx: Too many string parms\n");
961                                 return;
962                 }
963                 str = temp;
964         }
965
966         if (last < 6)  
967         {
968                 printk("PC/Xx: Insufficient parms specified\n");
969                 return;
970         }
971  
972         /* I should REALLY validate the stuff here */
973
974         memcpy(&boards[numcards],&board, sizeof(board));
975         printk("PC/Xx: Added board %i, %s %s %i ports at 0x%4.4X base 0x%6.6X\n", 
976                 numcards, board_desc[board.type], board_mem[board.type], 
977                 board.numports, board.port, (unsigned int) board.membase);
978
979         /* keep track of my initial minor number */
980         if (numcards)
981                 boards[numcards].first_minor = boards[numcards-1].first_minor + boards[numcards-1].numports;
982         else
983                 boards[numcards].first_minor = 0;
984
985         /* yeha!  string parameter was successful! */
986         numcards++;
987 }
988 #endif
989
990 static struct tty_operations pcxe_ops = {
991         .open = pcxe_open,
992         .close = pcxe_close,
993         .write = pcxe_write,
994         .put_char = pcxe_put_char,
995         .flush_chars = pcxe_flush_chars,
996         .write_room = pcxe_write_room,
997         .chars_in_buffer = pcxe_chars_in_buffer,
998         .flush_buffer = pcxe_flush_buffer,
999         .ioctl = pcxe_ioctl,
1000         .throttle = pcxe_throttle,
1001         .unthrottle = pcxe_unthrottle,
1002         .set_termios = pcxe_set_termios,
1003         .stop = pcxe_stop,
1004         .start = pcxe_start,
1005         .hangup = pcxe_hangup,
1006         .tiocmget = pcxe_tiocmget,
1007         .tiocmset = pcxe_tiocmset,
1008 };
1009
1010 /*
1011  * function to initialize the driver with the given parameters, which are either
1012  * the default values from this file or the parameters given at boot.
1013  */
1014 static int __init pcxe_init(void)
1015 {
1016         ulong memory_seg=0, memory_size=0;
1017         int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
1018         int ret = -ENOMEM;
1019         unchar *fepos, *memaddr, *bios, v;
1020         volatile struct global_data *gd;
1021         volatile struct board_chan *bc;
1022         struct board_info *bd;
1023         struct channel *ch;
1024
1025         printk(KERN_NOTICE "Digiboard PC/X{i,e,eve} driver v%s\n", VERSION);
1026
1027 #ifdef MODULE
1028         for (i = 0; i < MAX_DIGI_BOARDS; i++) {
1029                 if (io[i]) {
1030                         numcards = 0;
1031                         break;
1032                 }
1033         }
1034         if (numcards == 0) {
1035                 int first_minor = 0;
1036
1037                 for (i = 0; i < MAX_DIGI_BOARDS; i++) {
1038                         if (io[i] == 0) {
1039                                 boards[i].port    = 0;
1040                                 boards[i].status  = DISABLED;
1041                         }
1042                         else {
1043                                 boards[i].port         = (ushort)io[i];
1044                                 boards[i].status       = ENABLED;
1045                                 boards[i].first_minor  = first_minor;
1046                                 numcards=i+1;
1047                         }
1048                         if (membase[i])
1049                                 boards[i].membase = (ulong)membase[i];
1050                         else
1051                                 boards[i].membase = 0xD0000;
1052
1053                         if (memsize[i])
1054                                 boards[i].memsize = (ulong)(memsize[i] * 1024);
1055                         else
1056                                 boards[i].memsize = 0;
1057
1058                         if (altpin[i])
1059                                 boards[i].altpin  = ON;
1060                         else
1061                                 boards[i].altpin  = OFF;
1062
1063                         if (numports[i])
1064                                 boards[i].numports  = (ushort)numports[i];
1065                         else
1066                                 boards[i].numports  = 16;
1067
1068                         boards[i].region = NULL;
1069                         first_minor += boards[i].numports;
1070                 }
1071         }
1072 #endif
1073
1074         if (numcards <= 0)
1075         {
1076                 printk("PC/Xx: No cards configured, driver not active.\n");
1077                 return -EIO;
1078         }
1079 #if 1
1080         if (debug)
1081             for (i = 0; i < numcards; i++) {
1082                     printk("Card %d:status=%d, port=0x%x, membase=0x%lx, memsize=0x%lx, altpin=%d, numports=%d, first_minor=%d\n",
1083                             i+1,
1084                             boards[i].status,
1085                             boards[i].port,
1086                             boards[i].membase,
1087                             boards[i].memsize,
1088                             boards[i].altpin,
1089                             boards[i].numports,
1090                             boards[i].first_minor);
1091             }
1092 #endif
1093
1094         for (i=0;i<numcards;i++)
1095                 nbdevs += boards[i].numports;
1096
1097         if (nbdevs <= 0)
1098         {
1099                 printk("PC/Xx: No devices activated, driver not active.\n");
1100                 return -EIO;
1101         }
1102
1103         pcxe_driver = alloc_tty_driver(nbdevs);
1104         if (!pcxe_driver)
1105                 return -ENOMEM;
1106
1107         /*
1108          * this turns out to be more memory efficient, as there are no 
1109          * unused spaces.
1110          */
1111         digi_channels = kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL);
1112         if (!digi_channels) {
1113                 printk(KERN_ERR "Unable to allocate digi_channel struct\n");
1114                 put_tty_driver(pcxe_driver);
1115                 return -ENOMEM;
1116         }
1117         memset(digi_channels, 0, sizeof(struct channel) * nbdevs);
1118
1119         init_timer(&pcxx_timer);
1120         pcxx_timer.function = pcxxpoll;
1121
1122         pcxe_driver->owner = THIS_MODULE;
1123         pcxe_driver->name = "ttyD";
1124         pcxe_driver->devfs_name = "pcxe/";
1125         pcxe_driver->major = DIGI_MAJOR; 
1126         pcxe_driver->minor_start = 0;
1127         pcxe_driver->type = TTY_DRIVER_TYPE_SERIAL;
1128         pcxe_driver->subtype = SERIAL_TYPE_NORMAL;
1129         pcxe_driver->init_termios = tty_std_termios;
1130         pcxe_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
1131         pcxe_driver->flags = TTY_DRIVER_REAL_RAW;
1132         tty_set_operations(pcxe_driver, &pcxe_ops);
1133
1134         for(crd=0; crd < numcards; crd++) {
1135                 bd = &boards[crd];
1136                 outb(FEPRST, bd->port);
1137                 mdelay(1);
1138
1139                 for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
1140                         if(i > 100) {
1141                                 printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n",
1142                                         bd->port);
1143                                 bd->status = DISABLED;
1144                                 break;
1145                         }
1146 #ifdef MODULE
1147                         schedule();
1148 #endif
1149                         mdelay(10);
1150                 }
1151                 if(bd->status == DISABLED)
1152                         continue;
1153
1154                 v = inb(bd->port);
1155
1156                 if((v & 0x1) == 0x1) {
1157                         if((v & 0x30) == 0) {        /* PC/Xi 64K card */
1158                                 memory_seg = 0xf000;
1159                                 memory_size = 0x10000;
1160                         } 
1161
1162                         if((v & 0x30) == 0x10) {     /* PC/Xi 128K card */
1163                                 memory_seg = 0xe000;
1164                                 memory_size = 0x20000;
1165                         }
1166                         
1167                         if((v & 0x30) == 0x20) {     /* PC/Xi 256K card */
1168                                 memory_seg = 0xc000;
1169                                 memory_size = 0x40000;
1170                         }
1171
1172                         if((v & 0x30) == 0x30) {     /* PC/Xi 512K card */
1173                                 memory_seg = 0x8000;
1174                                 memory_size = 0x80000;
1175                         }
1176                         bd->type = PCXI;
1177                 } else {
1178                         if((v & 0x1) == 0x1) {
1179                                 bd->status = DISABLED;   /* PC/Xm unsupported card */
1180                                 printk("PC/Xx: PC/Xm at 0x%x not supported!!\n", bd->port);
1181                                 continue;
1182                         } else {
1183                                 if(v & 0xC0) {    
1184                                         topwin = 0x1f00L;
1185                                         outb((((ulong)bd->membase>>8) & 0xe0) | 0x10, bd->port+2);
1186                                         outb(((ulong)bd->membase>>16) & 0xff, bd->port+3);
1187                                         bd->type = PCXEVE; /* PC/Xe 8K card */
1188                                 } else { 
1189                                         bd->type = PCXE;    /* PC/Xe 64K card */
1190                                 }
1191                                         
1192                                 memory_seg = 0xf000;
1193                                 memory_size = 0x10000;
1194                         }
1195                 }
1196                 if (verbose)
1197                         printk("Configuring card %d as a %s %ldK card. io=0x%x, mem=%lx-%lx\n",
1198                                 crd+1, board_desc[bd->type], memory_size/1024,
1199                                 bd->port,bd->membase,bd->membase+memory_size-1);
1200
1201                 if (boards[crd].memsize == 0)
1202                         boards[crd].memsize = memory_size;
1203                 else
1204                         if (boards[crd].memsize != memory_size) {
1205                             printk("PC/Xx: memory size mismatch:supplied=%lx(%ldK) probed=%ld(%ldK)\n",
1206                                     boards[crd].memsize, boards[crd].memsize / 1024,
1207                                     memory_size, memory_size / 1024);
1208                             continue;
1209                         }
1210
1211                 memaddr = (unchar *)phys_to_virt(bd->membase);
1212
1213                 if (verbose)
1214                         printk("Resetting board and testing memory access:");
1215
1216                 outb(FEPRST|FEPMEM, bd->port);
1217
1218                 for(i=0; (inb(bd->port) & FEPMASK) != (FEPRST|FEPMEM); i++) {
1219                         if(i > 1000) {
1220                                 printk("\nPC/Xx: %s not resetting at port 0x%x! Check switch settings.\n",
1221                                         board_desc[bd->type], bd->port);
1222                                 bd->status = DISABLED;
1223                                 break;
1224                         }
1225 #ifdef MODULE
1226                         schedule();
1227 #endif
1228                         mdelay(1);
1229                 }
1230                 if(bd->status == DISABLED)
1231                         continue;
1232
1233                 memwinon(bd,0);
1234                 *(ulong *)(memaddr + botwin) = 0xa55a3cc3;
1235                 *(ulong *)(memaddr + topwin) = 0x5aa5c33c;
1236
1237                 if(*(ulong *)(memaddr + botwin) != 0xa55a3cc3 ||
1238                                         *(ulong *)(memaddr + topwin) != 0x5aa5c33c) {
1239                         printk("PC/Xx: Failed memory test at %lx for %s at port %x, check switch settings.\n",
1240                                 bd->membase, board_desc[bd->type], bd->port);
1241                         bd->status = DISABLED;
1242                         continue;
1243                 }
1244                 if (verbose)
1245                         printk(" done.\n");
1246
1247                 for(i=0; i < 16; i++) {
1248                         memaddr[MISCGLOBAL+i] = 0;
1249                 }
1250
1251                 if(bd->type == PCXI || bd->type == PCXE) {
1252                         bios = memaddr + BIOSCODE + ((0xf000 - memory_seg) << 4);
1253
1254                         if (verbose)
1255                                 printk("Downloading BIOS to 0x%lx:", virt_to_phys(bios));
1256
1257                         memcpy(bios, pcxx_bios, pcxx_nbios);
1258
1259                         if (verbose)
1260                                 printk(" done.\n");
1261
1262                         outb(FEPMEM, bd->port);
1263
1264                         if (verbose)
1265                                 printk("Waiting for BIOS to become ready");
1266
1267                         for(i=1; i <= 30; i++) {
1268                                 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
1269                                         goto load_fep;
1270                                 }
1271                                 if (verbose) {
1272                                         printk(".");
1273                                         if (i % 50 == 0)
1274                                                 printk("\n");
1275                                 }
1276 #ifdef MODULE
1277                                 schedule();
1278 #endif
1279                                 mdelay(50);
1280                         }
1281
1282                         printk("\nPC/Xx: BIOS download failed for board at 0x%x(addr=%lx-%lx)!\n",
1283                                                         bd->port, bd->membase, bd->membase+bd->memsize);
1284                         bd->status = DISABLED;
1285                         continue;
1286                 }
1287
1288                 if(bd->type == PCXEVE) {
1289                         bios = memaddr + (BIOSCODE & 0x1fff);
1290                         memwinon(bd,0xff);
1291                         
1292                         memcpy(bios, pcxx_bios, pcxx_nbios);
1293
1294                         outb(FEPCLR, bd->port);
1295                         memwinon(bd,0);
1296
1297                         for(i=0; i <= 1000; i++) {
1298                                 if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
1299                                         goto load_fep;
1300                                 }
1301                                 if (verbose) {
1302                                         printk(".");
1303                                         if (i % 50 == 0)
1304                                                 printk("\n");
1305                                 }
1306 #ifdef MODULE
1307                                 schedule();
1308 #endif
1309                                 mdelay(10);
1310                         }
1311
1312                         printk("\nPC/Xx: BIOS download failed on the %s at 0x%x!\n",
1313                                 board_desc[bd->type], bd->port);
1314                         bd->status = DISABLED;
1315                         continue;
1316                 }
1317
1318 load_fep:
1319                 fepos = memaddr + FEPCODE;
1320                 if(bd->type == PCXEVE)
1321                         fepos = memaddr + (FEPCODE & 0x1fff);
1322
1323                 if (verbose)
1324                         printk(" ok.\nDownloading FEP/OS to 0x%lx:", virt_to_phys(fepos));
1325
1326                 memwinon(bd, (FEPCODE >> 13));
1327                 memcpy(fepos, pcxx_cook, pcxx_ncook);
1328                 memwinon(bd, 0);
1329
1330                 if (verbose)
1331                         printk(" done.\n");
1332
1333                 *(ushort *)((ulong)memaddr + MBOX +  0) = 2;
1334                 *(ushort *)((ulong)memaddr + MBOX +  2) = memory_seg + FEPCODESEG;
1335                 *(ushort *)((ulong)memaddr + MBOX +  4) = 0;
1336                 *(ushort *)((ulong)memaddr + MBOX +  6) = FEPCODESEG;
1337                 *(ushort *)((ulong)memaddr + MBOX +  8) = 0;
1338                 *(ushort *)((ulong)memaddr + MBOX + 10) = pcxx_ncook;
1339
1340                 outb(FEPMEM|FEPINT, bd->port);
1341                 outb(FEPMEM, bd->port);
1342
1343                 for(i=0; *(ushort *)((ulong)memaddr + MBOX); i++) {
1344                         if(i > 2000) {
1345                                 printk("PC/Xx: Command failed for the %s at 0x%x!\n",
1346                                         board_desc[bd->type], bd->port);
1347                                 bd->status = DISABLED;
1348                                 break;
1349                         }
1350 #ifdef MODULE
1351                         schedule();
1352 #endif
1353                         mdelay(1);
1354                 }
1355
1356                 if(bd->status == DISABLED)
1357                         continue;
1358
1359                 if (verbose)
1360                         printk("Waiting for FEP/OS to become ready");
1361
1362                 *(ushort *)(memaddr + FEPSTAT) = 0;
1363                 *(ushort *)(memaddr + MBOX + 0) = 1;
1364                 *(ushort *)(memaddr + MBOX + 2) = FEPCODESEG;
1365                 *(ushort *)(memaddr + MBOX + 4) = 0x4L;
1366
1367                 outb(FEPINT, bd->port);
1368                 outb(FEPCLR, bd->port);
1369                 memwinon(bd, 0);
1370
1371                 for(i=1; *(ushort *)((ulong)memaddr + FEPSTAT) != *(ushort *)"OS"; i++) {
1372                         if(i > 1000) {
1373                                 printk("\nPC/Xx: FEP/OS download failed on the %s at 0x%x!\n",
1374                                         board_desc[bd->type], bd->port);
1375                                 bd->status = DISABLED;
1376                                 break;
1377                         }
1378                         if (verbose) {
1379                                 printk(".");
1380                                 if (i % 50 == 0)
1381                                         printk("\n%5d",i/50);
1382                         }
1383 #ifdef MODULE
1384                         schedule();
1385 #endif
1386                         mdelay(1);
1387                 }
1388                 if(bd->status == DISABLED)
1389                         continue;
1390
1391                 if (verbose)
1392                         printk(" ok.\n");
1393
1394                 ch = digi_channels+bd->first_minor;
1395                 pcxxassert(ch < digi_channels+nbdevs, "ch out of range");
1396
1397                 bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
1398                 gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
1399
1400                 if((bd->type == PCXEVE) && (*(ushort *)((ulong)memaddr+NPORT) < 3))
1401                         shrinkmem = 1;
1402
1403                 bd->region = request_region(bd->port, 4, "PC/Xx");
1404
1405                 if (!bd->region) {
1406                         printk(KERN_ERR "I/O port 0x%x is already used\n", bd->port);
1407                         ret = -EBUSY;
1408                         goto cleanup_boards;
1409                 }
1410
1411                 for(i=0; i < bd->numports; i++, ch++, bc++) {
1412                         if(((ushort *)((ulong)memaddr + PORTBASE))[i] == 0) {
1413                                 ch->brdchan = 0;
1414                                 continue;
1415                         }
1416                         ch->brdchan = bc;
1417                         ch->mailbox = gd;
1418                         INIT_WORK(&ch->tqueue, do_softint, ch);
1419                         ch->board = &boards[crd];
1420 #ifdef DEFAULT_HW_FLOW
1421                         ch->digiext.digi_flags = RTSPACE|CTSPACE;
1422 #endif
1423                         if(boards[crd].altpin) {
1424                                 ch->dsr = CD;
1425                                 ch->dcd = DSR;
1426                                 ch->digiext.digi_flags |= DIGI_ALTPIN;
1427                         } else { 
1428                                 ch->dcd = CD;
1429                                 ch->dsr = DSR;
1430                         }
1431
1432                         ch->magic = PCXX_MAGIC;
1433                         ch->boardnum = crd;
1434                         ch->channelnum = i;
1435
1436                         ch->dev = bd->first_minor + i;
1437                         ch->tty = 0;
1438
1439                         if(shrinkmem) {
1440                                 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1441                                 shrinkmem = 0;
1442                         }
1443                         
1444                         if(bd->type != PCXEVE) {
1445                                 ch->txptr = memaddr+((bc->tseg-memory_seg) << 4);
1446                                 ch->rxptr = memaddr+((bc->rseg-memory_seg) << 4);
1447                                 ch->txwin = ch->rxwin = 0;
1448                         } else {
1449                                 ch->txptr = memaddr+(((bc->tseg-memory_seg) << 4) & 0x1fff);
1450                                 ch->txwin = FEPWIN | ((bc->tseg-memory_seg) >> 9);
1451                                 ch->rxptr = memaddr+(((bc->rseg-memory_seg) << 4) & 0x1fff);
1452                                 ch->rxwin = FEPWIN | ((bc->rseg-memory_seg) >>9 );
1453                         }
1454
1455                         ch->txbufsize = bc->tmax + 1;
1456                         ch->rxbufsize = bc->rmax + 1;
1457                         ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
1458                         init_MUTEX(&ch->tmp_buf_sem);
1459
1460                         if (!ch->tmp_buf) {
1461                                 printk(KERN_ERR "Unable to allocate memory for temp buffers\n");
1462                                 goto cleanup_boards;
1463                         }
1464
1465                         lowwater = ch->txbufsize >= 2000 ? 1024 : ch->txbufsize/2;
1466                         fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1467                         fepcmd(ch, SRXLWATER, ch->rxbufsize/4, 0, 10, 0);
1468                         fepcmd(ch, SRXHWATER, 3 * ch->rxbufsize/4, 0, 10, 0);
1469
1470                         bc->edelay = 100;
1471                         bc->idata = 1;
1472
1473                         ch->startc = bc->startc;
1474                         ch->stopc = bc->stopc;
1475                         ch->startca = bc->startca;
1476                         ch->stopca = bc->stopca;
1477
1478                         ch->fepcflag = 0;
1479                         ch->fepiflag = 0;
1480                         ch->fepoflag = 0;
1481                         ch->fepstartc = 0;
1482                         ch->fepstopc = 0;
1483                         ch->fepstartca = 0;
1484                         ch->fepstopca = 0;
1485
1486                         ch->close_delay = 50;
1487                         ch->count = 0;
1488                         ch->blocked_open = 0;
1489                         init_waitqueue_head(&ch->open_wait);
1490                         init_waitqueue_head(&ch->close_wait);
1491                         ch->asyncflags = 0;
1492                 }
1493
1494                 if (verbose)
1495                     printk("Card No. %d ready: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n", 
1496                             crd+1, board_desc[bd->type], board_mem[bd->type], bd->port, 
1497                             bd->membase, bd->numports);
1498                 else
1499                     printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n", 
1500                             board_desc[bd->type], board_mem[bd->type], bd->port, 
1501                             bd->membase, bd->numports);
1502
1503                 memwinoff(bd, 0);
1504                 enabled_cards++;
1505         }
1506
1507         if (enabled_cards <= 0) {
1508                 printk(KERN_NOTICE "PC/Xx: No cards enabled, no driver.\n");
1509                 ret = -EIO;
1510                 goto cleanup_boards;
1511         }
1512
1513         ret = tty_register_driver(pcxe_driver);
1514         if(ret) {
1515                 printk(KERN_ERR "Couldn't register PC/Xe driver\n");
1516                 goto cleanup_boards;
1517         }
1518
1519         /*
1520          * Start up the poller to check for events on all enabled boards
1521          */
1522         mod_timer(&pcxx_timer, HZ/25);
1523
1524         if (verbose)
1525                 printk(KERN_NOTICE "PC/Xx: Driver with %d card(s) ready.\n", enabled_cards);
1526
1527         return 0;
1528 cleanup_boards:
1529         cleanup_board_resources();
1530         kfree(digi_channels);
1531         put_tty_driver(pcxe_driver);
1532         return ret;
1533 }
1534
1535 module_init(pcxe_init)
1536 module_exit(pcxe_cleanup)
1537
1538 static void pcxxpoll(unsigned long dummy)
1539 {
1540         unsigned long flags;
1541         int crd;
1542         volatile unsigned int head, tail;
1543         struct channel *ch;
1544         struct board_info *bd;
1545
1546         save_flags(flags);
1547         cli();
1548
1549         for(crd=0; crd < numcards; crd++) {
1550                 bd = &boards[crd];
1551
1552                 ch = digi_channels+bd->first_minor;
1553
1554                 if(bd->status == DISABLED)
1555                         continue;
1556
1557                 assertmemoff(ch);
1558
1559                 globalwinon(ch);
1560                 head = ch->mailbox->ein;
1561                 tail = ch->mailbox->eout;
1562
1563                 if(head != tail)
1564                         doevent(crd);
1565
1566                 memoff(ch);
1567         }
1568
1569         mod_timer(&pcxx_timer, jiffies + HZ/25);
1570         restore_flags(flags);
1571 }
1572
1573 static void doevent(int crd)
1574 {
1575         volatile struct board_info *bd;
1576         static struct tty_struct *tty;
1577         volatile struct board_chan *bc;
1578         volatile unchar *eventbuf;
1579         volatile unsigned int head;
1580         volatile unsigned int tail;
1581         struct channel *ch;
1582         struct channel *chan0;
1583         int channel, event, mstat, lstat;
1584
1585         bd = &boards[crd];
1586
1587         chan0 = digi_channels+bd->first_minor;
1588         pcxxassert(chan0 < digi_channels+nbdevs, "ch out of range");
1589
1590
1591         assertgwinon(chan0);
1592
1593         while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) {
1594                 assertgwinon(chan0);
1595                 eventbuf = (volatile unchar *)phys_to_virt(bd->membase + tail + ISTART);
1596                 channel = eventbuf[0];
1597                 event = eventbuf[1];
1598                 mstat = eventbuf[2];
1599                 lstat = eventbuf[3];
1600
1601                 ch=chan0+channel;
1602
1603                 if ((unsigned)channel >= bd->numports || !ch) { 
1604                         printk("physmem=%lx, tail=%x, head=%x\n", bd->membase, tail, head);
1605                         printk("doevent(%x) channel %x, event %x, mstat %x, lstat %x\n",
1606                                         crd, (unsigned)channel, event, (unsigned)mstat, lstat);
1607                         if(channel >= bd->numports)
1608                                 ch = chan0;
1609                         bc = ch->brdchan;
1610                         goto next;
1611                 }
1612                 if ((bc = ch->brdchan) == NULL)
1613                         goto next;
1614
1615                 if (event & DATA_IND) {
1616                         receive_data(ch);
1617                         assertgwinon(ch);
1618                 }
1619
1620                 if (event & MODEMCHG_IND) {
1621                         ch->imodem = mstat;
1622                         if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) {
1623                                 if (ch->asyncflags & ASYNC_CHECK_CD) {
1624                                         if (mstat & ch->dcd) {
1625                                                 wake_up_interruptible(&ch->open_wait);
1626                                         } else {
1627                                                 pcxe_sched_event(ch, PCXE_EVENT_HANGUP);
1628                                         }
1629                                 }
1630                         }
1631                 }
1632
1633                 tty = ch->tty;
1634
1635                 if (tty) {
1636
1637                         if (event & BREAK_IND) {
1638                                 tty->flip.count++;
1639                                 *tty->flip.flag_buf_ptr++ = TTY_BREAK;
1640                                 *tty->flip.char_buf_ptr++ = 0;
1641 #if 0
1642                                 if (ch->asyncflags & ASYNC_SAK)
1643                                         do_SAK(tty);
1644 #endif
1645                                 tty_schedule_flip(tty); 
1646                         }
1647
1648                         if (event & LOWTX_IND) {
1649                                 if (ch->statusflags & LOWWAIT) {
1650                                         ch->statusflags &= ~LOWWAIT;
1651                                         tty_wakeup(tty);
1652                                 }
1653                         }
1654
1655                         if (event & EMPTYTX_IND) {
1656                                 ch->statusflags &= ~TXBUSY;
1657                                 if (ch->statusflags & EMPTYWAIT) {
1658                                         ch->statusflags &= ~EMPTYWAIT;
1659                                         tty_wakeup(tty);
1660                                 }
1661                         }
1662                 }
1663
1664         next:
1665                 globalwinon(ch);
1666                 if(!bc) printk("bc == NULL in doevent!\n");
1667                 else bc->idata = 1;
1668
1669                 chan0->mailbox->eout = (tail+4) & (IMAX-ISTART-4);
1670                 globalwinon(chan0);
1671         }
1672
1673 }
1674
1675
1676 static void 
1677 fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
1678                                                 int bytecmd)
1679 {
1680         unchar *memaddr;
1681         unsigned int head, tail;
1682         long count;
1683         int n;
1684
1685         if(ch->board->status == DISABLED)
1686                 return;
1687
1688         assertgwinon(ch);
1689
1690         memaddr = (unchar *)phys_to_virt(ch->board->membase);
1691         head = ch->mailbox->cin;
1692
1693         if(head >= (CMAX-CSTART) || (head & 03)) {
1694                 printk("line %d: Out of range, cmd=%x, head=%x\n", __LINE__, cmd, head);
1695                 return;
1696         }
1697
1698         if(bytecmd) {
1699                 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1700
1701                 *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
1702
1703                 *(unchar *)(memaddr+head+CSTART+2) = word_or_byte;
1704                 *(unchar *)(memaddr+head+CSTART+3) = byte2;
1705         } else {
1706                 *(unchar *)(memaddr+head+CSTART+0) = cmd;
1707
1708                 *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
1709                 *(ushort*)(memaddr+head+CSTART+2) = word_or_byte;
1710         }
1711
1712         head = (head+4) & (CMAX-CSTART-4);
1713         ch->mailbox->cin = head;
1714
1715         count = FEPTIMEOUT;
1716
1717         while(1) {
1718                 count--;
1719                 if(count == 0) {
1720                         printk("Fep not responding in fepcmd()\n");
1721                         return;
1722                 }
1723
1724                 head = ch->mailbox->cin;
1725                 tail = ch->mailbox->cout;
1726
1727                 n = (head-tail) & (CMAX-CSTART-4);
1728
1729                 if(n <= ncmds * (sizeof(short)*4))
1730                         break;
1731                 /* Seems not to be good here: schedule(); */
1732         }
1733 }
1734
1735
1736 static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
1737 {
1738         unsigned res = 0;
1739         if (cflag & CBAUDEX)
1740         {
1741                 ch->digiext.digi_flags |= DIGI_FAST;
1742                 res |= FEP_HUPCL;
1743                 /* This gets strange but if we don't do this we will get 78600
1744                  * instead of 115200. 57600 is mapped to 50 baud yielding 57600 in
1745                  * FAST mode. 115200 is mapped to 75. We need to map it to 110 to
1746                  * do 115K
1747                  */
1748                 if (cflag & B115200) res|=1;
1749         }
1750         else ch->digiext.digi_flags &= ~DIGI_FAST;
1751         res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE | CLOCAL);
1752         return res;
1753 }
1754
1755 static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
1756 {
1757         unsigned res = iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|IXON|IXANY|IXOFF);
1758         
1759         if(ch->digiext.digi_flags & DIGI_AIXON)
1760                 res |= IAIXON;
1761         return res;
1762 }
1763
1764 static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
1765 {
1766         unsigned res = 0;
1767
1768         if(cflag & CRTSCTS) {
1769                 ch->digiext.digi_flags |= (RTSPACE|CTSPACE);
1770                 res |= (CTS | RTS);
1771         }
1772         if(ch->digiext.digi_flags & RTSPACE)
1773                 res |= RTS;
1774         if(ch->digiext.digi_flags & DTRPACE)
1775                 res |= DTR;
1776         if(ch->digiext.digi_flags & CTSPACE)
1777                 res |= CTS;
1778         if(ch->digiext.digi_flags & DSRPACE)
1779                 res |= ch->dsr;
1780         if(ch->digiext.digi_flags & DCDPACE)
1781                 res |= ch->dcd;
1782
1783         if (res & RTS)
1784                 ch->digiext.digi_flags |= RTSPACE;
1785         if (res & CTS)
1786                 ch->digiext.digi_flags |= CTSPACE;
1787
1788         return res;
1789 }
1790
1791 static void pcxxparam(struct tty_struct *tty, struct channel *ch)
1792 {
1793         volatile struct board_chan *bc;
1794         unsigned int head;
1795         unsigned mval, hflow, cflag, iflag;
1796         struct termios *ts;
1797
1798         bc = ch->brdchan;
1799         assertgwinon(ch);
1800         ts = tty->termios;
1801
1802         if((ts->c_cflag & CBAUD) == 0) {
1803                 head = bc->rin;
1804                 bc->rout = head;
1805                 head = bc->tin;
1806                 fepcmd(ch, STOUT, (unsigned) head, 0, 0, 0);
1807                 mval = 0;
1808         } else {
1809
1810                 cflag = termios2digi_c(ch, ts->c_cflag);
1811
1812                 if(cflag != ch->fepcflag) {
1813                         ch->fepcflag = cflag;
1814                         fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1815                 }
1816
1817                 if(cflag & CLOCAL)
1818                         ch->asyncflags &= ~ASYNC_CHECK_CD;
1819                 else {
1820                         ch->asyncflags |= ASYNC_CHECK_CD;
1821                 }
1822
1823                 mval = DTR | RTS;
1824         }
1825
1826         iflag = termios2digi_i(ch, ts->c_iflag);
1827
1828         if(iflag != ch->fepiflag) {
1829                 ch->fepiflag = iflag;
1830                 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1831         }
1832
1833         bc->mint = ch->dcd;
1834         if((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1835                 if(ch->digiext.digi_flags & DIGI_FORCEDCD)
1836                         bc->mint = 0;
1837
1838         ch->imodem = bc->mstat;
1839
1840         hflow = termios2digi_h(ch, ts->c_cflag);
1841
1842         if(hflow != ch->hflow) {
1843                 ch->hflow = hflow;
1844                 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1845         }
1846
1847         /* mval ^= ch->modemfake & (mval ^ ch->modem); */
1848
1849         if(ch->omodem != mval) {
1850                 ch->omodem = mval;
1851                 fepcmd(ch, SETMODEM, mval, RTS|DTR, 0, 1);
1852         }
1853
1854         if(ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
1855                 ch->fepstartc = ch->startc;
1856                 ch->fepstopc = ch->stopc;
1857                 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1858         }
1859
1860         if(ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
1861                 ch->fepstartca = ch->startca;
1862                 ch->fepstopca = ch->stopca;
1863                 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1864         }
1865 }
1866
1867
1868 static void receive_data(struct channel *ch)
1869 {
1870         volatile struct board_chan *bc;
1871         struct tty_struct *tty;
1872         unsigned int tail, head, wrapmask;
1873         int n;
1874         int piece;
1875         struct termios *ts=0;
1876         unchar *rptr;
1877         int rc;
1878         int wrapgap;
1879
1880     globalwinon(ch);
1881
1882         if (ch->statusflags & RXSTOPPED)
1883                 return;
1884
1885         tty = ch->tty;
1886         if(tty)
1887                 ts = tty->termios;
1888
1889         bc = ch->brdchan;
1890
1891         if(!bc) {
1892                 printk("bc is NULL in receive_data!\n");
1893                 return;
1894         }
1895
1896         wrapmask = ch->rxbufsize - 1;
1897
1898         head = bc->rin;
1899         head &= wrapmask;
1900         tail = bc->rout & wrapmask;
1901
1902         n = (head-tail) & wrapmask;
1903
1904         if(n == 0)
1905                 return;
1906
1907         /*
1908          * If CREAD bit is off or device not open, set TX tail to head
1909          */
1910         if(!tty || !ts || !(ts->c_cflag & CREAD)) {
1911                 bc->rout = head;
1912                 return;
1913         }
1914
1915         if(tty->flip.count == TTY_FLIPBUF_SIZE) {
1916                 /* printk("tty->flip.count = TTY_FLIPBUF_SIZE\n"); */
1917                 return;
1918         }
1919
1920         if(bc->orun) {
1921                 bc->orun = 0;
1922                 printk("overrun! DigiBoard device %s\n", tty->name);
1923         }
1924
1925         rxwinon(ch);
1926         rptr = tty->flip.char_buf_ptr;
1927         rc = tty->flip.count;
1928         while(n > 0) {
1929                 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
1930                 piece = (wrapgap < n) ? wrapgap : n;
1931
1932                 /*
1933                  * Make sure we don't overflow the buffer
1934                  */
1935
1936                 if ((rc + piece) > TTY_FLIPBUF_SIZE)
1937                         piece = TTY_FLIPBUF_SIZE - rc;
1938
1939                 if (piece == 0)
1940                         break;
1941
1942                 memcpy(rptr, ch->rxptr + tail, piece);
1943                 rptr += piece;
1944                 rc += piece;
1945                 tail = (tail + piece) & wrapmask;
1946                 n -= piece;
1947         }
1948         tty->flip.count = rc;
1949         tty->flip.char_buf_ptr = rptr;
1950     globalwinon(ch);
1951         bc->rout = tail;
1952
1953         /* Must be called with global data */
1954         tty_schedule_flip(ch->tty); 
1955         return;
1956 }
1957
1958
1959 static int pcxe_tiocmget(struct tty_struct *tty, struct file *file)
1960 {
1961         struct channel *ch = (struct channel *) tty->driver_data;
1962         volatile struct board_chan *bc;
1963         unsigned long flags;
1964         int mflag = 0;
1965         int mstat;
1966
1967         if(ch)
1968                 bc = ch->brdchan;
1969         else {
1970                 printk("ch is NULL in %s!\n", __FUNCTION__);
1971                 return(-EINVAL);
1972         }
1973
1974         save_flags(flags);
1975         cli();
1976         globalwinon(ch);
1977         mstat = bc->mstat;
1978         memoff(ch);
1979         restore_flags(flags);
1980
1981         if(mstat & DTR)
1982                 mflag |= TIOCM_DTR;
1983         if(mstat & RTS)
1984                 mflag |= TIOCM_RTS;
1985         if(mstat & CTS)
1986                 mflag |= TIOCM_CTS;
1987         if(mstat & ch->dsr)
1988                 mflag |= TIOCM_DSR;
1989         if(mstat & RI)
1990                 mflag |= TIOCM_RI;
1991         if(mstat & ch->dcd)
1992                 mflag |= TIOCM_CD;
1993
1994         return mflag;
1995 }
1996
1997
1998 static int pcxe_tiocmset(struct tty_struct *tty, struct file *file,
1999                          unsigned int set, unsigned int clear)
2000 {
2001         struct channel *ch = (struct channel *) tty->driver_data;
2002         volatile struct board_chan *bc;
2003         unsigned long flags;
2004
2005         if(ch)
2006                 bc = ch->brdchan;
2007         else {
2008                 printk("ch is NULL in %s!\n", __FUNCTION__);
2009                 return(-EINVAL);
2010         }
2011
2012         save_flags(flags);
2013         cli();
2014         /*
2015          * I think this modemfake stuff is broken.  It doesn't
2016          * correctly reflect the behaviour desired by the TIOCM*
2017          * ioctls.  Therefore this is probably broken.
2018          */
2019         if (set & TIOCM_DTR) {
2020                 ch->modemfake |= DTR;
2021                 ch->modem |= DTR;
2022         }
2023         if (set & TIOCM_RTS) {
2024                 ch->modemfake |= RTS;
2025                 ch->modem |= RTS;
2026         }
2027
2028         if (clear & TIOCM_DTR) {
2029                 ch->modemfake |= DTR;
2030                 ch->modem &= ~DTR;
2031         }
2032         if (clear & TIOCM_RTS) {
2033                 ch->modemfake |= RTS;
2034                 ch->modem &= ~RTS;
2035         }
2036         globalwinon(ch);
2037         pcxxparam(tty,ch);
2038         memoff(ch);
2039         restore_flags(flags);
2040         return 0;
2041 }
2042
2043
2044 static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
2045                     unsigned int cmd, unsigned long arg)
2046 {
2047         struct channel *ch = (struct channel *) tty->driver_data;
2048         volatile struct board_chan *bc;
2049         int retval;
2050         unsigned int mflag, mstat;
2051         unsigned char startc, stopc;
2052         unsigned long flags;
2053         digiflow_t dflow;
2054
2055         if(ch)
2056                 bc = ch->brdchan;
2057         else {
2058                 printk("ch is NULL in pcxe_ioctl!\n");
2059                 return(-EINVAL);
2060         }
2061
2062         save_flags(flags);
2063
2064         switch(cmd) {
2065                 case TCSBRK:    /* SVID version: non-zero arg --> no break */
2066                         retval = tty_check_change(tty);
2067                         if(retval)
2068                                 return retval;
2069                         setup_empty_event(tty,ch);              
2070                         tty_wait_until_sent(tty, 0);
2071                         if(!arg)
2072                                 digi_send_break(ch, HZ/4);    /* 1/4 second */
2073                         return 0;
2074
2075                 case TCSBRKP:   /* support for POSIX tcsendbreak() */
2076                         retval = tty_check_change(tty);
2077                         if(retval)
2078                                 return retval;
2079                         setup_empty_event(tty,ch);              
2080                         tty_wait_until_sent(tty, 0);
2081                         digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
2082                         return 0;
2083
2084                 case TIOCGSOFTCAR:
2085                         return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *)arg);
2086
2087                 case TIOCSSOFTCAR:
2088                         {
2089                             unsigned int value;
2090                             if (get_user(value, (unsigned int *) arg))
2091                                     return -EFAULT;
2092                             tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (value ? CLOCAL : 0));
2093                         }
2094                         return 0;
2095
2096                 case TIOCMODG:
2097                         mflag = pcxe_tiocmget(tty, file);
2098                         if (put_user(mflag, (unsigned int *) arg))
2099                                 return -EFAULT;
2100                         break;
2101
2102                 case TIOCMODS:
2103                         if (get_user(mstat, (unsigned int *) arg))
2104                                 return -EFAULT;
2105                         return pcxe_tiocmset(tty, file, mstat, ~mstat);
2106
2107                 case TIOCSDTR:
2108                         cli();
2109                         ch->omodem |= DTR;
2110                         globalwinon(ch);
2111                         fepcmd(ch, SETMODEM, DTR, 0, 10, 1);
2112                         memoff(ch);
2113                         restore_flags(flags);
2114                         break;
2115
2116                 case TIOCCDTR:
2117                         ch->omodem &= ~DTR;
2118                         cli();
2119                         globalwinon(ch);
2120                         fepcmd(ch, SETMODEM, 0, DTR, 10, 1);
2121                         memoff(ch);
2122                         restore_flags(flags);
2123                         break;
2124
2125                 case DIGI_GETA:
2126                         if (copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t)))
2127                                 return -EFAULT;
2128                         break;
2129
2130                 case DIGI_SETAW:
2131                 case DIGI_SETAF:
2132                         if(cmd == DIGI_SETAW) {
2133                                 setup_empty_event(tty,ch);              
2134                                 tty_wait_until_sent(tty, 0);
2135                         }
2136                         else {
2137                                 tty_ldisc_flush(tty);
2138                         }
2139
2140                         /* Fall Thru */
2141
2142                 case DIGI_SETA:
2143                         if (copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t)))
2144                                 return -EFAULT;
2145 #ifdef DEBUG_IOCTL
2146                         printk("ioctl(DIGI_SETA): flags = %x\n", ch->digiext.digi_flags);
2147 #endif
2148                         
2149                         if(ch->digiext.digi_flags & DIGI_ALTPIN) {
2150                                 ch->dcd = DSR;
2151                                 ch->dsr = CD;
2152                         } else {
2153                                 ch->dcd = CD;
2154                                 ch->dsr = DSR;
2155                         }
2156                 
2157                         cli();
2158                         globalwinon(ch);
2159                         pcxxparam(tty,ch);
2160                         memoff(ch);
2161                         restore_flags(flags);
2162                         break;
2163
2164                 case DIGI_GETFLOW:
2165                 case DIGI_GETAFLOW:
2166                         cli();  
2167                         globalwinon(ch);
2168                         if(cmd == DIGI_GETFLOW) {
2169                                 dflow.startc = bc->startc;
2170                                 dflow.stopc = bc->stopc;
2171                         } else {
2172                                 dflow.startc = bc->startca;
2173                                 dflow.stopc = bc->stopca;
2174                         }
2175                         memoff(ch);
2176                         restore_flags(flags);
2177
2178                         if (copy_to_user((char*)arg, &dflow, sizeof(dflow)))
2179                                 return -EFAULT;
2180                         break;
2181
2182                 case DIGI_SETAFLOW:
2183                 case DIGI_SETFLOW:
2184                         if(cmd == DIGI_SETFLOW) {
2185                                 startc = ch->startc;
2186                                 stopc = ch->stopc;
2187                         } else {
2188                                 startc = ch->startca;
2189                                 stopc = ch->stopca;
2190                         }
2191
2192                         if (copy_from_user(&dflow, (char*)arg, sizeof(dflow)))
2193                                 return -EFAULT;
2194
2195                         if(dflow.startc != startc || dflow.stopc != stopc) {
2196                                 cli();
2197                                 globalwinon(ch);
2198
2199                                 if(cmd == DIGI_SETFLOW) {
2200                                         ch->fepstartc = ch->startc = dflow.startc;
2201                                         ch->fepstopc = ch->stopc = dflow.stopc;
2202                                         fepcmd(ch,SONOFFC,ch->fepstartc,ch->fepstopc,0, 1);
2203                                 } else {
2204                                         ch->fepstartca = ch->startca = dflow.startc;
2205                                         ch->fepstopca  = ch->stopca = dflow.stopc;
2206                                         fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
2207                                 }
2208
2209                                 if(ch->statusflags & TXSTOPPED)
2210                                         pcxe_start(tty);
2211
2212                                 memoff(ch);
2213                                 restore_flags(flags);
2214                         }
2215                         break;
2216
2217                 default:
2218                         return -ENOIOCTLCMD;
2219         }
2220
2221         return 0;
2222 }
2223
2224 static void pcxe_set_termios(struct tty_struct *tty, struct termios *old_termios)
2225 {
2226         struct channel *info;
2227
2228         if ((info=chan(tty))!=NULL) {
2229                 unsigned long flags;
2230                 save_flags(flags);
2231                 cli();
2232                 globalwinon(info);
2233                 pcxxparam(tty,info);
2234                 memoff(info);
2235
2236                 if ((old_termios->c_cflag & CRTSCTS) &&
2237                         ((tty->termios->c_cflag & CRTSCTS) == 0))
2238                         tty->hw_stopped = 0;
2239                 if(!(old_termios->c_cflag & CLOCAL) &&
2240                         (tty->termios->c_cflag & CLOCAL))
2241                         wake_up_interruptible(&info->open_wait);
2242                 restore_flags(flags);
2243         }
2244 }
2245
2246
2247
2248 static void do_softint(void *private_)
2249 {
2250         struct channel *info = (struct channel *) private_;
2251         
2252         if(info && info->magic == PCXX_MAGIC) {
2253                 struct tty_struct *tty = info->tty;
2254                 if (tty && tty->driver_data) {
2255                         if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
2256                                 tty_hangup(tty);
2257                                 wake_up_interruptible(&info->open_wait);
2258                                 info->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
2259                         }
2260                 }
2261         }
2262 }
2263
2264
2265 static void pcxe_stop(struct tty_struct *tty)
2266 {
2267         struct channel *info;
2268
2269         if ((info=chan(tty))!=NULL) {
2270                 unsigned long flags;
2271                 save_flags(flags); 
2272                 cli();
2273                 if ((info->statusflags & TXSTOPPED) == 0) {
2274                         globalwinon(info);
2275                         fepcmd(info, PAUSETX, 0, 0, 0, 0);
2276                         info->statusflags |= TXSTOPPED;
2277                         memoff(info);
2278                 }
2279                 restore_flags(flags);
2280         }
2281 }
2282
2283 static void pcxe_throttle(struct tty_struct * tty)
2284 {
2285         struct channel *info;
2286
2287         if ((info=chan(tty))!=NULL) {
2288                 unsigned long flags;
2289                 save_flags(flags);
2290                 cli();
2291                 if ((info->statusflags & RXSTOPPED) == 0) {
2292                         globalwinon(info);
2293                         fepcmd(info, PAUSERX, 0, 0, 0, 0);
2294                         info->statusflags |= RXSTOPPED;
2295                         memoff(info);
2296                 }
2297                 restore_flags(flags);
2298         }
2299 }
2300
2301 static void pcxe_unthrottle(struct tty_struct *tty)
2302 {
2303         struct channel *info;
2304
2305         if ((info=chan(tty)) != NULL) {
2306                 unsigned long flags;
2307
2308                 /* Just in case output was resumed because of a change in Digi-flow */
2309                 save_flags(flags);
2310                 cli();
2311                 if(info->statusflags & RXSTOPPED) {
2312                         volatile struct board_chan *bc;
2313                         globalwinon(info);
2314                         bc = info->brdchan;
2315                         fepcmd(info, RESUMERX, 0, 0, 0, 0);
2316                         info->statusflags &= ~RXSTOPPED;
2317                         memoff(info);
2318                 }
2319                 restore_flags(flags);
2320         }
2321 }
2322
2323
2324 static void pcxe_start(struct tty_struct *tty)
2325 {
2326         struct channel *info;
2327
2328         if ((info=chan(tty))!=NULL) {
2329                 unsigned long flags;
2330
2331                 save_flags(flags);
2332                 cli();
2333                 /* Just in case output was resumed because of a change in Digi-flow */
2334                 if(info->statusflags & TXSTOPPED) {
2335                         volatile struct board_chan *bc;
2336                         globalwinon(info);
2337                         bc = info->brdchan;
2338                         if(info->statusflags & LOWWAIT)
2339                                 bc->ilow = 1;
2340                         fepcmd(info, RESUMETX, 0, 0, 0, 0);
2341                         info->statusflags &= ~TXSTOPPED;
2342                         memoff(info);
2343                 }
2344                 restore_flags(flags);
2345         }
2346 }
2347
2348
2349 void digi_send_break(struct channel *ch, int msec)
2350 {
2351         unsigned long flags;
2352
2353         save_flags(flags);
2354         cli();
2355         globalwinon(ch);
2356
2357         /* 
2358          * Maybe I should send an infinite break here, schedule() for
2359          * msec amount of time, and then stop the break.  This way,
2360          * the user can't screw up the FEP by causing digi_send_break()
2361          * to be called (i.e. via an ioctl()) more than once in msec amount 
2362          * of time.  Try this for now...
2363          */
2364
2365         fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2366         memoff(ch);
2367
2368         restore_flags(flags);
2369 }
2370
2371 static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
2372 {
2373         volatile struct board_chan *bc;
2374         unsigned long flags;
2375
2376         save_flags(flags);
2377         cli();
2378         globalwinon(ch);
2379         ch->statusflags |= EMPTYWAIT;
2380         bc = ch->brdchan;
2381         bc->iempty = 1;
2382         memoff(ch);
2383         restore_flags(flags);
2384 }