11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * proteon.c: A network driver for Proteon ISA token ring cards. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based on tmspci written 1999 by Adam Fritzler 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Written 2003 by Jochen Friedrich 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver module supports the following cards: 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Proteon 1392, 1392+ 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maintainer(s): 15726a645913694619876dd20645f88aad25cfbcd5Joe Perches * AF Adam Fritzler 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * JF Jochen Friedrich jochen@scram.de 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modification History: 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 02-Jan-03 JF Created 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char version[] = "proteon.c: v1.00 02/01/2003 by Jochen Friedrich\n"; 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/trdevice.h> 32d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pci.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "tms380tr.h" 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PROTEON_IO_EXTENT 32 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A zero-terminated list of I/O addresses to be probed. */ 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int portlist[] __initdata = { 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x0A20, 0x0E20, 0x1A20, 0x1E20, 0x2A20, 0x2E20, 0x3A20, 0x3E20,// Prot. 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x4A20, 0x4E20, 0x5A20, 0x5E20, 0x6A20, 0x6E20, 0x7A20, 0x7E20,// Prot. 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x8A20, 0x8E20, 0x9A20, 0x9E20, 0xAA20, 0xAE20, 0xBA20, 0xBE20,// Prot. 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0xCA20, 0xCE20, 0xDA20, 0xDE20, 0xEA20, 0xEE20, 0xFA20, 0xFE20,// Prot. 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A zero-terminated list of IRQs to be probed. */ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short irqlist[] = { 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7, 6, 5, 4, 3, 12, 11, 10, 9, 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A zero-terminated list of DMAs to be probed. */ 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dmalist[] __initdata = { 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5, 6, 7, 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char cardname[] = "Proteon 1392\0"; 65504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrichstatic u64 dma_mask = ISA_MAX_ADDRESS; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int proteon_open(struct net_device *dev); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void proteon_read_eeprom(struct net_device *dev); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short proteon_setnselout_pins(struct net_device *dev); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short proteon_sifreadb(struct net_device *dev, unsigned short reg) 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return inb(dev->base_addr + reg); 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short proteon_sifreadw(struct net_device *dev, unsigned short reg) 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return inw(dev->base_addr + reg); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void proteon_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(val, dev->base_addr + reg); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void proteon_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(val, dev->base_addr + reg); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init proteon_probe1(struct net_device *dev, int ioaddr) 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char chk1, chk2; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region(ioaddr, PROTEON_IO_EXTENT, cardname)) 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chk1 = inb(ioaddr + 0x1f); /* Get Proteon ID reg 1 */ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (chk1 != 0x1f) 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto nodev; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chk1 = inb(ioaddr + 0x1e) & 0x07; /* Get Proteon ID reg 0 */ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i<16; i++) { 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chk2 = inb(ioaddr + 0x1e) & 0x07; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((chk1 + 1) & 0x07) != chk2) 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto nodev; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chk1 = chk2; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = ioaddr; 112807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet return 0; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnodev: 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(ioaddr, PROTEON_IO_EXTENT); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11879f8ae3aa27f2f17a50ad1deee1e16ff02be01bbStephen Hemmingerstatic struct net_device_ops proteon_netdev_ops __read_mostly; 11979f8ae3aa27f2f17a50ad1deee1e16ff02be01bbStephen Hemminger 120504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrichstatic int __init setup_card(struct net_device *dev, struct device *pdev) 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_local *tp; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static int versionprinted; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned *port; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int j,err = 0; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->base_addr) /* probe specific location */ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = proteon_probe1(dev, dev->base_addr); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (port = portlist; *port; port++) { 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = proteon_probe1(dev, *port); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!err) 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 140504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich goto out5; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* At this point we have found a valid card. */ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (versionprinted++ == 0) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "%s", version); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EIO; 148504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich pdev->dma_mask = &dma_mask; 14984c3ea01d163a24323d827e1d280dc3346905972Jochen Friedrich if (tmsdev_init(dev, pdev)) 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out4; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr &= ~3; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds proteon_read_eeprom(dev); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 156e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk(KERN_DEBUG "proteon.c: Ring Station Address: %pM\n", 157e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->dev_addr); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp = netdev_priv(dev); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->setnselout = proteon_setnselout_pins; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->sifreadb = proteon_sifreadb; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->sifreadw = proteon_sifreadw; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->sifwriteb = proteon_sifwriteb; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->sifwritew = proteon_sifwritew; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(tp->ProductID, cardname, PROD_ID_SIZE + 1); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tmspriv = NULL; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17179f8ae3aa27f2f17a50ad1deee1e16ff02be01bbStephen Hemminger dev->netdev_ops = &proteon_netdev_ops; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->irq == 0) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(j = 0; irqlist[j] != 0; j++) 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = irqlist[j]; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_irq(dev->irq, tms380tr_interrupt, 0, 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardname, dev)) 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(irqlist[j] == 0) 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 185504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich printk(KERN_INFO "proteon.c: AutoSelect no IRQ available\n"); 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out3; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(j = 0; irqlist[j] != 0; j++) 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irqlist[j] == dev->irq) 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irqlist[j] == 0) 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 196504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich printk(KERN_INFO "proteon.c: Illegal IRQ %d specified\n", 197504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich dev->irq); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out3; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request_irq(dev->irq, tms380tr_interrupt, 0, 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardname, dev)) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 203504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich printk(KERN_INFO "proteon.c: Selected IRQ %d not available\n", 204504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich dev->irq); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out3; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->dma == 0) 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(j = 0; dmalist[j] != 0; j++) 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->dma = dmalist[j]; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_dma(dev->dma, cardname)) 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(dmalist[j] == 0) 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 220504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich printk(KERN_INFO "proteon.c: AutoSelect no DMA available\n"); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out2; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(j = 0; dmalist[j] != 0; j++) 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dmalist[j] == dev->dma) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dmalist[j] == 0) 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 231504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich printk(KERN_INFO "proteon.c: Illegal DMA %d specified\n", 232504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich dev->dma); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out2; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request_dma(dev->dma, cardname)) 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 237504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich printk(KERN_INFO "proteon.c: Selected DMA %d not available\n", 238504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich dev->dma); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out2; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = register_netdev(dev); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 247504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", 248504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich dev->name, dev->base_addr, dev->irq, dev->dma); 249504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dma(dev->dma); 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout2: 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, dev); 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout3: 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmsdev_term(dev); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout4: 258504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich release_region(dev->base_addr, PROTEON_IO_EXTENT); 259504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrichout5: 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reads MAC address from adapter RAM, which should've read it from 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the onboard ROM. 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calling this on a board that does not support it can be a very 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dangerous thing. The Madge board, for instance, will lock your 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * machine hard when this is called. Luckily, its supported in a 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * separate driver. --ASF 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void proteon_read_eeprom(struct net_device *dev) 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Address: 0000:0000 */ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds proteon_sifwritew(dev, 0, SIFADX); 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds proteon_sifwritew(dev, 0, SIFADR); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Read six byte MAC address data */ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->addr_len = 6; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i = 0; i < 6; i++) 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->dev_addr[i] = proteon_sifreadw(dev, SIFINC) >> 8; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28627cd6ae5619084f363630683e77d70be38075afeHannes Ederstatic unsigned short proteon_setnselout_pins(struct net_device *dev) 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int proteon_open(struct net_device *dev) 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_local *tp = netdev_priv(dev); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short val = 0; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Proteon reset sequence */ 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, dev->base_addr + 0x11); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay(20); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x04, dev->base_addr + 0x11); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay(20); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, dev->base_addr + 0x11); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay(100); 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set control/status reg */ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = inb(dev->base_addr + 0x11); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= 0x78; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val &= 0xf9; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(tp->DataRate == SPEED_4) 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= 0x20; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val &= ~0x20; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(val, dev->base_addr + 0x11); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, dev->base_addr + 0x12); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i = 0; irqlist[i] != 0; i++) 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(irqlist[i] == dev->irq) 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = i; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = (7 - dev->dma) << 4; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= i; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(val, dev->base_addr + 0x13); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tms380tr_open(dev); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ISATR_MAX_ADAPTERS 3 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int io[ISATR_MAX_ADAPTERS]; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irq[ISATR_MAX_ADAPTERS]; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dma[ISATR_MAX_ADAPTERS]; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(io, int, NULL, 0); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(irq, int, NULL, 0); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(dma, int, NULL, 0); 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrichstatic struct platform_device *proteon_dev[ISATR_MAX_ADAPTERS]; 342504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich 3433ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver proteon_driver = { 3443ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .driver = { 3453ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .name = "proteon", 3463ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King }, 347504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich}; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 349504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrichstatic int __init proteon_init(void) 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 352504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich struct platform_device *pdev; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, num = 0, err = 0; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35579f8ae3aa27f2f17a50ad1deee1e16ff02be01bbStephen Hemminger proteon_netdev_ops = tms380tr_netdev_ops; 35679f8ae3aa27f2f17a50ad1deee1e16ff02be01bbStephen Hemminger proteon_netdev_ops.ndo_open = proteon_open; 35779f8ae3aa27f2f17a50ad1deee1e16ff02be01bbStephen Hemminger proteon_netdev_ops.ndo_stop = tms380tr_close; 35879f8ae3aa27f2f17a50ad1deee1e16ff02be01bbStephen Hemminger 3593ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King err = platform_driver_register(&proteon_driver); 360504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich if (err) 361504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich return err; 362504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = alloc_trdev(sizeof(struct net_local)); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = io[i]; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = irq[i]; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->dma = dma[i]; 371504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich pdev = platform_device_register_simple("proteon", 372504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich i, NULL, 0); 3739d4df9e0fadfc84cd826e0f7e946691b4d7baee5Akinobu Mita if (IS_ERR(pdev)) { 3749d4df9e0fadfc84cd826e0f7e946691b4d7baee5Akinobu Mita free_netdev(dev); 3759d4df9e0fadfc84cd826e0f7e946691b4d7baee5Akinobu Mita continue; 3769d4df9e0fadfc84cd826e0f7e946691b4d7baee5Akinobu Mita } 377504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich err = setup_card(dev, &pdev->dev); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!err) { 379504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich proteon_dev[i] = pdev; 3803ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_set_drvdata(pdev, dev); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++num; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 383504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich platform_device_unregister(pdev); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE "proteon.c: %d cards found.\n", num); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Probe for cards. */ 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (num == 0) { 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE "proteon.c: No cards found.\n"); 3929d4df9e0fadfc84cd826e0f7e946691b4d7baee5Akinobu Mita platform_driver_unregister(&proteon_driver); 3939d4df9e0fadfc84cd826e0f7e946691b4d7baee5Akinobu Mita return -ENODEV; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3959d4df9e0fadfc84cd826e0f7e946691b4d7baee5Akinobu Mita return 0; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 398504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrichstatic void __exit proteon_cleanup(void) 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 400504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich struct net_device *dev; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { 404504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich struct platform_device *pdev = proteon_dev[i]; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 406504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich if (!pdev) 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 4083ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King dev = platform_get_drvdata(pdev); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdev(dev); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(dev->base_addr, PROTEON_IO_EXTENT); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, dev); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dma(dev->dma); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmsdev_term(dev); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 4153ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_set_drvdata(pdev, NULL); 416504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrich platform_device_unregister(pdev); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4183ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_driver_unregister(&proteon_driver); 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrichmodule_init(proteon_init); 422504ff16cecf2a788181eddc9d6e47d94ce50a9f6Jochen Friedrichmodule_exit(proteon_cleanup); 423