patch-2.4.4 linux/drivers/net/wan/sdladrv.c

Next file: linux/drivers/net/wan/sdlamain.c
Previous file: linux/drivers/net/wan/sdla_x25.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c
@@ -6,13 +6,19 @@
 *
 * Author:	Gideon Hack	
 *
-* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-2000 Sangoma Technologies Inc.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* Mar 20, 2001  Nenad Corbic	Added the auto_pci_cfg filed, to support
+*                               the PCISLOT #0. 
+* Apr 04, 2000  Nenad Corbic	Fixed the auto memory detection code.
+*                               The memory test at address 0xC8000.
+* Mar 09, 2000  Nenad Corbic 	Added Gideon's Bug Fix: clear pci
+*                               interrupt flags on initial load.
 * Jun 02, 1999  Gideon Hack     Added support for the S514 adapter.
 *				Updates for Linux 2.2.X kernels.	
 * Sep 17, 1998	Jaspreet Singh	Updates for linux 2.2.X kernels
@@ -84,7 +90,6 @@
 
 #if	defined(_LINUX_)	/****** Linux *******************************/
 
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
@@ -102,7 +107,16 @@
 #define _OUTB(port, byte)	(outb((byte),(port)))
 #define	SYSTEM_TICK		jiffies
 
-#include <linux/init.h>
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4) 
+ #include <linux/init.h>
+#else
+ #include <linux/bios32.h>/* BIOS32, PCI BIOS functions and definitions */
+ #define ioremap vremap
+ #define iounmap vfree
+ extern void * vremap (unsigned long offset, unsigned long size);
+ extern void vfree (void *addr);
+#endif
 
 #elif	defined(_SCO_UNIX_)	/****** SCO Unix ****************************/
 
@@ -190,16 +204,21 @@
 static unsigned check_memregion (void* ptr, unsigned len);
 static unsigned	test_memregion (void* ptr, unsigned len);
 static unsigned short checksum (unsigned char* buf, unsigned len);
+static int init_pci_slot(sdlahw_t *);
+
+static int pci_probe(sdlahw_t *hw);
 
 /****** Global Data **********************************************************
  * Note: All data must be explicitly initialized!!!
  */
 
+#ifdef LINUX_2_4
 static struct pci_device_id sdladrv_pci_tbl[] __initdata = {
 	{ V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
 	{ }			/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl);
+#endif
 
 /* private data */
 static char modname[]	= "sdladrv";
@@ -298,6 +317,8 @@
 	0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0
 };
 
+static int pci_slot_ar[MAX_S514_CARDS];
+
 /******* Kernel Loadable Module Entry Points ********************************/
 
 /*============================================================================
@@ -314,15 +335,24 @@
 #ifdef MODULE
 int init_module (void)
 #else
-int __init wanpipe_init(void)
+int sdladrv_init(void)
 #endif
 {
+	int i=0;
+
 	printk(KERN_INFO "%s v%u.%u %s\n",
 		fullname, MOD_VERSION, MOD_RELEASE, copyright);
 	exec_idle = calibrate_delay(EXEC_DELAY);
 #ifdef WANDEBUG	
 	printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle);
 #endif	
+
+	/* Initialize the PCI Card array, which
+         * will store flags, used to mark 
+         * card initialization state */
+	for (i=0; i<MAX_S514_CARDS; i++)
+		pci_slot_ar[i] = 0xFF;
+
 	return 0;
 }
 
@@ -350,7 +380,9 @@
  *		< 0	error
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4) 
 EXPORT_SYMBOL(sdla_setup);
+#endif
 
 int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)
 {
@@ -361,7 +393,7 @@
 
 	if (sdla_detect(hw)) {
                 if(hw->type != SDLA_S514)
-                        printk(KERN_ERR "%s: no SDLA card found at port 0x%X\n",
+                        printk(KERN_INFO "%s: no SDLA card found at port 0x%X\n",
                         modname, hw->port);
 		return -EINVAL;
 	}
@@ -410,7 +442,7 @@
 
                 /* Verify IRQ configuration options */
                 if (!get_option_index(irq_opt, hw->irq)) {
-                        printk(KERN_ERR "%s: IRQ %d is illegal!\n",
+                        printk(KERN_INFO "%s: IRQ %d is illegal!\n",
                         	modname, hw->irq);
                       return -EINVAL;
                 } 
@@ -420,7 +452,7 @@
                         hw->pclk = pclk_opt[1];  /* use default */
         
                 else if (!get_option_index(pclk_opt, hw->pclk)) {
-                        printk(KERN_ERR "%s: CPU clock %u is illegal!\n",
+                        printk(KERN_INFO "%s: CPU clock %u is illegal!\n",
 				modname, hw->pclk);
                         return -EINVAL;
                 } 
@@ -431,7 +463,7 @@
                 if (hw->dpmbase == 0) {
                         err = sdla_autodpm(hw);
                         if (err) {
-                                printk(KERN_ERR
+                                printk(KERN_INFO
 				"%s: can't find available memory region!\n",
 					modname);
                                 return err;
@@ -439,13 +471,13 @@
                 }
                 else if (!get_option_index(dpmbase_opt,
 			virt_to_phys(hw->dpmbase))) {
-                        printk(KERN_ERR
+                        printk(KERN_INFO
 				"%s: memory address 0x%lX is illegal!\n",
 				modname, virt_to_phys(hw->dpmbase));
                         return -EINVAL;
                 }               
                 else if (sdla_setdpm(hw)) {
-                        printk(KERN_ERR
+                        printk(KERN_INFO
 			"%s: 8K memory region at 0x%lX is not available!\n",
 				modname, virt_to_phys(hw->dpmbase));
                         return -EINVAL;
@@ -453,13 +485,27 @@
                 printk(KERN_INFO
 			"%s: dual-port memory window is set at 0x%lX.\n",
 				modname, virt_to_phys(hw->dpmbase));
+
+
+		/* If we find memory in 0xE**** Memory region, 
+                 * warn the user to disable the SHADOW RAM.  
+                 * Since memory corruption can occur if SHADOW is
+                 * enabled. This can causes random crashes ! */
+		if (virt_to_phys(hw->dpmbase) >= 0xE0000){
+			printk(KERN_WARNING "\n%s: !!!!!!!!  WARNING !!!!!!!!\n",modname);
+			printk(KERN_WARNING "%s: WANPIPE is using 0x%lX memory region !!!\n",
+						modname, virt_to_phys(hw->dpmbase));
+			printk(KERN_WARNING "         Please disable the SHADOW RAM, otherwise\n");
+			printk(KERN_WARNING "         your system might crash randomly from time to time !\n");
+			printk(KERN_WARNING "%s: !!!!!!!!  WARNING !!!!!!!!\n\n",modname);
+		}
         }
 
 	else {
 		hw->memory = test_memregion((void*)hw->dpmbase, 
 			MAX_SIZEOF_S514_MEMORY);
 		if(hw->memory < (256 * 1024)) {
-			printk(KERN_ERR
+			printk(KERN_INFO
 				"%s: error in testing S514 memory (0x%lX)\n",
 				modname, hw->memory);
 			sdla_down(hw);
@@ -481,7 +527,9 @@
  * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_down);
+#endif
 
 int sdla_down (sdlahw_t* hw)
 {
@@ -523,9 +571,10 @@
                 *(char *)hw->vector = S514_CPU_HALT;
         	CPU_no = hw->S514_cpu_no[0];
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 		/* disable the PCI IRQ and disable memory access */
                 pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config);
-	        int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : 			~PCI_DISABLE_IRQ_CPU_B;
+	        int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A :	~PCI_DISABLE_IRQ_CPU_B;
                 pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config);
 		read_S514_int_stat(hw, &int_status);
 		S514_intack(hw, int_status);
@@ -535,6 +584,22 @@
 		else
                         pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD,
 				PCI_CPU_B_MEM_DISABLE);
+#else
+                /* disable the PCI IRQ and disable memory access */
+             	pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func,
+			PCI_INT_CONFIG, &int_config);
+	        int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A :	~PCI_DISABLE_IRQ_CPU_B;
+        	pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func,
+			PCI_INT_CONFIG, int_config);
+                read_S514_int_stat(hw, &int_status);
+                S514_intack(hw, int_status);
+     		// disable PCI memory access
+		if(CPU_no == S514_CPU_A)
+	     		pcibios_write_config_dword(hw->pci_bus,hw->pci_dev_func,
+				PCI_MAP0_DWORD, PCI_CPU_A_MEM_DISABLE);
+		else
+                        pcibios_write_config_dword(hw->pci_bus,hw->pci_dev_func,							PCI_MAP1_DWORD, PCI_CPU_B_MEM_DISABLE);
+#endif
 
 		/* free up the allocated virtual memory */
  		iounmap((void *)hw->dpmbase);
@@ -552,7 +617,9 @@
  * Map shared memory window into SDLA address space.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_mapmem);
+#endif
 
 int sdla_mapmem (sdlahw_t* hw, unsigned long addr)
 {
@@ -613,7 +680,9 @@
  * Enable interrupt generation.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_inten);
+#endif
 
 int sdla_inten (sdlahw_t* hw)
 {
@@ -669,7 +738,9 @@
  * Disable interrupt generation.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_intde);
+#endif
 
 int sdla_intde (sdlahw_t* hw)
 {
@@ -724,7 +795,9 @@
  * Acknowledge SDLA hardware interrupt.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_intack);
+#endif
 
 int sdla_intack (sdlahw_t* hw)
 {
@@ -774,11 +847,18 @@
  * Acknowledge S514 hardware interrupt.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(S514_intack);
+#endif
 
 void S514_intack (sdlahw_t* hw, u32 int_status)
 {
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status);
+#else
+	pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func,
+                PCI_INT_STATUS, int_status);
+#endif
 }
 
 
@@ -786,11 +866,18 @@
  * Read the S514 hardware interrupt status.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(read_S514_int_stat);
+#endif
 
 void read_S514_int_stat (sdlahw_t* hw, u32* int_status)
 {
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status);
+#else
+        pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, PCI_INT_STATUS,
+		int_status);
+#endif
 }
 
 
@@ -798,7 +885,9 @@
  * Generate an interrupt to adapter's CPU.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_intr);
+#endif
 
 int sdla_intr (sdlahw_t* hw)
 {
@@ -842,7 +931,9 @@
  * o Return number of loops made, or 0 if command timed out.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_exec);
+#endif
 
 int sdla_exec (void* opflag)
 {
@@ -878,7 +969,9 @@
  * interrupt routines are accessing adapter shared memory.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_peek);
+#endif
 
 int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
 {
@@ -960,7 +1053,9 @@
  * interrupt routines are accessing adapter shared memory.
  */
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 EXPORT_SYMBOL(sdla_poke);
+#endif
  
 int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
 {
@@ -1124,7 +1219,11 @@
 		return -EINVAL;
 	}
 
-	for (i = opt[0]; i && err; --i) {
+	/* Start testing from 8th position, address
+         * 0xC8000 from the 508 address table. 
+         * We don't want to test A**** addresses, since
+         * they are usually used for Video */
+	for (i = 8; i <= opt[0] && err; i++) {
 		hw->dpmbase = phys_to_virt(opt[i]);
 		err = sdla_setdpm(hw);
 	}
@@ -1176,14 +1275,14 @@
 
 	/* Verify firmware signature */
 	if (strcmp(sfm->signature, SFM_SIGNATURE)) {
-		printk(KERN_ERR "%s: not SDLA firmware!\n",
+		printk(KERN_INFO "%s: not SDLA firmware!\n",
 			modname);
 		return -EINVAL;
 	}
 
 	/* Verify firmware module format version */
 	if (sfm->version != SFM_VERSION) {
-		printk(KERN_ERR
+		printk(KERN_INFO
 			"%s: firmware format %u rejected! Expecting %u.\n",
 			modname, sfm->version, SFM_VERSION);
 		return -EINVAL;
@@ -1193,7 +1292,7 @@
 	if ((len - offsetof(sfm_t, image) != sfm->info.codesize) ||
 		(checksum((void*)&sfm->info,
 		sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) {
-		printk(KERN_ERR "%s: firmware corrupted!\n", modname);
+		printk(KERN_INFO "%s: firmware corrupted!\n", modname);
 		return -EINVAL;
 	}
 
@@ -1211,19 +1310,18 @@
 	 */
 	for (i = 0;
 	     (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type);
-	     ++i)
-	;
+	     ++i);
+	
 	if (i == SFM_MAX_SDLA) {
-		printk(KERN_ERR "%s: firmware is not compatible with S%u!\n",
+		printk(KERN_INFO "%s: firmware is not compatible with S%u!\n",
 			modname, hw->type);
-		;
 		return -EINVAL;
 	}
 
 
 	/* Make sure there is enough on-board memory */
 	if (hw->memory < sfm->info.memsize) {
-		printk(KERN_ERR
+		printk(KERN_INFO
 			"%s: firmware needs %lu bytes of on-board memory!\n",
 			modname, sfm->info.memsize);
 		return -EINVAL;
@@ -1231,7 +1329,7 @@
 
 	/* Move code onto adapter */
 	if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) {
-		printk(KERN_ERR "%s: failed to load code segment!\n",
+		printk(KERN_INFO "%s: failed to load code segment!\n",
 			modname);
 		return -EIO;
 	}
@@ -1239,14 +1337,14 @@
 	/* Prepare boot-time configuration data and kick-off CPU */
 	sdla_bootcfg(hw, &sfm->info);
 	if (sdla_start(hw, sfm->info.startoffs)) {
-		printk(KERN_ERR "%s: Damn... Adapter won't start!\n",
+		printk(KERN_INFO "%s: Damn... Adapter won't start!\n",
 			modname);
 		return -EIO;
 	}
 
 	/* position DPM window over the mailbox and enable interrupts */
         if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) {
-		printk(KERN_ERR "%s: adapter hardware failure!\n",
+		printk(KERN_INFO "%s: adapter hardware failure!\n",
 			modname);
 		return -EIO;
 	}
@@ -1858,22 +1956,30 @@
  */
 static int detect_s514 (sdlahw_t* hw)
 {
-	unsigned char CPU_no, slot_no;
+	unsigned char CPU_no, slot_no, auto_slot_cfg;
 	int number_S514_cards = 0;
 	u32 S514_mem_base_addr = 0;
 	u32 ut_u32;
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	struct pci_dev *pci_dev;
+#else
+	u8 ut_u8;
+#endif
 
 
 #ifdef CONFIG_PCI
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         if(!pci_present())
+#else
+	if(!pcibios_present())
+#endif
         {
-                printk(KERN_ERR "%s: PCI BIOS not present!\n", modname);
+                printk(KERN_INFO "%s: PCI BIOS not present!\n", modname);
                 return 0;
         }
 #else
-        printk(KERN_ERR "%s: Linux not compiled for PCI usage!\n", modname);
+        printk(KERN_INFO "%s: Linux not compiled for PCI usage!\n", modname);
         return 0;
 #endif
 
@@ -1883,10 +1989,17 @@
 	*/
 	CPU_no = hw->S514_cpu_no[0];
 	slot_no = hw->S514_slot_no;
-	
-	printk(KERN_INFO "%s: detecting S514 card, CPU %c, slot #%d\n",
-		modname, CPU_no, slot_no);
+	auto_slot_cfg = hw->auto_pci_cfg;
 
+	if (auto_slot_cfg){
+		printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot=Auto\n",
+		modname, CPU_no);
+
+	}else{
+		printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot #%d\n",
+		modname, CPU_no, slot_no);
+	}
+	
 	/* check to see that CPU A or B has been selected in 'router.conf' */
 	switch(CPU_no) {
 		case S514_CPU_A:
@@ -1894,9 +2007,9 @@
 			break;
 	
 		default:
-			printk(KERN_ERR "%s: S514 CPU definition invalid.\n", 
+			printk(KERN_INFO "%s: S514 CPU definition invalid.\n", 
 				modname);
-			printk(KERN_ERR "Must be 'A' or 'B'\n");
+			printk(KERN_INFO "Must be 'A' or 'B'\n");
 			return 0;
 	}
 
@@ -1904,50 +2017,110 @@
 	if(!number_S514_cards)
 		return 0;
 
-	/* we are using a single S514 adapter with a slot of 0 so re-read the */	/* location of this adapter */
-	if((number_S514_cards == 1) && !slot_no) {	
+	/* we are using a single S514 adapter with a slot of 0 so re-read the */	
+	/* location of this adapter */
+	if((number_S514_cards == 1) && auto_slot_cfg) {	
         	number_S514_cards = find_s514_adapter(hw, 1);
 		if(!number_S514_cards) {
-			printk(KERN_ERR "%s: Error finding PCI card\n",
+			printk(KERN_INFO "%s: Error finding PCI card\n",
 				modname);
 			return 0;
 		}
 	}
 
+      #if defined(LINUX_2_4)
 	pci_dev = hw->pci_dev;
 	/* read the physical memory base address */
 	S514_mem_base_addr = (CPU_no == S514_CPU_A) ? 
 		(pci_dev->resource[1].start) :
 		(pci_dev->resource[2].start);
+	
+      #elif defined (LINUX_2_1)
+	pci_dev = hw->pci_dev;
+	/* read the physical memory base address */
+	S514_mem_base_addr = (CPU_no == S514_CPU_A) ? 
+		(pci_dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK) :
+		(pci_dev->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK);
+	
+      #else
+	pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func,
+		(CPU_no == S514_CPU_A) ? PCI_MEM_BASE0_DWORD :
+		PCI_MEM_BASE1_DWORD, &S514_mem_base_addr);
+      #endif
 
 	printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n",
 		modname, S514_mem_base_addr);
 	if(!S514_mem_base_addr) {
 		if(CPU_no == S514_CPU_B)
-			printk(KERN_ERR "%s: CPU #B not present on the card\n", 				modname);
+			printk(KERN_INFO "%s: CPU #B not present on the card\n", 				modname);
 		else
-			printk(KERN_ERR "%s: No PCI memory allocated to card\n",				modname);
+			printk(KERN_INFO "%s: No PCI memory allocated to card\n",				modname);
 		return 0;
 	}
 
 	/* enable the PCI memory */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	pci_read_config_dword(pci_dev, 
 		(CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
 		&ut_u32);
 	pci_write_config_dword(pci_dev,
 		(CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
 		(ut_u32 | PCI_MEMORY_ENABLE));
+#else
+        pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func,
+		(CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
+		&ut_u32); 
+        pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func,
+		(CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
+		(ut_u32 | PCI_MEMORY_ENABLE));
+#endif
 
 	/* check the IRQ allocated and enable IRQ usage */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	if(!(hw->irq = pci_dev->irq)) {
-		printk(KERN_ERR "%s: IRQ not allocated to S514 adapter\n",
+		printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n",
 			modname);
                 return 0;
 	}
+
+	/* BUG FIX : Mar 6 2000
+ 	 * On a initial loading of the card, we must check
+         * and clear PCI interrupt bits, due to a reset
+         * problem on some other boards.  i.e. An interrupt
+         * might be pending, even after system bootup, 
+         * in which case, when starting wanrouter the machine
+         * would crash. 
+	 */
+	if (init_pci_slot(hw))
+		return 0;
+
         pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32);
         ut_u32 |= (CPU_no == S514_CPU_A) ?
                 PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B;
         pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32);
+#else
+	/* the INTPIN must not be 0 - if it is, then the S514 adapter is not */
+	/* configured for IRQ usage */
+	pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func,
+		PCI_INT_PIN_BYTE, &ut_u8);
+        if(!ut_u8) {
+                printk(KERN_INFO "%s: invalid setting for INTPIN on S514 card\n", modname);
+                printk(KERN_INFO "Please contact your Sangoma representative\n");
+                return 0;
+        }
+        pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func,
+		PCI_INT_LINE_BYTE, (unsigned char *)&hw->irq);
+        if(hw->irq == PCI_IRQ_NOT_ALLOCATED) {
+                printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n",
+			modname);
+                return 0;
+        }
+	pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, PCI_INT_CONFIG, &ut_u32);
+	ut_u32 |= (CPU_no == S514_CPU_A) ?
+		PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B;
+        pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func, 
+		PCI_INT_CONFIG, ut_u32);
+#endif
 
 	printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n",
 		modname, hw->irq);
@@ -1961,7 +2134,7 @@
 		(unsigned long)16);
      
         if(!hw->dpmbase || !hw->vector) {
-		printk(KERN_ERR "%s: PCI virtual memory allocation failed\n",
+		printk(KERN_INFO "%s: PCI virtual memory allocation failed\n",
 			modname);
                 return 0;
 	}
@@ -1983,49 +2156,99 @@
 	char S514_found_in_slot = 0;
         u16 PCI_subsys_vendor;
 
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
         struct pci_dev *pci_dev = NULL;
+#else
+        int pci_index;
+#endif
  
        slot_no = hw->S514_slot_no;
   
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
 	while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev))
         	!= NULL) {
-		if (pci_enable_device(pci_dev))
-			continue;
-		PCI_subsys_vendor = pci_dev->subsystem_vendor;
-                if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+                
+		pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD,
+                        &PCI_subsys_vendor);
+                
+		if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
                 	continue;
-        	hw->pci_dev = pci_dev;
+        	
+		hw->pci_dev = pci_dev;
+		
 		if(find_first_S514_card)
 			return(1);
+		
                 number_S514_cards ++;
-                printk(KERN_INFO
+                
+		printk(KERN_INFO
 			"%s: S514 card found, slot #%d (devfn 0x%X)\n",
                         modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
 			pci_dev->devfn);
-                if(slot_no && (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) ==
-                        slot_no)) {
+		
+		if (hw->auto_pci_cfg){
+			hw->S514_slot_no = ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK);
+			slot_no = hw->S514_slot_no;
+			
+		}else if (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == slot_no){
+                        S514_found_in_slot = 1;
+                        break;
+                }
+        }
+
+#else
+	//LINUX VERSION 2.0.X 
+        for (pci_index = 0; pci_index < MAX_S514_CARDS; pci_index ++) {
+                if (pcibios_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_index,
+                        &hw->pci_bus, &hw->pci_dev_func)!=PCIBIOS_SUCCESSFUL) {
+                                break;
+                }
+                
+		pcibios_read_config_word(hw->pci_bus, hw->pci_dev_func,
+                        PCI_SUBSYS_VENDOR_WORD, &PCI_subsys_vendor);
+                
+		if (PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+                        continue;
+                
+		if (find_first_S514_card)
+                        return(1);
+           	
+		number_S514_cards ++;
+		
+                printk(KERN_INFO "%s: S514 card found, bus #%d, slot #%d\n",
+                        modname, hw->pci_bus,
+                        ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK));
+
+		if (hw->auto_pci_cfg){
+			hw->S514_slot_no = ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK)
+			slot_no = hw->S514_slot_no;
+				
+		}else if (((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK) == slot_no) {
                         S514_found_in_slot = 1;
                         break;
                 }
         }
+#endif
 
 	/* if no S514 adapter has been found, then exit */
-        if(!number_S514_cards) {
-                printk(KERN_ERR "%s: no S514 adapters found\n", modname);
+        if (!number_S514_cards) {
+                printk(KERN_INFO "%s: Error, no S514 adapters found\n", modname);
                 return 0;
         }
         /* if more than one S514 card has been found, then the user must have */        /* defined a slot number so that the correct adapter is used */
-        else if((number_S514_cards > 1) && !slot_no) {
-                printk(KERN_ERR "%s: More than one S514 adapter found\n",
-                        modname);
-                printk(KERN_ERR "Define a PCI slot number for this adapter\n");
+        else if ((number_S514_cards > 1) && hw->auto_pci_cfg) {
+                printk(KERN_INFO "%s: Error, PCI Slot autodetect Failed! \n"
+				 "%s:        More than one S514 adapter found.\n"
+				 "%s:        Disable the Autodetect feature and supply\n"
+				 "%s:        the PCISLOT numbers for each card.\n",
+                        modname,modname,modname,modname);
                 return 0;
         }
         /* if the user has specified a slot number and the S514 adapter has */
         /* not been found in that slot, then exit */
-        else if (slot_no && !S514_found_in_slot) {
-                printk(KERN_ERR
-			"%s: S514 card not found in specified slot #%d\n",
+        else if (!hw->auto_pci_cfg && !S514_found_in_slot) {
+                printk(KERN_INFO
+			"%s: Error, S514 card not found in specified slot #%d\n",
                         modname, slot_no);
                 return 0;
         }
@@ -2138,5 +2361,170 @@
 	return crc;
 }
 
+static int init_pci_slot(sdlahw_t *hw)
+{
+
+	u32 int_status;
+	int volatile found=0;
+	int i=0;
+
+	/* Check if this is a very first load for a specific
+         * pci card. If it is, clear the interrput bits, and
+         * set the flag indicating that this card was initialized.
+	 */
+	
+	for (i=0; (i<MAX_S514_CARDS) && !found; i++){
+		if (pci_slot_ar[i] == hw->S514_slot_no){
+			found=1;
+			break;
+		}
+		if (pci_slot_ar[i] == 0xFF){
+			break;
+		}
+	}
+
+	if (!found){
+		read_S514_int_stat(hw,&int_status);
+		S514_intack(hw,int_status);
+		if (i == MAX_S514_CARDS){
+			printk(KERN_INFO "%s: Critical Error !!!\n",modname);
+			printk(KERN_INFO 
+				"%s: Number of Sangoma PCI cards exceeded maximum limit.\n",
+					modname);
+			printk(KERN_INFO "Please contact Sangoma Technologies\n");
+			return 1;
+		}
+		pci_slot_ar[i] = hw->S514_slot_no;
+	}
+	return 0;
+}
+
+static int pci_probe(sdlahw_t *hw)
+{
+
+        unsigned char slot_no;
+        int number_S514_cards = 0;
+        u16 PCI_subsys_vendor;
+	u16 PCI_card_type;
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+        struct pci_dev *pci_dev = NULL;
+	struct pci_bus *bus = NULL;
+#else
+        int pci_index;
+	u8 irq;
+#endif
+ 
+       slot_no = 0;
+  
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+	while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev))
+        	!= NULL) {
+		
+                pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD,
+                        &PCI_subsys_vendor);
+		
+                if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+                	continue;
+
+		pci_read_config_word(pci_dev, PCI_CARD_TYPE,
+                        &PCI_card_type);
+	
+		bus = pci_dev->bus;
+		
+		/* A dual cpu card can support up to 4 physical connections,
+		 * where a single cpu card can support up to 2 physical
+		 * connections.  The FT1 card can only support a single 
+		 * connection, however we cannot distinguish between a Single
+		 * CPU card and an FT1 card. */
+		if (PCI_card_type == S514_DUAL_CPU){
+                	number_S514_cards += 4;
+			 printk(KERN_INFO
+				"wanpipe: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n",
+                        	bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
+				pci_dev->irq);
+		}else{
+			number_S514_cards += 2;
+			printk(KERN_INFO
+				"wanpipe: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n",
+                        	bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
+				pci_dev->irq);
+		}
+        }
+
+#else
+        for (pci_index = 0; pci_index < MAX_S514_CARDS; pci_index ++) {
+		
+                if(pcibios_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_index,
+                        &hw->pci_bus, &hw->pci_dev_func)!=PCIBIOS_SUCCESSFUL) {
+                                break;
+                }
+                pcibios_read_config_word(hw->pci_bus, hw->pci_dev_func,
+                        PCI_SUBSYS_VENDOR_WORD, &PCI_subsys_vendor);
+                if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+                        continue;
+		
+		pcibios_read_config_word(hw->pci_bus,hw->pci_dev_func,PCI_CARD_TYPE,
+                        &PCI_card_type);
+
+		pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func,
+				PCI_INT_LINE_BYTE, &irq);
+
+		/* A dual cpu card can support up to 4 physical connections,
+		 * where a single cpu card can support up to 2 physical
+		 * connections.  The FT1 card can only support a single 
+		 * connection, however we cannot distinguish between a Single
+		 * CPU card and an FT1 card. */
+		if (PCI_card_type == S514_DUAL_CPU){
+                	number_S514_cards += 4;
+			 printk(KERN_INFO "%s: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n",
+                        	modname, hw->pci_bus,
+                        	((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK),irq);
+		}else{
+			printk(KERN_INFO "%s: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n",
+                        	modname, hw->pci_bus,
+                        	((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK),irq);
+			number_S514_cards += 2;
+		}
+        }
+#endif
+
+	return number_S514_cards;
+
+}
+
+
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+EXPORT_SYMBOL(wanpipe_hw_probe);
+#endif
+
+unsigned wanpipe_hw_probe(void)
+{
+	sdlahw_t hw;
+	unsigned* opt = s508_port_options; 
+	unsigned cardno=0;
+	int i;
+	
+	memset(&hw, 0, sizeof(hw));
+	
+	for (i = 1; i <= opt[0]; i++) {
+		if (detect_s508(opt[i])){
+			/* S508 card can support up to two physical links */
+			cardno+=2;
+			printk(KERN_INFO "wanpipe: S508-ISA card found, port 0x%x\n",opt[i]);
+		}
+	}
+
+      #ifdef CONFIG_PCI
+	hw.S514_slot_no = 0;
+	cardno += pci_probe(&hw);
+      #else
+	printk(KERN_INFO "wanpipe: Warning, Kernel not compiled for PCI support!\n");
+	printk(KERN_INFO "wanpipe: PCI Hardware Probe Failed!\n");
+      #endif
+
+	return cardno;
+}
 
 /****** End *****************************************************************/

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