patch-2.4.14 linux/drivers/char/ip2main.c

Next file: linux/drivers/char/istallion.c
Previous file: linux/drivers/char/ip2.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.13/linux/drivers/char/ip2main.c linux/drivers/char/ip2main.c
@@ -12,8 +12,42 @@
 *******************************************************************************/
 // ToDo:
 //
+// Fix the immediate DSS_NOW problem.
+// Work over the channel stats return logic in ip2_ipl_ioctl so they
+//	make sense for all 256 possible channels and so the user space
+//	utilities will compile and work properly.
+//
 // Done:
 //
+// 1.2.14	/\/\|=mhw=|\/\/
+// Added bounds checking to ip2_ipl_ioctl to avoid potential terroristic acts.
+// Changed the definition of ip2trace to be more consistant with kernel style
+//	Thanks to Andreas Dilger <adilger@turbolabs.com> for these updates
+//
+// 1.2.13	/\/\|=mhw=|\/\/
+// DEVFS: Renamed ttf/{n} to tts/F{n} and cuf/{n} to cua/F{n} to conform
+//	to agreed devfs serial device naming convention.
+//
+// 1.2.12	/\/\|=mhw=|\/\/
+// Cleaned up some remove queue cut and paste errors
+//
+// 1.2.11	/\/\|=mhw=|\/\/
+// Clean up potential NULL pointer dereferences
+// Clean up devfs registration
+// Add kernel command line parsing for io and irq
+//	Compile defaults for io and irq are now set in ip2.c not ip2/ip2.h!
+// Reworked poll_only hack for explicit parameter setting
+//	You must now EXPLICITLY set poll_only = 1 or set all irqs to 0
+// Merged ip2_loadmain and old_ip2_init
+// Converted all instances of interruptible_sleep_on into queue calls
+//	Most of these had no race conditions but better to clean up now
+//
+// 1.2.10	/\/\|=mhw=|\/\/
+// Fixed the bottom half interrupt handler and enabled USE_IQI
+//	to split the interrupt handler into a formal top-half / bottom-half
+// Fixed timing window on high speed processors that queued messages to
+// 	the outbound mail fifo faster than the board could handle.
+//
 // 1.2.9
 // Four box EX was barfing on >128k kmalloc, made structure smaller by
 // reducing output buffer size
@@ -193,13 +227,13 @@
 
 /* String constants to identify ourselves */
 static char *pcName    = "Computone IntelliPort Plus multiport driver";
-static char *pcVersion = "1.2.9";
+static char *pcVersion = "1.2.14";
 
 /* String constants for port names */
 static char *pcDriver_name   = "ip2";
 #ifdef	CONFIG_DEVFS_FS
-static char *pcTty    		 = "ttf/%d";
-static char *pcCallout		 = "cuf/%d";
+static char *pcTty    		 = "tts/F%d";
+static char *pcCallout		 = "cua/F%d";
 #else
 static char *pcTty    		 = "ttyF";
 static char *pcCallout		 = "cuf";
@@ -225,8 +259,6 @@
 void cleanup_module(void);
 #endif
 
-int old_ip2_init(void);
-
 /* Private (static) functions */
 static int  ip2_open(PTTY, struct file *);
 static void ip2_close(PTTY, struct file *);
@@ -246,6 +278,7 @@
 static void ip2_hangup(PTTY);
 
 static void set_irq(int, int);
+static void ip2_interrupt_bh(i2eBordStrPtr pB);
 static void ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs);
 static void ip2_poll(unsigned long arg);
 static inline void service_all_boards(void);
@@ -268,7 +301,6 @@
 static int ip2_ipl_ioctl(struct inode *, struct file *, UINT, ULONG);
 static int ip2_ipl_open(struct inode *, struct file *);
 
-void ip2trace(unsigned short,unsigned char,unsigned char,unsigned long,...);
 static int DumpTraceBuffer(char *, int);
 static int DumpFifoBuffer( char *, int);
 
@@ -310,11 +342,11 @@
 	open:		ip2_ipl_open,
 }; 
 
-static long irq_counter;
-static long bh_counter;
+static unsigned long irq_counter = 0;
+static unsigned long bh_counter = 0;
 
 // Use immediate queue to service interrupts
-//#define USE_IQI	// PCI&2.2 needs work
+#define USE_IQI
 //#define USE_IQ	// PCI&2.2 needs work
 
 /* The timer_list entry for our poll routine. If interrupt operation is not
@@ -364,7 +396,7 @@
 #	endif	/* LINUX_VERSION */
 #endif	/* MODULE */
 
-static int poll_only;
+static int poll_only = 0;
 
 static int Eisa_irq;
 static int Eisa_slot;
@@ -373,32 +405,6 @@
 static char rirqs[IP2_MAX_BOARDS];
 static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
 
-/******************************************************************************/
-/* Initialisation Section                                                     */
-/******************************************************************************/
-int 
-ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) 
-{
-	int i;
-	/* process command line arguments to modprobe or insmod i.e. iop & irqp */
-	/* otherwise ip2config is initialized by what's in ip2/ip2.h */
-	/* command line trumps initialization in ip2.h */
-	/* first two args are null if builtin to kernel */
-	if ((irqp != NULL) || (iop != NULL)) {
-		for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-			if (irqp && irqp[i]) {
-				ip2config.irq[i] = irqp[i];
-			}
-			if (iop && iop[i]) {
-				ip2config.addr[i] = iop[i];
-			}
-		}
-	}
-	Fip_firmware = firmware;
-	Fip_firmware_size = firmsize;
-	return old_ip2_init();
-}
-
 // Some functions to keep track of what irq's we have
 
 static int __init
@@ -461,7 +467,6 @@
 #ifdef IP2DEBUG_INIT
 	printk (KERN_DEBUG "Loading module ...\n" );
 #endif
-    //was	return old_ip2_init();
     return 0;
 }
 #endif /* MODULE */
@@ -559,8 +564,9 @@
 #endif /* MODULE */
 
 /******************************************************************************/
-/* Function:   old_ip2_init()                                                 */
+/* Function:   ip2_loadmain()                                                 */
 /* Parameters: irq, io from command line of insmod et. al.                    */
+/*		pointer to fip firmware and firmware size for boards	      */
 /* Returns:    Success (0)                                                    */
 /*                                                                            */
 /* Description:                                                               */
@@ -575,7 +581,7 @@
 #define IP2_SA_FLAGS	0
 
 int __init
-old_ip2_init(void)
+ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) 
 {
 #ifdef	CONFIG_DEVFS_FS
 	static devfs_handle_t devfs_handle;
@@ -588,9 +594,40 @@
 	i2eBordStrPtr pB = NULL;
 	int rc = -1;
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 );
-#endif
+
+	/* process command line arguments to modprobe or
+		insmod i.e. iop & irqp */
+	/* irqp and iop should ALWAYS be specified now...  But we check
+		them individually just to be sure, anyways... */
+	for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+		if (iop) {
+			ip2config.addr[i] = iop[i];
+			if (irqp) {
+				if( irqp[i] >= 0 ) {
+					ip2config.irq[i] = irqp[i];
+				} else {
+					ip2config.irq[i] = 0;
+				}
+	// This is a little bit of a hack.  If poll_only=1 on command
+	// line back in ip2.c OR all IRQs on all specified boards are
+	// explicitly set to 0, then drop to poll only mode and override
+	// PCI or EISA interrupts.  This superceeds the old hack of
+	// triggering if all interrupts were zero (like da default).
+	// Still a hack but less prone to random acts of terrorism.
+	//
+	// What we really should do, now that the IRQ default is set
+	// to -1, is to use 0 as a hard coded, do not probe.
+	//
+	//	/\/\|=mhw=|\/\/
+				poll_only |= irqp[i];
+			}
+		}
+	}
+	poll_only = !poll_only;
+
+	Fip_firmware = firmware;
+	Fip_firmware_size = firmsize;
 
 	/* Announce our presence */
 	printk( KERN_INFO "%s version %s\n", pcName, pcVersion );
@@ -604,12 +641,6 @@
 	}
 	loaded++;
 
-	/* if all irq config is zero we shall poll_only */
-	for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-		poll_only |= ip2config.irq[i];
-	}
-	poll_only = !poll_only;
-
 	/* Initialise the iiEllis subsystem. */
 	iiEllisInit();
 
@@ -672,10 +703,13 @@
 					pcibios_read_config_byte(pci_bus, pci_devfn,
 								  PCI_INTERRUPT_LINE, &pci_irq);
 
-					if (!is_valid_irq(pci_irq)) {
-						printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-						pci_irq = 0;
-					}
+//		If the PCI BIOS assigned it, lets try and use it.  If we
+//		can't acquire it or it screws up, deal with it then.
+
+//					if (!is_valid_irq(pci_irq)) {
+//						printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
+//						pci_irq = 0;
+//					}
 					ip2config.irq[i] = pci_irq;
 				} else {	// ann error
 					ip2config.addr[i] = 0;
@@ -706,10 +740,13 @@
 					status =
 					pci_read_config_byte(pci_dev_i, PCI_INTERRUPT_LINE, &pci_irq);
 
-					if (!is_valid_irq(pci_irq)) {
-						printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-						pci_irq = 0;
-					}
+//		If the PCI BIOS assigned it, lets try and use it.  If we
+//		can't acquire it or it screws up, deal with it then.
+
+//					if (!is_valid_irq(pci_irq)) {
+//						printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
+//						pci_irq = 0;
+//					}
 					ip2config.irq[i] = pci_irq;
 				} else {	// ann error
 					ip2config.addr[i] = 0;
@@ -761,9 +798,7 @@
 		}
 	}
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 );
-#endif
 
 	/* Zero out the normal tty device structure. */
 	memset ( &ip2_tty_driver, 0, sizeof ip2_tty_driver );
@@ -822,9 +857,7 @@
 	ip2_callout_driver.major   = IP2_CALLOUT_MAJOR;
 	ip2_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 );
-#endif
 
 	/* Register the tty devices. */
 	if ( ( err = tty_register_driver ( &ip2_tty_driver ) ) ) {
@@ -847,9 +880,7 @@
 		printk(KERN_ERR "IP2: failed to register read_procmem\n");
 	} else {
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 );
-#endif
 		/* Register the interrupt handler or poll handler, depending upon the
 		 * specified interrupt.
 		 */
@@ -868,41 +899,45 @@
 			}
 
 #ifdef	CONFIG_DEVFS_FS
-			sprintf( name, "ipl%d", i );
-			i2BoardPtrTable[i]->devfs_ipl_handle =
-				devfs_register (devfs_handle, name,
-					DEVFS_FL_DEFAULT,
-					IP2_IPL_MAJOR, 4 * i,
-					S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
-					&ip2_ipl, NULL);
-
-			sprintf( name, "stat%d", i );
-			i2BoardPtrTable[i]->devfs_stat_handle =
-				devfs_register (devfs_handle, name,
-					DEVFS_FL_DEFAULT,
-					IP2_IPL_MAJOR, 4 * i + 1,
-					S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
-					&ip2_ipl, NULL);
+			if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
+				sprintf( name, "ipl%d", i );
+				pB->devfs_ipl_handle =
+					devfs_register (devfs_handle, name,
+						DEVFS_FL_DEFAULT,
+						IP2_IPL_MAJOR, 4 * i,
+						S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
+						&ip2_ipl, NULL);
+
+				sprintf( name, "stat%d", i );
+				pB->devfs_stat_handle =
+					devfs_register (devfs_handle, name,
+						DEVFS_FL_DEFAULT,
+						IP2_IPL_MAJOR, 4 * i + 1,
+						S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
+						&ip2_ipl, NULL);
 
-			for ( box = 0; box < ABS_MAX_BOXES; ++box )
-			{
-			    for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
+			    for ( box = 0; box < ABS_MAX_BOXES; ++box )
 			    {
-				if ( pB->i2eChannelMap[box] & (1 << j) )
-				{
-				    tty_register_devfs(&ip2_tty_driver,
-					0, j + ABS_BIGGEST_BOX *
-						(box+i*ABS_MAX_BOXES));
-				    tty_register_devfs(&ip2_callout_driver,
-					0, j + ABS_BIGGEST_BOX *
-						(box+i*ABS_MAX_BOXES));
-				}
+			        for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
+			        {
+				    if ( pB->i2eChannelMap[box] & (1 << j) )
+				    {
+				        tty_register_devfs(&ip2_tty_driver,
+					    0, j + ABS_BIGGEST_BOX *
+						    (box+i*ABS_MAX_BOXES));
+				            tty_register_devfs(&ip2_callout_driver,
+					    0, j + ABS_BIGGEST_BOX *
+						    (box+i*ABS_MAX_BOXES));
+			    	    }
+			        }
 			    }
 			}
 #endif
 
 			if (poll_only) {
-					ip2config.irq[i] = CIR_POLL;
+//		Poll only forces driver to only use polling and
+//		to ignore the probed PCI or EISA interrupts.
+				ip2config.irq[i] = CIR_POLL;
 			}
 			if ( ip2config.irq[i] == CIR_POLL ) {
 retry:
@@ -935,9 +970,7 @@
 			}
 		}
 	}
-#ifdef IP2DEBUG_TRACE
 	ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
-#endif
 
 	return 0;
 }
@@ -963,26 +996,24 @@
 	if ( !iiInitialize ( pB ) ) {
 		printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n",
 			 pB->i2eBase, pB->i2eError );
-		kfree ( pB );
-		i2BoardPtrTable[boardnum] = NULL;
-		return;
+		goto err_initialize;
 	}
-	printk(KERN_INFO "Board %d: addr=0x%x irq=%d ", boardnum + 1,
+	printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1,
 	       ip2config.addr[boardnum], ip2config.irq[boardnum] );
 
 	if (0 != ( rc = check_region( ip2config.addr[boardnum], 8))) {
-		i2BoardPtrTable[boardnum] = NULL;
-		printk(KERN_ERR "bad addr=0x%x rc = %d\n",
+		printk(KERN_ERR "IP2: bad addr=0x%x rc = %d\n",
 				ip2config.addr[boardnum], rc );
-		return;
+		goto err_initialize;
 	}
 	request_region( ip2config.addr[boardnum], 8, pcName );
 
 	if ( iiDownloadAll ( pB, (loadHdrStrPtr)Fip_firmware, 1, Fip_firmware_size )
 	    != II_DOWN_GOOD ) {
-		printk ( KERN_ERR "IP2:failed to download loadware " );
+		printk ( KERN_ERR "IP2: failed to download loadware\n" );
+		goto err_release_region;
 	} else {
-		printk ( KERN_INFO "fv=%d.%d.%d lv=%d.%d.%d\n",
+		printk ( KERN_INFO "IP2: fv=%d.%d.%d lv=%d.%d.%d\n",
 			 pB->i2ePom.e.porVersion,
 			 pB->i2ePom.e.porRevision,
 			 pB->i2ePom.e.porSubRev, pB->i2eLVersion,
@@ -992,24 +1023,24 @@
 	switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) {
 
 	default:
-		printk( KERN_ERR "IP2: Unknown board type, ID = %x",
+		printk( KERN_ERR "IP2: Unknown board type, ID = %x\n",
 				pB->i2ePom.e.porID );
 		nports = 0;
-		goto ex_exit;
+		goto err_release_region;
 		break;
 
 	case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */
-		printk ( KERN_INFO "ISA-4" );
+		printk ( KERN_INFO "IP2: ISA-4\n" );
 		nports = 4;
 		break;
 
 	case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */
-		printk ( KERN_INFO "ISA-8 std" );
+		printk ( KERN_INFO "IP2: ISA-8 std\n" );
 		nports = 8;
 		break;
 
 	case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */
-		printk ( KERN_INFO "ISA-8 RJ11" );
+		printk ( KERN_INFO "IP2: ISA-8 RJ11\n" );
 		nports = 8;
 		break;
 
@@ -1030,8 +1061,14 @@
 		}
 		DevTableMem[boardnum] = pCh =
 			kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL );
+		if ( !pCh ) {
+			printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
+			goto err_release_region;
+		}
 		if ( !i2InitChannels( pB, nports, pCh ) ) {
-			printk(KERN_ERR "i2InitChannels failed: %d\n",pB->i2eError);
+			printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
+			kfree ( pCh );
+			goto err_release_region;
 		}
 		pB->i2eChannelPtr = &DevTable[portnum];
 		pB->i2eChannelCnt = ABS_MOST_PORTS;
@@ -1045,17 +1082,24 @@
 				}
 			}
 		}
-		printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit",
+		printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit\n",
 			nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 );
 		}
 		goto ex_exit;
-		break;
 	}
 	DevTableMem[boardnum] = pCh =
 		kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL );
+	if ( !pCh ) {
+		printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
+		goto err_release_region;
+	}
 	pB->i2eChannelPtr = pCh;
 	pB->i2eChannelCnt = nports;
-	i2InitChannels ( pB, pB->i2eChannelCnt, pCh );
+	if ( !i2InitChannels( pB, nports, pCh ) ) {
+		printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
+		kfree ( pCh );
+		goto err_release_region;
+	}
 	pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum];
 
 	for( i = 0; i < pB->i2eChannelCnt; ++i ) {
@@ -1064,7 +1108,16 @@
 		pCh++;
 	}
 ex_exit:
-	printk ( KERN_INFO "\n" );
+	pB->tqueue_interrupt.routine = (void(*)(void*)) ip2_interrupt_bh;
+	pB->tqueue_interrupt.data = pB;
+	return;
+
+err_release_region:
+	release_region(ip2config.addr[boardnum], 8);
+err_initialize:
+	kfree ( pB );
+	i2BoardPtrTable[boardnum] = NULL;
+	return;
 }
 
 /******************************************************************************/
@@ -1262,16 +1315,34 @@
 }
 
 
-#ifdef USE_IQI
-static struct tq_struct 
-senior_service =
-{	// it's the death that worse than fate
-	NULL,
-	0,
-	(void(*)(void*)) service_all_boards,
-	NULL,	//later - board address XXX
-};
-#endif
+/******************************************************************************/
+/* Function:   ip2_interrupt_bh(pB)                                           */
+/* Parameters: pB - pointer to the board structure                            */
+/* Returns:    Nothing                                                        */
+/*                                                                            */
+/* Description:                                                               */
+/*	Service the board in a bottom half interrupt handler and then         */
+/*	reenable the board's interrupts if it has an IRQ number               */
+/*                                                                            */
+/******************************************************************************/
+static void
+ip2_interrupt_bh(i2eBordStrPtr pB)
+{
+//	pB better well be set or we have a problem!  We can only get
+//	here from the IMMEDIATE queue.  Here, we process the boards.
+//	Checking pB doesn't cost much and it saves us from the sanity checkers.
+
+	bh_counter++; 
+
+	if ( pB ) {
+		i2ServiceBoard( pB );
+		if( pB->i2eUsingIrq ) {
+//			Re-enable his interrupts
+			iiEnableMailIrq(pB);
+		}
+	}
+}
+
 
 /******************************************************************************/
 /* Function:   ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs)    */
@@ -1282,6 +1353,14 @@
 /*                                                                            */
 /* Description:                                                               */
 /*                                                                            */
+/*	Our task here is simply to identify each board which needs servicing. */
+/*	If we are queuing then, queue it to be serviced, and disable its irq  */
+/*	mask otherwise process the board directly.                            */
+/*                                                                            */
+/*	We could queue by IRQ but that just complicates things on both ends   */
+/*	with very little gain in performance (how many instructions does      */
+/*	it take to iterate on the immediate queue).                           */
+/*                                                                            */
 /*                                                                            */
 /******************************************************************************/
 static void
@@ -1290,31 +1369,41 @@
 	int i;
 	i2eBordStrPtr  pB;
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq );
-#endif
-
-#ifdef USE_IQI
-
-	queue_task(&senior_service, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
 
-#else
 	/* Service just the boards on the list using this irq */
 	for( i = 0; i < i2nBoards; ++i ) {
 		pB = i2BoardPtrTable[i];
+
+//		Only process those boards which match our IRQ.
+//			IRQ = 0 for polled boards, we won't poll "IRQ" boards
+
 		if ( pB && (pB->i2eUsingIrq == irq) ) {
+#ifdef USE_IQI
+
+		    if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
+//			Disable his interrupt (will be enabled when serviced)
+//			This is mostly to protect from reentrancy.
+			iiDisableMailIrq(pB);
+
+//			Park the board on the immediate queue for processing.
+			queue_task(&pB->tqueue_interrupt, &tq_immediate);
+
+//			Make sure the immediate queue is flagged to fire.
+			mark_bh(IMMEDIATE_BH);
+		    }
+#else
+//		We are using immediate servicing here.  This sucks and can
+//		cause all sorts of havoc with ppp and others.  The failsafe
+//		check on iiSendPendingMail could also throw a hairball.
 			i2ServiceBoard( pB );
+#endif /* USE_IQI */
 		}
 	}
 
-#endif /* USE_IQI */
-
 	++irq_counter;
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
-#endif
 }
 
 /******************************************************************************/
@@ -1330,31 +1419,20 @@
 static void
 ip2_poll(unsigned long arg)
 {
-#ifdef IP2DEBUG_TRACE
 	ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
-#endif
-	TimerOn = 0; // it's the truth but not checked in service
-
-	bh_counter++; 
 
-#ifdef USE_IQI
-
-	queue_task(&senior_service, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
+	TimerOn = 0; // it's the truth but not checked in service
 
-#else
-	// Just polled boards, service_all might be better
+	// Just polled boards, IRQ = 0 will hit all non-interrupt boards.
+	// It will NOT poll boards handled by hard interrupts.
+	// The issue of queued BH interrups is handled in ip2_interrupt().
 	ip2_interrupt(0, NULL, NULL);
 
-#endif /* USE_IQI */
-
 	PollTimer.expires = POLL_TIMEOUT;
 	add_timer( &PollTimer );
 	TimerOn = 1;
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
-#endif
 }
 
 static inline void 
@@ -1362,9 +1440,8 @@
 {
 	unsigned long flags;
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace(CHANN, ITRC_INPUT, 21, 0 );
-#endif
+
 	// Data input
 	if ( pCh->pTTY != NULL ) {
 		READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
@@ -1374,9 +1451,8 @@
 		} else
 			READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
 	} else {
-#ifdef IP2DEBUG_TRACE
 		ip2trace(CHANN, ITRC_INPUT, 22, 0 );
-#endif
+
 		i2InputFlush( pCh );
 	}
 }
@@ -1401,9 +1477,7 @@
 
 	status =  i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) );
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (CHANN, ITRC_STATUS, 21, 1, status );
-#endif
 
 	if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) {
 		if ( (status & I2_BRK) ) {
@@ -1463,9 +1537,7 @@
 		}
 	}
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (CHANN, ITRC_STATUS, 26, 0 );
-#endif
 }
 
 /******************************************************************************/
@@ -1515,13 +1587,12 @@
 static int
 ip2_open( PTTY tty, struct file *pFile )
 {
+	wait_queue_t wait;
 	int rc = 0;
 	int do_clocal = 0;
 	i2ChanStrPtr  pCh = DevTable[MINOR(tty->device)];
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (MINOR(tty->device), ITRC_OPEN, ITRC_ENTER, 0 );
-#endif
 
 	if ( pCh == NULL ) {
 		return -ENODEV;
@@ -1548,14 +1619,23 @@
 	 * 1. If the port is in the middle of closing wait for the completion
 	 *    and then return the appropriate error.
 	 */
+	init_waitqueue_entry(&wait, current);
+	add_wait_queue(&pCh->close_wait, &wait);
+	set_current_state( TASK_INTERRUPTIBLE );
+
 	if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
 		if ( pCh->flags & ASYNC_CLOSING ) {
-			interruptible_sleep_on( &pCh->close_wait);
+			schedule();
 		}
 		if ( tty_hung_up_p(pFile) ) {
+			set_current_state( TASK_RUNNING );
+			remove_wait_queue(&pCh->close_wait, &wait);
 			return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS;
 		}
 	}
+	set_current_state( TASK_RUNNING );
+	remove_wait_queue(&pCh->close_wait, &wait);
+
 	/*
 	 * 2. If this is a callout device, make sure the normal port is not in
 	 *    use, and that someone else doesn't have the callout device locked.
@@ -1608,13 +1688,20 @@
 #endif
 
 	++pCh->wopen;
+
+	init_waitqueue_entry(&wait, current);
+	add_wait_queue(&pCh->open_wait, &wait);
+
 	for(;;) {
 		if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE)) {
 			i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
 			pCh->dataSetOut |= (I2_DTR | I2_RTS);
+			set_current_state( TASK_INTERRUPTIBLE );
 			serviceOutgoingFifo( pCh->pMyBord );
 		}
 		if ( tty_hung_up_p(pFile) ) {
+			set_current_state( TASK_RUNNING );
+			remove_wait_queue(&pCh->open_wait, &wait);
 			return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
 		}
 		if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) &&
@@ -1631,21 +1718,22 @@
 			(pCh->flags & ASYNC_CLOSING)?"True":"False");
 		printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
 #endif
-#ifdef IP2DEBUG_TRACE
 		ip2trace (CHANN, ITRC_OPEN, 3, 2, (pCh->flags & ASYNC_CALLOUT_ACTIVE),
-								(pCh->flags & ASYNC_CLOSING) );
-#endif
+				(pCh->flags & ASYNC_CLOSING) );
 		/* check for signal */
 		if (signal_pending(current)) {
 			rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
 			break;
 		}
-		interruptible_sleep_on(&pCh->open_wait);
+		schedule();
 	}
+	set_current_state( TASK_RUNNING );
+	remove_wait_queue(&pCh->open_wait, &wait);
+
 	--pCh->wopen; //why count?
-#ifdef IP2DEBUG_TRACE
+
 	ip2trace (CHANN, ITRC_OPEN, 4, 0 );
-#endif
+
 	if (rc != 0 ) {
 		return rc;
 	}
@@ -1682,9 +1770,8 @@
 #endif
 	serviceOutgoingFifo( pCh->pMyBord );
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (CHANN, ITRC_OPEN, ITRC_RETURN, 0 );
-#endif
+
 	return 0;
 }
 
@@ -1707,9 +1794,7 @@
 		return;
 	}
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (CHANN, ITRC_CLOSE, ITRC_ENTER, 0 );
-#endif
 
 #ifdef IP2DEBUG_OPEN
 	printk(KERN_DEBUG "IP2:close ttyF%02X:\n",MINOR(tty->device));
@@ -1718,16 +1803,15 @@
 	if ( tty_hung_up_p ( pFile ) ) {
 		MOD_DEC_USE_COUNT;
 
-#ifdef IP2DEBUG_TRACE
 		ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 );
-#endif
+
 		return;
 	}
 	if ( tty->count > 1 ) { /* not the last close */
 		MOD_DEC_USE_COUNT;
-#ifdef IP2DEBUG_TRACE
+
 		ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 );
-#endif
+
 		return;
 	}
 	pCh->flags |= ASYNC_CLOSING;	// last close actually
@@ -1794,9 +1878,8 @@
 
 	MOD_DEC_USE_COUNT;
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
-#endif
+
 	return;
 }
 
@@ -1814,9 +1897,11 @@
 {
 	i2ChanStrPtr  pCh = tty->driver_data;
 
-#ifdef IP2DEBUG_TRACE
+	if( !pCh ) {
+		return;
+	}
+
 	ip2trace (CHANN, ITRC_HANGUP, ITRC_ENTER, 0 );
-#endif
 
 	ip2_flush_buffer(tty);
 
@@ -1824,7 +1909,7 @@
 
 	i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP);
 	i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
-	if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
+	if ( (tty->termios->c_cflag & HUPCL) ) {
 		i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN);
 		pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
 		i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
@@ -1839,9 +1924,7 @@
 	pCh->pTTY = NULL;
 	wake_up_interruptible ( &pCh->open_wait );
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (CHANN, ITRC_HANGUP, ITRC_RETURN, 0 );
-#endif
 }
 
 /******************************************************************************/
@@ -1869,9 +1952,7 @@
 	int bytesSent = 0;
 	unsigned long flags;
 
-#ifdef IP2DEBUG_TRACE
-   ip2trace (CHANN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
-#endif
+	ip2trace (CHANN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
 
 	/* Flush out any buffered data left over from ip2_putchar() calls. */
 	ip2_flush_chars( tty );
@@ -1881,9 +1962,8 @@
 	bytesSent = i2Output( pCh, pData, count, user );
 	WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
 
-#ifdef IP2DEBUG_TRACE
-   ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
-#endif
+	ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
+
 	return bytesSent > 0 ? bytesSent : 0;
 }
 
@@ -1903,9 +1983,7 @@
 	i2ChanStrPtr  pCh = tty->driver_data;
 	unsigned long flags;
 
-#ifdef IP2DEBUG_TRACE
 //	ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
-#endif
 
 	WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
 	pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
@@ -1915,9 +1993,7 @@
 	} else
 		WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
 
-#ifdef IP2DEBUG_TRACE
 //	ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
-#endif
 }
 
 /******************************************************************************/
@@ -1937,9 +2013,9 @@
 
 	WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
 	if ( pCh->Pbuf_stuff ) {
-#ifdef IP2DEBUG_TRACE
-//	ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
-#endif
+
+//		ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
+
 		//
 		// We may need to restart i2Output if it does not fullfill this request
 		//
@@ -1971,9 +2047,7 @@
 	bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
 	READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
-#endif
 
 	return ((bytesFree > 0) ? bytesFree : 0);
 }
@@ -1993,9 +2067,9 @@
 	i2ChanStrPtr  pCh = tty->driver_data;
 	int rc;
 	unsigned long flags;
-#ifdef IP2DEBUG_TRACE
+
 	ip2trace (CHANN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
-#endif
+
 #ifdef IP2DEBUG_WRITE
 	printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n",
 				 pCh->Obuf_char_count + pCh->Pbuf_stuff,
@@ -2025,9 +2099,8 @@
 	i2ChanStrPtr  pCh = tty->driver_data;
 	unsigned long flags;
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (CHANN, ITRC_FLUSH, ITRC_ENTER, 0 );
-#endif
+
 #ifdef IP2DEBUG_WRITE
 	printk (KERN_DEBUG "IP2: flush buffer\n" );
 #endif
@@ -2036,9 +2109,9 @@
 	WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
 	i2FlushOutput( pCh );
 	ip2_owake(tty);
-#ifdef IP2DEBUG_TRACE
+
 	ip2trace (CHANN, ITRC_FLUSH, ITRC_RETURN, 0 );
-#endif
+
 }
 
 /******************************************************************************/
@@ -2173,6 +2246,7 @@
 static int
 ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
 {
+	wait_queue_t wait;
 	i2ChanStrPtr pCh = DevTable[MINOR(tty->device)];
 	struct async_icount cprev, cnow;	/* kernel counter temps */
 	struct serial_icounter_struct *p_cuser;	/* user space */
@@ -2183,9 +2257,7 @@
 		return -ENODEV;
 	}
 
-#ifdef IP2DEBUG_TRACE
 	ip2trace (CHANN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
-#endif
 
 #ifdef IP2DEBUG_IOCTL
 	printk(KERN_DEBUG "IP2: ioctl cmd (%x), arg (%lx)\n", cmd, arg );
@@ -2193,18 +2265,18 @@
 
 	switch(cmd) {
 	case TIOCGSERIAL:
-#ifdef IP2DEBUG_TRACE
+
 		ip2trace (CHANN, ITRC_IOCTL, 2, 1, rc );
-#endif
+
 		rc = get_serial_info(pCh, (struct serial_struct *) arg);
 		if (rc)
 			return rc;
 		break;
 
 	case TIOCSSERIAL:
-#ifdef IP2DEBUG_TRACE
+
 		ip2trace (CHANN, ITRC_IOCTL, 3, 1, rc );
-#endif
+
 		rc = set_serial_info(pCh, (struct serial_struct *) arg);
 		if (rc)
 			return rc;
@@ -2240,9 +2312,9 @@
 
 	case TCSBRK:   /* SVID version: non-zero arg --> no break */
 		rc = tty_check_change(tty);
-#ifdef IP2DEBUG_TRACE
+
 		ip2trace (CHANN, ITRC_IOCTL, 4, 1, rc );
-#endif
+
 		if (!rc) {
 			ip2_wait_until_sent(tty,0);
 			if (!arg) {
@@ -2254,9 +2326,9 @@
 
 	case TCSBRKP:  /* support for POSIX tcsendbreak() */
 		rc = tty_check_change(tty);
-#ifdef IP2DEBUG_TRACE
+
 		ip2trace (CHANN, ITRC_IOCTL, 5, 1, rc );
-#endif
+
 		if (!rc) {
 			ip2_wait_until_sent(tty,0);
 			i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
@@ -2266,18 +2338,18 @@
 		break;
 
 	case TIOCGSOFTCAR:
-#ifdef IP2DEBUG_TRACE
+
 		ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc );
-#endif
+
 			PUT_USER(rc,C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
 		if (rc)	
 			return rc;
 	break;
 
 	case TIOCSSOFTCAR:
-#ifdef IP2DEBUG_TRACE
+
 		ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc );
-#endif
+
 		GET_USER(rc,arg,(unsigned long *) arg);
 		if (rc) 
 			return rc;
@@ -2287,23 +2359,38 @@
 		break;
 
 	case TIOCMGET:
-#ifdef IP2DEBUG_TRACE
+
 		ip2trace (CHANN, ITRC_IOCTL, 8, 1, rc );
-#endif
+
 /*
 	FIXME - the following code is causing a NULL pointer dereference in
 	2.3.51 in an interrupt handler.  It's suppose to prompt the board
 	to return the DSS signal status immediately.  Why doesn't it do
 	the same thing in 2.2.14?
 */
-/*
+
+/*	This thing is still busted in the 1.2.12 driver on 2.4.x
+	and even hoses the serial console so the oops can be trapped.
+		/\/\|=mhw=|\/\/			*/
+
+#ifdef	ENABLE_DSSNOW
 		i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
+
+		init_waitqueue_entry(&wait, current);
+		add_wait_queue(&pCh->dss_now_wait, &wait);
+		set_current_state( TASK_INTERRUPTIBLE );
+
 		serviceOutgoingFifo( pCh->pMyBord );
-		interruptible_sleep_on(&pCh->dss_now_wait);
+
+		schedule();
+
+		set_current_state( TASK_RUNNING );
+		remove_wait_queue(&pCh->dss_now_wait, &wait);
+
 		if (signal_pending(current)) {
 			return -EINTR;
 		}
-*/
+#endif
 		PUT_USER(rc,
 				    ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
 				  | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
@@ -2317,9 +2404,8 @@
 	case TIOCMBIS:
 	case TIOCMBIC:
 	case TIOCMSET:
-#ifdef IP2DEBUG_TRACE
 		ip2trace (CHANN, ITRC_IOCTL, 9, 0 );
-#endif
+
 		rc = set_modem_info(pCh, cmd, (unsigned int *) arg);
 		break;
 
@@ -2334,15 +2420,18 @@
 		restore_flags(flags);
 		i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4, 
 						CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
+		init_waitqueue_entry(&wait, current);
+		add_wait_queue(&pCh->delta_msr_wait, &wait);
+		set_current_state( TASK_INTERRUPTIBLE );
+
 		serviceOutgoingFifo( pCh->pMyBord );
 		for(;;) {
-#ifdef IP2DEBUG_TRACE
 			ip2trace (CHANN, ITRC_IOCTL, 10, 0 );
-#endif
-			interruptible_sleep_on(&pCh->delta_msr_wait);
-#ifdef IP2DEBUG_TRACE
+
+			schedule();
+
 			ip2trace (CHANN, ITRC_IOCTL, 11, 0 );
-#endif
+
 			/* see if a signal did it */
 			if (signal_pending(current)) {
 				rc = -ERESTARTSYS;
@@ -2365,6 +2454,9 @@
 			}
 			cprev = cnow;
 		}
+		set_current_state( TASK_RUNNING );
+		remove_wait_queue(&pCh->delta_msr_wait, &wait);
+
 		i2QueueCommands(PTYPE_BYPASS, pCh, 100, 3, 
 						 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
 		if ( ! (pCh->flags	& ASYNC_CHECK_CD)) {
@@ -2383,9 +2475,8 @@
 	 * serial driver.
 	 */
 	case TIOCGICOUNT:
-#ifdef IP2DEBUG_TRACE
 		ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
-#endif
+
 		save_flags(flags);cli();
 		cnow = pCh->icount;
 		restore_flags(flags);
@@ -2416,15 +2507,14 @@
 	case TIOCSERSETMULTI:
 
 	default:
-#ifdef IP2DEBUG_TRACE
 		ip2trace (CHANN, ITRC_IOCTL, 12, 0 );
-#endif
+
 		rc =  -ENOIOCTLCMD;
 		break;
 	}
-#ifdef IP2DEBUG_TRACE
+
 	ip2trace (CHANN, ITRC_IOCTL, ITRC_RETURN, 0 );
-#endif
+
 	return rc;
 }
 
@@ -2635,9 +2725,9 @@
 #ifdef IP2DEBUG_IOCTL
 	printk (KERN_DEBUG "IP2: set line discipline\n" );
 #endif
-#ifdef IP2DEBUG_TRACE
+
 	ip2trace (((i2ChanStrPtr)tty->driver_data)->port_index, ITRC_IOCTL, 16, 0 );
-#endif
+
 }
 
 /******************************************************************************/
@@ -3093,12 +3183,16 @@
 			break;
 
 		default:
-			pCh = DevTable[cmd];
-			if ( pCh )
-			{
-				COPY_TO_USER(rc, (char*)arg, (char*)pCh, sizeof(i2ChanStr) );
+			if (cmd < IP2_MAX_PORTS) {
+				pCh = DevTable[cmd];
+				if ( pCh )
+				{
+					COPY_TO_USER(rc, (char*)arg, (char*)pCh, sizeof(i2ChanStr) );
+				} else {
+					rc = -ENODEV;
+				}
 			} else {
-				rc = cmd < 64 ? -ENODEV : -EINVAL;
+				rc = -EINVAL;
 			}
 		}
 		break;
@@ -3411,10 +3505,10 @@
 /*                                                                            */
 /*                                                                            */
 /******************************************************************************/
+#ifdef IP2DEBUG_TRACE
 void
 ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned long codes, ...)
 {
-#ifdef IP2DEBUG_TRACE
 	long flags;
 	unsigned long *pCode = &codes;
 	union ip2breadcrumb bc;
@@ -3454,8 +3548,8 @@
 
 		tracebuf[tracestuff++] = *++pCode;
 	}
-#endif
 }
+#endif
 
 
 MODULE_LICENSE("GPL");

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)