linux/drivers/net/tokenring/proteon.c
<<
>>
Prefs
   1/*
   2 *  proteon.c: A network driver for Proteon ISA token ring cards.
   3 *
   4 *  Based on tmspci written 1999 by Adam Fritzler
   5 *  
   6 *  Written 2003 by Jochen Friedrich
   7 *
   8 *  This software may be used and distributed according to the terms
   9 *  of the GNU General Public License, incorporated herein by reference.
  10 *
  11 *  This driver module supports the following cards:
  12 *      - Proteon 1392, 1392+
  13 *
  14 *  Maintainer(s):
  15 *    AF        Adam Fritzler
  16 *    JF        Jochen Friedrich        jochen@scram.de
  17 *
  18 *  Modification History:
  19 *      02-Jan-03       JF      Created
  20 *
  21 */
  22static const char version[] = "proteon.c: v1.00 02/01/2003 by Jochen Friedrich\n";
  23
  24#include <linux/module.h>
  25#include <linux/kernel.h>
  26#include <linux/delay.h>
  27#include <linux/errno.h>
  28#include <linux/pci.h>
  29#include <linux/init.h>
  30#include <linux/netdevice.h>
  31#include <linux/trdevice.h>
  32#include <linux/platform_device.h>
  33
  34#include <asm/io.h>
  35#include <asm/irq.h>
  36#include <asm/pci.h>
  37#include <asm/dma.h>
  38
  39#include "tms380tr.h"
  40
  41#define PROTEON_IO_EXTENT 32
  42
  43/* A zero-terminated list of I/O addresses to be probed. */
  44static unsigned int portlist[] __initdata = {
  45        0x0A20, 0x0E20, 0x1A20, 0x1E20, 0x2A20, 0x2E20, 0x3A20, 0x3E20,// Prot.
  46        0x4A20, 0x4E20, 0x5A20, 0x5E20, 0x6A20, 0x6E20, 0x7A20, 0x7E20,// Prot.
  47        0x8A20, 0x8E20, 0x9A20, 0x9E20, 0xAA20, 0xAE20, 0xBA20, 0xBE20,// Prot.
  48        0xCA20, 0xCE20, 0xDA20, 0xDE20, 0xEA20, 0xEE20, 0xFA20, 0xFE20,// Prot.
  49        0
  50};
  51
  52/* A zero-terminated list of IRQs to be probed. */
  53static unsigned short irqlist[] = {
  54        7, 6, 5, 4, 3, 12, 11, 10, 9,
  55        0
  56};
  57
  58/* A zero-terminated list of DMAs to be probed. */
  59static int dmalist[] __initdata = {
  60        5, 6, 7,
  61        0
  62};
  63
  64static char cardname[] = "Proteon 1392\0";
  65static u64 dma_mask = ISA_MAX_ADDRESS;
  66static int proteon_open(struct net_device *dev);
  67static void proteon_read_eeprom(struct net_device *dev);
  68static unsigned short proteon_setnselout_pins(struct net_device *dev);
  69
  70static unsigned short proteon_sifreadb(struct net_device *dev, unsigned short reg)
  71{
  72        return inb(dev->base_addr + reg);
  73}
  74
  75static unsigned short proteon_sifreadw(struct net_device *dev, unsigned short reg)
  76{
  77        return inw(dev->base_addr + reg);
  78}
  79
  80static void proteon_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg)
  81{
  82        outb(val, dev->base_addr + reg);
  83}
  84
  85static void proteon_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg)
  86{
  87        outw(val, dev->base_addr + reg);
  88}
  89
  90static int __init proteon_probe1(struct net_device *dev, int ioaddr)
  91{
  92        unsigned char chk1, chk2;
  93        int i;
  94
  95        if (!request_region(ioaddr, PROTEON_IO_EXTENT, cardname))
  96                return -ENODEV;
  97                
  98
  99        chk1 = inb(ioaddr + 0x1f);      /* Get Proteon ID reg 1 */
 100        if (chk1 != 0x1f) 
 101                goto nodev;
 102
 103        chk1 = inb(ioaddr + 0x1e) & 0x07;       /* Get Proteon ID reg 0 */
 104        for (i=0; i<16; i++) {
 105                chk2 = inb(ioaddr + 0x1e) & 0x07;
 106                if (((chk1 + 1) & 0x07) != chk2)
 107                        goto nodev;
 108                chk1 = chk2;
 109        }
 110
 111        dev->base_addr = ioaddr;
 112        return 0;
 113nodev:
 114        release_region(ioaddr, PROTEON_IO_EXTENT); 
 115        return -ENODEV;
 116}
 117
 118static struct net_device_ops proteon_netdev_ops __read_mostly;
 119
 120static int __init setup_card(struct net_device *dev, struct device *pdev)
 121{
 122        struct net_local *tp;
 123        static int versionprinted;
 124        const unsigned *port;
 125        int j,err = 0;
 126
 127        if (!dev)
 128                return -ENOMEM;
 129
 130        if (dev->base_addr)     /* probe specific location */
 131                err = proteon_probe1(dev, dev->base_addr);
 132        else {
 133                for (port = portlist; *port; port++) {
 134                        err = proteon_probe1(dev, *port);
 135                        if (!err)
 136                                break;
 137                }
 138        }
 139        if (err)
 140                goto out5;
 141
 142        /* At this point we have found a valid card. */
 143
 144        if (versionprinted++ == 0)
 145                printk(KERN_DEBUG "%s", version);
 146
 147        err = -EIO;
 148        pdev->dma_mask = &dma_mask;
 149        if (tmsdev_init(dev, pdev))
 150                goto out4;
 151
 152        dev->base_addr &= ~3; 
 153                
 154        proteon_read_eeprom(dev);
 155
 156        printk(KERN_DEBUG "proteon.c:    Ring Station Address: %pM\n",
 157               dev->dev_addr);
 158                
 159        tp = netdev_priv(dev);
 160        tp->setnselout = proteon_setnselout_pins;
 161                
 162        tp->sifreadb = proteon_sifreadb;
 163        tp->sifreadw = proteon_sifreadw;
 164        tp->sifwriteb = proteon_sifwriteb;
 165        tp->sifwritew = proteon_sifwritew;
 166        
 167        memcpy(tp->ProductID, cardname, PROD_ID_SIZE + 1);
 168
 169        tp->tmspriv = NULL;
 170
 171        dev->netdev_ops = &proteon_netdev_ops;
 172
 173        if (dev->irq == 0)
 174        {
 175                for(j = 0; irqlist[j] != 0; j++)
 176                {
 177                        dev->irq = irqlist[j];
 178                        if (!request_irq(dev->irq, tms380tr_interrupt, 0, 
 179                                cardname, dev))
 180                                break;
 181                }
 182                
 183                if(irqlist[j] == 0)
 184                {
 185                        printk(KERN_INFO "proteon.c: AutoSelect no IRQ available\n");
 186                        goto out3;
 187                }
 188        }
 189        else
 190        {
 191                for(j = 0; irqlist[j] != 0; j++)
 192                        if (irqlist[j] == dev->irq)
 193                                break;
 194                if (irqlist[j] == 0)
 195                {
 196                        printk(KERN_INFO "proteon.c: Illegal IRQ %d specified\n",
 197                                dev->irq);
 198                        goto out3;
 199                }
 200                if (request_irq(dev->irq, tms380tr_interrupt, 0, 
 201                        cardname, dev))
 202                {
 203                        printk(KERN_INFO "proteon.c: Selected IRQ %d not available\n",
 204                                dev->irq);
 205                        goto out3;
 206                }
 207        }
 208
 209        if (dev->dma == 0)
 210        {
 211                for(j = 0; dmalist[j] != 0; j++)
 212                {
 213                        dev->dma = dmalist[j];
 214                        if (!request_dma(dev->dma, cardname))
 215                                break;
 216                }
 217
 218                if(dmalist[j] == 0)
 219                {
 220                        printk(KERN_INFO "proteon.c: AutoSelect no DMA available\n");
 221                        goto out2;
 222                }
 223        }
 224        else
 225        {
 226                for(j = 0; dmalist[j] != 0; j++)
 227                        if (dmalist[j] == dev->dma)
 228                                break;
 229                if (dmalist[j] == 0)
 230                {
 231                        printk(KERN_INFO "proteon.c: Illegal DMA %d specified\n",
 232                                dev->dma);
 233                        goto out2;
 234                }
 235                if (request_dma(dev->dma, cardname))
 236                {
 237                        printk(KERN_INFO "proteon.c: Selected DMA %d not available\n",
 238                                dev->dma);
 239                        goto out2;
 240                }
 241        }
 242
 243        err = register_netdev(dev);
 244        if (err)
 245                goto out;
 246
 247        printk(KERN_DEBUG "%s:    IO: %#4lx  IRQ: %d  DMA: %d\n",
 248               dev->name, dev->base_addr, dev->irq, dev->dma);
 249
 250        return 0;
 251out:
 252        free_dma(dev->dma);
 253out2:
 254        free_irq(dev->irq, dev);
 255out3:
 256        tmsdev_term(dev);
 257out4:
 258        release_region(dev->base_addr, PROTEON_IO_EXTENT);
 259out5:
 260        return err;
 261}
 262
 263/*
 264 * Reads MAC address from adapter RAM, which should've read it from
 265 * the onboard ROM.  
 266 *
 267 * Calling this on a board that does not support it can be a very
 268 * dangerous thing.  The Madge board, for instance, will lock your
 269 * machine hard when this is called.  Luckily, its supported in a
 270 * separate driver.  --ASF
 271 */
 272static void proteon_read_eeprom(struct net_device *dev)
 273{
 274        int i;
 275        
 276        /* Address: 0000:0000 */
 277        proteon_sifwritew(dev, 0, SIFADX);
 278        proteon_sifwritew(dev, 0, SIFADR);      
 279        
 280        /* Read six byte MAC address data */
 281        dev->addr_len = 6;
 282        for(i = 0; i < 6; i++)
 283                dev->dev_addr[i] = proteon_sifreadw(dev, SIFINC) >> 8;
 284}
 285
 286static unsigned short proteon_setnselout_pins(struct net_device *dev)
 287{
 288        return 0;
 289}
 290
 291static int proteon_open(struct net_device *dev)
 292{  
 293        struct net_local *tp = netdev_priv(dev);
 294        unsigned short val = 0;
 295        int i;
 296
 297        /* Proteon reset sequence */
 298        outb(0, dev->base_addr + 0x11);
 299        mdelay(20);
 300        outb(0x04, dev->base_addr + 0x11);
 301        mdelay(20);
 302        outb(0, dev->base_addr + 0x11);
 303        mdelay(100);
 304
 305        /* set control/status reg */
 306        val = inb(dev->base_addr + 0x11);
 307        val |= 0x78;
 308        val &= 0xf9;
 309        if(tp->DataRate == SPEED_4)
 310                val |= 0x20;
 311        else
 312                val &= ~0x20;
 313
 314        outb(val, dev->base_addr + 0x11);
 315        outb(0xff, dev->base_addr + 0x12);
 316        for(i = 0; irqlist[i] != 0; i++)
 317        {
 318                if(irqlist[i] == dev->irq)
 319                        break;
 320        }
 321        val = i;
 322        i = (7 - dev->dma) << 4;
 323        val |= i;
 324        outb(val, dev->base_addr + 0x13);
 325
 326        return tms380tr_open(dev);
 327}
 328
 329#define ISATR_MAX_ADAPTERS 3
 330
 331static int io[ISATR_MAX_ADAPTERS];
 332static int irq[ISATR_MAX_ADAPTERS];
 333static int dma[ISATR_MAX_ADAPTERS];
 334
 335MODULE_LICENSE("GPL");
 336
 337module_param_array(io, int, NULL, 0);
 338module_param_array(irq, int, NULL, 0);
 339module_param_array(dma, int, NULL, 0);
 340
 341static struct platform_device *proteon_dev[ISATR_MAX_ADAPTERS];
 342
 343static struct platform_driver proteon_driver = {
 344        .driver         = {
 345                .name   = "proteon",
 346        },
 347};
 348
 349static int __init proteon_init(void)
 350{
 351        struct net_device *dev;
 352        struct platform_device *pdev;
 353        int i, num = 0, err = 0;
 354
 355        proteon_netdev_ops = tms380tr_netdev_ops;
 356        proteon_netdev_ops.ndo_open = proteon_open;
 357        proteon_netdev_ops.ndo_stop = tms380tr_close;
 358
 359        err = platform_driver_register(&proteon_driver);
 360        if (err)
 361                return err;
 362
 363        for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
 364                dev = alloc_trdev(sizeof(struct net_local));
 365                if (!dev)
 366                        continue;
 367
 368                dev->base_addr = io[i];
 369                dev->irq = irq[i];
 370                dev->dma = dma[i];
 371                pdev = platform_device_register_simple("proteon",
 372                        i, NULL, 0);
 373                if (IS_ERR(pdev)) {
 374                        free_netdev(dev);
 375                        continue;
 376                }
 377                err = setup_card(dev, &pdev->dev);
 378                if (!err) {
 379                        proteon_dev[i] = pdev;
 380                        platform_set_drvdata(pdev, dev);
 381                        ++num;
 382                } else {
 383                        platform_device_unregister(pdev);
 384                        free_netdev(dev);
 385                }
 386        }
 387
 388        printk(KERN_NOTICE "proteon.c: %d cards found.\n", num);
 389        /* Probe for cards. */
 390        if (num == 0) {
 391                printk(KERN_NOTICE "proteon.c: No cards found.\n");
 392                platform_driver_unregister(&proteon_driver);
 393                return -ENODEV;
 394        }
 395        return 0;
 396}
 397
 398static void __exit proteon_cleanup(void)
 399{
 400        struct net_device *dev;
 401        int i;
 402
 403        for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
 404                struct platform_device *pdev = proteon_dev[i];
 405                
 406                if (!pdev)
 407                        continue;
 408                dev = platform_get_drvdata(pdev);
 409                unregister_netdev(dev);
 410                release_region(dev->base_addr, PROTEON_IO_EXTENT);
 411                free_irq(dev->irq, dev);
 412                free_dma(dev->dma);
 413                tmsdev_term(dev);
 414                free_netdev(dev);
 415                platform_set_drvdata(pdev, NULL);
 416                platform_device_unregister(pdev);
 417        }
 418        platform_driver_unregister(&proteon_driver);
 419}
 420
 421module_init(proteon_init);
 422module_exit(proteon_cleanup);
 423