diff options
Diffstat (limited to 'drivers/net/tokenring/proteon.c')
| -rw-r--r-- | drivers/net/tokenring/proteon.c | 432 | 
1 files changed, 432 insertions, 0 deletions
diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c new file mode 100644 index 00000000000..675b063508e --- /dev/null +++ b/drivers/net/tokenring/proteon.c @@ -0,0 +1,432 @@ +/* + *  proteon.c: A network driver for Proteon ISA token ring cards. + * + *  Based on tmspci written 1999 by Adam Fritzler + *   + *  Written 2003 by Jochen Friedrich + * + *  This software may be used and distributed according to the terms + *  of the GNU General Public License, incorporated herein by reference. + * + *  This driver module supports the following cards: + *	- Proteon 1392, 1392+ + * + *  Maintainer(s): + *    AF        Adam Fritzler           mid@auk.cx + *    JF	Jochen Friedrich	jochen@scram.de + * + *  Modification History: + *	02-Jan-03	JF	Created + * + */ +static const char version[] = "proteon.c: v1.00 02/01/2003 by Jochen Friedrich\n"; + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/trdevice.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/pci.h> +#include <asm/dma.h> + +#include "tms380tr.h" + +#define PROTEON_IO_EXTENT 32 + +/* A zero-terminated list of I/O addresses to be probed. */ +static unsigned int portlist[] __initdata = { +	0x0A20, 0x0E20, 0x1A20, 0x1E20, 0x2A20, 0x2E20, 0x3A20, 0x3E20,// Prot. +	0x4A20, 0x4E20, 0x5A20, 0x5E20, 0x6A20, 0x6E20, 0x7A20, 0x7E20,// Prot. +	0x8A20, 0x8E20, 0x9A20, 0x9E20, 0xAA20, 0xAE20, 0xBA20, 0xBE20,// Prot. +	0xCA20, 0xCE20, 0xDA20, 0xDE20, 0xEA20, 0xEE20, 0xFA20, 0xFE20,// Prot. +	0 +}; + +/* A zero-terminated list of IRQs to be probed. */ +static unsigned short irqlist[] = { +	7, 6, 5, 4, 3, 12, 11, 10, 9, +	0 +}; + +/* A zero-terminated list of DMAs to be probed. */ +static int dmalist[] __initdata = { +	5, 6, 7, +	0 +}; + +static char cardname[] = "Proteon 1392\0"; + +struct net_device *proteon_probe(int unit); +static int proteon_open(struct net_device *dev); +static void proteon_read_eeprom(struct net_device *dev); +static unsigned short proteon_setnselout_pins(struct net_device *dev); + +static unsigned short proteon_sifreadb(struct net_device *dev, unsigned short reg) +{ +	return inb(dev->base_addr + reg); +} + +static unsigned short proteon_sifreadw(struct net_device *dev, unsigned short reg) +{ +	return inw(dev->base_addr + reg); +} + +static void proteon_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) +{ +	outb(val, dev->base_addr + reg); +} + +static void proteon_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) +{ +	outw(val, dev->base_addr + reg); +} + +static int __init proteon_probe1(struct net_device *dev, int ioaddr) +{ +	unsigned char chk1, chk2; +	int i; + +	if (!request_region(ioaddr, PROTEON_IO_EXTENT, cardname)) +		return -ENODEV; +		 + +	chk1 = inb(ioaddr + 0x1f);      /* Get Proteon ID reg 1 */ +	if (chk1 != 0x1f)  +		goto nodev; + +	chk1 = inb(ioaddr + 0x1e) & 0x07;       /* Get Proteon ID reg 0 */ +	for (i=0; i<16; i++) { +		chk2 = inb(ioaddr + 0x1e) & 0x07; +		if (((chk1 + 1) & 0x07) != chk2) +			goto nodev; +		chk1 = chk2; +	} + +	dev->base_addr = ioaddr; +	return (0); +nodev: +	release_region(ioaddr, PROTEON_IO_EXTENT);  +	return -ENODEV; +} + +static int __init setup_card(struct net_device *dev) +{ +	struct net_local *tp; +        static int versionprinted; +	const unsigned *port; +	int j,err = 0; + +	if (!dev) +		return -ENOMEM; + +	SET_MODULE_OWNER(dev); +	if (dev->base_addr)	/* probe specific location */ +		err = proteon_probe1(dev, dev->base_addr); +	else { +		for (port = portlist; *port; port++) { +			err = proteon_probe1(dev, *port); +			if (!err) +				break; +		} +	} +	if (err) +		goto out4; + +	/* At this point we have found a valid card. */ + +	if (versionprinted++ == 0) +		printk(KERN_DEBUG "%s", version); + +	err = -EIO; +	if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) +		goto out4; + +	dev->base_addr &= ~3;  +		 +	proteon_read_eeprom(dev); + +	printk(KERN_DEBUG "%s:    Ring Station Address: ", dev->name); +	printk("%2.2x", dev->dev_addr[0]); +	for (j = 1; j < 6; j++) +		printk(":%2.2x", dev->dev_addr[j]); +	printk("\n"); +		 +	tp = netdev_priv(dev); +	tp->setnselout = proteon_setnselout_pins; +		 +	tp->sifreadb = proteon_sifreadb; +	tp->sifreadw = proteon_sifreadw; +	tp->sifwriteb = proteon_sifwriteb; +	tp->sifwritew = proteon_sifwritew; +	 +	memcpy(tp->ProductID, cardname, PROD_ID_SIZE + 1); + +	tp->tmspriv = NULL; + +	dev->open = proteon_open; +	dev->stop = tms380tr_close; + +	if (dev->irq == 0) +	{ +		for(j = 0; irqlist[j] != 0; j++) +		{ +			dev->irq = irqlist[j]; +			if (!request_irq(dev->irq, tms380tr_interrupt, 0,  +				cardname, dev)) +				break; +                } +		 +                if(irqlist[j] == 0) +                { +                        printk(KERN_INFO "%s: AutoSelect no IRQ available\n", dev->name); +			goto out3; +		} +	} +	else +	{ +		for(j = 0; irqlist[j] != 0; j++) +			if (irqlist[j] == dev->irq) +				break; +		if (irqlist[j] == 0) +		{ +			printk(KERN_INFO "%s: Illegal IRQ %d specified\n", +				dev->name, dev->irq); +			goto out3; +		} +		if (request_irq(dev->irq, tms380tr_interrupt, 0,  +			cardname, dev)) +		{ +                        printk(KERN_INFO "%s: Selected IRQ %d not available\n",  +				dev->name, dev->irq); +			goto out3; +		} +	} + +	if (dev->dma == 0) +	{ +		for(j = 0; dmalist[j] != 0; j++) +		{ +			dev->dma = dmalist[j]; +                        if (!request_dma(dev->dma, cardname)) +				break; +		} + +		if(dmalist[j] == 0) +		{ +			printk(KERN_INFO "%s: AutoSelect no DMA available\n", dev->name); +			goto out2; +		} +	} +	else +	{ +		for(j = 0; dmalist[j] != 0; j++) +			if (dmalist[j] == dev->dma) +				break; +		if (dmalist[j] == 0) +		{ +                        printk(KERN_INFO "%s: Illegal DMA %d specified\n",  +				dev->name, dev->dma); +			goto out2; +		} +		if (request_dma(dev->dma, cardname)) +		{ +                        printk(KERN_INFO "%s: Selected DMA %d not available\n",  +				dev->name, dev->dma); +			goto out2; +		} +	} + +	printk(KERN_DEBUG "%s:    IO: %#4lx  IRQ: %d  DMA: %d\n", +	       dev->name, dev->base_addr, dev->irq, dev->dma); +		 +	err = register_netdev(dev); +	if (err) +		goto out; + +	return 0; +out: +	free_dma(dev->dma); +out2: +	free_irq(dev->irq, dev); +out3: +	tmsdev_term(dev); +out4: +	release_region(dev->base_addr, PROTEON_IO_EXTENT);  +	return err; +} + +struct net_device * __init proteon_probe(int unit) +{ +	struct net_device *dev = alloc_trdev(sizeof(struct net_local)); +	int err = 0; + +	if (!dev) +		return ERR_PTR(-ENOMEM); + +	if (unit >= 0) { +		sprintf(dev->name, "tr%d", unit); +		netdev_boot_setup_check(dev); +	} + +	err = setup_card(dev); +	if (err) +		goto out; + +	return dev; + +out: +	free_netdev(dev); +	return ERR_PTR(err); +} + +/* + * Reads MAC address from adapter RAM, which should've read it from + * the onboard ROM.   + * + * Calling this on a board that does not support it can be a very + * dangerous thing.  The Madge board, for instance, will lock your + * machine hard when this is called.  Luckily, its supported in a + * separate driver.  --ASF + */ +static void proteon_read_eeprom(struct net_device *dev) +{ +	int i; +	 +	/* Address: 0000:0000 */ +	proteon_sifwritew(dev, 0, SIFADX); +	proteon_sifwritew(dev, 0, SIFADR);	 +	 +	/* Read six byte MAC address data */ +	dev->addr_len = 6; +	for(i = 0; i < 6; i++) +		dev->dev_addr[i] = proteon_sifreadw(dev, SIFINC) >> 8; +} + +unsigned short proteon_setnselout_pins(struct net_device *dev) +{ +	return 0; +} + +static int proteon_open(struct net_device *dev) +{   +	struct net_local *tp = netdev_priv(dev); +	unsigned short val = 0; +	int i; + +	/* Proteon reset sequence */ +	outb(0, dev->base_addr + 0x11); +	mdelay(20); +	outb(0x04, dev->base_addr + 0x11); +	mdelay(20); +	outb(0, dev->base_addr + 0x11); +	mdelay(100); + +	/* set control/status reg */ +	val = inb(dev->base_addr + 0x11); +	val |= 0x78; +	val &= 0xf9; +	if(tp->DataRate == SPEED_4) +		val |= 0x20; +	else +		val &= ~0x20; + +	outb(val, dev->base_addr + 0x11); +	outb(0xff, dev->base_addr + 0x12); +	for(i = 0; irqlist[i] != 0; i++) +	{ +		if(irqlist[i] == dev->irq) +			break; +	} +	val = i; +	i = (7 - dev->dma) << 4; +	val |= i; +	outb(val, dev->base_addr + 0x13); + +	return tms380tr_open(dev); +} + +#ifdef MODULE + +#define ISATR_MAX_ADAPTERS 3 + +static int io[ISATR_MAX_ADAPTERS]; +static int irq[ISATR_MAX_ADAPTERS]; +static int dma[ISATR_MAX_ADAPTERS]; + +MODULE_LICENSE("GPL"); + +module_param_array(io, int, NULL, 0); +module_param_array(irq, int, NULL, 0); +module_param_array(dma, int, NULL, 0); + +static struct net_device *proteon_dev[ISATR_MAX_ADAPTERS]; + +int init_module(void) +{ +	struct net_device *dev; +	int i, num = 0, err = 0; + +	for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { +		dev = alloc_trdev(sizeof(struct net_local)); +		if (!dev) +			continue; + +		dev->base_addr = io[i]; +		dev->irq = irq[i]; +		dev->dma = dma[i]; +		err = setup_card(dev); +		if (!err) { +			proteon_dev[i] = dev; +			++num; +		} else { +			free_netdev(dev); +		} +	} + +	printk(KERN_NOTICE "proteon.c: %d cards found.\n", num); +	/* Probe for cards. */ +	if (num == 0) { +		printk(KERN_NOTICE "proteon.c: No cards found.\n"); +		return (-ENODEV); +	} +	return (0); +} + +void cleanup_module(void) +{ +	int i; + +	for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { +		struct net_device *dev = proteon_dev[i]; +		 +		if (!dev)  +			continue; +		 +		unregister_netdev(dev); +		release_region(dev->base_addr, PROTEON_IO_EXTENT); +		free_irq(dev->irq, dev); +		free_dma(dev->dma); +		tmsdev_term(dev); +		free_netdev(dev); +	} +} +#endif /* MODULE */ + + +/* + * Local variables: + *  compile-command: "gcc -DMODVERSIONS  -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c proteon.c" + *  alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c proteon.c" + *  c-set-style "K&R" + *  c-indent-level: 8 + *  c-basic-offset: 8 + *  tab-width: 8 + * End: + */  |