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