~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/char/ip2main.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2 *
  3 *   (c) 1999 by Computone Corporation
  4 *
  5 ********************************************************************************
  6 *
  7 *   PACKAGE:     Linux tty Device Driver for IntelliPort family of multiport
  8 *                serial I/O controllers.
  9 *
 10 *   DESCRIPTION: Mainline code for the device driver
 11 *
 12 *******************************************************************************/
 13 // ToDo:
 14 //
 15 // Done:
 16 //
 17 // 1.2.9
 18 // Four box EX was barfing on >128k kmalloc, made structure smaller by
 19 // reducing output buffer size
 20 //
 21 // 1.2.8
 22 // Device file system support (MHW)
 23 //
 24 // 1.2.7 
 25 // Fixed
 26 // Reload of ip2 without unloading ip2main hangs system on cat of /proc/modules
 27 //
 28 // 1.2.6
 29 //Fixes DCD problems
 30 //      DCD was not reported when CLOCAL was set on call to TIOCMGET
 31 //
 32 //Enhancements:
 33 //      TIOCMGET requests and waits for status return
 34 //      No DSS interrupts enabled except for DCD when needed
 35 //
 36 // For internal use only
 37 //
 38 //#define IP2DEBUG_INIT
 39 //#define IP2DEBUG_OPEN
 40 //#define IP2DEBUG_WRITE
 41 //#define IP2DEBUG_READ
 42 //#define IP2DEBUG_IOCTL
 43 //#define IP2DEBUG_IPL
 44 
 45 //#define IP2DEBUG_TRACE
 46 //#define DEBUG_FIFO
 47 
 48 /************/
 49 /* Includes */
 50 /************/
 51 #include <linux/config.h>
 52 // Uncomment the following if you want it compiled with modversions
 53 #ifdef MODULE
 54 #       if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
 55 #               define MODVERSIONS
 56 #       endif
 57 #       ifdef MODVERSIONS
 58 #               include <linux/modversions.h>
 59 #       endif
 60 #endif
 61 
 62 #include <linux/version.h>
 63 
 64 #include <linux/ctype.h>
 65 #include <linux/string.h>
 66 #include <linux/fcntl.h>
 67 #include <linux/errno.h>
 68 #include <linux/module.h>
 69 #include <linux/signal.h>
 70 #include <linux/sched.h>
 71 #ifdef  CONFIG_DEVFS_FS
 72 #include <linux/devfs_fs_kernel.h>
 73 #endif
 74 #include <linux/timer.h>
 75 #include <linux/interrupt.h>
 76 #include <linux/pci.h>
 77 #include <linux/mm.h>
 78 #include <linux/malloc.h>
 79 #include <linux/major.h>
 80 #include <linux/wait.h>
 81 
 82 #include <linux/tty.h>
 83 #include <linux/tty_flip.h>
 84 #include <linux/termios.h>
 85 #include <linux/tty_driver.h>
 86 #include <linux/serial.h>
 87 #include <linux/ptrace.h>
 88 #include <linux/ioport.h>
 89 
 90 #include <linux/cdk.h>
 91 #include <linux/comstats.h>
 92 #include <linux/delay.h>
 93 
 94 #include <asm/system.h>
 95 #include <asm/io.h>
 96 #include <asm/irq.h>
 97 #include <asm/bitops.h>
 98 
 99 #ifndef KERNEL_VERSION
100 #define KERNEL_VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
101 #endif
102 
103 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
104 #       include <linux/vmalloc.h>
105 #       include <linux/init.h>
106 #       include <asm/serial.h>
107 #else
108 #       include <linux/bios32.h>
109 #endif
110 
111 // These VERSION switches maybe inexact because I simply don't know
112 // when the various features appeared in the 2.1.XX kernels.
113 // They are good enough for 2.0 vs 2.2 and if you are fooling with
114 // the 2.1.XX stuff then it would be trivial for you to fix.
115 // Most of these macros were stolen from some other drivers
116 // so blame them.
117 
118 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,4)
119 #       include <asm/segment.h>
120 #       define GET_USER(error,value,addr) error = get_user(value,addr)
121 #       define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
122 #       define PUT_USER(error,value,addr) error = put_user(value,addr)
123 #       define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
124 
125 #       if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,5)
126 #               include <asm/uaccess.h>
127 #               define          pcibios_strerror(status)        \
128                                         printk( KERN_ERR "IP2: PCI error 0x%x \n", status );
129 #       endif
130 
131 #else  /* 2.0.x and 2.1.x before 2.1.4 */
132 
133 #       define          proc_register_dynamic(a,b) proc_register(a,b) 
134 
135 #       define GET_USER(error,value,addr)                                         \
136         do {                                                                      \
137                 error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \
138                 if (error == 0)                                                   \
139                         value = get_user(addr);                                   \
140         } while (0)
141 
142 #       define COPY_FROM_USER(error,dest,src,size)                                \
143         do {                                                                      \
144                 error = verify_area (VERIFY_READ, (void *) src, size);            \
145                 if (error == 0)                                                   \
146                         memcpy_fromfs (dest, src, size);                          \
147         } while (0)
148 
149 #       define PUT_USER(error,value,addr)                                          \
150         do {                                                                       \
151                 error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \
152                 if (error == 0)                                                    \
153                         put_user (value, addr);                                    \
154         } while (0)
155 
156 #       define COPY_TO_USER(error,dest,src,size)                                  \
157         do {                                                                      \
158                 error = verify_area (VERIFY_WRITE, (void *) dest, size);                  \
159                 if (error == 0)                                                   \
160                         memcpy_tofs (dest, src, size);                            \
161         } while (0)
162 
163 #endif
164 
165 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
166 #define __init
167 #define __initfunc(a) a
168 #define __initdata
169 #define ioremap(a,b) vremap((a),(b))
170 #define iounmap(a) vfree((a))
171 #define SERIAL_TYPE_NORMAL      1
172 #define SERIAL_TYPE_CALLOUT     2
173 #define schedule_timeout(a){current->timeout = jiffies + (a); schedule();}
174 #define signal_pending(a) ((a)->signal & ~(a)->blocked)
175 #define in_interrupt()  intr_count
176 #endif
177 
178 #include "./ip2/ip2types.h"
179 #include "./ip2/ip2trace.h"
180 #include "./ip2/ip2ioctl.h"
181 #include "./ip2/ip2.h"
182 #include "./ip2/i2ellis.h"
183 #include "./ip2/i2lib.h"
184 
185 /*****************
186  * /proc/ip2mem  *
187  *****************/
188 
189 #include <linux/proc_fs.h>
190 
191 static int ip2_read_procmem(char *, char **, off_t, int);
192 int ip2_read_proc(char *, char **, off_t, int, int *, void * );
193 
194 /********************/
195 /* Type Definitions */
196 /********************/
197 
198 /*************/
199 /* Constants */
200 /*************/
201 
202 /* String constants to identify ourselves */
203 static char *pcName    = "Computone IntelliPort Plus multiport driver";
204 static char *pcVersion = "1.2.9";
205 
206 /* String constants for port names */
207 static char *pcDriver_name   = "ip2";
208 #ifdef  CONFIG_DEVFS_FS
209 static char *pcTty               = "ttf/%d";
210 static char *pcCallout           = "cuf/%d";
211 #else
212 static char *pcTty               = "ttyF";
213 static char *pcCallout           = "cuf";
214 #endif
215 static char *pcIpl               = "ip2ipl";
216 
217 /* Serial subtype definitions */
218 #define SERIAL_TYPE_NORMAL    1
219 #define SERIAL_TYPE_CALLOUT   2
220 
221 // cheezy kludge or genius - you decide?
222 int ip2_loadmain(int *, int *, unsigned char *, int);
223 static unsigned char *Fip_firmware;
224 static int Fip_firmware_size;
225 
226 /***********************/
227 /* Function Prototypes */
228 /***********************/
229 
230 /* Global module entry functions */
231 #ifdef MODULE
232 int init_module(void);
233 void cleanup_module(void);
234 #endif
235 
236 int old_ip2_init(void);
237 
238 /* Private (static) functions */
239 static int  ip2_open(PTTY, struct file *);
240 static void ip2_close(PTTY, struct file *);
241 static int  ip2_write(PTTY, int, const unsigned char *, int);
242 static void ip2_putchar(PTTY, unsigned char);
243 static void ip2_flush_chars(PTTY);
244 static int  ip2_write_room(PTTY);
245 static int  ip2_chars_in_buf(PTTY);
246 static void ip2_flush_buffer(PTTY);
247 static int  ip2_ioctl(PTTY, struct file *, UINT, ULONG);
248 static void ip2_set_termios(PTTY, struct termios *);
249 static void ip2_set_line_discipline(PTTY);
250 static void ip2_throttle(PTTY);
251 static void ip2_unthrottle(PTTY);
252 static void ip2_stop(PTTY);
253 static void ip2_start(PTTY);
254 static void ip2_hangup(PTTY);
255 
256 static void set_irq(int, int);
257 static void ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs);
258 static void ip2_poll(unsigned long arg);
259 static inline void service_all_boards(void);
260 static inline void do_input(i2ChanStrPtr pCh);
261 static inline void do_status(i2ChanStrPtr pCh);
262 
263 static void ip2_wait_until_sent(PTTY,int);
264 
265 static void set_params (i2ChanStrPtr, struct termios *);
266 static int set_modem_info(i2ChanStrPtr, unsigned int, unsigned int *);
267 static int get_serial_info(i2ChanStrPtr, struct serial_struct *);
268 static int set_serial_info(i2ChanStrPtr, struct serial_struct *);
269 
270 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
271 static int     ip2_ipl_read(struct inode *, char *, size_t , loff_t *);
272 #else
273 static ssize_t ip2_ipl_read(struct file *, char *, size_t, loff_t *) ;
274 #endif
275 static ssize_t ip2_ipl_write(struct file *, const char *, size_t, loff_t *);
276 static int ip2_ipl_ioctl(struct inode *, struct file *, UINT, ULONG);
277 static int ip2_ipl_open(struct inode *, struct file *);
278 
279 void ip2trace(unsigned short,unsigned char,unsigned char,unsigned long,...);
280 static int DumpTraceBuffer(char *, int);
281 static int DumpFifoBuffer( char *, int);
282 
283 static void ip2_init_board(int);
284 static unsigned short find_eisa_board(int);
285 
286 /***************/
287 /* Static Data */
288 /***************/
289 
290 static struct tty_driver ip2_tty_driver;
291 static struct tty_driver ip2_callout_driver;
292 
293 static int ref_count;
294 
295 /* Here, then is a table of board pointers which the interrupt routine should
296  * scan through to determine who it must service.
297  */
298 static unsigned short i2nBoards; // Number of boards here
299 
300 static i2eBordStrPtr i2BoardPtrTable[IP2_MAX_BOARDS];
301 
302 static i2ChanStrPtr  DevTable[IP2_MAX_PORTS];
303 //DevTableMem just used to save addresses for kfree
304 static void  *DevTableMem[IP2_MAX_BOARDS];
305 
306 static struct tty_struct * TtyTable[IP2_MAX_PORTS];
307 static struct termios    * Termios[IP2_MAX_PORTS];
308 static struct termios    * TermiosLocked[IP2_MAX_PORTS];
309 
310 /* This is the driver descriptor for the ip2ipl device, which is used to
311  * download the loadware to the boards.
312  */
313 static struct file_operations ip2_ipl = {
314         owner:          THIS_MODULE,
315         read:           ip2_ipl_read,
316         write:          ip2_ipl_write,
317         ioctl:          ip2_ipl_ioctl,
318         open:           ip2_ipl_open,
319 }; 
320 
321 static long irq_counter;
322 static long bh_counter;
323 
324 // Use immediate queue to service interrupts
325 //#define USE_IQI       // PCI&2.2 needs work
326 //#define USE_IQ        // PCI&2.2 needs work
327 
328 /* The timer_list entry for our poll routine. If interrupt operation is not
329  * selected, the board is serviced periodically to see if anything needs doing.
330  */
331 #define  POLL_TIMEOUT   (jiffies + 1)
332 static struct timer_list PollTimer = { function: ip2_poll };
333 static char  TimerOn;
334 
335 #ifdef IP2DEBUG_TRACE
336 /* Trace (debug) buffer data */
337 #define TRACEMAX  1000
338 static unsigned long tracebuf[TRACEMAX];
339 static int tracestuff;
340 static int tracestrip;
341 static int tracewrap;
342 #endif
343 
344 /**********/
345 /* Macros */
346 /**********/
347 
348 #if defined(MODULE) && defined(IP2DEBUG_OPEN)
349 #define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \
350                     kdevname(tty->device),(pCh->flags),ref_count, \
351                     tty->count,/*GET_USE_COUNT(module)*/0,s)
352 #else
353 #define DBG_CNT(s)
354 #endif
355 
356 #define MIN(a,b)        ( ( (a) < (b) ) ? (a) : (b) )
357 #define MAX(a,b)        ( ( (a) > (b) ) ? (a) : (b) )
358 
359 /********/
360 /* Code */
361 /********/
362 
363 #include "./ip2/i2ellis.c"    /* Extremely low-level interface services */
364 #include "./ip2/i2cmd.c"      /* Standard loadware command definitions */
365 #include "./ip2/i2lib.c"      /* High level interface services */
366 
367 /* Configuration area for modprobe */
368 #ifdef MODULE
369 #       if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
370                 MODULE_AUTHOR("Doug McNash");
371                 MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
372 #       endif   /* LINUX_VERSION */
373 #endif  /* MODULE */
374 
375 static int poll_only;
376 
377 static int Eisa_irq;
378 static int Eisa_slot;
379 
380 static int iindx;
381 static char rirqs[IP2_MAX_BOARDS];
382 static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
383 
384 /******************************************************************************/
385 /* Initialisation Section                                                     */
386 /******************************************************************************/
387 int 
388 ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) 
389 {
390         int i;
391         /* process command line arguments to modprobe or insmod i.e. iop & irqp */
392         /* otherwise ip2config is initialized by what's in ip2/ip2.h */
393         /* command line trumps initialization in ip2.h */
394         /* first two args are null if builtin to kernel */
395         if ((irqp != NULL) || (iop != NULL)) {
396                 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
397                         if (irqp && irqp[i]) {
398                                 ip2config.irq[i] = irqp[i];
399                         }
400                         if (iop && iop[i]) {
401                                 ip2config.addr[i] = iop[i];
402                         }
403                 }
404         }
405         Fip_firmware = firmware;
406         Fip_firmware_size = firmsize;
407         return old_ip2_init();
408 }
409 
410 // Some functions to keep track of what irq's we have
411 
412 static int __init
413 is_valid_irq(int irq)
414 {
415         int *i = Valid_Irqs;
416         
417         while ((*i != 0) && (*i != irq)) {
418                 i++;
419         }
420         return (*i);
421 }
422 
423 static void __init
424 mark_requested_irq( char irq )
425 {
426         rirqs[iindx++] = irq;
427 }
428 
429 static int __init
430 clear_requested_irq( char irq )
431 {
432         int i;
433         for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
434                 if (rirqs[i] == irq) {
435                         rirqs[i] = 0;
436                         return 1;
437                 }
438         }
439         return 0;
440 }
441 
442 static int __init
443 have_requested_irq( char irq )
444 {
445         // array init to zeros so 0 irq will not be requested as a side effect
446         int i;
447         for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
448                 if (rirqs[i] == irq)
449                         return 1;
450         }
451         return 0;
452 }
453 
454 /******************************************************************************/
455 /* Function:   init_module()                                                  */
456 /* Parameters: None                                                           */
457 /* Returns:    Success (0)                                                    */
458 /*                                                                            */
459 /* Description:                                                               */
460 /* This is a required entry point for an installable module. It simply calls  */
461 /* the driver initialisation function and returns what it returns.            */
462 /******************************************************************************/
463 #ifdef MODULE
464 int
465 init_module(void)
466 {
467 #ifdef IP2DEBUG_INIT
468         printk (KERN_DEBUG "Loading module ...\n" );
469 #endif
470     //was       return old_ip2_init();
471     return 0;
472 }
473 #endif /* MODULE */
474 
475 /******************************************************************************/
476 /* Function:   cleanup_module()                                               */
477 /* Parameters: None                                                           */
478 /* Returns:    Nothing                                                        */
479 /*                                                                            */
480 /* Description:                                                               */
481 /* This is a required entry point for an installable module. It has to return */
482 /* the device and the driver to a passive state. It should not be necessary   */
483 /* to reset the board fully, especially as the loadware is downloaded         */
484 /* externally rather than in the driver. We just want to disable the board    */
485 /* and clear the loadware to a reset state. To allow this there has to be a   */
486 /* way to detect whether the board has the loadware running at init time to   */
487 /* handle subsequent installations of the driver. All memory allocated by the */
488 /* driver should be returned since it may be unloaded from memory.            */
489 /******************************************************************************/
490 #ifdef MODULE
491 void
492 cleanup_module(void)
493 {
494         int err;
495         int i;
496 
497 #ifdef IP2DEBUG_INIT
498         printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion );
499 #endif
500         /* Stop poll timer if we had one. */
501         if ( TimerOn ) {
502                 del_timer ( &PollTimer );
503                 TimerOn = 0;
504         }
505 
506         /* Reset the boards we have. */
507         for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
508                 if ( i2BoardPtrTable[i] ) {
509                         iiReset( i2BoardPtrTable[i] );
510                 }
511         }
512 
513         /* The following is done at most once, if any boards were installed. */
514         for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
515                 if ( i2BoardPtrTable[i] ) {
516                         iiResetDelay( i2BoardPtrTable[i] );
517                         /* free io addresses and Tibet */
518                         release_region( ip2config.addr[i], 8 );
519 #ifdef  CONFIG_DEVFS_FS
520                         devfs_unregister (i2BoardPtrTable[i]->devfs_ipl_handle);
521                         devfs_unregister (i2BoardPtrTable[i]->devfs_stat_handle);
522 #endif
523                 }
524                 /* Disable and remove interrupt handler. */
525                 if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { 
526                         free_irq ( ip2config.irq[i], (void *)&pcName);
527                         clear_requested_irq( ip2config.irq[i]);
528                 }
529         }
530         if ( ( err = tty_unregister_driver ( &ip2_tty_driver ) ) ) {
531                 printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
532         }
533         if ( ( err = tty_unregister_driver ( &ip2_callout_driver ) ) ) {
534                 printk(KERN_ERR "IP2: failed to unregister callout driver (%d)\n", err);
535         }
536 #ifdef  CONFIG_DEVFS_FS
537         if ( ( err = devfs_unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) )
538 #else
539         if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) )
540 #endif
541         {
542                 printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err);
543         }
544         remove_proc_entry("ip2mem", &proc_root);
545 
546         // free memory
547         for (i = 0; i < IP2_MAX_BOARDS; i++) {
548                 void *pB;
549                 if ((pB = i2BoardPtrTable[i]) != 0 ) {
550                         kfree ( pB );
551                         i2BoardPtrTable[i] = NULL;
552                 }
553                 if ((DevTableMem[i]) != NULL ) {
554                         kfree ( DevTableMem[i]  );
555                         DevTableMem[i] = NULL;
556                 }
557         }
558 
559         /* Cleanup the iiEllis subsystem. */
560         iiEllisCleanup();
561 #ifdef IP2DEBUG_INIT
562         printk (KERN_DEBUG "IP2 Unloaded\n" );
563 #endif
564 }
565 #endif /* MODULE */
566 
567 /******************************************************************************/
568 /* Function:   old_ip2_init()                                                 */
569 /* Parameters: irq, io from command line of insmod et. al.                    */
570 /* Returns:    Success (0)                                                    */
571 /*                                                                            */
572 /* Description:                                                               */
573 /* This was the required entry point for all drivers (now in ip2.c)           */
574 /* It performs all                                                            */
575 /* initialisation of the devices and driver structures, and registers itself  */
576 /* with the relevant kernel modules.                                          */
577 /******************************************************************************/
578 /* SA_INTERRUPT- if set blocks all interrupts else only this line */
579 /* SA_SHIRQ    - for shared irq PCI or maybe EISA only */
580 /* SA_RANDOM   - can be source for cert. random number generators */
581 #define IP2_SA_FLAGS    0
582 
583 int __init
584 old_ip2_init(void)
585 {
586 #ifdef  CONFIG_DEVFS_FS
587         static devfs_handle_t devfs_handle;
588         int j, box;
589 #endif
590         int i;
591         int err;
592         int status = 0;
593         static int loaded;
594         i2eBordStrPtr pB = NULL;
595         int rc = -1;
596 
597 #ifdef IP2DEBUG_TRACE
598         ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 );
599 #endif
600 
601         /* Announce our presence */
602         printk( KERN_INFO "%s version %s\n", pcName, pcVersion );
603 
604         // ip2 can be unloaded and reloaded for no good reason
605         // we can't let that happen here or bad things happen
606         // second load hoses board but not system - fixme later
607         if (loaded) {
608                 printk( KERN_INFO "Still loaded\n" );
609                 return 0;
610         }
611         loaded++;
612 
613         /* if all irq config is zero we shall poll_only */
614         for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
615                 poll_only |= ip2config.irq[i];
616         }
617         poll_only = !poll_only;
618 
619         /* Initialise the iiEllis subsystem. */
620         iiEllisInit();
621 
622         /* Initialize arrays. */
623         memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable );
624         memset( DevTable, 0, sizeof DevTable );
625         memset( TtyTable, 0, sizeof TtyTable );
626         memset( Termios, 0, sizeof Termios );
627         memset( TermiosLocked, 0, sizeof TermiosLocked );
628 
629         /* Initialise all the boards we can find (up to the maximum). */
630         for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
631                 switch ( ip2config.addr[i] ) { 
632                 case 0: /* skip this slot even if card is present */
633                         break;
634                 default: /* ISA */
635                    /* ISA address must be specified */
636                         if ( (ip2config.addr[i] < 0x100) || (ip2config.addr[i] > 0x3f8) ) {
637                                 printk ( KERN_ERR "IP2: Bad ISA board %d address %x\n",
638                                                          i, ip2config.addr[i] );
639                                 ip2config.addr[i] = 0;
640                         } else {
641                                 ip2config.type[i] = ISA;
642 
643                                 /* Check for valid irq argument, set for polling if invalid */
644                                 if (ip2config.irq[i] && !is_valid_irq(ip2config.irq[i])) {
645                                         printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",ip2config.irq[i]);
646                                         ip2config.irq[i] = 0;// 0 is polling and is valid in that sense
647                                 }
648                         }
649                         break;
650                 case PCI:
651 #ifdef CONFIG_PCI
652 #if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
653                         if (pcibios_present()) {
654                                 unsigned char pci_bus, pci_devfn;
655                                 int Pci_index = 0;
656                                 status = pcibios_find_device(PCI_VENDOR_ID_COMPUTONE,
657                                                           PCI_DEVICE_ID_COMPUTONE_IP2EX, Pci_index,
658                                                           &pci_bus, &pci_devfn);
659                                 if (status == 0) {
660                                         unsigned int addr;
661                                         unsigned char pci_irq;
662 
663                                         ip2config.type[i] = PCI;
664                                         /* 
665                                          * Update Pci_index, so that the next time we go
666                                          * searching for a PCI board we find a different
667                                          * one.
668                                          */
669                                         ++Pci_index;
670 
671                                         pcibios_read_config_dword(pci_bus, pci_devfn,
672                                                                   PCI_BASE_ADDRESS_1, &addr);
673                                         if ( addr & 1 ) {
674                                                 ip2config.addr[i]=(USHORT)(addr&0xfffe);
675                                         } else {
676                                                 printk( KERN_ERR "IP2: PCI I/O address error\n");
677                                         }
678                                         pcibios_read_config_byte(pci_bus, pci_devfn,
679                                                                   PCI_INTERRUPT_LINE, &pci_irq);
680 
681                                         if (!is_valid_irq(pci_irq)) {
682                                                 printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
683                                                 pci_irq = 0;
684                                         }
685                                         ip2config.irq[i] = pci_irq;
686                                 } else {        // ann error
687                                         ip2config.addr[i] = 0;
688                                         if (status == PCIBIOS_DEVICE_NOT_FOUND) {
689                                                 printk( KERN_ERR "IP2: PCI board %d not found\n", i );
690                                         } else {
691                                                 pcibios_strerror(status);
692                                         }
693                                 } 
694                         } 
695 #else /* LINUX_VERSION_CODE > 2.1.99 */
696                         if (pci_present()) {
697                                 struct pci_dev *pci_dev_i = NULL;
698                                 pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE,
699                                                           PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
700                                 if (pci_dev_i != NULL) {
701                                         unsigned int addr;
702                                         unsigned char pci_irq;
703 
704                                         ip2config.type[i] = PCI;
705                                         status =
706                                         pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
707                                         if ( addr & 1 ) {
708                                                 ip2config.addr[i]=(USHORT)(addr&0xfffe);
709                                         } else {
710                                                 printk( KERN_ERR "IP2: PCI I/O address error\n");
711                                         }
712                                         status =
713                                         pci_read_config_byte(pci_dev_i, PCI_INTERRUPT_LINE, &pci_irq);
714 
715                                         if (!is_valid_irq(pci_irq)) {
716                                                 printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
717                                                 pci_irq = 0;
718                                         }
719                                         ip2config.irq[i] = pci_irq;
720                                 } else {        // ann error
721                                         ip2config.addr[i] = 0;
722                                         if (status == PCIBIOS_DEVICE_NOT_FOUND) {
723                                                 printk( KERN_ERR "IP2: PCI board %d not found\n", i );
724                                         } else {
725                                                 pcibios_strerror(status);
726                                         }
727                                 } 
728                         } 
729 #endif  /* ! 2_0_X */
730 #else
731                         printk( KERN_ERR "IP2: PCI card specified but PCI support not\n");
732                         printk( KERN_ERR "IP2: configured in this kernel.\n");
733                         printk( KERN_ERR "IP2: Recompile kernel with CONFIG_PCI defined!\n");
734 #endif /* CONFIG_PCI */
735                         break;
736                 case EISA:
737                         if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) {
738                                 /* Eisa_irq set as side effect, boo */
739                                 ip2config.type[i] = EISA;
740                         } 
741                         ip2config.irq[i] = Eisa_irq;
742                         break;
743                 }       /* switch */
744         }       /* for */
745         for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
746                 if ( ip2config.addr[i] ) {
747                         pB = kmalloc( sizeof(i2eBordStr), GFP_KERNEL);
748                         if ( pB != NULL ) {
749                                 i2BoardPtrTable[i] = pB;
750                                 memset( pB, 0, sizeof(i2eBordStr) );
751                                 iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer );
752                                 iiReset( pB );
753                         } else {
754                                 printk(KERN_ERR "IP2: board memory allocation error\n");
755                         }
756                 }
757         }
758         for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
759                 if ( ( pB = i2BoardPtrTable[i] ) != NULL ) {
760                         iiResetDelay( pB );
761                         break;
762                 }
763         }
764         for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
765                 if ( i2BoardPtrTable[i] != NULL ) {
766                         ip2_init_board( i );
767                 }
768         }
769 
770 #ifdef IP2DEBUG_TRACE
771         ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 );
772 #endif
773 
774         /* Zero out the normal tty device structure. */
775         memset ( &ip2_tty_driver, 0, sizeof ip2_tty_driver );
776 
777         /* Initialise the relevant fields. */
778         ip2_tty_driver.magic                = TTY_DRIVER_MAGIC;
779         ip2_tty_driver.name                 = pcTty;
780 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
781         ip2_tty_driver.driver_name          = pcDriver_name;
782         ip2_tty_driver.read_proc                = ip2_read_proc;
783 #endif
784         ip2_tty_driver.major                = IP2_TTY_MAJOR;
785         ip2_tty_driver.minor_start          = 0;
786         ip2_tty_driver.num                  = IP2_MAX_PORTS;
787         ip2_tty_driver.type                 = TTY_DRIVER_TYPE_SERIAL;
788         ip2_tty_driver.subtype              = SERIAL_TYPE_NORMAL;
789         ip2_tty_driver.init_termios         = tty_std_termios;
790         ip2_tty_driver.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
791 #ifdef  CONFIG_DEVFS_FS
792         ip2_tty_driver.flags                = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
793 #else
794         ip2_tty_driver.flags                = TTY_DRIVER_REAL_RAW;
795 #endif
796         ip2_tty_driver.refcount             = &ref_count;
797         ip2_tty_driver.table                = TtyTable;
798         ip2_tty_driver.termios              = Termios;
799         ip2_tty_driver.termios_locked       = TermiosLocked;
800 
801         /* Setup the pointers to the implemented functions. */
802         ip2_tty_driver.open            = ip2_open;
803         ip2_tty_driver.close           = ip2_close;
804         ip2_tty_driver.write           = ip2_write;
805         ip2_tty_driver.put_char        = ip2_putchar;
806         ip2_tty_driver.flush_chars     = ip2_flush_chars;
807         ip2_tty_driver.write_room      = ip2_write_room;
808         ip2_tty_driver.chars_in_buffer = ip2_chars_in_buf;
809         ip2_tty_driver.flush_buffer    = ip2_flush_buffer;
810         ip2_tty_driver.ioctl           = ip2_ioctl;
811         ip2_tty_driver.throttle        = ip2_throttle;
812         ip2_tty_driver.unthrottle      = ip2_unthrottle;
813         ip2_tty_driver.set_termios     = ip2_set_termios;
814         ip2_tty_driver.set_ldisc       = ip2_set_line_discipline;
815         ip2_tty_driver.stop            = ip2_stop;
816         ip2_tty_driver.start           = ip2_start;
817         ip2_tty_driver.hangup          = ip2_hangup;
818 
819         /* Initialise the callout driver structure from the tty driver, and
820          * make the needed adjustments.
821          */
822         ip2_callout_driver         = ip2_tty_driver;
823         ip2_callout_driver.name    = pcCallout;
824 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
825         ip2_callout_driver.driver_name = pcDriver_name;
826         ip2_callout_driver.read_proc  = NULL;
827 #endif
828         ip2_callout_driver.major   = IP2_CALLOUT_MAJOR;
829         ip2_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
830 
831 #ifdef IP2DEBUG_TRACE
832         ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 );
833 #endif
834 
835         /* Register the tty devices. */
836         if ( ( err = tty_register_driver ( &ip2_tty_driver ) ) ) {
837                 printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err);
838         } else
839         if ( ( err = tty_register_driver ( &ip2_callout_driver ) ) ) {
840                 printk(KERN_ERR "IP2: failed to register callout driver (%d)\n", err);
841         } else
842         /* Register the IPL driver. */
843 #ifdef  CONFIG_DEVFS_FS
844         if (( err = devfs_register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl )))
845 #else
846         if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) )
847 #endif
848         {
849                 printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err );
850         } else
851         /* Register the read_procmem thing */
852         if (!create_proc_info_entry("ip2mem",0,&proc_root,ip2_read_procmem)) {
853                 printk(KERN_ERR "IP2: failed to register read_procmem\n");
854         } else {
855 
856 #ifdef IP2DEBUG_TRACE
857         ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 );
858 #endif
859                 /* Register the interrupt handler or poll handler, depending upon the
860                  * specified interrupt.
861                  */
862 #ifdef  CONFIG_DEVFS_FS
863                 if (!devfs_handle)
864                         devfs_handle = devfs_mk_dir (NULL, "ip2", NULL);
865 #endif
866 
867                 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
868 #ifdef  CONFIG_DEVFS_FS
869                         char name[16];
870 #endif
871 
872                         if ( 0 == ip2config.addr[i] ) {
873                                 continue;
874                         }
875 
876 #ifdef  CONFIG_DEVFS_FS
877                         sprintf( name, "ipl%d", i );
878                         i2BoardPtrTable[i]->devfs_ipl_handle =
879                                 devfs_register (devfs_handle, name,
880                                         DEVFS_FL_DEFAULT,
881                                         IP2_IPL_MAJOR, 4 * i,
882                                         S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
883                                         &ip2_ipl, NULL);
884 
885                         sprintf( name, "stat%d", i );
886                         i2BoardPtrTable[i]->devfs_stat_handle =
887                                 devfs_register (devfs_handle, name,
888                                         DEVFS_FL_DEFAULT,
889                                         IP2_IPL_MAJOR, 4 * i + 1,
890                                         S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
891                                         &ip2_ipl, NULL);
892 
893                         for ( box = 0; box < ABS_MAX_BOXES; ++box )
894                         {
895                             for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
896                             {
897                                 if ( pB->i2eChannelMap[box] & (1 << j) )
898                                 {
899                                     tty_register_devfs(&ip2_tty_driver,
900                                         0, j + ABS_BIGGEST_BOX *
901                                                 (box+i*ABS_MAX_BOXES));
902                                     tty_register_devfs(&ip2_callout_driver,
903                                         0, j + ABS_BIGGEST_BOX *
904                                                 (box+i*ABS_MAX_BOXES));
905                                 }
906                             }
907                         }
908 #endif
909 
910                         if (poll_only) {
911                                         ip2config.irq[i] = CIR_POLL;
912                         }
913                         if ( ip2config.irq[i] == CIR_POLL ) {
914 retry:
915                                 if (!TimerOn) {
916                                         PollTimer.expires = POLL_TIMEOUT;
917                                         add_timer ( &PollTimer );
918                                         TimerOn = 1;
919                                         printk( KERN_INFO "IP2: polling\n");
920                                 }
921                         } else {
922                                 if (have_requested_irq(ip2config.irq[i]))
923                                         continue;
924                                 rc = request_irq( ip2config.irq[i], ip2_interrupt,
925                                         IP2_SA_FLAGS | (ip2config.type[i] == PCI ? SA_SHIRQ : 0),
926                                         pcName, (void *)&pcName);
927                                 if (rc) {
928                                         printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc);
929                                         ip2config.irq[i] = CIR_POLL;
930                                         printk( KERN_INFO "IP2: Polling %ld/sec.\n",
931                                                         (POLL_TIMEOUT - jiffies));
932                                         goto retry;
933                                 } 
934                                 mark_requested_irq(ip2config.irq[i]);
935                                 /* Initialise the interrupt handler bottom half (aka slih). */
936                         }
937                 }
938                 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
939                         if ( i2BoardPtrTable[i] ) {
940                                 set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */
941                         }
942                 }
943         }
944 #ifdef IP2DEBUG_TRACE
945         ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
946 #endif
947 
948         return 0;
949 }
950 
951 /******************************************************************************/
952 /* Function:   ip2_init_board()                                               */
953 /* Parameters: Index of board in configuration structure                      */
954 /* Returns:    Success (0)                                                    */
955 /*                                                                            */
956 /* Description:                                                               */
957 /* This function initializes the specified board. The loadware is copied to   */
958 /* the board, the channel structures are initialized, and the board details   */
959 /* are reported on the console.                                               */
960 /******************************************************************************/
961 static void __init
962 ip2_init_board( int boardnum )
963 {
964         int i,rc;
965         int nports = 0, nboxes = 0;
966         i2ChanStrPtr pCh;
967         i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
968 
969         if ( !iiInitialize ( pB ) ) {
970                 printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n",
971                          pB->i2eBase, pB->i2eError );
972                 kfree ( pB );
973                 i2BoardPtrTable[boardnum] = NULL;
974                 return;
975         }
976         printk(KERN_INFO "Board %d: addr=0x%x irq=%d ", boardnum + 1,
977                ip2config.addr[boardnum], ip2config.irq[boardnum] );
978 
979         if (0 != ( rc = check_region( ip2config.addr[boardnum], 8))) {
980                 i2BoardPtrTable[boardnum] = NULL;
981                 printk(KERN_ERR "bad addr=0x%x rc = %d\n",
982                                 ip2config.addr[boardnum], rc );
983                 return;
984         }
985         request_region( ip2config.addr[boardnum], 8, pcName );
986 
987         if ( iiDownloadAll ( pB, (loadHdrStrPtr)Fip_firmware, 1, Fip_firmware_size )
988             != II_DOWN_GOOD ) {
989                 printk ( KERN_ERR "IP2:failed to download loadware " );
990         } else {
991                 printk ( KERN_INFO "fv=%d.%d.%d lv=%d.%d.%d\n",
992                          pB->i2ePom.e.porVersion,
993                          pB->i2ePom.e.porRevision,
994                          pB->i2ePom.e.porSubRev, pB->i2eLVersion,
995                          pB->i2eLRevision, pB->i2eLSub );
996         }
997 
998         switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) {
999 
1000         default:
1001                 printk( KERN_ERR "IP2: Unknown board type, ID = %x",
1002                                 pB->i2ePom.e.porID );
1003                 nports = 0;
1004                 goto ex_exit;
1005                 break;
1006 
1007         case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */
1008                 printk ( KERN_INFO "ISA-4" );
1009                 nports = 4;
1010                 break;
1011 
1012         case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */
1013                 printk ( KERN_INFO "ISA-8 std" );
1014                 nports = 8;
1015                 break;
1016 
1017         case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */
1018                 printk ( KERN_INFO "ISA-8 RJ11" );
1019                 nports = 8;
1020                 break;
1021 
1022         case POR_ID_FIIEX: /* IntelliPort IIEX */
1023         {
1024                 int portnum = IP2_PORTS_PER_BOARD * boardnum;
1025                 int            box;
1026 
1027                 for( box = 0; box < ABS_MAX_BOXES; ++box ) {
1028                         if ( pB->i2eChannelMap[box] != 0 ) {
1029                                 ++nboxes;
1030                         }
1031                         for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
1032                                 if ( pB->i2eChannelMap[box] & 1<< i ) {
1033                                         ++nports;
1034                                 }
1035                         }
1036                 }
1037                 DevTableMem[boardnum] = pCh =
1038                         kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL );
1039                 if ( !i2InitChannels( pB, nports, pCh ) ) {
1040                         printk(KERN_ERR "i2InitChannels failed: %d\n",pB->i2eError);
1041                 }
1042                 pB->i2eChannelPtr = &DevTable[portnum];
1043                 pB->i2eChannelCnt = ABS_MOST_PORTS;
1044 
1045                 for( box = 0; box < ABS_MAX_BOXES; ++box, portnum += ABS_BIGGEST_BOX ) {
1046                         for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
1047                                 if ( pB->i2eChannelMap[box] & (1 << i) ) {
1048                                         DevTable[portnum + i] = pCh;
1049                                         pCh->port_index = portnum + i;
1050                                         pCh++;
1051                                 }
1052                         }
1053                 }
1054                 printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit",
1055                         nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 );
1056                 }
1057                 goto ex_exit;
1058                 break;
1059         }
1060         DevTableMem[boardnum] = pCh =
1061                 kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL );
1062         pB->i2eChannelPtr = pCh;
1063         pB->i2eChannelCnt = nports;
1064         i2InitChannels ( pB, pB->i2eChannelCnt, pCh );
1065         pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum];
1066 
1067         for( i = 0; i < pB->i2eChannelCnt; ++i ) {
1068                 DevTable[IP2_PORTS_PER_BOARD * boardnum + i] = pCh;
1069                 pCh->port_index = (IP2_PORTS_PER_BOARD * boardnum) + i;
1070                 pCh++;
1071         }
1072 ex_exit:
1073         printk ( KERN_INFO "\n" );
1074 }
1075 
1076 /******************************************************************************/
1077 /* Function:   find_eisa_board ( int start_slot )                             */
1078 /* Parameters: First slot to check                                            */
1079 /* Returns:    Address of EISA IntelliPort II controller                      */
1080 /*                                                                            */
1081 /* Description:                                                               */
1082 /* This function searches for an EISA IntelliPort controller, starting        */
1083 /* from the specified slot number. If the motherboard is not identified as an */
1084 /* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
1085 /* it returns the base address of the controller.                             */
1086 /******************************************************************************/
1087 static unsigned short __init
1088 find_eisa_board( int start_slot )
1089 {
1090         int i, j;
1091         unsigned int idm = 0;
1092         unsigned int idp = 0;
1093         unsigned int base = 0;
1094         unsigned int value;
1095         int setup_address;
1096         int setup_irq;
1097         int ismine = 0;
1098 
1099         /*
1100          * First a check for an EISA motherboard, which we do by comparing the
1101          * EISA ID registers for the system board and the first couple of slots.
1102          * No slot ID should match the system board ID, but on an ISA or PCI
1103          * machine the odds are that an empty bus will return similar values for
1104          * each slot.
1105          */
1106         i = 0x0c80;
1107         value = (inb(i) << 24) + (inb(i+1) << 16) + (inb(i+2) << 8) + inb(i+3);
1108         for( i = 0x1c80; i <= 0x4c80; i += 0x1000 ) {
1109                 j = (inb(i)<<24)+(inb(i+1)<<16)+(inb(i+2)<<8)+inb(i+3);
1110                 if ( value == j )
1111                         return 0;
1112         }
1113 
1114         /*
1115          * OK, so we are inclined to believe that this is an EISA machine. Find
1116          * an IntelliPort controller.
1117          */
1118         for( i = start_slot; i < 16; i++ ) {
1119                 base = i << 12;
1120                 idm = (inb(base + 0xc80) << 8) | (inb(base + 0xc81) & 0xff);
1121                 idp = (inb(base + 0xc82) << 8) | (inb(base + 0xc83) & 0xff);
1122                 ismine = 0;
1123                 if ( idm == 0x0e8e ) {
1124                         if ( idp == 0x0281 || idp == 0x0218 ) {
1125                                 ismine = 1;
1126                         } else if ( idp == 0x0282 || idp == 0x0283 ) {
1127                                 ismine = 3;     /* Can do edge-trigger */
1128                         }
1129                         if ( ismine ) {
1130                                 Eisa_slot = i;
1131                                 break;
1132                         }
1133                 }
1134         }
1135         if ( !ismine )
1136                 return 0;
1137 
1138         /* It's some sort of EISA card, but at what address is it configured? */
1139 
1140         setup_address = base + 0xc88;
1141         value = inb(base + 0xc86);
1142         setup_irq = (value & 8) ? Valid_Irqs[value & 7] : 0;
1143 
1144         if ( (ismine & 2) && !(value & 0x10) ) {
1145                 ismine = 1;     /* Could be edging, but not */
1146         }
1147 
1148         if ( Eisa_irq == 0 ) {
1149                 Eisa_irq = setup_irq;
1150         } else if ( Eisa_irq != setup_irq ) {
1151                 printk ( KERN_ERR "IP2: EISA irq mismatch between EISA controllers\n" );
1152         }
1153 
1154 #ifdef IP2DEBUG_INIT
1155 printk(KERN_DEBUG "Computone EISA board in slot %d, I.D. 0x%x%x, Address 0x%x",
1156                base >> 12, idm, idp, setup_address);
1157         if ( Eisa_irq ) {
1158                 printk(KERN_DEBUG ", Interrupt %d %s\n",
1159                        setup_irq, (ismine & 2) ? "(edge)" : "(level)");
1160         } else {
1161                 printk(KERN_DEBUG ", (polled)\n");
1162         }
1163 #endif
1164         return setup_address;
1165 }
1166 
1167 /******************************************************************************/
1168 /* Function:   set_irq()                                                      */
1169 /* Parameters: index to board in board table                                  */
1170 /*             IRQ to use                                                     */
1171 /* Returns:    Success (0)                                                    */
1172 /*                                                                            */
1173 /* Description:                                                               */
1174 /******************************************************************************/
1175 static void
1176 set_irq( int boardnum, int boardIrq )
1177 {
1178         unsigned char tempCommand[16];
1179         i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
1180         unsigned long flags;
1181 
1182         /*
1183          * Notify the boards they may generate interrupts. This is done by
1184          * sending an in-line command to channel 0 on each board. This is why
1185          * the channels have to be defined already. For each board, if the
1186          * interrupt has never been defined, we must do so NOW, directly, since
1187          * board will not send flow control or even give an interrupt until this
1188          * is done.  If polling we must send 0 as the interrupt parameter.
1189          */
1190 
1191         // We will get an interrupt here at the end of this function
1192 
1193         iiDisableMailIrq(pB);
1194 
1195         /* We build up the entire packet header. */
1196         CHANNEL_OF(tempCommand) = 0;
1197         PTYPE_OF(tempCommand) = PTYPE_INLINE;
1198         CMD_COUNT_OF(tempCommand) = 2;
1199         (CMD_OF(tempCommand))[0] = CMDVALUE_IRQ;
1200         (CMD_OF(tempCommand))[1] = boardIrq;
1201         /*
1202          * Write to FIFO; don't bother to adjust fifo capacity for this, since
1203          * board will respond almost immediately after SendMail hit.
1204          */
1205         WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
1206         iiWriteBuf(pB, tempCommand, 4);
1207         WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
1208         pB->i2eUsingIrq = boardIrq;
1209         pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
1210 
1211         /* Need to update number of boards before you enable mailbox int */
1212         ++i2nBoards;
1213 
1214         CHANNEL_OF(tempCommand) = 0;
1215         PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1216         CMD_COUNT_OF(tempCommand) = 6;
1217         (CMD_OF(tempCommand))[0] = 88;  // SILO
1218         (CMD_OF(tempCommand))[1] = 64;  // chars
1219         (CMD_OF(tempCommand))[2] = 32;  // ms
1220 
1221         (CMD_OF(tempCommand))[3] = 28;  // MAX_BLOCK
1222         (CMD_OF(tempCommand))[4] = 64;  // chars
1223 
1224         (CMD_OF(tempCommand))[5] = 87;  // HW_TEST
1225         WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
1226         iiWriteBuf(pB, tempCommand, 8);
1227         WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
1228 
1229         CHANNEL_OF(tempCommand) = 0;
1230         PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1231         CMD_COUNT_OF(tempCommand) = 1;
1232         (CMD_OF(tempCommand))[0] = 84;  /* get BOX_IDS */
1233         iiWriteBuf(pB, tempCommand, 3);
1234 
1235 #ifdef XXX
1236         // enable heartbeat for test porpoises
1237         CHANNEL_OF(tempCommand) = 0;
1238         PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1239         CMD_COUNT_OF(tempCommand) = 2;
1240         (CMD_OF(tempCommand))[0] = 44;  /* get ping */
1241         (CMD_OF(tempCommand))[1] = 200; /* 200 ms */
1242         WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
1243         iiWriteBuf(pB, tempCommand, 4);
1244         WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
1245 #endif
1246 
1247         iiEnableMailIrq(pB);
1248         iiSendPendingMail(pB);
1249 }
1250 
1251 /******************************************************************************/
1252 /* Interrupt Handler Section                                                  */
1253 /******************************************************************************/
1254 
1255 static inline void
1256 service_all_boards()
1257 {
1258         int i;
1259         i2eBordStrPtr  pB;
1260 
1261         /* Service every board on the list */
1262         for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
1263                 pB = i2BoardPtrTable[i];
1264                 if ( pB ) {
1265                         i2ServiceBoard( pB );
1266                 }
1267         }
1268 }
1269 
1270 
1271 #ifdef USE_IQI
1272 static struct tq_struct 
1273 senior_service =
1274 {       // it's the death that worse than fate
1275         NULL,
1276         0,
1277         (void(*)(void*)) service_all_boards,
1278         NULL,   //later - board address XXX
1279 };
1280 #endif
1281 
1282 /******************************************************************************/
1283 /* Function:   ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs)    */
1284 /* Parameters: irq - interrupt number                                         */
1285 /*             pointer to optional device ID structure                        */
1286 /*             pointer to register structure                                  */
1287 /* Returns:    Nothing                                                        */
1288 /*                                                                            */
1289 /* Description:                                                               */
1290 /*                                                                            */
1291 /*                                                                            */
1292 /******************************************************************************/
1293 static void
1294 ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs)
1295 {
1296         int i;
1297         i2eBordStrPtr  pB;
1298 
1299 #ifdef IP2DEBUG_TRACE
1300         ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq );
1301 #endif
1302 
1303 #ifdef USE_IQI
1304 
1305         queue_task(&senior_service, &tq_immediate);
1306         mark_bh(IMMEDIATE_BH);
1307 
1308 #else
1309         /* Service just the boards on the list using this irq */
1310         for( i = 0; i < i2nBoards; ++i ) {
1311                 pB = i2BoardPtrTable[i];
1312                 if ( pB && (pB->i2eUsingIrq == irq) ) {
1313                         i2ServiceBoard( pB );
1314                 }
1315         }
1316 
1317 #endif /* USE_IQI */
1318 
1319         ++irq_counter;
1320 
1321 #ifdef IP2DEBUG_TRACE
1322         ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1323 #endif
1324 }
1325 
1326 /******************************************************************************/
1327 /* Function:   ip2_poll(unsigned long arg)                                    */
1328 /* Parameters: ?                                                              */
1329 /* Returns:    Nothing                                                        */
1330 /*                                                                            */
1331 /* Description:                                                               */
1332 /* This function calls the library routine i2ServiceBoard for each board in   */
1333 /* the board table. This is used instead of the interrupt routine when polled */
1334 /* mode is specified.                                                         */
1335 /******************************************************************************/
1336 static void
1337 ip2_poll(unsigned long arg)
1338 {
1339 #ifdef IP2DEBUG_TRACE
1340         ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
1341 #endif
1342         TimerOn = 0; // it's the truth but not checked in service
1343 
1344         bh_counter++; 
1345 
1346 #ifdef USE_IQI
1347 
1348         queue_task(&senior_service, &tq_immediate);
1349         mark_bh(IMMEDIATE_BH);
1350 
1351 #else
1352         // Just polled boards, service_all might be better
1353         ip2_interrupt(0, NULL, NULL);
1354 
1355 #endif /* USE_IQI */
1356 
1357         PollTimer.expires = POLL_TIMEOUT;
1358         add_timer( &PollTimer );
1359         TimerOn = 1;
1360 
1361 #ifdef IP2DEBUG_TRACE
1362         ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1363 #endif
1364 }
1365 
1366 static inline void 
1367 do_input( i2ChanStrPtr pCh )
1368 {
1369         unsigned long flags;
1370 
1371 #ifdef IP2DEBUG_TRACE
1372         ip2trace(CHANN, ITRC_INPUT, 21, 0 );
1373 #endif
1374         // Data input
1375         if ( pCh->pTTY != NULL ) {
1376                 READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
1377                 if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
1378                         READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
1379                         i2Input( pCh );
1380                 } else
1381                         READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
1382         } else {
1383 #ifdef IP2DEBUG_TRACE
1384                 ip2trace(CHANN, ITRC_INPUT, 22, 0 );
1385 #endif
1386                 i2InputFlush( pCh );
1387         }
1388 }
1389 
1390 // code duplicated from n_tty (ldisc)
1391 static inline void 
1392 isig(int sig, struct tty_struct *tty, int flush)
1393 {
1394         if (tty->pgrp > 0)
1395                 kill_pg(tty->pgrp, sig, 1);
1396         if (flush || !L_NOFLSH(tty)) {
1397                 if ( tty->ldisc.flush_buffer )  
1398                         tty->ldisc.flush_buffer(tty);
1399                 i2InputFlush( tty->driver_data );
1400         }
1401 }
1402 
1403 static inline void
1404 do_status( i2ChanStrPtr pCh )
1405 {
1406         int status;
1407 
1408         status =  i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) );
1409 
1410 #ifdef IP2DEBUG_TRACE
1411         ip2trace (CHANN, ITRC_STATUS, 21, 1, status );
1412 #endif
1413 
1414         if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) {
1415                 if ( (status & I2_BRK) ) {
1416                         // code duplicated from n_tty (ldisc)
1417                         if (I_IGNBRK(pCh->pTTY))
1418                                 goto skip_this;
1419                         if (I_BRKINT(pCh->pTTY)) {
1420                                 isig(SIGINT, pCh->pTTY, 1);
1421                                 goto skip_this;
1422                         }
1423                         wake_up_interruptible(&pCh->pTTY->read_wait);
1424                 }
1425 #ifdef NEVER_HAPPENS_AS_SETUP_XXX
1426         // and can't work because we don't know the_char
1427         // as the_char is reported on a seperate path
1428         // The intelligent board does this stuff as setup
1429         {
1430         char brkf = TTY_NORMAL;
1431         unsigned char brkc = '\0';
1432         unsigned char tmp;
1433                 if ( (status & I2_BRK) ) {
1434                         brkf = TTY_BREAK;
1435                         brkc = '\0';
1436                 } 
1437                 else if (status & I2_PAR) {
1438                         brkf = TTY_PARITY;
1439                         brkc = the_char;
1440                 } else if (status & I2_FRA) {
1441                         brkf = TTY_FRAME;
1442                         brkc = the_char;
1443                 } else if (status & I2_OVR) {
1444                         brkf = TTY_OVERRUN;
1445                         brkc = the_char;
1446                 }
1447                 tmp = pCh->pTTY->real_raw;
1448                 pCh->pTTY->real_raw = 0;
1449                 pCh->pTTY->ldisc.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
1450                 pCh->pTTY->real_raw = tmp;
1451         }
1452 #endif /* NEVER_HAPPENS_AS_SETUP_XXX */
1453         }
1454 skip_this:
1455 
1456         if ( status & (I2_DDCD | I2_DDSR | I2_DCTS | I2_DRI) ) {
1457                 wake_up_interruptible(&pCh->delta_msr_wait);
1458 
1459                 if ( (pCh->flags & ASYNC_CHECK_CD) && (status & I2_DDCD) ) {
1460                         if ( status & I2_DCD ) {
1461                                 if ( pCh->wopen ) {
1462                                         wake_up_interruptible ( &pCh->open_wait );
1463                                 }
1464                         } else if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) ) {
1465                                 if (pCh->pTTY &&  (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) {
1466                                         tty_hangup( pCh->pTTY );
1467                                 }
1468                         }
1469                 }
1470         }
1471 
1472 #ifdef IP2DEBUG_TRACE
1473         ip2trace (CHANN, ITRC_STATUS, 26, 0 );
1474 #endif
1475 }
1476 
1477 /******************************************************************************/
1478 /* Device Open/Close/Ioctl Entry Point Section                                */
1479 /******************************************************************************/
1480 
1481 /******************************************************************************/
1482 /* Function:   open_sanity_check()                                            */
1483 /* Parameters: Pointer to tty structure                                       */
1484 /*             Pointer to file structure                                      */
1485 /* Returns:    Success or failure                                             */
1486 /*                                                                            */
1487 /* Description:                                                               */
1488 /* Verifies the structure magic numbers and cross links.                      */
1489 /******************************************************************************/
1490 #ifdef IP2DEBUG_OPEN
1491 static void 
1492 open_sanity_check( i2ChanStrPtr pCh, i2eBordStrPtr pBrd )
1493 {
1494         if ( pBrd->i2eValid != I2E_MAGIC ) {
1495                 printk(KERN_ERR "IP2: invalid board structure\n" );
1496         } else if ( pBrd != pCh->pMyBord ) {
1497                 printk(KERN_ERR "IP2: board structure pointer mismatch (%p)\n",
1498                          pCh->pMyBord );
1499         } else if ( pBrd->i2eChannelCnt < pCh->port_index ) {
1500                 printk(KERN_ERR "IP2: bad device index (%d)\n", pCh->port_index );
1501         } else if (&((i2ChanStrPtr)pBrd->i2eChannelPtr)[pCh->port_index] != pCh) {
1502         } else {
1503                 printk(KERN_INFO "IP2: all pointers check out!\n" );
1504         }
1505 }
1506 #endif
1507 
1508 
1509 /******************************************************************************/
1510 /* Function:   ip2_open()                                                     */
1511 /* Parameters: Pointer to tty structure                                       */
1512 /*             Pointer to file structure                                      */
1513 /* Returns:    Success or failure                                             */
1514 /*                                                                            */
1515 /* Description: (MANDATORY)                                                   */
1516 /* A successful device open has to run a gauntlet of checks before it         */
1517 /* completes. After some sanity checking and pointer setup, the function      */
1518 /* blocks until all conditions are satisfied. It then initialises the port to */
1519 /* the default characteristics and returns.                                   */
1520 /******************************************************************************/
1521 static int
1522 ip2_open( PTTY tty, struct file *pFile )
1523 {
1524         int rc = 0;
1525         int do_clocal = 0;
1526         i2ChanStrPtr  pCh = DevTable[MINOR(tty->device)];
1527 
1528 #ifdef IP2DEBUG_TRACE
1529         ip2trace (MINOR(tty->device), ITRC_OPEN, ITRC_ENTER, 0 );
1530 #endif
1531 
1532         if ( pCh == NULL ) {
1533                 return -ENODEV;
1534         }
1535         /* Setup pointer links in device and tty structures */
1536         pCh->pTTY = tty;
1537         tty->driver_data = pCh;
1538         MOD_INC_USE_COUNT;
1539 
1540 #ifdef IP2DEBUG_OPEN
1541         printk(KERN_DEBUG \
1542                         "IP2:open(tty=%p,pFile=%p):dev=%x,maj=%d,min=%d,ch=%d,idx=%d\n",
1543                tty, pFile, tty->device, MAJOR(tty->device), MINOR(tty->device),
1544                          pCh->infl.hd.i2sChannel, pCh->port_index);
1545         open_sanity_check ( pCh, pCh->pMyBord );
1546 #endif
1547 
1548         i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, CMD_DTRUP,CMD_RTSUP,CMD_DCD_REP);
1549         pCh->dataSetOut |= (I2_DTR | I2_RTS);
1550         serviceOutgoingFifo( pCh->pMyBord );
1551 
1552         /* Block here until the port is ready (per serial and istallion) */
1553         /*
1554          * 1. If the port is in the middle of closing wait for the completion
1555          *    and then return the appropriate error.
1556          */
1557         if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
1558                 if ( pCh->flags & ASYNC_CLOSING ) {
1559                         interruptible_sleep_on( &pCh->close_wait);
1560                 }
1561                 if ( tty_hung_up_p(pFile) ) {
1562                         return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS;
1563                 }
1564         }
1565         /*
1566          * 2. If this is a callout device, make sure the normal port is not in
1567          *    use, and that someone else doesn't have the callout device locked.
1568          *    (These are the only tests the standard serial driver makes for
1569          *    callout devices.)
1570          */
1571         if ( tty->driver.subtype == SERIAL_TYPE_CALLOUT ) {
1572                 if ( pCh->flags & ASYNC_NORMAL_ACTIVE ) {
1573                         return -EBUSY;
1574                 }
1575                 if ( ( pCh->flags & ASYNC_CALLOUT_ACTIVE )  &&
1576                     ( pCh->flags & ASYNC_SESSION_LOCKOUT ) &&
1577                     ( pCh->session != current->session ) ) {
1578                         return -EBUSY;
1579                 }
1580                 if ( ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) &&
1581                     ( pCh->flags & ASYNC_PGRP_LOCKOUT )   &&
1582                     ( pCh->pgrp != current->pgrp ) ) {
1583                         return -EBUSY;
1584                 }
1585                 pCh->flags |= ASYNC_CALLOUT_ACTIVE;
1586                 goto noblock;
1587         }
1588         /*
1589          * 3. Handle a non-blocking open of a normal port.
1590          */
1591         if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<<TTY_IO_ERROR) )) {
1592                 if ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) {
1593                         return -EBUSY;
1594                 }
1595                 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1596                 goto noblock;
1597         }
1598         /*
1599          * 4. Now loop waiting for the port to be free and carrier present
1600          *    (if required).
1601          */
1602         if ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) {
1603                 if ( pCh->NormalTermios.c_cflag & CLOCAL ) {
1604                         do_clocal = 1;
1605                 }
1606         } else {
1607                 if ( tty->termios->c_cflag & CLOCAL ) {
1608                         do_clocal = 1;
1609                 }
1610         }
1611 
1612 #ifdef IP2DEBUG_OPEN
1613         printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal);
1614 #endif
1615 
1616         ++pCh->wopen;
1617         for(;;) {
1618                 if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE)) {
1619                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
1620                         pCh->dataSetOut |= (I2_DTR | I2_RTS);
1621                         serviceOutgoingFifo( pCh->pMyBord );
1622                 }
1623                 if ( tty_hung_up_p(pFile) ) {
1624                         return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
1625                 }
1626                 if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) &&
1627                                 !(pCh->flags & ASYNC_CLOSING) && 
1628                                 (do_clocal || (pCh->dataSetIn & I2_DCD) )) {
1629                         rc = 0;
1630                         break;
1631                 }
1632 
1633 #ifdef IP2DEBUG_OPEN
1634                 printk(KERN_DEBUG "ASYNC_CALLOUT_ACTIVE = %s\n",
1635                         (pCh->flags & ASYNC_CALLOUT_ACTIVE)?"True":"False");
1636                 printk(KERN_DEBUG "ASYNC_CLOSING = %s\n",
1637                         (pCh->flags & ASYNC_CLOSING)?"True":"False");
1638                 printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
1639 #endif
1640 #ifdef IP2DEBUG_TRACE
1641                 ip2trace (CHANN, ITRC_OPEN, 3, 2, (pCh->flags & ASYNC_CALLOUT_ACTIVE),
1642                                                                 (pCh->flags & ASYNC_CLOSING) );
1643 #endif
1644                 /* check for signal */
1645                 if (signal_pending(current)) {
1646                         rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
1647                         break;
1648                 }
1649                 interruptible_sleep_on(&pCh->open_wait);
1650         }
1651         --pCh->wopen; //why count?
1652 #ifdef IP2DEBUG_TRACE
1653         ip2trace (CHANN, ITRC_OPEN, 4, 0 );
1654 #endif
1655         if (rc != 0 ) {
1656                 return rc;
1657         }
1658         pCh->flags |= ASYNC_NORMAL_ACTIVE;
1659 
1660 noblock:
1661 
1662         /* first open - Assign termios structure to port */
1663         if ( tty->count == 1 ) {
1664                 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1665                 if ( pCh->flags & ASYNC_SPLIT_TERMIOS ) {
1666                         if ( tty->driver.subtype == SERIAL_TYPE_NORMAL ) {
1667                                 *tty->termios = pCh->NormalTermios;
1668                         } else {
1669                                 *tty->termios = pCh->CalloutTermios;
1670                         }
1671                 }
1672                 /* Now we must send the termios settings to the loadware */
1673                 set_params( pCh, NULL );
1674         }
1675 
1676         /* override previous and never reset ??? */
1677         pCh->session = current->session;
1678         pCh->pgrp = current->pgrp;
1679 
1680         /*
1681          * Now set any i2lib options. These may go away if the i2lib code ends
1682          * up rolled into the mainline.
1683          */
1684         pCh->channelOptions |= CO_NBLOCK_WRITE;
1685 
1686 #ifdef IP2DEBUG_OPEN
1687         printk (KERN_DEBUG "IP2: open completed\n" );
1688 #endif
1689         serviceOutgoingFifo( pCh->pMyBord );
1690 
1691 #ifdef IP2DEBUG_TRACE
1692         ip2trace (CHANN, ITRC_OPEN, ITRC_RETURN, 0 );
1693 #endif
1694         return 0;
1695 }
1696 
1697 /******************************************************************************/
1698 /* Function:   ip2_close()                                                    */
1699 /* Parameters: Pointer to tty structure                                       */
1700 /*             Pointer to file structure                                      */
1701 /* Returns:    Nothing                                                        */
1702 /*                                                                            */
1703 /* Description:                                                               */
1704 /*                                                                            */
1705 /*                                                                            */
1706 /******************************************************************************/
1707 static void
1708 ip2_close( PTTY tty, struct file *pFile )
1709 {
1710         i2ChanStrPtr  pCh = tty->driver_data;
1711 
1712         if ( !pCh ) {
1713                 return;
1714         }
1715 
1716 #ifdef IP2DEBUG_TRACE
1717         ip2trace (CHANN, ITRC_CLOSE, ITRC_ENTER, 0 );
1718 #endif
1719 
1720 #ifdef IP2DEBUG_OPEN
1721         printk(KERN_DEBUG "IP2:close ttyF%02X:\n",MINOR(tty->device));
1722 #endif
1723 
1724         if ( tty_hung_up_p ( pFile ) ) {
1725                 MOD_DEC_USE_COUNT;
1726 
1727 #ifdef IP2DEBUG_TRACE
1728                 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 );
1729 #endif
1730                 return;
1731         }
1732         if ( tty->count > 1 ) { /* not the last close */
1733                 MOD_DEC_USE_COUNT;
1734 #ifdef IP2DEBUG_TRACE
1735                 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 );
1736 #endif
1737                 return;
1738         }
1739         pCh->flags |= ASYNC_CLOSING;    // last close actually
1740 
1741         /*
1742          * Save the termios structure, since this port may have separate termios
1743          * for callout and dialin.
1744          */
1745         if (pCh->flags & ASYNC_NORMAL_ACTIVE)
1746                 pCh->NormalTermios = *tty->termios;
1747         if (pCh->flags & ASYNC_CALLOUT_ACTIVE)
1748                 pCh->CalloutTermios = *tty->termios;
1749 
1750         tty->closing = 1;
1751 
1752         if (pCh->ClosingWaitTime != ASYNC_CLOSING_WAIT_NONE) {
1753                 /*
1754                  * Before we drop DTR, make sure the transmitter has completely drained.
1755                  * This uses an timeout, after which the close
1756                  * completes.
1757                  */
1758                 ip2_wait_until_sent(tty, pCh->ClosingWaitTime );
1759         }
1760         /*
1761          * At this point we stop accepting input. Here we flush the channel
1762          * input buffer which will allow the board to send up more data. Any
1763          * additional input is tossed at interrupt/poll time.
1764          */
1765         i2InputFlush( pCh );
1766 
1767         /* disable DSS reporting */
1768         i2QueueCommands(PTYPE_INLINE, pCh, 100, 4,
1769                                 CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1770         if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
1771                 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
1772                 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1773                 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1774         }
1775 
1776         serviceOutgoingFifo ( pCh->pMyBord );
1777 
1778         if ( tty->driver.flush_buffer ) 
1779                 tty->driver.flush_buffer(tty);
1780         if ( tty->ldisc.flush_buffer )  
1781                 tty->ldisc.flush_buffer(tty);
1782         tty->closing = 0;
1783         
1784         pCh->pTTY = NULL;
1785 
1786         if (pCh->wopen) {
1787                 if (pCh->ClosingDelay) {
1788                         current->state = TASK_INTERRUPTIBLE;
1789                         schedule_timeout(pCh->ClosingDelay);
1790                 }
1791                 wake_up_interruptible(&pCh->open_wait);
1792         }
1793 
1794         pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
1795         wake_up_interruptible(&pCh->close_wait);
1796 
1797 #ifdef IP2DEBUG_OPEN
1798         DBG_CNT("ip2_close: after wakeups--");
1799 #endif
1800 
1801         MOD_DEC_USE_COUNT;
1802 
1803 #ifdef IP2DEBUG_TRACE
1804         ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
1805 #endif
1806         return;
1807 }
1808 
1809 /******************************************************************************/
1810 /* Function:   ip2_hangup()                                                   */
1811 /* Parameters: Pointer to tty structure                                       */
1812 /* Returns:    Nothing                                                        */
1813 /*                                                                            */
1814 /* Description:                                                               */
1815 /*                                                                            */
1816 /*                                                                            */
1817 /******************************************************************************/
1818 static void
1819 ip2_hangup ( PTTY tty )
1820 {
1821         i2ChanStrPtr  pCh = tty->driver_data;
1822 
1823 #ifdef IP2DEBUG_TRACE
1824         ip2trace (CHANN, ITRC_HANGUP, ITRC_ENTER, 0 );
1825 #endif
1826 
1827         ip2_flush_buffer(tty);
1828 
1829         /* disable DSS reporting */
1830 
1831         i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP);
1832         i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1833         if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
1834                 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN);
1835                 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1836                 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1837         }
1838         i2QueueCommands(PTYPE_INLINE, pCh, 1, 3, 
1839                                 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1840         serviceOutgoingFifo ( pCh->pMyBord );
1841 
1842         wake_up_interruptible ( &pCh->delta_msr_wait );
1843 
1844         pCh->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
1845         pCh->pTTY = NULL;
1846         wake_up_interruptible ( &pCh->open_wait );
1847 
1848 #ifdef IP2DEBUG_TRACE
1849         ip2trace (CHANN, ITRC_HANGUP, ITRC_RETURN, 0 );
1850 #endif
1851 }
1852 
1853 /******************************************************************************/
1854 /******************************************************************************/
1855 /* Device Output Section                                                      */
1856 /******************************************************************************/
1857 /******************************************************************************/
1858 
1859 /******************************************************************************/
1860 /* Function:   ip2_write()                                                    */
1861 /* Parameters: Pointer to tty structure                                       */
1862 /*             Flag denoting data is in user (1) or kernel (0) space          */
1863 /*             Pointer to data                                                */
1864 /*             Number of bytes to write                                       */
1865 /* Returns:    Number of bytes actually written                               */
1866 /*                                                                            */
1867 /* Description: (MANDATORY)                                                   */
1868 /*                                                                            */
1869 /*                                                                            */
1870 /******************************************************************************/
1871 static int
1872 ip2_write( PTTY tty, int user, const unsigned char *pData, int count)
1873 {
1874         i2ChanStrPtr  pCh = tty->driver_data;
1875         int bytesSent = 0;
1876         unsigned long flags;
1877 
1878 #ifdef IP2DEBUG_TRACE
1879    ip2trace (CHANN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
1880 #endif
1881 
1882         /* Flush out any buffered data left over from ip2_putchar() calls. */
1883         ip2_flush_chars( tty );
1884 
1885         /* This is the actual move bit. Make sure it does what we need!!!!! */
1886         WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
1887         bytesSent = i2Output( pCh, pData, count, user );
1888         WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
1889 
1890 #ifdef IP2DEBUG_TRACE
1891    ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
1892 #endif
1893         return bytesSent > 0 ? bytesSent : 0;
1894 }
1895 
1896 /******************************************************************************/
1897 /* Function:   ip2_putchar()                                                  */
1898 /* Parameters: Pointer to tty structure                                       */
1899 /*             Character to write                                             */
1900 /* Returns:    Nothing                                                        */
1901 /*                                                                            */
1902 /* Description:                                                               */
1903 /*                                                                            */
1904 /*                                                                            */
1905 /******************************************************************************/
1906 static void
1907 ip2_putchar( PTTY tty, unsigned char ch )
1908 {
1909         i2ChanStrPtr  pCh = tty->driver_data;
1910         unsigned long flags;
1911 
1912 #ifdef IP2DEBUG_TRACE
1913 //      ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
1914 #endif
1915 
1916         WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
1917         pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
1918         if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
1919                 WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
1920                 ip2_flush_chars( tty );
1921         } else
1922                 WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
1923 
1924 #ifdef IP2DEBUG_TRACE
1925 //      ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
1926 #endif
1927 }
1928 
1929 /******************************************************************************/
1930 /* Function:   ip2_flush_chars()                                              */
1931 /* Parameters: Pointer to tty structure                                       */
1932 /* Returns:    Nothing                                                        */
1933 /*                                                                            */
1934 /* Description:                                                               */
1935 /*                                                                            */
1936 /******************************************************************************/
1937 static void
1938 ip2_flush_chars( PTTY tty )
1939 {
1940         int   strip;
1941         i2ChanStrPtr  pCh = tty->driver_data;
1942         unsigned long flags;
1943 
1944         WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
1945         if ( pCh->Pbuf_stuff ) {
1946 #ifdef IP2DEBUG_TRACE
1947 //      ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
1948 #endif
1949                 //
1950                 // We may need to restart i2Output if it does not fullfill this request
1951                 //
1952                 strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff, 0 );
1953                 if ( strip != pCh->Pbuf_stuff ) {
1954                         memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip );
1955                 }
1956                 pCh->Pbuf_stuff -= strip;
1957         }
1958         WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
1959 }
1960 
1961 /******************************************************************************/
1962 /* Function:   ip2_write_room()                                               */
1963 /* Parameters: Pointer to tty structure                                       */
1964 /* Returns:    Number of bytes that the driver can accept                     */
1965 /*                                                                            */
1966 /* Description:                                                               */
1967 /*                                                                            */
1968 /******************************************************************************/
1969 static int
1970 ip2_write_room ( PTTY tty )
1971 {
1972         int bytesFree;
1973         i2ChanStrPtr  pCh = tty->driver_data;
1974         unsigned long flags;
1975 
1976         READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
1977         bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
1978         READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
1979 
1980 #ifdef IP2DEBUG_TRACE
1981         ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
1982 #endif
1983 
1984         return ((bytesFree > 0) ? bytesFree : 0);
1985 }
1986 
1987 /******************************************************************************/
1988 /* Function:   ip2_chars_in_buf()                                             */
1989 /* Parameters: Pointer to tty structure                                       */
1990 /* Returns:    Number of bytes queued for transmission                        */
1991 /*                                                                            */
1992 /* Description:                                                               */
1993 /*                                                                            */
1994 /*                                                                            */
1995 /******************************************************************************/
1996 static int
1997 ip2_chars_in_buf ( PTTY tty )
1998 {
1999         i2ChanStrPtr  pCh = tty->driver_data;
2000         int rc;
2001         unsigned long flags;
2002 #ifdef IP2DEBUG_TRACE
2003         ip2trace (CHANN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
2004 #endif
2005 #ifdef IP2DEBUG_WRITE
2006         printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n",
2007                                  pCh->Obuf_char_count + pCh->Pbuf_stuff,
2008                                  pCh->Obuf_char_count, pCh->Pbuf_stuff );
2009 #endif
2010         READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
2011         rc =  pCh->Obuf_char_count;
2012         READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
2013         READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
2014         rc +=  pCh->Pbuf_stuff;
2015         READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
2016         return rc;
2017 }
2018 
2019 /******************************************************************************/
2020 /* Function:   ip2_flush_buffer()                                             */
2021 /* Parameters: Pointer to tty structure                                       */
2022 /* Returns:    Nothing                                                        */
2023 /*                                                                            */
2024 /* Description:                                                               */
2025 /*                                                                            */
2026 /*                                                                            */
2027 /******************************************************************************/
2028 static void
2029 ip2_flush_buffer( PTTY tty )
2030 {
2031         i2ChanStrPtr  pCh = tty->driver_data;
2032         unsigned long flags;
2033 
2034 #ifdef IP2DEBUG_TRACE
2035         ip2trace (CHANN, ITRC_FLUSH, ITRC_ENTER, 0 );
2036 #endif
2037 #ifdef IP2DEBUG_WRITE
2038         printk (KERN_DEBUG "IP2: flush buffer\n" );
2039 #endif
2040         WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
2041         pCh->Pbuf_stuff = 0;
2042         WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
2043         i2FlushOutput( pCh );
2044         ip2_owake(tty);
2045 #ifdef IP2DEBUG_TRACE
2046         ip2trace (CHANN, ITRC_FLUSH, ITRC_RETURN, 0 );
2047 #endif
2048 }
2049 
2050 /******************************************************************************/
2051 /* Function:   ip2_wait_until_sent()                                          */
2052 /* Parameters: Pointer to tty structure                                       */
2053 /*             Timeout for wait.                                              */
2054 /* Returns:    Nothing                                                        */
2055 /*                                                                            */
2056 /* Description:                                                               */
2057 /* This function is used in place of the normal tty_wait_until_sent, which    */
2058 /* only waits for the driver buffers to be empty (or rather, those buffers    */
2059 /* reported by chars_in_buffer) which doesn't work for IP2 due to the         */
2060 /* indeterminate number of bytes buffered on the board.                       */
2061 /******************************************************************************/
2062 static void
2063 ip2_wait_until_sent ( PTTY tty, int timeout )
2064 {
2065         int i = jiffies;
2066         i2ChanStrPtr  pCh = tty->driver_data;
2067 
2068         tty_wait_until_sent(tty, timeout );
2069         if ( (i = timeout - (jiffies -i)) > 0)
2070                 i2DrainOutput( pCh, i );
2071 }
2072 
2073 /******************************************************************************/
2074 /******************************************************************************/
2075 /* Device Input Section                                                       */
2076 /******************************************************************************/
2077 /******************************************************************************/
2078 
2079 /******************************************************************************/
2080 /* Function:   ip2_throttle()                                                 */
2081 /* Parameters: Pointer to tty structure                                       */
2082 /* Returns:    Nothing                                                        */
2083 /*                                                                            */
2084 /* Description:                                                               */
2085 /*                                                                            */
2086 /*                                                                            */
2087 /******************************************************************************/
2088 static void
2089 ip2_throttle ( PTTY tty )
2090 {
2091         i2ChanStrPtr  pCh = tty->driver_data;
2092 
2093 #ifdef IP2DEBUG_READ
2094         printk (KERN_DEBUG "IP2: throttle\n" );
2095 #endif
2096         /*
2097          * Signal the poll/interrupt handlers not to forward incoming data to
2098          * the line discipline. This will cause the buffers to fill up in the
2099          * library and thus cause the library routines to send the flow control
2100          * stuff.
2101          */
2102         pCh->throttled = 1;
2103 }
2104 
2105 /******************************************************************************/
2106 /* Function:   ip2_unthrottle()                                               */
2107 /* Parameters: Pointer to tty structure                                       */
2108 /* Returns:    Nothing                                                        */
2109 /*                                                                            */
2110 /* Description:                                                               */
2111 /*                                                                            */
2112 /*                                                                            */
2113 /******************************************************************************/
2114 static void
2115 ip2_unthrottle ( PTTY tty )
2116 {
2117         i2ChanStrPtr  pCh = tty->driver_data;
2118         unsigned long flags;
2119 
2120 #ifdef IP2DEBUG_READ
2121         printk (KERN_DEBUG "IP2: unthrottle\n" );
2122 #endif
2123 
2124         /* Pass incoming data up to the line discipline again. */
2125         pCh->throttled = 0;
2126         i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
2127         serviceOutgoingFifo( pCh->pMyBord );
2128         READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
2129         if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
2130                 READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
2131 #ifdef IP2DEBUG_READ
2132                 printk (KERN_DEBUG "i2Input called from unthrottle\n" );
2133 #endif
2134                 i2Input( pCh );
2135         } else
2136                 READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
2137 }
2138 
2139 static void
2140 ip2_start ( PTTY tty )
2141 {
2142         i2ChanStrPtr  pCh = DevTable[MINOR(tty->device)];
2143 
2144         i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
2145         i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_UNSUSPEND);
2146         i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_RESUME);
2147 #ifdef IP2DEBUG_WRITE
2148         printk (KERN_DEBUG "IP2: start tx\n" );
2149 #endif
2150 }
2151 
2152 static void
2153 ip2_stop ( PTTY tty )
2154 {
2155         i2ChanStrPtr  pCh = DevTable[MINOR(tty->device)];
2156 
2157         i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_SUSPEND);
2158 #ifdef IP2DEBUG_WRITE
2159         printk (KERN_DEBUG "IP2: stop tx\n" );
2160 #endif
2161 }
2162 
2163 /******************************************************************************/
2164 /* Device Ioctl Section                                                       */
2165 /******************************************************************************/
2166 
2167 /******************************************************************************/
2168 /* Function:   ip2_ioctl()                                                    */
2169 /* Parameters: Pointer to tty structure                                       */
2170 /*             Pointer to file structure                                      */
2171 /*             Command                                                        */
2172 /*             Argument                                                       */
2173 /* Returns:    Success or failure                                             */
2174 /*                                                                            */
2175 /* Description:                                                               */
2176 /*                                                                            */
2177 /*                                                                            */
2178 /******************************************************************************/
2179 static int
2180 ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
2181 {
2182         i2ChanStrPtr pCh = DevTable[MINOR(tty->device)];
2183         struct async_icount cprev, cnow;        /* kernel counter temps */
2184         struct serial_icounter_struct *p_cuser; /* user space */
2185         int rc = 0;
2186         unsigned long flags;
2187 
2188         if ( pCh == NULL ) {
2189                 return -ENODEV;
2190         }
2191 
2192 #ifdef IP2DEBUG_TRACE
2193         ip2trace (CHANN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
2194 #endif
2195 
2196 #ifdef IP2DEBUG_IOCTL
2197         printk(KERN_DEBUG "IP2: ioctl cmd (%x), arg (%lx)\n", cmd, arg );
2198 #endif
2199 
2200         switch(cmd) {
2201         case TIOCGSERIAL:
2202 #ifdef IP2DEBUG_TRACE
2203                 ip2trace (CHANN, ITRC_IOCTL, 2, 1, rc );
2204 #endif
2205                 rc = get_serial_info(pCh, (struct serial_struct *) arg);
2206                 if (rc)
2207                         return rc;
2208                 break;
2209 
2210         case TIOCSSERIAL:
2211 #ifdef IP2DEBUG_TRACE
2212                 ip2trace (CHANN, ITRC_IOCTL, 3, 1, rc );
2213 #endif
2214                 rc = set_serial_info(pCh, (struct serial_struct *) arg);
2215                 if (rc)
2216                         return rc;
2217                 break;
2218 
2219         case TCXONC:
2220                 rc = tty_check_change(tty);
2221                 if (rc)
2222                         return rc;
2223                 switch (arg) {
2224                 case TCOOFF:
2225                         //return  -ENOIOCTLCMD;
2226                         break;
2227                 case TCOON:
2228                         //return  -ENOIOCTLCMD;
2229                         break;
2230                 case TCIOFF:
2231                         if (STOP_CHAR(tty) != __DISABLED_CHAR) {
2232                                 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2233                                                 CMD_XMIT_NOW(STOP_CHAR(tty)));
2234                         }
2235                         break;
2236                 case TCION:
2237                         if (START_CHAR(tty) != __DISABLED_CHAR) {
2238                                 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2239                                                 CMD_XMIT_NOW(START_CHAR(tty)));
2240                         }
2241                         break;
2242                 default:
2243                         return -EINVAL;
2244                 }
2245                 return 0;
2246 
2247         case TCSBRK:   /* SVID version: non-zero arg --> no break */
2248                 rc = tty_check_change(tty);
2249 #ifdef IP2DEBUG_TRACE
2250                 ip2trace (CHANN, ITRC_IOCTL, 4, 1, rc );
2251 #endif
2252                 if (!rc) {
2253                         ip2_wait_until_sent(tty,0);
2254                         if (!arg) {
2255                                 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SEND_BRK(250));
2256                                 serviceOutgoingFifo( pCh->pMyBord );
2257                         }
2258                 }
2259                 break;
2260 
2261         case TCSBRKP:  /* support for POSIX tcsendbreak() */
2262                 rc = tty_check_change(tty);
2263 #ifdef IP2DEBUG_TRACE
2264                 ip2trace (CHANN, ITRC_IOCTL, 5, 1, rc );
2265 #endif
2266                 if (!rc) {
2267                         ip2_wait_until_sent(tty,0);
2268                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2269                                 CMD_SEND_BRK(arg ? arg*100 : 250));
2270                         serviceOutgoingFifo ( pCh->pMyBord );   
2271                 }
2272                 break;
2273 
2274         case TIOCGSOFTCAR:
2275 #ifdef IP2DEBUG_TRACE
2276                 ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc );
2277 #endif
2278                         PUT_USER(rc,C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
2279                 if (rc) 
2280                         return rc;
2281         break;
2282 
2283         case TIOCSSOFTCAR:
2284 #ifdef IP2DEBUG_TRACE
2285                 ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc );
2286 #endif
2287                 GET_USER(rc,arg,(unsigned long *) arg);
2288                 if (rc) 
2289                         return rc;
2290                 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL)
2291                                          | (arg ? CLOCAL : 0));
2292                 
2293                 break;
2294 
2295         case TIOCMGET:
2296 #ifdef IP2DEBUG_TRACE
2297                 ip2trace (CHANN, ITRC_IOCTL, 8, 1, rc );
2298 #endif
2299 /*
2300         FIXME - the following code is causing a NULL pointer dereference in
2301         2.3.51 in an interrupt handler.  It's suppose to prompt the board
2302         to return the DSS signal status immediately.  Why doesn't it do
2303         the same thing in 2.2.14?
2304 */
2305 /*
2306                 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
2307                 serviceOutgoingFifo( pCh->pMyBord );
2308                 interruptible_sleep_on(&pCh->dss_now_wait);
2309                 if (signal_pending(current)) {
2310                         return -EINTR;
2311                 }
2312 */
2313                 PUT_USER(rc,
2314                                     ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
2315                                   | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
2316                                   | ((pCh->dataSetIn  & I2_DCD) ? TIOCM_CAR : 0)
2317                                   | ((pCh->dataSetIn  & I2_RI)  ? TIOCM_RNG : 0)
2318                                   | ((pCh->dataSetIn  & I2_DSR) ? TIOCM_DSR : 0)
2319                                   | ((pCh->dataSetIn  & I2_CTS) ? TIOCM_CTS : 0),
2320                                 (unsigned int *) arg);
2321                 break;
2322 
2323         case TIOCMBIS:
2324         case TIOCMBIC:
2325         case TIOCMSET:
2326 #ifdef IP2DEBUG_TRACE
2327                 ip2trace (CHANN, ITRC_IOCTL, 9, 0 );
2328 #endif
2329                 rc = set_modem_info(pCh, cmd, (unsigned int *) arg);
2330                 break;
2331 
2332         /*
2333          * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - mask
2334          * passed in arg for lines of interest (use |'ed TIOCM_RNG/DSR/CD/CTS
2335          * for masking). Caller should use TIOCGICOUNT to see which one it was
2336          */
2337         case TIOCMIWAIT:
2338                 save_flags(flags);cli();
2339                 cprev = pCh->icount;     /* note the counters on entry */
2340                 restore_flags(flags);
2341                 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4, 
2342                                                 CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
2343                 serviceOutgoingFifo( pCh->pMyBord );
2344                 for(;;) {
2345 #ifdef IP2DEBUG_TRACE
2346                         ip2trace (CHANN, ITRC_IOCTL, 10, 0 );
2347 #endif
2348                         interruptible_sleep_on(&pCh->delta_msr_wait);
2349 #ifdef IP2DEBUG_TRACE
2350                         ip2trace (CHANN, ITRC_IOCTL, 11, 0 );
2351 #endif
2352                         /* see if a signal did it */
2353                         if (signal_pending(current)) {
2354                                 rc = -ERESTARTSYS;
2355                                 break;
2356                         }
2357                         save_flags(flags);cli();
2358                         cnow = pCh->icount; /* atomic copy */
2359                         restore_flags(flags);
2360                         if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2361                                 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
2362                                 rc =  -EIO; /* no change => rc */
2363                                 break;
2364                         }
2365                         if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2366                             ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2367                             ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
2368                             ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
2369                                 rc =  0;
2370                                 break;
2371                         }
2372                         cprev = cnow;
2373                 }
2374                 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 3, 
2375                                                  CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
2376                 if ( ! (pCh->flags      & ASYNC_CHECK_CD)) {
2377                         i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DCD_NREP);
2378                 }
2379                 serviceOutgoingFifo( pCh->pMyBord );
2380                 return rc;
2381                 break;
2382 
2383         /*
2384          * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2385          * Return: write counters to the user passed counter struct
2386          * NB: both 1->0 and 0->1 transitions are counted except for RI where
2387          * only 0->1 is counted. The controller is quite capable of counting
2388          * both, but this done to preserve compatibility with the standard
2389          * serial driver.
2390          */
2391         case TIOCGICOUNT:
2392 #ifdef IP2DEBUG_TRACE
2393                 ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
2394 #endif
2395                 save_flags(flags);cli();
2396                 cnow = pCh->icount;
2397                 restore_flags(flags);
2398                 p_cuser = (struct serial_icounter_struct *) arg;
2399                 PUT_USER(rc,cnow.cts, &p_cuser->cts);
2400                 PUT_USER(rc,cnow.dsr, &p_cuser->dsr);
2401                 PUT_USER(rc,cnow.rng, &p_cuser->rng);
2402                 PUT_USER(rc,cnow.dcd, &p_cuser->dcd);
2403                 PUT_USER(rc,cnow.rx, &p_cuser->rx);
2404                 PUT_USER(rc,cnow.tx, &p_cuser->tx);
2405                 PUT_USER(rc,cnow.frame, &p_cuser->frame);
2406                 PUT_USER(rc,cnow.overrun, &p_cuser->overrun);
2407                 PUT_USER(rc,cnow.parity, &p_cuser->parity);
2408                 PUT_USER(rc,cnow.brk, &p_cuser->brk);
2409                 PUT_USER(rc,cnow.buf_overrun, &p_cuser->buf_overrun);
2410                 break;
2411 
2412         /*
2413          * The rest are not supported by this driver. By returning -ENOIOCTLCMD they
2414          * will be passed to the line discipline for it to handle.
2415          */
2416         case TIOCSERCONFIG:
2417         case TIOCSERGWILD:
2418         case TIOCSERGETLSR:
2419         case TIOCSERSWILD:
2420         case TIOCSERGSTRUCT:
2421         case TIOCSERGETMULTI:
2422         case TIOCSERSETMULTI:
2423 
2424         default:
2425 #ifdef IP2DEBUG_TRACE
2426                 ip2trace (CHANN, ITRC_IOCTL, 12, 0 );
2427 #endif
2428                 rc =  -ENOIOCTLCMD;
2429                 break;
2430         }
2431 #ifdef IP2DEBUG_TRACE
2432         ip2trace (CHANN, ITRC_IOCTL, ITRC_RETURN, 0 );
2433 #endif
2434         return rc;
2435 }
2436 
2437 /******************************************************************************/
2438 /* Function:   set_modem_info()                                               */
2439 /* Parameters: Pointer to channel structure                                   */
2440 /*             Specific ioctl command                                         */
2441 /*             Pointer to source for new settings                             */
2442 /* Returns:    Nothing                                                        */
2443 /*                                                                            */
2444 /* Description:                                                               */
2445 /* This returns the current settings of the dataset signal inputs to the user */
2446 /* program.                                                                   */
2447 /******************************************************************************/
2448 static int
2449 set_modem_info(i2ChanStrPtr pCh, unsigned cmd, unsigned int *value)
2450 {
2451         int rc;
2452         unsigned int arg;
2453 
2454         GET_USER(rc,arg,value);
2455         if (rc)
2456                 return rc;
2457         switch(cmd) {
2458         case TIOCMBIS:
2459                 if (arg & TIOCM_RTS) {
2460                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
2461                         pCh->dataSetOut |= I2_RTS;
2462                 }
2463                 if (arg & TIOCM_DTR) {
2464                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
2465                         pCh->dataSetOut |= I2_DTR;
2466                 }
2467                 break;
2468         case TIOCMBIC:
2469                 if (arg & TIOCM_RTS) {
2470                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
2471                         pCh->dataSetOut &= ~I2_RTS;
2472                 }
2473                 if (arg & TIOCM_DTR) {
2474                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
2475                         pCh->dataSetOut &= ~I2_DTR;
2476                 }
2477                 break;
2478         case TIOCMSET:
2479                 if ( (arg & TIOCM_RTS) && !(pCh->dataSetOut & I2_RTS) ) {
2480                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
2481                         pCh->dataSetOut |= I2_RTS;
2482                 } else if ( !(arg & TIOCM_RTS) && (pCh->dataSetOut & I2_RTS) ) {
2483                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
2484                         pCh->dataSetOut &= ~I2_RTS;
2485                 }
2486                 if ( (arg & TIOCM_DTR) && !(pCh->dataSetOut & I2_DTR) ) {
2487                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
2488                         pCh->dataSetOut |= I2_DTR;
2489                 } else if ( !(arg & TIOCM_DTR) && (pCh->dataSetOut & I2_DTR) ) {
2490                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
2491                         pCh->dataSetOut &= ~I2_DTR;
2492                 }
2493                 break;
2494         default:
2495                 return -EINVAL;
2496         }
2497         serviceOutgoingFifo( pCh->pMyBord );
2498         return 0;
2499 }
2500 
2501 /******************************************************************************/
2502 /* Function:   GetSerialInfo()                                                */
2503 /* Parameters: Pointer to channel structure                                   */
2504 /*             Pointer to old termios structure                               */
2505 /* Returns:    Nothing                                                        */
2506 /*                                                                            */
2507 /* Description:                                                               */
2508 /* This is to support the setserial command, and requires processing of the   */
2509 /* standard Linux serial structure.                                           */
2510 /******************************************************************************/
2511 static int
2512 get_serial_info ( i2ChanStrPtr pCh, struct serial_struct *retinfo )
2513 {
2514         struct serial_struct tmp;
2515         int rc;
2516 
2517         if ( !retinfo ) {
2518                 return -EFAULT;
2519         }
2520 
2521         memset ( &tmp, 0, sizeof(tmp) );
2522         tmp.type = pCh->pMyBord->channelBtypes.bid_value[(pCh->port_index & (IP2_PORTS_PER_BOARD-1))/16];
2523         if (BID_HAS_654(tmp.type)) {
2524                 tmp.type = PORT_16650;
2525         } else {
2526                 tmp.type = PORT_CIRRUS;
2527         }
2528         tmp.line = pCh->port_index;
2529         tmp.port = pCh->pMyBord->i2eBase;
2530         tmp.irq  = ip2config.irq[pCh->port_index/64];
2531         tmp.flags = pCh->flags;
2532         tmp.baud_base = pCh->BaudBase;
2533         tmp.close_delay = pCh->ClosingDelay;
2534         tmp.closing_wait = pCh->ClosingWaitTime;
2535         tmp.custom_divisor = pCh->BaudDivisor;
2536         COPY_TO_USER(rc,retinfo,&tmp,sizeof(*retinfo));
2537    return rc;
2538 }
2539 
2540 /******************************************************************************/
2541 /* Function:   SetSerialInfo()                                                */
2542 /* Parameters: Pointer to channel structure                                   */
2543 /*             Pointer to old termios structure                               */
2544 /* Returns:    Nothing                                                        */
2545 /*                                                                            */
2546 /* Description:                                                               */
2547 /* This function provides support for setserial, which uses the TIOCSSERIAL   */
2548 /* ioctl. Not all setserial parameters are relevant. If the user attempts to  */
2549 /* change the IRQ, address or type of the port the ioctl fails.               */
2550 /******************************************************************************/
2551 static int
2552 set_serial_info( i2ChanStrPtr pCh, struct serial_struct *new_info )
2553 {
2554         struct serial_struct ns;
2555         int   old_flags, old_baud_divisor;
2556         int     rc = 0;
2557 
2558         if ( !new_info ) {
2559                 return -EFAULT;
2560         }
2561         COPY_FROM_USER(rc, &ns, new_info, sizeof (ns) );
2562         if (rc) {
2563                 return rc;
2564         }
2565         /*
2566          * We don't allow setserial to change IRQ, board address, type or baud
2567          * base. Also line nunber as such is meaningless but we use it for our
2568          * array index so it is fixed also.
2569          */
2570         if ( (ns.irq        != ip2config.irq[pCh->port_index])
2571             || ((int) ns.port      != ((int) (pCh->pMyBord->i2eBase)))
2572             || (ns.baud_base != pCh->BaudBase)
2573             || (ns.line      != pCh->port_index) ) {
2574                 return -EINVAL;
2575         }
2576 
2577         old_flags = pCh->flags;
2578         old_baud_divisor = pCh->BaudDivisor;
2579 
2580         if ( !suser() ) {
2581                 if ( ( ns.close_delay != pCh->ClosingDelay ) ||
2582                     ( (ns.flags & ~ASYNC_USR_MASK) !=
2583                       (pCh->flags & ~ASYNC_USR_MASK) ) ) {
2584                         return -EPERM;
2585                 }
2586 
2587                 pCh->flags = (pCh->flags & ~ASYNC_USR_MASK) |
2588                                (ns.flags & ASYNC_USR_MASK);
2589                 pCh->BaudDivisor = ns.custom_divisor;
2590         } else {
2591                 pCh->flags = (pCh->flags & ~ASYNC_FLAGS) |
2592                                (ns.flags & ASYNC_FLAGS);
2593                 pCh->BaudDivisor = ns.custom_divisor;
2594                 pCh->ClosingDelay = ns.close_delay * HZ/100;
2595                 pCh->ClosingWaitTime = ns.closing_wait * HZ/100;
2596         }
2597 
2598         if ( ( (old_flags & ASYNC_SPD_MASK) != (pCh->flags & ASYNC_SPD_MASK) )
2599             || (old_baud_divisor != pCh->BaudDivisor) ) {
2600                 // Invalidate speed and reset parameters
2601                 set_params( pCh, NULL );
2602         }
2603 
2604         return rc;
2605 }
2606 
2607 /******************************************************************************/
2608 /* Function:   ip2_set_termios()                                              */
2609 /* Parameters: Pointer to tty structure                                       */
2610 /*             Pointer to old termios structure                               */
2611 /* Returns:    Nothing                                                        */
2612 /*                                                                            */
2613 /* Description:                                                               */
2614 /*                                                                            */
2615 /*                                                                            */
2616 /******************************************************************************/
2617 static void
2618 ip2_set_termios( PTTY tty, struct termios *old_termios )
2619 {
2620         i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data;
2621 
2622 #ifdef IP2DEBUG_IOCTL
2623         printk (KERN_DEBUG "IP2: set termios %p\n", old_termios );
2624 #endif
2625 
2626         set_params( pCh, old_termios );
2627 }
2628 
2629 /******************************************************************************/
2630 /* Function:   ip2_set_line_discipline()                                      */
2631 /* Parameters: Pointer to tty structure                                       */
2632 /* Returns:    Nothing                                                        */
2633 /*                                                                            */
2634 /* Description:  Does nothing                                                 */
2635 /*                                                                            */
2636 /*                                                                            */
2637 /******************************************************************************/
2638 static void
2639 ip2_set_line_discipline ( PTTY tty )
2640 {
2641 #ifdef IP2DEBUG_IOCTL
2642         printk (KERN_DEBUG "IP2: set line discipline\n" );
2643 #endif
2644 #ifdef IP2DEBUG_TRACE
2645         ip2trace (((i2ChanStrPtr)tty->driver_data)->port_index, ITRC_IOCTL, 16, 0 );
2646 #endif
2647 }
2648 
2649 /******************************************************************************/
2650 /* Function:   SetLine Characteristics()                                      */
2651 /* Parameters: Pointer to channel structure                                   */
2652 /* Returns:    Nothing                                                        */
2653 /*                                                                            */
2654 /* Description:                                                               */
2655 /* This routine is called to update the channel structure with the new line   */
2656 /* characteristics, and send the appropriate commands to the board when they  */
2657 /* change.                                                                    */
2658 /******************************************************************************/
2659 static void
2660 set_params( i2ChanStrPtr pCh, struct termios *o_tios )
2661 {
2662         tcflag_t cflag, iflag, lflag;
2663         char stop_char, start_char;
2664         struct termios dummy;
2665 
2666         lflag = pCh->pTTY->termios->c_lflag;
2667         cflag = pCh->pTTY->termios->c_cflag;
2668         iflag = pCh->pTTY->termios->c_iflag;
2669 
2670         if (o_tios == NULL) {
2671                 dummy.c_lflag = ~lflag;
2672                 dummy.c_cflag = ~cflag;
2673                 dummy.c_iflag = ~iflag;
2674                 o_tios = &dummy;
2675         }
2676 
2677         {
2678                 switch ( cflag & CBAUD ) {
2679                 case B0:
2680                         i2QueueCommands( PTYPE_BYPASS, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
2681                         pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
2682                         i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
2683                         pCh->pTTY->termios->c_cflag |= (CBAUD & o_tios->c_cflag);
2684                         goto service_it;
2685                         break;
2686                 case B38400:
2687                         /*
2688                          * This is the speed that is overloaded with all the other high
2689                          * speeds, depending upon the flag settings.
2690                          */
2691                         if ( ( pCh->flags & ASYNC_SPD_MASK ) == ASYNC_SPD_HI ) {
2692                                 pCh->speed = CBR_57600;
2693                         } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) {
2694                                 pCh->speed = CBR_115200;
2695                         } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST ) {
2696                                 pCh->speed = CBR_C1;
2697                         } else {
2698                                 pCh->speed = CBR_38400;
2699                         }
2700                         break;
2701                 case B50:      pCh->speed = CBR_50;      break;
2702                 case B75:      pCh->speed = CBR_75;      break;
2703                 case B110:     pCh->speed = CBR_110;     break;
2704                 case B134:     pCh->speed = CBR_134;     break;
2705                 case B150:     pCh->speed = CBR_150;     break;
2706                 case B200:     pCh->speed = CBR_200;     break;
2707                 case B300:     pCh->speed = CBR_300;     break;
2708                 case B600:     pCh->speed = CBR_600;     break;
2709                 case B1200:    pCh->speed = CBR_1200;    break;
2710                 case B1800:    pCh->speed = CBR_1800;    break;
2711                 case B2400:    pCh->speed = CBR_2400;    break;
2712                 case B4800:    pCh->speed = CBR_4800;    break;
2713                 case B9600:    pCh->speed = CBR_9600;    break;
2714                 case B19200:   pCh->speed = CBR_19200;   break;
2715                 case B57600:   pCh->speed = CBR_57600;   break;
2716                 case B115200:  pCh->speed = CBR_115200;  break;
2717                 case B153600:  pCh->speed = CBR_153600;  break;
2718                 case B230400:  pCh->speed = CBR_230400;  break;
2719                 case B307200:  pCh->speed = CBR_307200;  break;
2720                 case B460800:  pCh->speed = CBR_460800;  break;
2721                 case B921600:  pCh->speed = CBR_921600;  break;
2722                 default:       pCh->speed = CBR_9600;    break;
2723                 }
2724                 if ( pCh->speed == CBR_C1 ) {
2725                         // Process the custom speed parameters.
2726                         int bps = pCh->BaudBase / pCh->BaudDivisor;
2727                         if ( bps == 921600 ) {
2728                                 pCh->speed = CBR_921600;
2729                         } else {
2730                                 bps = bps/10;
2731                                 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_BAUD_DEF1(bps) );
2732                         }
2733                 }
2734                 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_SETBAUD(pCh->speed));
2735                 
2736                 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
2737                 pCh->dataSetOut |= (I2_DTR | I2_RTS);
2738         }
2739         if ( (CSTOPB & cflag) ^ (CSTOPB & o_tios->c_cflag)) 
2740         {
2741                 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, 
2742                         CMD_SETSTOP( ( cflag & CSTOPB ) ? CST_2 : CST_1));
2743         }
2744         if (((PARENB|PARODD) & cflag) ^ ((PARENB|PARODD) & o_tios->c_cflag)) 
2745         {
2746                 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2747                         CMD_SETPAR( 
2748                                 (cflag & PARENB ?  (cflag & PARODD ? CSP_OD : CSP_EV) : CSP_NP)
2749                         )
2750                 );
2751         }
2752         /* byte size and parity */
2753         if ( (CSIZE & cflag)^(CSIZE & o_tios->c_cflag)) 
2754         {
2755                 int datasize;
2756                 switch ( cflag & CSIZE ) {
2757                 case CS5: datasize = CSZ_5; break;
2758                 case CS6: datasize = CSZ_6; break;
2759                 case CS7: datasize = CSZ_7; break;
2760                 case CS8: datasize = CSZ_8; break;
2761                 default:  datasize = CSZ_5; break;      /* as per serial.c */
2762                 }
2763                 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, CMD_SETBITS(datasize) );
2764         }
2765         /* Process CTS flow control flag setting */
2766         if ( (cflag & CRTSCTS) ) {
2767                 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2768                                                 2, CMD_CTSFL_ENAB, CMD_RTSFL_ENAB);
2769         } else {
2770                 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2771                                                 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
2772         }
2773         //
2774         // Process XON/XOFF flow control flags settings
2775         //
2776         stop_char = STOP_CHAR(pCh->pTTY);
2777         start_char = START_CHAR(pCh->pTTY);
2778 
2779         //////////// can't be \000
2780         if (stop_char == __DISABLED_CHAR ) 
2781         {
2782                 stop_char = ~__DISABLED_CHAR; 
2783         }
2784         if (start_char == __DISABLED_CHAR ) 
2785         {
2786                 start_char = ~__DISABLED_CHAR;
2787         }
2788         /////////////////////////////////
2789 
2790         if ( o_tios->c_cc[VSTART] != start_char ) 
2791         {
2792                 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXON(start_char));
2793                 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXON(start_char));
2794         }
2795         if ( o_tios->c_cc[VSTOP] != stop_char ) 
2796         {
2797                  i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXOFF(stop_char));
2798                  i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXOFF(stop_char));
2799         }
2800         if (stop_char == __DISABLED_CHAR ) 
2801         {
2802                 stop_char = ~__DISABLED_CHAR;  //TEST123
2803                 goto no_xoff;
2804         }
2805         if ((iflag & (IXOFF))^(o_tios->c_iflag & (IXOFF))) 
2806         {
2807                 if ( iflag & IXOFF ) {  // Enable XOFF output flow control
2808                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_XON));
2809                 } else {        // Disable XOFF output flow control
2810 no_xoff:
2811                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_NONE));
2812                 }
2813         }
2814         if (start_char == __DISABLED_CHAR ) 
2815         {
2816                 goto no_xon;
2817         }
2818         if ((iflag & (IXON|IXANY)) ^ (o_tios->c_iflag & (IXON|IXANY))) 
2819         {
2820                 if ( iflag & IXON ) {
2821                         if ( iflag & IXANY ) { // Enable XON/XANY output flow control
2822                                 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XANY));
2823                         } else { // Enable XON output flow control
2824                                 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XON));
2825                         }
2826                 } else { // Disable XON output flow control
2827 no_xon:
2828                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_NONE));
2829                 }
2830         }
2831         if ( (iflag & ISTRIP) ^ ( o_tios->c_iflag & (ISTRIP)) ) 
2832         {
2833                 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, 
2834                                 CMD_ISTRIP_OPT((iflag & ISTRIP ? 1 : 0)));
2835         }
2836         if ( (iflag & INPCK) ^ ( o_tios->c_iflag & (INPCK)) ) 
2837         {
2838                 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, 
2839                                 CMD_PARCHK((iflag & INPCK) ? CPK_ENAB : CPK_DSAB));
2840         }
2841 
2842         if ( (iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) 
2843                         ^       ( o_tios->c_iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) ) 
2844         {
2845                 char brkrpt = 0;
2846                 char parrpt = 0;
2847 
2848                 if ( iflag & IGNBRK ) { /* Ignore breaks altogether */
2849                         /* Ignore breaks altogether */
2850                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_NREP);
2851                 } else {
2852                         if ( iflag & BRKINT ) {
2853                                 if ( iflag & PARMRK ) {
2854                                         brkrpt = 0x0a;  // exception an inline triple
2855                                 } else {
2856                                         brkrpt = 0x1a;  // exception and NULL
2857                                 }
2858                                 brkrpt |= 0x04; // flush input
2859                         } else {
2860                                 if ( iflag & PARMRK ) {
2861                                         brkrpt = 0x0b;  //POSIX triple \0377 \0 \0
2862                                 } else {
2863                                         brkrpt = 0x01;  // Null only
2864                                 }
2865                         }
2866                         i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_REP(brkrpt));
2867                 } 
2868 
2869                 if (iflag & IGNPAR) {
2870                         parrpt = 0x20;
2871                                                                                                         /* would be 2 for not cirrus bug */
2872                                                                                                         /* would be 0x20 cept for cirrus bug */
2873                 } else {
2874                         if ( iflag & PARMRK ) {
2875                                 /*
2876                                  * Replace error characters with 3-byte sequence (\0377,\0,char)
2877                                  */
2878                                 parrpt = 0x04 ;
2879                                 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_ISTRIP_OPT((char)0));
2880                         } else {
2881                                 parrpt = 0x03;
2882                         } 
2883                 }
2884                 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt));
2885         }
2886         if (cflag & CLOCAL) {
2887                 // Status reporting fails for DCD if this is off
2888                 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
2889                 pCh->flags &= ~ASYNC_CHECK_CD;
2890         } else {
2891                 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
2892                 pCh->flags      |= ASYNC_CHECK_CD;
2893         }
2894 
2895 #ifdef XXX
2896 do_flags_thing: // This is a test, we don't do the flags thing
2897         
2898         if ( (cflag & CRTSCTS) ) {
2899                 cflag |= 014000000000;
2900         }
2901         i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, 
2902                                 CMD_UNIX_FLAGS(iflag,cflag,lflag));
2903 #endif
2904                 
2905 service_it:
2906         i2DrainOutput( pCh, 100 );              
2907 }
2908 
2909 /******************************************************************************/
2910 /* IPL Device Section                                                         */
2911 /******************************************************************************/
2912 
2913 /******************************************************************************/
2914 /* Function:   ip2_ipl_read()                                                  */
2915 /* Parameters: Pointer to device inode                                        */
2916 /*             Pointer to file structure                                      */
2917 /*             Pointer to data                                                */
2918 /*             Number of bytes to read                                        */
2919 /* Returns:    Success or failure                                             */
2920 /*                                                                            */
2921 /* Description:   Ugly                                                        */
2922 /*                                                                            */
2923 /*                                                                            */
2924 /******************************************************************************/
2925 
2926 static 
2927 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
2928 int
2929 ip2_ipl_read(struct inode *pInode, char *pData, size_t count, loff_t *off )
2930         unsigned int minor = MINOR( pInode->i_rdev );
2931 #else
2932 ssize_t
2933 ip2_ipl_read(struct file *pFile, char *pData, size_t count, loff_t *off )
2934 {
2935         unsigned int minor = MINOR( pFile->f_dentry->d_inode->i_rdev );
2936 #endif
2937         int rc = 0;
2938 
2939 #ifdef IP2DEBUG_IPL
2940         printk (KERN_DEBUG "IP2IPL: read %p, %d bytes\n", pData, count );
2941 #endif
2942 
2943         switch( minor ) {
2944         case 0:     // IPL device
2945                 rc = -EINVAL;
2946                 break;
2947         case 1:     // Status dump
2948                 rc = -EINVAL;
2949                 break;
2950         case 2:     // Ping device
2951                 rc = -EINVAL;
2952                 break;
2953         case 3:     // Trace device
2954                 rc = DumpTraceBuffer ( pData, count );
2955                 break;
2956         case 4:     // Trace device
2957                 rc = DumpFifoBuffer ( pData, count );
2958                 break;
2959         default:
2960                 rc = -ENODEV;
2961                 break;
2962         }
2963         return rc;
2964 }
2965 
2966 static int
2967 DumpFifoBuffer ( char *pData, int count )
2968 {
2969 #ifdef DEBUG_FIFO
2970         int rc;
2971         COPY_TO_USER(rc, pData, DBGBuf, count);
2972 
2973         printk(KERN_DEBUG "Last index %d\n", I );
2974 
2975         return count;
2976 #endif  /* DEBUG_FIFO */
2977         return 0;
2978 }
2979 
2980 static int
2981 DumpTraceBuffer ( char *pData, int count )
2982 {
2983 #ifdef IP2DEBUG_TRACE
2984         int rc;
2985         int dumpcount;
2986         int chunk;
2987         int *pIndex = (int*)pData;
2988 
2989         if ( count < (sizeof(int) * 6) ) {
2990                 return -EIO;
2991         }
2992         PUT_USER(rc, tracewrap, pIndex );
2993         PUT_USER(rc, TRACEMAX, ++pIndex );
2994         PUT_USER(rc, tracestrip, ++pIndex );
2995         PUT_USER(rc, tracestuff, ++pIndex );
2996         pData += sizeof(int) * 6;
2997         count -= sizeof(int) * 6;
2998 
2999         dumpcount = tracestuff - tracestrip;
3000         if ( dumpcount < 0 ) {
3001                 dumpcount += TRACEMAX;
3002         }
3003         if ( dumpcount > count ) {
3004                 dumpcount = count;
3005         }
3006         chunk = TRACEMAX - tracestrip;
3007         if ( dumpcount > chunk ) {
3008                 COPY_TO_USER(rc, pData, &tracebuf[tracestrip],
3009                               chunk * sizeof(tracebuf[0]) );
3010                 pData += chunk * sizeof(tracebuf[0]);
3011                 tracestrip = 0;
3012                 chunk = dumpcount - chunk;
3013         } else {
3014                 chunk = dumpcount;
3015         }
3016         COPY_TO_USER(rc, pData, &tracebuf[tracestrip],
3017                       chunk * sizeof(tracebuf[0]) );
3018         tracestrip += chunk;
3019         tracewrap = 0;
3020 
3021         PUT_USER(rc, tracestrip, ++pIndex );
3022         PUT_USER(rc, tracestuff, ++pIndex );
3023 
3024         return dumpcount;
3025 #else
3026         return 0;
3027 #endif
3028 }
3029 
3030 /******************************************************************************/
3031 /* Function:   ip2_ipl_write()                                                 */
3032 /* Parameters:                                                                */
3033 /*             Pointer to file structure                                      */
3034 /*             Pointer to data                                                */
3035 /*             Number of bytes to write                                       */
3036 /* Returns:    Success or failure                                             */
3037 /*                                                                            */
3038 /* Description:                                                               */
3039 /*                                                                            */
3040 /*                                                                            */
3041 /******************************************************************************/
3042 static ssize_t
3043 ip2_ipl_write(struct file *pFile, const char *pData, size_t count, loff_t *off)
3044 {
3045 #ifdef IP2DEBUG_IPL
3046         printk (KERN_DEBUG "IP2IPL: write %p, %d bytes\n", pData, count );
3047 #endif
3048         return 0;
3049 }
3050 
3051 /******************************************************************************/
3052 /* Function:   ip2_ipl_ioctl()                                                */
3053 /* Parameters: Pointer to device inode                                        */
3054 /*             Pointer to file structure                                      */
3055 /*             Command                                                        */
3056 /*             Argument                                                       */
3057 /* Returns:    Success or failure                                             */
3058 /*                                                                            */
3059 /* Description:                                                               */
3060 /*                                                                            */
3061 /*                                                                            */
3062 /******************************************************************************/
3063 static int
3064 ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
3065 {
3066         unsigned int iplminor = MINOR(pInode->i_rdev);
3067         int rc = 0;
3068         ULONG *pIndex = (ULONG*)arg;
3069         i2eBordStrPtr pB = i2BoardPtrTable[iplminor / 4];
3070         i2ChanStrPtr pCh;
3071 
3072 #ifdef IP2DEBUG_IPL
3073         printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg );
3074 #endif
3075 
3076         switch ( iplminor ) {
3077         case 0:     // IPL device
3078                 rc = -EINVAL;
3079                 break;
3080         case 1:     // Status dump
3081         case 5:
3082         case 9:
3083         case 13:
3084                 switch ( cmd ) {
3085                 case 64:        /* Driver - ip2stat */
3086                         PUT_USER(rc, ref_count, pIndex++ );
3087                         PUT_USER(rc, irq_counter, pIndex++  );
3088                         PUT_USER(rc, bh_counter, pIndex++  );
3089                         break;
3090 
3091                 case 65:        /* Board  - ip2stat */
3092                         if ( pB ) {
3093                                 COPY_TO_USER(rc, (char*)arg, (char*)pB, sizeof(i2eBordStr) );
3094                                 PUT_USER(rc, INB(pB->i2eStatus),
3095                                         (ULONG*)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
3096                         } else {
3097                                 rc = -ENODEV;
3098                         }
3099                         break;
3100 
3101                 default:
3102                         pCh = DevTable[cmd];
3103                         if ( pCh )
3104                         {
3105                                 COPY_TO_USER(rc, (char*)arg, (char*)pCh, sizeof(i2ChanStr) );
3106                         } else {
3107                                 rc = cmd < 64 ? -ENODEV : -EINVAL;
3108                         }
3109                 }
3110                 break;
3111 
3112         case 2:     // Ping device
3113                 rc = -EINVAL;
3114                 break;
3115         case 3:     // Trace device
3116                 if ( cmd == 1 ) {
3117                         PUT_USER(rc, iiSendPendingMail, pIndex++ );
3118                         PUT_USER(rc, i2InitChannels, pIndex++ );
3119                         PUT_USER(rc, i2QueueNeeds, pIndex++ );
3120                         PUT_USER(rc, i2QueueCommands, pIndex++ );
3121                         PUT_USER(rc, i2GetStatus, pIndex++ );
3122                         PUT_USER(rc, i2Input, pIndex++ );
3123                         PUT_USER(rc, i2InputFlush, pIndex++ );
3124                         PUT_USER(rc, i2Output, pIndex++ );
3125                         PUT_USER(rc, i2FlushOutput, pIndex++ );
3126                         PUT_USER(rc, i2DrainWakeup, pIndex++ );
3127                         PUT_USER(rc, i2DrainOutput, pIndex++ );
3128                         PUT_USER(rc, i2OutputFree, pIndex++ );
3129                         PUT_USER(rc, i2StripFifo, pIndex++ );
3130                         PUT_USER(rc, i2StuffFifoBypass, pIndex++ );
3131                         PUT_USER(rc, i2StuffFifoFlow, pIndex++ );
3132                         PUT_USER(rc, i2StuffFifoInline, pIndex++ );
3133                         PUT_USER(rc, i2ServiceBoard, pIndex++ );
3134                         PUT_USER(rc, serviceOutgoingFifo, pIndex++ );
3135                         // PUT_USER(rc, ip2_init, pIndex++ );
3136                         PUT_USER(rc, ip2_init_board, pIndex++ );
3137                         PUT_USER(rc, find_eisa_board, pIndex++ );
3138                         PUT_USER(rc, set_irq, pIndex++ );
3139                         PUT_USER(rc, ip2_interrupt, pIndex++ );
3140                         PUT_USER(rc, ip2_poll, pIndex++ );
3141                         PUT_USER(rc, service_all_boards, pIndex++ );
3142                         PUT_USER(rc, do_input, pIndex++ );
3143                         PUT_USER(rc, do_status, pIndex++ );
3144 #ifndef IP2DEBUG_OPEN
3145                         PUT_USER(rc, 0, pIndex++ );
3146 #else
3147                         PUT_USER(rc, open_sanity_check, pIndex++ );
3148 #endif
3149                         PUT_USER(rc, ip2_open, pIndex++ );
3150                         PUT_USER(rc, ip2_close, pIndex++ );
3151                         PUT_USER(rc, ip2_hangup, pIndex++ );
3152                         PUT_USER(rc, ip2_write, pIndex++ );
3153                         PUT_USER(rc, ip2_putchar, pIndex++ );
3154                         PUT_USER(rc, ip2_flush_chars, pIndex++ );
3155                         PUT_USER(rc, ip2_write_room, pIndex++ );
3156                         PUT_USER(rc, ip2_chars_in_buf, pIndex++ );
3157                         PUT_USER(rc, ip2_flush_buffer, pIndex++ );
3158 
3159                         //PUT_USER(rc, ip2_wait_until_sent, pIndex++ );
3160                         PUT_USER(rc, 0, pIndex++ );
3161 
3162                         PUT_USER(rc, ip2_throttle, pIndex++ );
3163                         PUT_USER(rc, ip2_unthrottle, pIndex++ );
3164                         PUT_USER(rc, ip2_ioctl, pIndex++ );
3165                         PUT_USER(rc, set_modem_info, pIndex++ );
3166                         PUT_USER(rc, get_serial_info, pIndex++ );
3167                         PUT_USER(rc, set_serial_info, pIndex++ );
3168                         PUT_USER(rc, ip2_set_termios, pIndex++ );
3169                         PUT_USER(rc, ip2_set_line_discipline, pIndex++ );
3170                         PUT_USER(rc, set_params, pIndex++ );
3171                 } else {
3172                         rc = -EINVAL;
3173                 }
3174 
3175                 break;
3176 
3177         default:
3178                 rc = -ENODEV;
3179                 break;
3180         }
3181         return rc;
3182 }
3183 
3184 /******************************************************************************/
3185 /* Function:   ip2_ipl_open()                                                 */
3186 /* Parameters: Pointer to device inode                                        */
3187 /*             Pointer to file structure                                      */
3188 /* Returns:    Success or failure                                             */
3189 /*                                                                            */
3190 /* Description:                                                               */
3191 /*                                                                            */
3192 /*                                                                            */
3193 /******************************************************************************/
3194 static int
3195 ip2_ipl_open( struct inode *pInode, struct file *pFile )
3196 {
3197         unsigned int iplminor = MINOR(pInode->i_rdev);
3198         i2eBordStrPtr pB;
3199         i2ChanStrPtr  pCh;
3200 
3201 #ifdef IP2DEBUG_IPL
3202         printk (KERN_DEBUG "IP2IPL: open\n" );
3203 #endif
3204 
3205         switch(iplminor) {
3206         // These are the IPL devices
3207         case 0:
3208         case 4:
3209         case 8:
3210         case 12:
3211                 break;
3212 
3213         // These are the status devices
3214         case 1:
3215         case 5:
3216         case 9:
3217         case 13:
3218                 break;
3219 
3220         // These are the debug devices
3221         case 2:
3222         case 6:
3223         case 10:
3224         case 14:
3225                 pB = i2BoardPtrTable[iplminor / 4];
3226                 pCh = (i2ChanStrPtr) pB->i2eChannelPtr;
3227                 break;
3228 
3229         // This is the trace device
3230         case 3:
3231                 break;
3232         }
3233         return 0;
3234 }
3235 /******************************************************************************/
3236 /* Function:   ip2_read_procmem                                               */
3237 /* Parameters:                                                                */
3238 /*                                                                            */
3239 /* Returns: Length of output                                                  */
3240 /*                                                                            */
3241 /* Description:                                                               */
3242 /*   Supplies some driver operating parameters                                */
3243 /*      Not real useful unless your debugging the fifo                                                    */
3244 /*                                                                            */
3245 /******************************************************************************/
3246 
3247 #define LIMIT  (PAGE_SIZE - 120)
3248 
3249 static int
3250 ip2_read_procmem(char *buf, char **start, off_t offset, int len)
3251 {
3252         i2eBordStrPtr  pB;
3253         i2ChanStrPtr  pCh;
3254         PTTY tty;
3255         int i;
3256 
3257         len = 0;
3258 
3259 #define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n"
3260 #define FMTLIN2 "     0x%04x 0x%04x tx flow 0x%x\n"
3261 #define FMTLIN3 "     0x%04x 0x%04x rc flow\n"
3262 
3263         len += sprintf(buf+len,"\n");
3264 
3265         for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3266                 pB = i2BoardPtrTable[i];
3267                 if ( pB ) {
3268                         len += sprintf(buf+len,"board %d:\n",i);
3269                         len += sprintf(buf+len,"\tFifo rem: %d mty: %x outM %x\n",
3270                                 pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting);
3271                 }
3272         }
3273 
3274         len += sprintf(buf+len,"#: tty flags, port flags,     cflags,     iflags\n");
3275         for (i=0; i < IP2_MAX_PORTS; i++) {
3276                 if (len > LIMIT)
3277                         break;
3278                 pCh = DevTable[i];
3279                 if (pCh) {
3280                         tty = pCh->pTTY;
3281                         if (tty && tty->count) {
3282                                 len += sprintf(buf+len,FMTLINE,i,(int)tty->flags,pCh->flags,
3283                                                                         tty->termios->c_cflag,tty->termios->c_iflag);
3284 
3285                                 len += sprintf(buf+len,FMTLIN2,
3286                                                 pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds);
3287                                 len += sprintf(buf+len,FMTLIN3,pCh->infl.asof,pCh->infl.room);
3288                         }
3289                 }
3290         }
3291         return len;
3292 }
3293 
3294 /*
3295  * This is the handler for /proc/tty/driver/ip2
3296  *
3297  * This stretch of code has been largely plagerized from at least three
3298  * different sources including ip2mkdev.c and a couple of other drivers.
3299  * The bugs are all mine.  :-)  =mhw=
3300  */
3301 int ip2_read_proc(char *page, char **start, off_t off,
3302                                 int count, int *eof, void *data)
3303 {
3304         int     i, j, box;
3305         int     len = 0;
3306         int     boxes = 0;
3307         int     ports = 0;
3308         int     tports = 0;
3309         off_t   begin = 0;
3310         i2eBordStrPtr  pB;
3311 
3312         len += sprintf(page, "ip2info: 1.0 driver: %s\n", pcVersion );
3313         len += sprintf(page+len, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
3314                         IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR,
3315                         IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX);
3316 
3317         for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3318                 /* This need to be reset for a board by board count... */
3319                 boxes = 0;
3320                 pB = i2BoardPtrTable[i];
3321                 if( pB ) {
3322                         switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) 
3323                         {
3324                         case POR_ID_FIIEX:
3325                                 len += sprintf( page+len, "Board %d: EX ports=", i );
3326                                 for( box = 0; box < ABS_MAX_BOXES; ++box )
3327                                 {
3328                                         ports = 0;
3329 
3330                                         if( pB->i2eChannelMap[box] != 0 ) ++boxes;
3331                                         for( j = 0; j < ABS_BIGGEST_BOX; ++j ) 
3332                                         {
3333                                                 if( pB->i2eChannelMap[box] & 1<< j ) {
3334                                                         ++ports;
3335                                                 }
3336                                         }
3337                                         len += sprintf( page+len, "%d,", ports );
3338                                         tports += ports;
3339                                 }
3340 
3341                                 --len;  /* Backup over that last comma */
3342 
3343                                 len += sprintf( page+len, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8 );
3344                                 break;
3345 
3346                         case POR_ID_II_4:
3347                                 len += sprintf(page+len, "Board %d: ISA-4 ports=4 boxes=1", i );
3348                                 tports = ports = 4;
3349                                 break;
3350 
3351                         case POR_ID_II_8:
3352                                 len += sprintf(page+len, "Board %d: ISA-8-std ports=8 boxes=1", i );
3353                                 tports = ports = 8;
3354                                 break;
3355 
3356                         case POR_ID_II_8R:
3357                                 len += sprintf(page+len, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i );
3358                                 tports = ports = 8;
3359                                 break;
3360 
3361                         default:
3362                                 len += sprintf(page+len, "Board %d: unknown", i );
3363                                 /* Don't try and probe for minor numbers */
3364                                 tports = ports = 0;
3365                         }
3366 
3367                 } else {
3368                         /* Don't try and probe for minor numbers */
3369                         len += sprintf(page+len, "Board %d: vacant", i );
3370                         tports = ports = 0;
3371                 }
3372 
3373                 if( tports ) {
3374                         len += sprintf(page+len, " minors=" );
3375 
3376                         for ( box = 0; box < ABS_MAX_BOXES; ++box )
3377                         {
3378                                 for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
3379                                 {
3380                                         if ( pB->i2eChannelMap[box] & (1 << j) )
3381                                         {
3382                                                 len += sprintf (page+len,"%d,",
3383                                                         j + ABS_BIGGEST_BOX *
3384                                                         (box+i*ABS_MAX_BOXES));
3385                                         }
3386                                 }
3387                         }
3388 
3389                         page[ len - 1 ] = '\n'; /* Overwrite that last comma */
3390                 } else {
3391                         len += sprintf (page+len,"\n" );
3392                 }
3393 
3394                 if (len+begin > off+count)
3395                         break;
3396                 if (len+begin < off) {
3397                         begin += len;
3398                         len = 0;
3399                 }
3400         }
3401 
3402         if (i >= IP2_MAX_BOARDS)
3403                 *eof = 1;
3404         if (off >= len+begin)
3405                 return 0;
3406 
3407         *start = page + (off-begin);
3408         return ((count < begin+len-off) ? count : begin+len-off);
3409  }
3410  
3411 /******************************************************************************/
3412 /* Function:   ip2trace()                                                     */
3413 /* Parameters: Value to add to trace buffer                                   */
3414 /* Returns:    Nothing                                                        */
3415 /*                                                                            */
3416 /* Description:                                                               */
3417 /*                                                                            */
3418 /*                                                                            */
3419 /******************************************************************************/
3420 void
3421 ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned long codes, ...)
3422 {
3423 #ifdef IP2DEBUG_TRACE
3424         long flags;
3425         unsigned long *pCode = &codes;
3426         union ip2breadcrumb bc;
3427         i2ChanStrPtr  pCh;
3428 
3429 
3430         tracebuf[tracestuff++] = jiffies;
3431         if ( tracestuff == TRACEMAX ) {
3432                 tracestuff = 0;
3433         }
3434         if ( tracestuff == tracestrip ) {
3435                 if ( ++tracestrip == TRACEMAX ) {
3436                         tracestrip = 0;
3437                 }
3438                 ++tracewrap;
3439         }
3440 
3441         bc.hdr.port  = 0xff & pn;
3442         bc.hdr.cat   = cat;
3443         bc.hdr.codes = (unsigned char)( codes & 0xff );
3444         bc.hdr.label = label;
3445         tracebuf[tracestuff++] = bc.value;
3446 
3447         for (;;) {
3448                 if ( tracestuff == TRACEMAX ) {
3449                         tracestuff = 0;
3450                 }
3451                 if ( tracestuff == tracestrip ) {
3452                         if ( ++tracestrip == TRACEMAX ) {
3453                                 tracestrip = 0;
3454                         }
3455                         ++tracewrap;
3456                 }
3457 
3458                 if ( !codes-- )
3459                         break;
3460 
3461                 tracebuf[tracestuff++] = *++pCode;
3462         }
3463 #endif
3464 }
3465 
3466 
3467 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.