patch-2.4.9 linux/drivers/net/irda/smc-ircc.c

Next file: linux/drivers/net/irda/vlsi_ir.c
Previous file: linux/drivers/net/irda/irport.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.8/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c
@@ -8,8 +8,11 @@
  * Created at:    
  * Modified at:   Tue Feb 22 10:05:06 2000
  * Modified by:   Dag Brattli <dag@brattli.net>
+ * Modified at:   Tue Jun 26 2001
+ * Modified by:   Stefani Seibold <stefani@seibold.net>
  * 
- *     Copyright (c) 1999-2000 Dag Brattli
+ *     Copyright (c) 2001      Stefani Seibold
+ *     Copyright (c) 1999-2001 Dag Brattli
  *     Copyright (c) 1998-1999 Thomas Davis, 
  *     All Rights Reserved.
  *      
@@ -28,8 +31,9 @@
  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
  *     MA 02111-1307 USA
  *
- *     SIO's: SMC FDC37N869, FDC37C669, FDC37N958
- *     Applicable Models : Fujitsu Lifebook 635t, Sony PCG-505TX
+ *     SIO's: all SIO documentet by SMC (June, 2001)
+ *     Applicable Models :	Fujitsu Lifebook 635t, Sony PCG-505TX,
+ *     				Dell Inspiron 8000
  *
  ********************************************************************/
 
@@ -56,55 +60,106 @@
 #include <net/irda/irmod.h>
 #include <net/irda/irlap_frame.h>
 #include <net/irda/irda_device.h>
-
 #include <net/irda/smc-ircc.h>
 #include <net/irda/irport.h>
 
-static char *driver_name = "smc-ircc";
+struct smc_chip {
+	char *name;
+	u16 flags;
+	u8 devid;
+	u8 rev;
+};
+typedef struct smc_chip smc_chip_t;
 
-#define CHIP_IO_EXTENT 8
+static const char *driver_name = "smc-ircc";
 
-static unsigned int io[]  = { ~0, ~0 }; 
-static unsigned int io2[] = { 0, 0 };
+#define	DIM(x)	(sizeof(x)/(sizeof(*(x))))
+
+#define CHIP_IO_EXTENT 8
 
 static struct ircc_cb *dev_self[] = { NULL, NULL};
 
 /* Some prototypes */
-static int  ircc_open(int i, unsigned int iobase, unsigned int board_addr);
-#ifdef MODULE
-static int  ircc_close(struct ircc_cb *self);
-#endif /* MODULE */
-static int  ircc_probe(int iobase, int board_addr);
-static int  ircc_probe_58(smc_chip_t *chip, chipio_t *info);
-static int  ircc_probe_69(smc_chip_t *chip, chipio_t *info);
+static int  ircc_open(unsigned int iobase, unsigned int board_addr);
 static int  ircc_dma_receive(struct ircc_cb *self, int iobase); 
 static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase);
 static int  ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev);
 static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs);
-static void ircc_change_speed(void *priv, __u32 speed);
+static void ircc_change_speed(void *priv, u32 speed);
 static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-#if 0 /* unused */
-static int  ircc_is_receiving(struct ircc_cb *self);
-#endif /* unused */
-
 static int  ircc_net_open(struct net_device *dev);
 static int  ircc_net_close(struct net_device *dev);
 static int  ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
 
-/* These are the currently known SMC chipsets */
-static smc_chip_t chips[] =
+#define	KEY55_1	0	/* SuperIO Configuration mode with Key <0x55> */
+#define	KEY55_2	1	/* SuperIO Configuration mode with Key <0x55,0x55> */
+#define	NoIRDA	2	/* SuperIO Chip has no IRDA Port */
+#define	SIR	0	/* SuperIO Chip has only slow IRDA */
+#define	FIR	4	/* SuperIO Chip has fast IRDA */
+#define	SERx4	8	/* SuperIO Chip supports 115,2 KBaud * 4=460,8 KBaud */
+
+/* These are the currently known SMC SuperIO chipsets */
+static const smc_chip_t __init fdc_chips_flat[]=
+{
+	/* Base address 0x3f0 or 0x370 */
+	{ "37C44",	KEY55_1|NoIRDA,		0x00, 0x00 }, /* This chip can not detected */
+	{ "37C665GT",	KEY55_2|NoIRDA,		0x65, 0x01 },
+	{ "37C665GT",	KEY55_2|NoIRDA,		0x66, 0x01 },
+	{ "37C669",	KEY55_2|SIR|SERx4,	0x03, 0x02 },
+	{ "37C669",	KEY55_2|SIR|SERx4,	0x04, 0x02 }, /* ID? */
+	{ "37C78",	KEY55_2|NoIRDA,		0x78, 0x00 },
+	{ "37N769",	KEY55_1|FIR|SERx4,	0x28, 0x00 },
+	{ "37N869",	KEY55_1|FIR|SERx4,	0x29, 0x00 },
+	{ NULL }
+};
+
+static const smc_chip_t __init fdc_chips_paged[]=
 {
-	{ "FDC37C669", 0x55, 0x55, 0x0d, 0x04, ircc_probe_69 },
-	{ "FDC37N769", 0x55, 0x55, 0x0d, 0x28, ircc_probe_69 },
-	{ "FDC37N869", 0x55, 0x00, 0x0d, 0x29, ircc_probe_69 },
-	{ "FDC37N958", 0x55, 0x55, 0x20, 0x09, ircc_probe_58 },
-	{ "FDC37N971", 0x55, 0x55, 0x20, 0x0a, ircc_probe_58 },
-	{ "FDC37N972", 0x55, 0x55, 0x20, 0x0b, ircc_probe_58 },
+	/* Base address 0x3f0 or 0x370 */
+	{ "37B72X",	KEY55_1|SIR|SERx4,	0x4c, 0x00 },
+	{ "37B77X",	KEY55_1|SIR|SERx4,	0x43, 0x00 },
+	{ "37B78X",	KEY55_1|SIR|SERx4,	0x44, 0x00 },
+	{ "37B80X",	KEY55_1|SIR|SERx4,	0x42, 0x00 },
+	{ "37C67X",	KEY55_1|FIR|SERx4,	0x40, 0x00 },
+	{ "37C93X",	KEY55_2|SIR|SERx4,	0x02, 0x01 },
+	{ "37C93XAPM",	KEY55_1|SIR|SERx4,	0x30, 0x01 },
+	{ "37C93XFR",	KEY55_2|FIR|SERx4,	0x03, 0x01 },
+	{ "37M707",	KEY55_1|SIR|SERx4,	0x42, 0x00 },
+	{ "37M81X",	KEY55_1|SIR|SERx4,	0x4d, 0x00 },
+	{ "37N958FR",	KEY55_1|FIR|SERx4,	0x09, 0x04 },
+	{ "37N972",	KEY55_1|FIR|SERx4,	0x0a, 0x00 },
+	{ "37N972",	KEY55_1|FIR|SERx4,	0x0b, 0x00 },
+	{ NULL }
+};
+
+static const smc_chip_t __init lpc_chips_flat[]=
+{
+	/* Base address 0x2E or 0x4E */
+	{ "47N227",	KEY55_1|FIR|SERx4,	0x5a, 0x00 },
+	{ "47N267",	KEY55_1|FIR|SERx4,	0x5e, 0x00 },
+	{ NULL }
+};
+
+static const smc_chip_t __init lpc_chips_paged[]=
+{
+	/* Base address 0x2E or 0x4E */
+	{ "47B27X",	KEY55_1|SIR|SERx4,	0x51, 0x00 },
+	{ "47B37X",	KEY55_1|SIR|SERx4,	0x52, 0x00 },
+	{ "47M10X",	KEY55_1|SIR|SERx4,	0x59, 0x00 },
+	{ "47M120",	KEY55_1|NoIRDA|SERx4,	0x5c, 0x00 },
+	{ "47M13X",	KEY55_1|SIR|SERx4,	0x59, 0x00 },
+	{ "47M14X",	KEY55_1|SIR|SERx4,	0x5f, 0x00 },
+	{ "47N252",	KEY55_1|FIR|SERx4,	0x0e, 0x00 },
+	{ "47S42X",	KEY55_1|SIR|SERx4,	0x57, 0x00 },
 	{ NULL }
 };
 
 static int ircc_irq=255;
 static int ircc_dma=255;
+static int ircc_fir=0;
+static int ircc_sir=0;
+
+static unsigned short	dev_count=0;
 
 static inline void register_bank(int iobase, int bank)
 {
@@ -112,89 +167,303 @@
                iobase+IRCC_MASTER);
 }
 
+static int __init smc_access(unsigned short cfg_base,unsigned char reg)
+{
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	outb(reg, cfg_base);
+
+	if (inb(cfg_base)!=reg)
+		return -1;
+
+	return 0;
+}
+
+static const smc_chip_t * __init smc_probe(unsigned short cfg_base,u8 reg,const smc_chip_t *chip,char *type)
+{
+	u8 devid,xdevid,rev; 
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	/* Leave configuration */
+
+	outb(0xaa, cfg_base);
+
+	if (inb(cfg_base)==0xaa)	/* not a smc superio chip */
+		return NULL;
+
+	outb(reg, cfg_base);
+
+	xdevid=inb(cfg_base+1);
+
+	/* Enter configuration */
+
+	outb(0x55, cfg_base);
+
+	if (smc_access(cfg_base,0x55))	/* send second key and check */
+		return NULL;
+
+	/* probe device ID */
+
+	if (smc_access(cfg_base,reg))
+		return NULL;
+
+	devid=inb(cfg_base+1);
+
+	if (devid==0)			/* typical value for unused port */
+		return NULL;
+
+	if (devid==0xff)		/* typical value for unused port */
+		return NULL;
+
+	/* probe revision ID */
+
+	if (smc_access(cfg_base,reg+1))
+		return NULL;
+
+	rev=inb(cfg_base+1);
+
+	if (rev>=128)			/* i think this will make no sense */
+		return NULL;
+
+	if (devid==xdevid)		/* protection against false positives */        
+		return NULL;
+
+	/* Check for expected device ID; are there others? */
+
+	while(chip->devid!=devid) {
+
+		chip++;
+
+		if (chip->name==NULL)
+			return NULL;
+	}
+	if (chip->rev>rev)
+		return NULL;
+
+	MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",devid,rev,cfg_base,type,chip->name);
+	
+	if (chip->flags&NoIRDA)
+		MESSAGE("chipset does not support IRDA\n");
+
+	return chip;
+}
+
 /*
- * Function ircc_init ()
+ * Function smc_superio_flat (chip, base, type)
+ *
+ *    Try get configuration of a smc SuperIO chip with flat register model
  *
- *    Initialize chip. Just try to find out how many chips we are dealing with
- *    and where they are
  */
-int __init ircc_init(void)
+static int __init smc_superio_flat(const smc_chip_t *chips, unsigned short cfg_base, char *type)
 {
-	static int smcreg[] = { 0x3f0, 0x370 };
-	smc_chip_t *chip;
-	chipio_t info;
+	unsigned short fir_io;
+	unsigned short sir_io;
+	u8 mode;
 	int ret = -ENODEV;
-	int i;
 
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	if (smc_probe(cfg_base,0xD,chips,type)==NULL)
+		return ret;
 
-	/* Probe for all the NSC chipsets we know about */
-	for (chip=chips; chip->name ; chip++) {
-		for (i=0; i<2; i++) {
-			info.cfg_base = smcreg[i];
-			
-			/* 
-			 * First we check if the user has supplied any
-                         * parameters which we should use instead of probed
-			 * values
-			 */
-			if (io[i] < 0x2000) {
-				info.fir_base = io[i];
-				info.sir_base = io2[i];
-			} else if (chip->probe(chip, &info) < 0)
-				continue;
-			if (check_region(info.fir_base, CHIP_IO_EXTENT) < 0)
-				continue;
-			if (check_region(info.sir_base, CHIP_IO_EXTENT) < 0)
-				continue;
-			if (ircc_open(i, info.fir_base, info.sir_base) == 0)
-				ret = 0; 
+	outb(0x0c, cfg_base);
+
+	mode = inb(cfg_base+1);
+	mode = (mode & 0x38) >> 3;
+		
+	/* Value for IR port */
+	if (mode && mode < 4) {
+		/* SIR iobase */
+		outb(0x25, cfg_base);
+		sir_io = inb(cfg_base+1) << 2;
+
+	       	/* FIR iobase */
+		outb(0x2b, cfg_base);
+		fir_io = inb(cfg_base+1) << 3;
+
+		if (fir_io) {
+			if (ircc_open(fir_io, sir_io) == 0)
+				ret=0; 
 		}
 	}
+	
+	/* Exit configuration */
+	outb(0xaa, cfg_base);
+
 	return ret;
 }
 
 /*
- * Function ircc_cleanup ()
+ * Function smc_superio_paged (chip, base, type)
  *
- *    Close all configured chips
+ *    Try  get configuration of a smc SuperIO chip with paged register model
  *
  */
-#ifdef MODULE
-static void ircc_cleanup(void)
+static int __init smc_superio_paged(const smc_chip_t *chips, unsigned short cfg_base, char *type)
 {
-	int i;
+	unsigned short fir_io;
+	unsigned short sir_io;
+	int ret = -ENODEV;
+	
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	if (smc_probe(cfg_base,0x20,chips,type)==NULL)
+		return ret;
+	
+	/* Select logical device (UART2) */
+	outb(0x07, cfg_base);
+	outb(0x05, cfg_base + 1);
+		
+	/* SIR iobase */
+	outb(0x60, cfg_base);
+	sir_io  = inb(cfg_base + 1) << 8;
+	outb(0x61, cfg_base);
+	sir_io |= inb(cfg_base + 1);
+		
+	/* Read FIR base */
+	outb(0x62, cfg_base);
+	fir_io = inb(cfg_base + 1) << 8;
+	outb(0x63, cfg_base);
+	fir_io |= inb(cfg_base + 1);
+	outb(0x2b, cfg_base); /* ??? */
+
+	if (fir_io) {
+		if (ircc_open(fir_io, sir_io) == 0)
+			ret=0; 
+	}
+	
+	/* Exit configuration */
+	outb(0xaa, cfg_base);
+
+	return ret;
+}
+
+static int __init smc_superio_fdc(unsigned short cfg_base)
+{
+	if (check_region(cfg_base, 2) < 0) {
+		IRDA_DEBUG(0, __FUNCTION__ ": can't get cfg_base of 0x%03x\n",
+			   cfg_base);
+		return -1;
+	}
+
+	if (!smc_superio_flat(fdc_chips_flat,cfg_base,"FDC")||!smc_superio_paged(fdc_chips_paged,cfg_base,"FDC"))
+		return 0;
+
+	return -1;
+}
+
+static int __init smc_superio_lpc(unsigned short cfg_base)
+{
+#if 0
+	if (check_region(cfg_base, 2) < 0) {
+		IRDA_DEBUG(0, __FUNCTION__ ": can't get cfg_base of 0x%03x\n",
+			   cfg_base);
+		return -1;
+	}
+#endif
+
+	if (!smc_superio_flat(lpc_chips_flat,cfg_base,"LPC")||!smc_superio_paged(lpc_chips_paged,cfg_base,"LPC"))
+		return 0;
+
+	return -1;
+}
+
+/*
+ * Function ircc_init ()
+ *
+ *    Initialize chip. Just try to find out how many chips we are dealing with
+ *    and where they are
+ */
+int __init ircc_init(void)
+{
+	int ret=-ENODEV;
 
 	IRDA_DEBUG(0, __FUNCTION__ "\n");
 
-	for (i=0; i < 2; i++) {
-		if (dev_self[i])
-			ircc_close(dev_self[i]);
+	dev_count=0;
+
+	if ((ircc_fir>0)&&(ircc_sir>0)) {
+	        MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
+		MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
+
+		if (ircc_open(ircc_fir, ircc_sir) == 0)
+			return 0;
+
+		return -ENODEV;
 	}
+
+	/* Trys to open for all the SMC chipsets we know about */
+
+	IRDA_DEBUG(0, __FUNCTION__ 
+	" Try to open all known SMC chipsets\n");
+
+	if (!smc_superio_fdc(0x3f0))
+		ret=0;
+	if (!smc_superio_fdc(0x370))
+		ret=0;
+	if (!smc_superio_lpc(0x2e))
+		ret=0;
+	if (!smc_superio_lpc(0x4e))
+		ret=0;
+
+	return ret;
 }
-#endif /* MODULE */
 
 /*
  * Function ircc_open (iobase, irq)
  *
- *    Open driver instance
+ *    Try to open driver instance
  *
  */
-static int ircc_open(int i, unsigned int fir_base, unsigned int sir_base)
+static int __init ircc_open(unsigned int fir_base, unsigned int sir_base)
 {
 	struct ircc_cb *self;
         struct irport_cb *irport;
-	int config;
-	int ret;
+	unsigned char low, high, chip, config, dma, irq, version;
+
 
 	IRDA_DEBUG(0, __FUNCTION__ "\n");
 
-	if ((config = ircc_probe(fir_base, sir_base)) == -1) {
+	if (check_region(fir_base, CHIP_IO_EXTENT) < 0) {
+		IRDA_DEBUG(0, __FUNCTION__ ": can't get fir_base of 0x%03x\n",
+			   fir_base);
+		return -ENODEV;
+	}
+#if POSSIBLE_USED_BY_SERIAL_DRIVER
+	if (check_region(sir_base, CHIP_IO_EXTENT) < 0) {
+		IRDA_DEBUG(0, __FUNCTION__ ": can't get sir_base of 0x%03x\n",
+			   sir_base);
+		return -ENODEV;
+	}
+#endif
+
+	register_bank(fir_base, 3);
+
+	high    = inb(fir_base+IRCC_ID_HIGH);
+	low     = inb(fir_base+IRCC_ID_LOW);
+	chip    = inb(fir_base+IRCC_CHIP_ID);
+	version = inb(fir_base+IRCC_VERSION);
+	config  = inb(fir_base+IRCC_INTERFACE);
+
+	irq     = config >> 4 & 0x0f;
+	dma     = config & 0x0f;
+
+        if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) { 
 	        IRDA_DEBUG(0, __FUNCTION__ 
 			   "(), addr 0x%04x - no device found!\n", fir_base);
-		return -1;
+		return -ENODEV;
 	}
-	
+	MESSAGE("SMC IrDA Controller found\n IrCC version %d.%d, "
+		"firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n",
+		chip & 0x0f, version, fir_base, sir_base, dma, irq);
+
+	if (dev_count>DIM(dev_self)) {
+	        IRDA_DEBUG(0, __FUNCTION__ 
+			   "(), to many devices!\n");
+		return -ENOMEM;
+	}
+
 	/*
 	 *  Allocate new instance of the driver
 	 */
@@ -206,46 +475,75 @@
 	}
 	memset(self, 0, sizeof(struct ircc_cb));
 	spin_lock_init(&self->lock);
-   
-	/* Need to store self somewhere */
-	dev_self[i] = self;
 
-	irport = irport_open(i, sir_base, config >> 4 & 0x0f);
-	if (!irport)
+	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
+	self->rx_buff.truesize = 4000; 
+	self->tx_buff.truesize = 4000;
+
+	self->rx_buff.head = (u8 *) kmalloc(self->rx_buff.truesize,
+					      GFP_KERNEL|GFP_DMA);
+	if (self->rx_buff.head == NULL) {
+		ERROR("%s, Can't allocate memory for receive buffer!\n",
+                      driver_name);
+		kfree(self);
+		return -ENOMEM;
+	}
+
+	self->tx_buff.head = (u8 *) kmalloc(self->tx_buff.truesize, 
+					      GFP_KERNEL|GFP_DMA);
+	if (self->tx_buff.head == NULL) {
+		ERROR("%s, Can't allocate memory for transmit buffer!\n",
+                      driver_name);
+		kfree(self->rx_buff.head);
+		kfree(self);
+		return -ENOMEM;
+	}
+
+	irport = irport_open(dev_count, sir_base, irq);
+	if (!irport) {
+		kfree(self->tx_buff.head);
+		kfree(self->rx_buff.head);
+		kfree(self);
 		return -ENODEV;
+	}
+
+	memset(self->rx_buff.head, 0, self->rx_buff.truesize);
+	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
+   
+	/* Need to store self somewhere */
+	dev_self[dev_count++] = self;
 
 	/* Steal the network device from irport */
 	self->netdev = irport->netdev;
 	self->irport = irport;
+
 	irport->priv = self;
 
 	/* Initialize IO */
-	self->io.fir_base  = fir_base;
-        self->io.sir_base  = sir_base; /* Used by irport */
-        self->io.irq       = config >> 4 & 0x0f;
+	self->io           = &irport->io;
+	self->io->fir_base  = fir_base;
+        self->io->sir_base  = sir_base;	/* Used by irport */
+        self->io->fir_ext   = CHIP_IO_EXTENT;
+        self->io->sir_ext   = 8;		/* Used by irport */
+
 	if (ircc_irq < 255) {
-	        MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
-			driver_name, self->io.irq, ircc_irq);
-		self->io.irq = ircc_irq;
-	}
-        self->io.fir_ext   = CHIP_IO_EXTENT;
-        self->io.sir_ext   = 8;       /* Used by irport */
-        self->io.dma       = config & 0x0f;
+		if (ircc_irq!=irq)
+			MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
+				driver_name, self->io->irq, ircc_irq);
+		self->io->irq = ircc_irq;
+	}
+	else
+		self->io->irq = irq;
 	if (ircc_dma < 255) {
-	        MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
-			driver_name, self->io.dma, ircc_dma);
-		self->io.dma = ircc_dma;
+		if (ircc_dma!=dma)
+			MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
+				driver_name, self->io->dma, ircc_dma);
+		self->io->dma = ircc_dma;
 	}
+	else
+		self->io->dma = dma;
 
-	/* Lock the port that we need */
-	ret = check_region(self->io.fir_base, self->io.fir_ext);
-	if (ret < 0) { 
-		IRDA_DEBUG(0, __FUNCTION__ ": can't get fir_base of 0x%03x\n",
-			   self->io.fir_base);
-                kfree(self);
-		return -ENODEV;
-	}
-	request_region(self->io.fir_base, self->io.fir_ext, driver_name);
+	request_region(fir_base, CHIP_IO_EXTENT, driver_name);
 
 	/* Initialize QoS for this device */
 	irda_init_max_qos_capabilies(&irport->qos);
@@ -260,23 +558,6 @@
 
 	irport->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO;
 	
-	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
-	self->rx_buff.truesize = 4000; 
-	self->tx_buff.truesize = 4000;
-
-	self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
-					      GFP_KERNEL|GFP_DMA);
-	if (self->rx_buff.head == NULL)
-		return -ENOMEM;
-	memset(self->rx_buff.head, 0, self->rx_buff.truesize);
-	
-	self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
-					      GFP_KERNEL|GFP_DMA);
-	if (self->tx_buff.head == NULL) {
-		kfree(self->rx_buff.head);
-		return -ENOMEM;
-	}
-	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
 
 	self->rx_buff.in_frame = FALSE;
 	self->rx_buff.state = OUTSIDE_FRAME;
@@ -295,196 +576,12 @@
         if (self->pmdev)
                 self->pmdev->data = self;
 
-	return 0;
-}
-
-/*
- * Function ircc_close (self)
- *
- *    Close driver instance
- *
- */
-#ifdef MODULE
-static int ircc_close(struct ircc_cb *self)
-{
-	int iobase;
-
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
-
-	ASSERT(self != NULL, return -1;);
-
-        iobase = self->io.fir_base;
-
-	irport_close(self->irport);
-
-	/* Stop interrupts */
-	register_bank(iobase, 0);
-	outb(0, iobase+IRCC_IER);
-	outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
-	outb(0x00, iobase+IRCC_MASTER);
-#if 0
-	/* Reset to SIR mode */
-	register_bank(iobase, 1);
-        outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);
-        outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
-#endif
-	/* Release the PORT that this driver is using */
-	IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", 
-		   self->io.fir_base);
-
-	release_region(self->io.fir_base, self->io.fir_ext);
-
-	if (self->tx_buff.head)
-		kfree(self->tx_buff.head);
-	
-	if (self->rx_buff.head)
-		kfree(self->rx_buff.head);
+	/* Power on device */
 
-	kfree(self);
+	outb(0x00, fir_base+IRCC_MASTER);
 
 	return 0;
 }
-#endif /* MODULE */
-
-/*
- * Function ircc_probe_69 (chip, info)
- *
- *    Probes for the SMC FDC37C669 and FDC37N869
- *
- */
-static int ircc_probe_69(smc_chip_t *chip, chipio_t *info)
-{
-	int cfg_base = info->cfg_base;
-	__u8 devid, mode;
-	int ret = -ENODEV;
-	int fir_io;
-	
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
-
-	/* Enter configuration */
-	outb(chip->entr1, cfg_base);
-	outb(chip->entr2, cfg_base);
-	
-	outb(chip->cid_index, cfg_base);
-	devid = inb(cfg_base+1);
-	IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid);
-	
-	/* Check for expected device ID; are there others? */
-	if (devid == chip->cid_value) {
-		outb(0x0c, cfg_base);
-		mode = inb(cfg_base+1);
-		mode = (mode & 0x38) >> 3;
-		
-		/* Value for IR port */
-		if (mode && mode < 4) {
-			/* SIR iobase */
-			outb(0x25, cfg_base);
-			info->sir_base = inb(cfg_base+1) << 2;
-
-		       	/* FIR iobase */
-			outb(0x2b, cfg_base);
-			fir_io = inb(cfg_base+1) << 3;
-			if (fir_io) {
-				ret = 0;
-				info->fir_base = fir_io;
-			}
-		}
-	}
-	
-	/* Exit configuration */
-	outb(0xaa, cfg_base);
-
-	return ret;
-}
-
-/*
- * Function ircc_probe_58 (chip, info)
- *
- *    Probes for the SMC FDC37N958
- *
- */
-static int ircc_probe_58(smc_chip_t *chip, chipio_t *info)
-{
-	int cfg_base = info->cfg_base;
-	__u8 devid;
-	int ret = -ENODEV;
-	int fir_io;
-	
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
-
-	/* Enter configuration */
-	outb(chip->entr1, cfg_base);
-	outb(chip->entr2, cfg_base);
-	
-	outb(chip->cid_index, cfg_base);
-	devid = inb(cfg_base+1);
-	IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid);
-	
-	/* Check for expected device ID; are there others? */
-	if (devid == chip->cid_value) {
-		/* Select logical device (UART2) */
-		outb(0x07, cfg_base);
-		outb(0x05, cfg_base + 1);
-		
-		/* SIR iobase */
-		outb(0x60, cfg_base);
-		info->sir_base = inb(cfg_base + 1) << 8;
-		outb(0x61, cfg_base);
-		info->sir_base |= inb(cfg_base + 1);
-		
-		/* Read FIR base */
-		outb(0x62, cfg_base);
-		fir_io = inb(cfg_base + 1) << 8;
-		outb(0x63, cfg_base);
-		fir_io |= inb(cfg_base + 1);
-		outb(0x2b, cfg_base);
-		if (fir_io) {
-			ret = 0;
-			info->fir_base = fir_io;
-		}
-	}
-	
-	/* Exit configuration */
-	outb(0xaa, cfg_base);
-
-	return ret;
-}
-
-/*
- * Function ircc_probe (iobase, board_addr, irq, dma)
- *
- *    Returns non-negative on success.
- *
- */
-static int ircc_probe(int fir_base, int sir_base) 
-{
-	int low, high, chip, config, dma, irq;
-	int iobase = fir_base;
-	int version = 1;
-
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
-
-	register_bank(iobase, 3);
-	high    = inb(iobase+IRCC_ID_HIGH);
-	low     = inb(iobase+IRCC_ID_LOW);
-	chip    = inb(iobase+IRCC_CHIP_ID);
-	version = inb(iobase+IRCC_VERSION);
-	config  = inb(iobase+IRCC_INTERFACE);
-	irq     = config >> 4 & 0x0f;
-	dma     = config & 0x0f;
-
-        if (high == 0x10 && low == 0xb8 && (chip == 0xf1 || chip == 0xf2)) { 
-                MESSAGE("SMC IrDA Controller found; IrCC version %d.%d, "
-			"port 0x%03x, dma=%d, irq=%d\n",
-			chip & 0x0f, version, iobase, dma, irq);
-	} else
-		return -ENODEV;
-
-	/* Power on device */
-	outb(0x00, iobase+IRCC_MASTER);
-
-	return config;
-}
 
 /*
  * Function ircc_change_speed (self, baud)
@@ -492,7 +589,7 @@
  *    Change the speed of the device
  *
  */
-static void ircc_change_speed(void *priv, __u32 speed)
+static void ircc_change_speed(void *priv, u32 speed)
 {
 	int iobase, ir_mode, ctrl, fast; 
 	struct ircc_cb *self = (struct ircc_cb *) priv;
@@ -503,10 +600,10 @@
 	ASSERT(self != NULL, return;);
 
 	dev = self->netdev;
-	iobase = self->io.fir_base;
+	iobase = self->io->fir_base;
 
 	/* Update accounting for new speed */
-	self->io.speed = speed;
+	self->io->speed = speed;
 
 	outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
 	outb(0x00, iobase+IRCC_MASTER);
@@ -560,7 +657,7 @@
 		 * Don't know why we have to do this, but FIR interrupts 
 		 * stops working if we remove it.
 		 */
-		/* outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR); */
+		/* outb(UART_MCR_OUT2, self->io->sir_base + UART_MCR); */
 
 		/* Be ready for incoming frames */
 		ircc_dma_receive(self, iobase);
@@ -608,7 +705,7 @@
 	struct irport_cb *irport;
 	struct ircc_cb *self;
 	unsigned long flags;
-	__s32 speed;
+	s32 speed;
 	int iobase;
 	int mtt;
 
@@ -616,13 +713,13 @@
 	self = (struct ircc_cb *) irport->priv;
 	ASSERT(self != NULL, return 0;);
 
-	iobase = self->io.fir_base;
+	iobase = self->io->fir_base;
 
 	netif_stop_queue(dev);
 
 	/* Check if we need to change the speed after this frame */
 	speed = irda_get_next_speed(skb);
-	if ((speed != self->io.speed) && (speed != -1)) {
+	if ((speed != self->io->speed) && (speed != -1)) {
 		/* Check for empty frame */
 		if (!skb->len) {
 			ircc_change_speed(self, speed); 
@@ -647,7 +744,7 @@
 		 * Compute how many BOFs (STA or PA's) we need to waste the
 		 * min turn time given the speed of the link.
 		 */
-		bofs = mtt * (self->io.speed / 1000) / 8000;
+		bofs = mtt * (self->io->speed / 1000) / 8000;
 		if (bofs > 4095)
 			bofs = 4095;
 
@@ -670,7 +767,7 @@
  */
 static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs)
 {
-	__u8 ctrl;
+	u8 ctrl;
 
 	IRDA_DEBUG(2, __FUNCTION__ "\n");
 #if 0	
@@ -682,7 +779,7 @@
 	outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, 
 	     iobase+IRCC_SCE_CFGB);
 
-	self->io.direction = IO_XMIT;
+	self->io->direction = IO_XMIT;
 
 	/* Set BOF additional count for generating the min turn time */
 	register_bank(iobase, 4);
@@ -695,10 +792,10 @@
 	outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO);
 
 	/* Setup DMA controller (must be done after enabling chip DMA) */
-	setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len, 
+	setup_dma(self->io->dma, self->tx_buff.data, self->tx_buff.len, 
 		  DMA_TX_MODE);
 
-	outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);
+	outb(UART_MCR_OUT2, self->io->sir_base + UART_MCR);
 	/* Enable burst mode chip Tx DMA */
 	register_bank(iobase, 1);
 	outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
@@ -728,9 +825,9 @@
 	register_bank(iobase, 0);
 	outb(0x00, iobase+IRCC_LCR_B);
 #endif
-	register_bank(self->io.fir_base, 1);
-	outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
-	     self->io.fir_base+IRCC_SCE_CFGB);
+	register_bank(self->io->fir_base, 1);
+	outb(inb(self->io->fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+	     self->io->fir_base+IRCC_SCE_CFGB);
 
 	/* Check for underrrun! */
 	register_bank(iobase, 0);
@@ -765,12 +862,13 @@
  */
 static int ircc_dma_receive(struct ircc_cb *self, int iobase) 
 {	
+#if 0
 	/* Turn off chip DMA */
-	//register_bank(iobase, 1);
-	//outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, 
-	//     iobase+IRCC_SCE_CFGB);
-
-	setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, 
+	register_bank(iobase, 1);
+	outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, 
+	     iobase+IRCC_SCE_CFGB);
+#endif
+	setup_dma(self->io->dma, self->rx_buff.data, self->rx_buff.truesize, 
 		  DMA_RX_MODE);
 
 	/* Set max Rx frame size */
@@ -778,7 +876,7 @@
 	outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI);
 	outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO);
 
-	self->io.direction = IO_RECV;
+	self->io->direction = IO_RECV;
 	self->rx_buff.data = self->rx_buff.head;
 
 	/* Setup DMA controller */
@@ -817,12 +915,12 @@
 	msgcnt = inb(iobase+IRCC_LCR_B) & 0x08;
 
 	IRDA_DEBUG(2, __FUNCTION__ ": dma count = %d\n",
-		   get_dma_residue(self->io.dma));
+		   get_dma_residue(self->io->dma));
 
-	len = self->rx_buff.truesize - get_dma_residue(self->io.dma);
+	len = self->rx_buff.truesize - get_dma_residue(self->io->dma);
 	
 	/* Remove CRC */
-	if (self->io.speed < 4000000)
+	if (self->io->speed < 4000000)
 		len -= 2;
 	else
 		len -= 4;
@@ -875,11 +973,11 @@
 	ASSERT(self != NULL, return;);
 
 	/* Check if we should use the SIR interrupt handler */
-	if (self->io.speed < 576000) {
+	if (self->io->speed < 576000) {
 		irport_interrupt(irq, dev_id, regs);
 		return;
 	}
-	iobase = self->io.fir_base;
+	iobase = self->io->fir_base;
 
 	spin_lock(&self->lock);	
 
@@ -892,7 +990,7 @@
 	IRDA_DEBUG(2, __FUNCTION__ "(), iir = 0x%02x\n", iir);
 
 	if (iir & IRCC_IIR_EOM) {
-		if (self->io.direction == IO_RECV)
+		if (self->io->direction == IO_RECV)
 			ircc_dma_receive_complete(self, iobase);
 		else
 			ircc_dma_xmit_complete(self, iobase);
@@ -924,7 +1022,7 @@
 	ASSERT(self != NULL, return FALSE;);
 
 	IRDA_DEBUG(0, __FUNCTION__ ": dma count = %d\n",
-		   get_dma_residue(self->io.dma));
+		   get_dma_residue(self->io->dma));
 
 	status = (self->rx_buff.state != OUTSIDE_FRAME);
 	
@@ -952,7 +1050,7 @@
 
 	ASSERT(self != NULL, return 0;);
 	
-	iobase = self->io.fir_base;
+	iobase = self->io->fir_base;
 
 	irport_net_open(dev); /* irport allocates the irq */
 
@@ -960,9 +1058,10 @@
 	 * Always allocate the DMA channel after the IRQ,
 	 * and clean up on failure.
 	 */
-	if (request_dma(self->io.dma, dev->name)) {
+	if (request_dma(self->io->dma, dev->name)) {
 		irport_net_close(dev);
 
+		WARNING(__FUNCTION__ "(), unable to allocate DMA=%d\n", self->io->dma);
 		return -EAGAIN;
 	}
 	
@@ -991,13 +1090,13 @@
 	
 	ASSERT(self != NULL, return 0;);
 	
-	iobase = self->io.fir_base;
+	iobase = self->io->fir_base;
 
 	irport_net_close(dev);
 
-	disable_dma(self->io.dma);
+	disable_dma(self->io->dma);
 
-	free_dma(self->io.dma);
+	free_dma(self->io->dma);
 
 	MOD_DEC_USE_COUNT;
 
@@ -1008,19 +1107,19 @@
 {
 	MESSAGE("%s, Suspending\n", driver_name);
 
-	if (self->io.suspended)
+	if (self->io->suspended)
 		return;
 
 	ircc_net_close(self->netdev);
 
-	self->io.suspended = 1;
+	self->io->suspended = 1;
 }
 
 static void ircc_wakeup(struct ircc_cb *self)
 {
 	unsigned long flags;
 
-	if (!self->io.suspended)
+	if (!self->io->suspended)
 		return;
 
 	save_flags(flags);
@@ -1049,21 +1148,84 @@
 }
 
 #ifdef MODULE
-MODULE_AUTHOR("Thomas Davis <tadavis@jps.net>");
-MODULE_DESCRIPTION("SMC IrCC controller driver");
-MODULE_PARM(ircc_dma, "1i");
-MODULE_PARM_DESC(ircc_dma, "DMA channel");
-MODULE_PARM(ircc_irq, "1i");
-MODULE_PARM_DESC(ircc_irq, "IRQ line");
 
-int init_module(void)
+/*
+ * Function ircc_close (self)
+ *
+ *    Close driver instance
+ *
+ */
+#ifdef MODULE
+static int __exit ircc_close(struct ircc_cb *self)
+{
+	int iobase;
+
+	IRDA_DEBUG(0, __FUNCTION__ "\n");
+
+	ASSERT(self != NULL, return -1;);
+
+        iobase = self->irport->io.fir_base;
+
+	irport_close(self->irport);
+
+	/* Stop interrupts */
+	register_bank(iobase, 0);
+	outb(0, iobase+IRCC_IER);
+	outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
+	outb(0x00, iobase+IRCC_MASTER);
+#if 0
+	/* Reset to SIR mode */
+	register_bank(iobase, 1);
+        outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);
+        outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
+#endif
+	/* Release the PORT that this driver is using */
+	IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", 
+		   self->io->fir_base);
+
+	release_region(self->io->fir_base, self->io->fir_ext);
+
+	if (self->tx_buff.head)
+		kfree(self->tx_buff.head);
+	
+	if (self->rx_buff.head)
+		kfree(self->rx_buff.head);
+
+	kfree(self);
+
+	return 0;
+}
+#endif /* MODULE */
+
+int __init smc_init(void)
 {
 	return ircc_init();
 }
 
-void cleanup_module(void)
+void __exit smc_cleanup(void)
 {
-	ircc_cleanup();
+	int i;
+
+	IRDA_DEBUG(0, __FUNCTION__ "\n");
+
+	for (i=0; i < 2; i++) {
+		if (dev_self[i])
+			ircc_close(dev_self[i]);
+	}
 }
+
+module_init(smc_init);
+module_exit(smc_cleanup);
+ 
+MODULE_AUTHOR("Thomas Davis <tadavis@jps.net>");
+MODULE_DESCRIPTION("SMC IrCC controller driver");
+MODULE_PARM(ircc_dma, "1i");
+MODULE_PARM_DESC(ircc_dma, "DMA channel");
+MODULE_PARM(ircc_irq, "1i");
+MODULE_PARM_DESC(ircc_irq, "IRQ line");
+MODULE_PARM(ircc_fir, "1-4i");
+MODULE_PARM_DESC(ircc_fir, "FIR Base Address");
+MODULE_PARM(ircc_sir, "1-4i");
+MODULE_PARM_DESC(ircc_sir, "SIR Base Address");
 
 #endif /* MODULE */

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