patch-2.3.31 linux/drivers/net/aironet4500_card.c

Next file: linux/drivers/net/aironet4500_core.c
Previous file: linux/drivers/net/aironet4500.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.30/linux/drivers/net/aironet4500_card.c linux/drivers/net/aironet4500_card.c
@@ -0,0 +1,1118 @@
+/*
+ *	 Aironet 4500 PCI-ISA-i365 driver
+ *
+ *		Elmer Joandi, Januar 1999
+ *	Copyright Elmer Joandi, all rights restricted
+ *	
+ *
+ *	Revision 0.1 ,started  30.12.1998
+ *
+ *
+ */
+#ifdef MODULE
+static const char *awc_version =
+"aironet4500_cards.c v0.1 28/03/99 Elmer Joandi, elmer@ylenurme.ee.\n";
+#endif
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#if LINUX_VERSION_CODE < 0x20100
+#include <linux/bios32.h>
+#endif
+
+#include "aironet4500.h"
+
+#define PCI_VENDOR_ID_AIRONET 	0x14b9
+#define PCI_DEVICE_AIRONET_4800_1 0x1
+#define PCI_DEVICE_AIRONET_4800 0x4500
+#define PCI_DEVICE_AIRONET_4500 0x4800
+#define AIRONET4X00_IO_SIZE 	0x40
+#define AIRONET4X00_CIS_SIZE	0x300
+#define AIRONET4X00_MEM_SIZE	0x300
+
+#define AIRONET4500_PCI 	1
+#define AIRONET4500_PNP		2
+#define AIRONET4500_ISA		3
+#define AIRONET4500_365		4
+
+
+#ifdef CONFIG_AIRONET4500_PCI
+
+#include <linux/pci.h>
+
+
+static int reverse_probe =0 ;
+
+
+static int awc_pci_init(struct NET_DEVICE * dev, int pci_bus, int device_nr,
+ 			int ioaddr, int cis_addr, int mem_addr,u8 pci_irq_line) ;
+
+
+int awc4500_pci_probe(struct NET_DEVICE *dev)
+{
+	int cards_found = 0;
+	static int pci_index = 0;	/* Static, for multiple probe calls. */
+	u8 pci_irq_line = 0;
+//	int p;
+
+	unsigned char awc_pci_dev, awc_pci_bus;
+
+	if (!pcibios_present()) 
+		return -1;
+
+	for (;pci_index < 0xff; pci_index++) {
+		u16 vendor, device, pci_command, new_command;
+		u32 pci_memaddr;
+		u32 pci_ioaddr;
+		u32 pci_cisaddr;
+#if LINUX_VERSION_CODE < 0x20100
+		u16 pci_caps =0;
+		u8  pci_caps_ptr =0;
+#endif
+		if (pcibios_find_class	(PCI_CLASS_NETWORK_OTHER << 8,
+			 reverse_probe ? 0xfe - pci_index : pci_index,
+				 &awc_pci_bus, &awc_pci_dev) != PCIBIOS_SUCCESSFUL){
+				if (reverse_probe){
+					continue;
+				} else {
+					break;
+				}
+		}
+		pcibios_read_config_word(awc_pci_bus, awc_pci_dev,
+									 PCI_VENDOR_ID, &vendor);
+		pcibios_read_config_word(awc_pci_bus, awc_pci_dev,
+									 PCI_DEVICE_ID, &device);
+#if LINUX_VERSION_CODE >= 0x20300
+	        pci_irq_line = pci_find_slot(awc_pci_bus, awc_pci_dev)->irq;
+		pci_memaddr = pci_find_slot(awc_pci_bus, awc_pci_dev)->resource[0].start;
+                pci_cisaddr = pci_find_slot(awc_pci_bus, awc_pci_dev)->resource[1].start;
+		pci_ioaddr = pci_find_slot(awc_pci_bus, awc_pci_dev)->resource[2].start;
+#else
+#if LINUX_VERSION_CODE >= 0x20155
+	        pci_irq_line = pci_find_slot(awc_pci_bus, awc_pci_dev)->irq;
+		pci_memaddr = pci_find_slot(awc_pci_bus, awc_pci_dev)->base_address[0];
+                pci_cisaddr = pci_find_slot(awc_pci_bus, awc_pci_dev)->base_address[1];
+		pci_ioaddr = pci_find_slot(awc_pci_bus, awc_pci_dev)->base_address[2];		
+#else
+		pcibios_read_config_dword(awc_pci_bus, awc_pci_dev,PCI_BASE_ADDRESS_0, &pci_memaddr);
+		pcibios_read_config_dword(awc_pci_bus, awc_pci_dev,PCI_BASE_ADDRESS_1, &pci_cisaddr);
+		pcibios_read_config_dword(awc_pci_bus, awc_pci_dev,PCI_BASE_ADDRESS_2, &pci_ioaddr);
+		pcibios_read_config_byte(awc_pci_bus, awc_pci_dev, PCI_INTERRUPT_LINE, &pci_irq_line);
+		pcibios_read_config_word(awc_pci_bus, awc_pci_dev,PCI_STATUS, &pci_caps);
+		pcibios_read_config_byte(awc_pci_bus, awc_pci_dev, 0x34, &pci_caps_ptr);
+
+#endif // 2.2
+#endif // 2.3
+//		printk("\n pci capabilities %x and ptr %x \n",pci_caps,pci_caps_ptr);
+		/* Remove I/O space marker in bit 0. */
+
+		if (vendor != PCI_VENDOR_ID_AIRONET)
+			continue;
+		if (device != PCI_DEVICE_AIRONET_4800_1 && 
+				device != PCI_DEVICE_AIRONET_4800 &&
+				device != PCI_DEVICE_AIRONET_4500 )
+                        continue;
+#if LINUX_VERSION_CODE < 0x20300
+
+		if (!(pci_ioaddr & 1)){
+			printk("awc4X00 ioaddr location mismatch \n");
+			return -1;
+		};
+
+		pci_ioaddr &= ~3;
+		pci_cisaddr &= ~0xf;
+		pci_memaddr &= ~0xf;
+#endif		
+//		if (check_region(pci_ioaddr, AIRONET4X00_IO_SIZE) ||
+//			check_region(pci_cisaddr, AIRONET4X00_CIS_SIZE) ||
+//			check_region(pci_memaddr, AIRONET4X00_MEM_SIZE)) {
+//				printk(KERN_ERR "aironet4X00 mem addrs not available for maping \n");
+//				continue;
+//		}
+		request_region(pci_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr");
+//		request_region(pci_cisaddr, AIRONET4X00_CIS_SIZE, "aironet4x00 cis");
+//		request_region(pci_memaddr, AIRONET4X00_MEM_SIZE, "aironet4x00 mem");
+
+//		pcibios_write_config_word(awc_pci_bus, awc_pci_dev,
+//						  PCI_COMMAND, 0);
+		udelay(10000);
+
+		pcibios_read_config_word(awc_pci_bus, awc_pci_dev,
+					 PCI_COMMAND, &pci_command);
+		new_command = pci_command |0x100 | PCI_COMMAND_MEMORY|PCI_COMMAND_IO;
+		if (pci_command != new_command) {
+			printk(KERN_INFO "  The PCI BIOS has not enabled this"
+				   " device!  Updating PCI command %4.4x->%4.4x.\n",
+				   pci_command, new_command);
+			pcibios_write_config_word(awc_pci_bus, awc_pci_dev,
+						  PCI_COMMAND, new_command);
+		}
+
+
+/*		if (device == PCI_DEVICE_AIRONET_4800)
+			pcibios_write_config_dword(awc_pci_bus, awc_pci_dev,
+				0x40, 0x00000000);
+
+		udelay(1000);
+*/
+		if (device == PCI_DEVICE_AIRONET_4800)
+			pcibios_write_config_dword(awc_pci_bus, awc_pci_dev,
+				0x40, 0x40000000);
+
+		if (awc_pci_init(dev, awc_pci_bus, awc_pci_dev, pci_ioaddr,pci_cisaddr,pci_memaddr,pci_irq_line)){
+			printk(KERN_ERR "awc4800 pci init failed \n");
+			break;
+		}
+		dev = 0;
+		cards_found++;
+	}
+
+	return cards_found ? 0 : -ENODEV;
+}
+
+
+static int awc_pci_init(struct NET_DEVICE * dev, int pci_bus, int device_nr,
+ 			int ioaddr, int cis_addr, int mem_addr, u8 pci_irq_line) {
+
+	int i;
+
+	if (!dev) {
+		dev = init_etherdev(dev, 0 );	
+	}
+	dev->priv = kmalloc(sizeof(struct awc_private),GFP_KERNEL );
+	memset(dev->priv,0,sizeof(struct awc_private));
+	if (!dev->priv) {
+		printk(KERN_CRIT "aironet4x00: could not allocate device private, some unstability may follow\n");
+		return -1;
+	};
+
+//	ether_setup(dev);
+
+//	dev->tx_queue_len = tx_queue_len;
+
+	dev->hard_start_xmit = 		&awc_start_xmit;
+//	dev->set_config = 		&awc_config_misiganes,aga mitte awc_config;
+	dev->get_stats = 		&awc_get_stats;
+//	dev->set_multicast_list = 	&awc_set_multicast_list;
+	dev->change_mtu		=	awc_change_mtu;
+	dev->init = &awc_init;
+	dev->open = &awc_open;
+	dev->stop = &awc_close;
+	dev->tbusy = 1;
+	dev->start  = 0;
+
+    	dev->base_addr = ioaddr;
+
+
+    	dev->irq = pci_irq_line;
+#if LINUX_VERSION_CODE > 0x20100
+	request_irq(dev->irq,awc_interrupt, SA_SHIRQ | SA_INTERRUPT ,"Aironet 4X00",dev);
+#else 
+	request_irq(dev->irq,awc_interrupt, SA_SHIRQ | SA_INTERRUPT ,"Aironet 4X00",dev);
+#endif
+	awc_private_init( dev);
+	awc_init(dev);
+
+	i=0;
+	while (aironet4500_devices[i] && i < MAX_AWCS-1) i++;
+	if (!aironet4500_devices[i]){
+		aironet4500_devices[i]=dev;
+		((struct awc_private *)
+		aironet4500_devices[i]->priv)->card_type = AIRONET4500_PCI;
+
+		if (awc_proc_set_fun)
+			awc_proc_set_fun(i);
+	}
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	
+//	if (register_netdev(dev) != 0) {
+//		printk(KERN_NOTICE "awc_cs: register_netdev() failed\n");
+//		goto failed;
+//	}
+
+	
+
+	return 0; 
+//  failed:
+//  	return -1;
+
+}
+
+#ifdef MODULE
+static void awc_pci_release(void) {
+
+//	long flags;
+	int i=0;
+
+	DEBUG(0, "awc_detach \n");
+
+	i=0;
+	while ( i < MAX_AWCS) {
+		if (!aironet4500_devices[i])
+                        {i++; continue;};
+		if (((struct awc_private *)aironet4500_devices[i]->priv)->card_type != AIRONET4500_PCI)
+		                  {i++;      continue;}
+
+		if (awc_proc_unset_fun)
+			awc_proc_unset_fun(i);
+		release_region(aironet4500_devices[i]->base_addr, AIRONET4X00_IO_SIZE);
+//		release_region(pci_cisaddr, AIRONET4X00_CIS_SIZE, "aironet4x00 cis");
+//		release_region(pci_memaddr, AIRONET4X00_MEM_SIZE, "aironet4x00 mem");
+
+		unregister_netdev(aironet4500_devices[i]);
+		free_irq(aironet4500_devices[i]->irq,aironet4500_devices[i]);
+		kfree_s(aironet4500_devices[i]->priv, sizeof(struct awc_private));
+		kfree_s(aironet4500_devices[i], sizeof(struct NET_DEVICE));
+
+		aironet4500_devices[i]=0;
+
+
+		i++;
+	}
+	
+
+} 
+
+
+#endif //MODULE
+
+
+#endif /* CONFIG_AIRONET4500_PCI */
+
+#ifdef CONFIG_AIRONET4500_PNP
+
+#if LINUX_VERSION_CODE > 0x20300
+#include <linux/isapnp.h>
+#else
+#include "isapnp.h"
+#endif
+#define AIRONET4X00_IO_SIZE 	0x40
+
+#if LINUX_VERSION_CODE > 0x20300
+#define isapnp_logdev pci_dev
+#define isapnp_dev    pci_bus
+#define isapnp_find_device isapnp_find_card
+#define isapnp_find_logdev isapnp_find_dev
+#define PNP_BUS bus
+#define PNP_BUS_NUMBER number
+#define PNP_DEV_NUMBER devfn
+#else 
+#define PNP_BUS dev
+#define PNP_BUS_NUMBER csn
+#define PNP_DEV_NUMBER number
+#endif
+
+int awc4500_pnp_hw_reset(struct NET_DEVICE *dev){
+	struct isapnp_logdev *logdev;
+#if LINUX_VERSION_CODE < 0x20300
+	struct isapnp_config cfg;
+#endif
+	DEBUG(0, "awc_pnp_reset \n");
+
+	if (!dev->priv ) {
+		printk("awc4500 no dev->priv in hw_reset\n");
+		return -1;
+	};
+
+	logdev = ((struct isapnp_logdev *) ((struct awc_private *)dev->priv)->bus);
+
+	if (!logdev ) {
+		printk("awc4500 no pnp logdev in hw_reset\n");
+		return -1;
+	};
+
+	if (isapnp_cfg_begin(logdev->PNP_BUS->PNP_BUS_NUMBER, logdev->PNP_DEV_NUMBER)<0)
+		printk("isapnp cfg failed at release \n");
+	isapnp_deactivate(logdev->PNP_DEV_NUMBER);
+	isapnp_cfg_end();
+
+	udelay(100);
+
+
+	if (isapnp_cfg_begin(logdev->PNP_BUS->PNP_BUS_NUMBER, logdev->PNP_DEV_NUMBER) < 0) {
+		printk("%s cfg begin failed in hw_reset for csn %x devnum %x \n",
+				dev->name, logdev->PNP_BUS->PNP_BUS_NUMBER, logdev->PNP_DEV_NUMBER);
+		return -EAGAIN;
+	}
+#if LINUX_VERSION_CODE < 0x20300
+	if (isapnp_config_init(&cfg, logdev)<0) {
+		printk("cfg init failed \n");
+		isapnp_cfg_end();
+		return -EAGAIN;
+	}
+	cfg.port[0] 	= dev->base_addr;
+	cfg.irq[0]	= dev->irq;
+
+	if (isapnp_configure(&cfg)<0) {
+		printk("%s hw_reset, isapnp configure failed (out of resources?)\n",dev->name);
+		isapnp_cfg_end();
+		return -ENOMEM;
+	}
+#else
+	
+#endif
+	isapnp_activate(logdev->PNP_DEV_NUMBER);	/* activate device */
+	isapnp_cfg_end();
+
+	return 0;
+}
+
+int awc4500_pnp_probe(struct NET_DEVICE *dev)
+{
+	int isa_index = 0;
+	int isa_irq_line = 0;
+	int isa_ioaddr = 0;
+	int card = 0;
+	int i=0;
+	struct isapnp_dev * pnp_dev ;
+	struct isapnp_logdev *logdev;
+#if LINUX_VERSION_CODE < 0x20300
+	struct isapnp_config cfg;
+#endif
+
+	while (1) {
+
+		pnp_dev = isapnp_find_device(
+						ISAPNP_VENDOR('A','W','L'), 
+						ISAPNP_DEVICE(1),
+#if LINUX_VERSION_CODE < 0x20300						
+						 isa_index 
+#else
+						0
+#endif						 
+						 );
+	
+		if (!pnp_dev) break;  
+		
+		isa_index++;
+
+		logdev = isapnp_find_logdev(pnp_dev, ISAPNP_VENDOR('A','W','L'),
+				    ISAPNP_FUNCTION(1),
+				    0);
+		if (!logdev){
+			printk("No logical device found on Aironet board \n");
+			return -ENODEV;
+		}
+		if (isapnp_cfg_begin(logdev->PNP_BUS->PNP_BUS_NUMBER, logdev->PNP_DEV_NUMBER) < 0) {
+			printk("cfg begin failed for csn %x devnum %x \n",
+					logdev->PNP_BUS->PNP_BUS_NUMBER, logdev->PNP_DEV_NUMBER);
+			return -EAGAIN;
+		}
+#if LINUX_VERSION_CODE < 0x20300
+		if (isapnp_config_init(&cfg, logdev)<0) {
+			printk("cfg init failed \n");
+			isapnp_cfg_end();
+			return -EAGAIN;
+		}
+		if (isapnp_configure(&cfg)<0) {
+			printk("isapnp configure failed (out of resources?)\n");
+			isapnp_cfg_end();
+			return -ENOMEM;
+		}
+#endif
+		isapnp_activate(logdev->PNP_DEV_NUMBER);	/* activate device */
+		isapnp_cfg_end();
+
+#if LINUX_VERSION_CODE < 0x20300		
+		isa_ioaddr = cfg.port[0];
+		isa_irq_line = cfg.irq[0];
+#else
+		isa_irq_line = logdev->irq;
+		isa_ioaddr = logdev->resource[0].start;
+#endif
+		request_region(isa_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr");
+
+		if (!dev) {
+			dev = init_etherdev(dev, 0 );	
+		}
+		dev->priv = kmalloc(sizeof(struct awc_private),GFP_KERNEL );
+		memset(dev->priv,0,sizeof(struct awc_private));
+		if (!dev->priv) {
+			printk(KERN_CRIT "aironet4x00: could not allocate device private, some unstability may follow\n");
+			return -1;
+		};
+		((struct awc_private *)dev->priv)->bus =  logdev;
+
+	//	ether_setup(dev);
+	
+	//	dev->tx_queue_len = tx_queue_len;
+	
+		dev->hard_start_xmit = 		&awc_start_xmit;
+	//	dev->set_config = 		&awc_config_misiganes,aga mitte awc_config;
+		dev->get_stats = 		&awc_get_stats;
+	//	dev->set_multicast_list = 	&awc_set_multicast_list;	
+		dev->change_mtu		=	awc_change_mtu;	
+		dev->init = &awc_init;
+		dev->open = &awc_open;
+		dev->stop = &awc_close;
+		dev->tbusy = 1;
+		dev->start  = 0;
+		
+	    	dev->base_addr = isa_ioaddr;
+
+
+	    	dev->irq = isa_irq_line;
+#if LINUX_VERSION_CODE > 0x20100
+		request_irq(dev->irq,awc_interrupt , SA_SHIRQ | SA_INTERRUPT ,"Aironet 4X00",dev);
+#else
+		request_irq(dev->irq,awc_interrupt, SA_SHIRQ  ,"Aironet 4X00",dev);
+#endif
+
+		awc_private_init( dev);
+
+		((struct awc_private *)dev->priv)->bus =  logdev;
+
+		cli();
+		if ( awc_init(dev) ){
+			printk("card not found at irq %x io %lx\n",dev->irq, dev->base_addr);
+			if (card==0){
+				sti();
+				return -1;
+			}
+			sti();
+			break;
+		}
+		udelay(10);
+		sti();
+		i=0;
+		while (aironet4500_devices[i] && i < MAX_AWCS-1) i++;
+		if (!aironet4500_devices[i] && i < MAX_AWCS-1 ){
+			aironet4500_devices[i]=dev;
+
+		((struct awc_private *)
+		aironet4500_devices[i]->priv)->card_type = AIRONET4500_PNP;
+
+			if (awc_proc_set_fun)
+				awc_proc_set_fun(i);	
+		} else { 
+			printk(KERN_CRIT "Out of resources (MAX_AWCS) \n");
+			return -1;
+		}
+
+		dev->tbusy = 1;
+		dev->start = 0;
+
+		card++;	
+	}
+
+	if (card == 0) return -ENODEV;
+	return 0;
+}
+
+#ifdef MODULE
+static void awc_pnp_release(void) {
+
+//	long flags;
+	int i=0;
+	struct isapnp_logdev *logdev;
+
+	DEBUG(0, "awc_detach \n");
+
+	i=0;
+	while ( i < MAX_AWCS) {
+		if (!aironet4500_devices[i])
+		                  {i++;      continue;}
+		if (((struct awc_private *)aironet4500_devices[i]->priv)->card_type != AIRONET4500_PNP)
+		                  {i++;      continue;}
+
+		logdev = ((struct isapnp_logdev *) ((struct awc_private *)aironet4500_devices[i]->priv)->bus);
+
+		if (!logdev ) 
+			printk("awc4500 no pnp logdev in pnp_release\n");
+
+		if (awc_proc_unset_fun)
+			awc_proc_unset_fun(i);
+		if (isapnp_cfg_begin(logdev->PNP_BUS->PNP_BUS_NUMBER, logdev->PNP_DEV_NUMBER)<0)
+			printk("isapnp cfg failed at release \n");
+		isapnp_deactivate(logdev->PNP_DEV_NUMBER);
+		isapnp_cfg_end();
+
+		release_region(aironet4500_devices[i]->base_addr, AIRONET4X00_IO_SIZE);
+//		release_region(isa_cisaddr, AIRONET4X00_CIS_SIZE, "aironet4x00 cis");
+//		release_region(isa_memaddr, AIRONET4X00_MEM_SIZE, "aironet4x00 mem");
+
+		unregister_netdev(aironet4500_devices[i]);
+		free_irq(aironet4500_devices[i]->irq,aironet4500_devices[i]);
+		kfree_s(aironet4500_devices[i]->priv, sizeof(struct awc_private));
+		kfree_s(aironet4500_devices[i], sizeof(struct NET_DEVICE));
+
+		aironet4500_devices[i]=0;
+
+
+		i++;
+	}
+	
+
+} 
+
+#endif //MODULE
+#endif /* CONFIG_AIRONET4500_PNP */
+
+#ifdef  CONFIG_AIRONET4500_ISA 
+
+static int irq[] = {0,0,0,0,0};
+static int io[] = {0,0,0,0,0};
+
+/* 
+	EXPORT_SYMBOL(irq);
+	EXPORT_SYMBOL(io);
+*/
+#if LINUX_VERSION_CODE >= 0x20100
+MODULE_PARM(irq,"i");
+MODULE_PARM_DESC(irq,"Aironet 4x00 ISA non-PNP irqs,required");
+MODULE_PARM(io,"i");
+MODULE_PARM_DESC(io,"Aironet 4x00 ISA non-PNP ioports,required");
+#endif
+
+
+
+int awc4500_isa_probe(struct NET_DEVICE *dev)
+{
+//	int cards_found = 0;
+//	static int isa_index = 0;	/* Static, for multiple probe calls. */
+	int isa_irq_line = 0;
+	int isa_ioaddr = 0;
+//	int p;
+	int card = 0;
+	int i=0;
+
+	if (! io[0] || ! irq[0]){
+	
+		printk("       Both irq and io params must be supplied  for ISA mode !!!\n");
+		return -ENODEV;
+	}
+
+	printk(KERN_WARNING "     Aironet ISA Card in non-PNP(ISA) mode sometimes feels bad on interrupt \n");
+	printk(KERN_WARNING "     Use aironet4500_pnp if any problems(i.e. card malfunctioning). \n");
+	printk(KERN_WARNING "     Note that this isa probe is not friendly... must give exact parameters \n");
+
+	while (irq[card] !=0){
+	
+		isa_ioaddr = io[card];
+		isa_irq_line = irq[card];
+
+		request_region(isa_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr");
+
+		if (!dev) {
+			dev = init_etherdev(dev, 0 );	
+		}
+		dev->priv = kmalloc(sizeof(struct awc_private),GFP_KERNEL );
+		memset(dev->priv,0,sizeof(struct awc_private));
+		if (!dev->priv) {
+			printk(KERN_CRIT "aironet4x00: could not allocate device private, some unstability may follow\n");
+			return -1;
+		};
+
+	//	ether_setup(dev);
+	
+	//	dev->tx_queue_len = tx_queue_len;
+	
+		dev->hard_start_xmit = 		&awc_start_xmit;
+	//	dev->set_config = 		&awc_config_misiganes,aga mitte awc_config;
+		dev->get_stats = 		&awc_get_stats;
+	//	dev->set_multicast_list = 	&awc_set_multicast_list;	
+		dev->change_mtu		=	awc_change_mtu;	
+		dev->init = &awc_init;
+		dev->open = &awc_open;
+		dev->stop = &awc_close;
+		dev->tbusy = 1;
+		dev->start  = 0;
+		
+	    	dev->base_addr = isa_ioaddr;
+
+
+	    	dev->irq = isa_irq_line;
+
+#if LINUX_VERSION_CODE > 0x20100
+		request_irq(dev->irq,awc_interrupt ,SA_INTERRUPT ,"Aironet 4X00",dev);
+#else
+		request_irq(dev->irq,awc_interrupt ,0 ,"Aironet 4X00",dev);
+#endif
+
+		awc_private_init( dev);
+		if ( awc_init(dev) ){
+			printk("card not found at irq %x mem %x\n",irq[card],io[card]);
+			if (card==0)
+				return -1;
+			break;
+		}
+
+		i=0;
+		while (aironet4500_devices[i] && i < MAX_AWCS-1) i++;
+		if (!aironet4500_devices[i]){
+			aironet4500_devices[i]=dev;
+		((struct awc_private *)
+		aironet4500_devices[i]->priv)->card_type = AIRONET4500_ISA;
+
+			if (awc_proc_set_fun)
+				awc_proc_set_fun(i);	
+		}
+
+		dev->tbusy = 1;
+		dev->start = 0;
+
+		card++;	
+	}
+	if (card == 0 ) {
+		return -ENODEV;
+	};
+	return 0;
+}
+
+#ifdef MODULE
+static void awc_isa_release(void) {
+
+//	long flags;
+	int i=0;
+
+	DEBUG(0, "awc_detach \n");
+
+	i=0;
+	while ( i < MAX_AWCS) {
+	
+		if (!aironet4500_devices[i])
+		                  {i++;      continue;}
+		if (((struct awc_private *)aironet4500_devices[i]->priv)->card_type != AIRONET4500_ISA)
+		                  {i++;      continue;}
+
+		if (awc_proc_unset_fun)
+			awc_proc_unset_fun(i);
+		release_region(aironet4500_devices[i]->base_addr, AIRONET4X00_IO_SIZE);
+//		release_region(isa_cisaddr, AIRONET4X00_CIS_SIZE, "aironet4x00 cis");
+//		release_region(isa_memaddr, AIRONET4X00_MEM_SIZE, "aironet4x00 mem");
+
+		unregister_netdev(aironet4500_devices[i]);
+		free_irq(aironet4500_devices[i]->irq,aironet4500_devices[i]);
+		kfree_s(aironet4500_devices[i]->priv, sizeof(struct awc_private));
+		kfree_s(aironet4500_devices[i], sizeof(struct NET_DEVICE));
+
+		aironet4500_devices[i]=0;
+
+
+		i++;
+	}
+	
+
+} 
+           
+#endif //MODULE   
+
+#endif /* CONFIG_AIRONET4500_ISA */
+
+#ifdef  CONFIG_AIRONET4500_365 
+
+#define port_range 0x40
+
+int awc_i365_offset_ports[] = {0x3e0,0x3e0,0x3e2,0x3e2};
+int awc_i365_data_ports [] = {0x3e1,0x3e1,0x3e3,0x3e3};
+int awc_i365_irq[]	= {5,5,11,12};
+int awc_i365_io[]	= {0x140,0x100,0x400,0x440};
+int awc_i365_sockets	= 0;
+
+struct i365_socket {
+	int offset_port ;
+	int data_port;
+	int socket;
+	int irq; 
+	int io;
+	int manufacturer;
+	int product;
+};
+	
+inline u8 i365_in (struct i365_socket * s, int offset) { 
+	outb(offset  + (s->socket % 2)* 0x40, s->offset_port);
+	return inb(s->data_port); 
+};
+
+inline void i365_out (struct i365_socket * s, int offset,int data){
+	outb(offset + (s->socket % 2)* 0x40 ,s->offset_port);
+	outb((data & 0xff),s->data_port)	;
+	
+};
+
+void awc_i365_card_release(struct i365_socket * s){
+	
+	i365_out(s, 0x5, 0); 		// clearing ints
+	i365_out(s, 0x6, 0x20); 	// mem 16 bits
+	i365_out(s, 0x7, 0); 		// clear IO
+	i365_out(s, 0x3, 0);		// gen ctrl reset + mem mode
+	i365_out(s, 0x2, 0);		// reset power
+	i365_out(s, 0x2, i365_in(s, 0x2) & 0x7f ); // cardenable off
+	i365_out(s, 0x2, 0);		// remove power
+	
+
+};
+int awc_i365_probe_once(struct i365_socket * s ){
+
+
+	int caps=i365_in(s, 0);
+	int ret;
+	unsigned long jiff;
+//	short rev	= 0x3000;
+	unsigned char cis [0x3e3];
+	unsigned char * mem = phys_to_virt(0xd000);
+	int i;
+	int port ;
+	
+	DEBUG(1," i365 control ID %x \n", caps);
+
+	if (caps & 0xC){
+		return 1;
+	};
+	
+	ret = i365_in(s, 0x1);
+
+	if ((ret & 0xC0) != 0xC0){
+		printk("card in socket %d port %x not in known state, %x \n",
+			s->socket, s->offset_port, ret );
+		return -1;
+	};
+
+	
+	awc_i365_card_release(s);
+
+
+	udelay(100000);
+	
+	i365_out(s, 0x2, 0x10 ); 	// power enable
+	udelay(200000);
+	
+	i365_out(s, 0x2, 0x10 | 0x01 | 0x04 | 0x80);	//power enable
+	
+	udelay(250000);
+	
+	if (!s->irq)
+		s->irq = 11;
+	
+	i365_out(s, 0x3, 0x40 | 0x20 | s->irq);
+	
+	jiff = jiffies;
+	
+	while (jiffies-jiff < HZ ) 
+		if (i365_in(s,0x1) & 0x20)
+			break;
+			
+	if (! (i365_in(s,0x1) & 0x20) ){
+		printk("irq enable timeout on socket %x \n", s->socket);
+		return -1;
+	};
+	
+	i365_out(s,0x10,0xd0);
+	i365_out(s,0x11,0x0);
+	i365_out(s,0x12,0xd0);
+	i365_out(s,0x13,0x0);
+	i365_out(s,0x14,0x30 );
+	i365_out(s,0x15,0x3f | 0x40);		// enab mem reg bit
+	i365_out(s,0x06,0x01);			// enab mem 
+	
+	udelay(10000);
+	
+	cis[0] = 0x45;
+	
+//	memcpy_toio( 0xd3e0, &(cis[0]),0x1);
+
+//	mem[0x3e0] = 0x0;
+//	mem[0] = 0x45;
+
+	mem[0x3e0] = 0x45;
+
+	udelay(10000);
+	
+	memcpy_fromio(cis,0xD000, 0x3e0);
+	
+	for (i = 0; i <= 0x3e2; i++)
+		printk("%02x", mem[i]);
+	for (i = 0; i <= 0x3e2; i++)
+		printk("%c", mem[i]);
+
+	i=0;	
+	while (i < 0x3e0){
+		if (cis[i] == 0xff)
+			break;
+		if (cis[i] != 0x20 ){
+			i = i + 2 + cis[i+1];
+			continue;
+		}else {
+			s->manufacturer = cis[i+2] | (cis[i+3]<<8);
+			s->product	= cis[i+4] | (cis[i+5]<<8);
+			break;
+		};
+		i++;
+	};
+	
+	DEBUG(1,"socket %x manufacturer %x product %x \n",
+		s->socket, s->manufacturer,s->product);
+
+	i365_out(s,0x07, 0x1 | 0x2); 		// enable io 16bit
+	udelay(1000);
+	port = s->io;
+	i365_out(s,0x08, port & 0xff);
+	i365_out(s,0x09, (port & 0xff00)/ 0x100);
+	i365_out(s,0x0A, (port+port_range) & 0xff);
+	i365_out(s,0x0B, ((port+port_range) & 0xff00) /0x100);	
+
+	i365_out(s,0x06, 0x40); 		// enable io window
+
+	udelay(1000);
+
+	i365_out(s,0x3e0,0x45);
+	
+	outw(0x10, s->io);
+
+	jiff = jiffies;
+	while (!(inw(s->io + 0x30) & 0x10)){
+	
+		if (jiffies - jiff > HZ ){
+		
+			printk("timed out waitin for command ack \n");
+			break;
+		}
+	};
+
+	
+	outw(0x10, s->io + 0x34);
+	udelay(10000);
+	
+	return 0;
+	
+	
+
+		
+};
+
+
+static int awc_i365_init(struct i365_socket * s) {
+
+	struct NET_DEVICE * dev;
+	int i;
+
+
+	dev = init_etherdev(0, sizeof(struct awc_private) );
+
+//	dev->tx_queue_len = tx_queue_len;
+	ether_setup(dev);
+
+	dev->hard_start_xmit = 		&awc_start_xmit;
+//	dev->set_config = 		&awc_config_misiganes,aga mitte awc_config;
+	dev->get_stats = 		&awc_get_stats;
+	dev->set_multicast_list = 	&awc_set_multicast_list;
+
+	dev->init = &awc_init;
+	dev->open = &awc_open;
+	dev->stop = &awc_close;
+	dev->tbusy = 1;
+	dev->start  = 0;
+    	dev->irq = s->irq;
+    	dev->base_addr = s->io;
+
+
+	awc_private_init( dev);
+
+	i=0;
+	while (aironet4500_devices[i] && i < MAX_AWCS-1) i++;
+	if (!aironet4500_devices[i]){
+		aironet4500_devices[i]=dev;
+
+		((struct awc_private *)
+		aironet4500_devices[i]->priv)->card_type = AIRONET4500_365;
+
+		if (awc_proc_set_fun)
+			awc_proc_set_fun(i);
+	}
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	
+	if (register_netdev(dev) != 0) {
+		printk(KERN_NOTICE "awc_cs: register_netdev() failed\n");
+		goto failed;
+	}
+
+	
+
+	return 0;
+ 
+  failed:
+  	return -1;
+
+}
+
+static void awc_i365_release(void) {
+
+//	long flags;
+	int i=0;
+
+	DEBUG(0, "awc_detach \n");
+
+	i=0;
+	while ( i < MAX_AWCS) {
+	
+		if (!aironet4500_devices[i])
+		         {i++; continue;}
+
+		if (((struct awc_private *)aironet4500_devices[i]->priv)->card_type != AIRONET4500_365)
+		                  {i++;      continue;}
+
+		if (awc_proc_unset_fun)
+			awc_proc_unset_fun(i);
+
+		unregister_netdev(aironet4500_devices[i]);
+
+		//kfree_s(aironet4500_devices[i]->priv, sizeof(struct awc_private));
+		kfree_s(aironet4500_devices[i], sizeof(struct NET_DEVICE));
+
+		aironet4500_devices[i]=0;
+
+
+		i++;
+	}
+	
+
+} 
+
+
+
+
+
+        
+        
+int awc_i365_probe(void) {
+
+	int i = 1;
+	int k = 0;
+	int ret = 0;
+	int found=0;
+	
+	struct i365_socket s;
+	/* Always emit the version, before any failure. */
+
+	if (!awc_i365_sockets) {
+		printk("	awc i82635 4x00: use bitfiel opts awc_i365_sockets=0x3 <- (1|2) to probe sockets 0 and 1\n");
+		return -1;
+	};
+
+	while (k < 4){
+		if (i & awc_i365_sockets){
+
+			s.offset_port 	= awc_i365_offset_ports[k];
+			s.data_port	= awc_i365_data_ports[k];
+			s.socket	= k;
+			s.manufacturer	= 0;
+			s.product	= 0;
+			s.irq		= awc_i365_irq[k];
+			s.io		= awc_i365_io[k];
+			
+			ret = awc_i365_probe_once(&s);
+			if (!ret){
+				if (awc_i365_init(&s))
+					goto failed;
+				else found++;
+			} else if (ret == -1)
+				goto failed;
+		};
+		k++;
+		i *=2;
+	};
+
+	if (!found){
+		printk("no aironet 4x00 cards found\n");
+		return -1;
+	}
+	return 0;
+
+failed: 
+	awc_i365_release();
+	return -1;
+	
+
+}
+
+#endif /* CONFIG_AIRONET4500_365 */
+
+#ifdef MODULE        
+int init_module(void)
+{
+	int found = 0;
+
+	printk("%s\n ", awc_version);
+		
+#ifdef CONFIG_AIRONET4500_PCI
+	if (awc4500_pci_probe(NULL) == -ENODEV){
+		printk("PCI 4X00 aironet cards not found\n");
+	} else {
+		found++;
+		printk("PCI 4X00 found some cards \n");
+	}
+#endif
+#ifdef CONFIG_AIRONET4500_PNP
+	if (awc4500_pnp_probe(NULL) == -ENODEV){
+		printk("PNP 4X00 aironet cards not found\n");
+	} else {
+		found++;
+		printk("PNP 4X00 found some cards \n");
+	}
+#endif
+#ifdef CONFIG_AIRONET4500_365
+	if ( awc_i365_probe() == -1) {
+		printk("PCMCIA 4X00 aironet cards not found for i365(without card services) initialization\n");
+	} else {
+		 found++ ;
+		 printk("PCMCIA 4X00 found some cards, take care, this code is not supposed to work yet \n");
+	}
+#endif
+#ifdef CONFIG_AIRONET4500_ISA
+	if (awc4500_isa_probe(NULL) == -ENODEV){
+		printk("ISA 4X00 aironet ISA-bus non-PNP-mode cards not found\n");
+	} else {
+		found++;
+		printk("ISA 4X00 found some cards \n");
+	}
+#endif
+	if (!found) return -1;
+	return 0;
+	
+
+}
+
+void cleanup_module(void)
+{
+	DEBUG(0, "awc_cs: unloading %c ",'\n');
+#ifdef CONFIG_AIRONET4500_PCI	
+	awc_pci_release();
+#endif
+#ifdef CONFIG_AIRONET4500_PNP
+	awc_pnp_release();
+#endif
+#ifdef CONFIG_AIRONET4500_365
+	awc_i365_release();
+#endif
+#ifdef CONFIG_AIRONET4500_ISA
+	awc_isa_release();
+#endif
+
+}
+#endif
\ No newline at end of file

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