linux/drivers/net/tokenring/skisa.c
<<
>>
Prefs
   1/*
   2 *  skisa.c: A network driver for SK-NET TMS380-based ISA token ring cards.
   3 *
   4 *  Based on tmspci written 1999 by Adam Fritzler
   5 *  
   6 *  Written 2000 by Jochen Friedrich
   7 *  Dedicated to my girlfriend Steffi Bopp
   8 *
   9 *  This software may be used and distributed according to the terms
  10 *  of the GNU General Public License, incorporated herein by reference.
  11 *
  12 *  This driver module supports the following cards:
  13 *      - SysKonnect TR4/16(+) ISA      (SK-4190)
  14 *
  15 *  Maintainer(s):
  16 *    AF        Adam Fritzler
  17 *    JF        Jochen Friedrich        jochen@scram.de
  18 *
  19 *  Modification History:
  20 *      14-Jan-01       JF      Created
  21 *      28-Oct-02       JF      Fixed probe of card for static compilation.
  22 *                              Fixed module init to not make hotplug go wild.
  23 *      09-Nov-02       JF      Fixed early bail out on out of memory
  24 *                              situations if multiple cards are found.
  25 *                              Cleaned up some unnecessary console SPAM.
  26 *      09-Dec-02       JF      Fixed module reference counting.
  27 *      02-Jan-03       JF      Renamed to skisa.c
  28 *
  29 */
  30static const char version[] = "skisa.c: v1.03 09/12/2002 by Jochen Friedrich\n";
  31
  32#include <linux/module.h>
  33#include <linux/kernel.h>
  34#include <linux/errno.h>
  35#include <linux/pci.h>
  36#include <linux/init.h>
  37#include <linux/netdevice.h>
  38#include <linux/trdevice.h>
  39#include <linux/platform_device.h>
  40
  41#include <asm/system.h>
  42#include <asm/io.h>
  43#include <asm/irq.h>
  44#include <asm/pci.h>
  45#include <asm/dma.h>
  46
  47#include "tms380tr.h"
  48
  49#define SK_ISA_IO_EXTENT 32
  50
  51/* A zero-terminated list of I/O addresses to be probed. */
  52static unsigned int portlist[] __initdata = {
  53        0x0A20, 0x1A20, 0x0B20, 0x1B20, 0x0980, 0x1980, 0x0900, 0x1900,// SK
  54        0
  55};
  56
  57/* A zero-terminated list of IRQs to be probed. 
  58 * Used again after initial probe for sktr_chipset_init, called from sktr_open.
  59 */
  60static const unsigned short irqlist[] = {
  61        3, 5, 9, 10, 11, 12, 15,
  62        0
  63};
  64
  65/* A zero-terminated list of DMAs to be probed. */
  66static int dmalist[] __initdata = {
  67        5, 6, 7,
  68        0
  69};
  70
  71static char isa_cardname[] = "SK NET TR 4/16 ISA\0";
  72static u64 dma_mask = ISA_MAX_ADDRESS;
  73static int sk_isa_open(struct net_device *dev);
  74static void sk_isa_read_eeprom(struct net_device *dev);
  75static unsigned short sk_isa_setnselout_pins(struct net_device *dev);
  76
  77static unsigned short sk_isa_sifreadb(struct net_device *dev, unsigned short reg)
  78{
  79        return inb(dev->base_addr + reg);
  80}
  81
  82static unsigned short sk_isa_sifreadw(struct net_device *dev, unsigned short reg)
  83{
  84        return inw(dev->base_addr + reg);
  85}
  86
  87static void sk_isa_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg)
  88{
  89        outb(val, dev->base_addr + reg);
  90}
  91
  92static void sk_isa_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg)
  93{
  94        outw(val, dev->base_addr + reg);
  95}
  96
  97
  98static int __init sk_isa_probe1(struct net_device *dev, int ioaddr)
  99{
 100        unsigned char old, chk1, chk2;
 101
 102        if (!request_region(ioaddr, SK_ISA_IO_EXTENT, isa_cardname))
 103                return -ENODEV;
 104
 105        old = inb(ioaddr + SIFADR);     /* Get the old SIFADR value */
 106
 107        chk1 = 0;       /* Begin with check value 0 */
 108        do {
 109                /* Write new SIFADR value */
 110                outb(chk1, ioaddr + SIFADR);
 111
 112                /* Read, invert and write */
 113                chk2 = inb(ioaddr + SIFADD);
 114                chk2 ^= 0x0FE;
 115                outb(chk2, ioaddr + SIFADR);
 116
 117                /* Read, invert and compare */
 118                chk2 = inb(ioaddr + SIFADD);
 119                chk2 ^= 0x0FE;
 120
 121                if(chk1 != chk2) {
 122                        release_region(ioaddr, SK_ISA_IO_EXTENT);
 123                        return -ENODEV;
 124                }
 125
 126                chk1 -= 2;
 127        } while(chk1 != 0);     /* Repeat 128 times (all byte values) */
 128
 129        /* Restore the SIFADR value */
 130        outb(old, ioaddr + SIFADR);
 131
 132        dev->base_addr = ioaddr;
 133        return 0;
 134}
 135
 136static struct net_device_ops sk_isa_netdev_ops __read_mostly;
 137
 138static int __init setup_card(struct net_device *dev, struct device *pdev)
 139{
 140        struct net_local *tp;
 141        static int versionprinted;
 142        const unsigned *port;
 143        int j, err = 0;
 144
 145        if (!dev)
 146                return -ENOMEM;
 147
 148        if (dev->base_addr)     /* probe specific location */
 149                err = sk_isa_probe1(dev, dev->base_addr);
 150        else {
 151                for (port = portlist; *port; port++) {
 152                        err = sk_isa_probe1(dev, *port);
 153                        if (!err)
 154                                break;
 155                }
 156        }
 157        if (err)
 158                goto out5;
 159
 160        /* At this point we have found a valid card. */
 161
 162        if (versionprinted++ == 0)
 163                printk(KERN_DEBUG "%s", version);
 164
 165        err = -EIO;
 166        pdev->dma_mask = &dma_mask;
 167        if (tmsdev_init(dev, pdev))
 168                goto out4;
 169
 170        dev->base_addr &= ~3; 
 171                
 172        sk_isa_read_eeprom(dev);
 173
 174        printk(KERN_DEBUG "skisa.c:    Ring Station Address: %pM\n",
 175               dev->dev_addr);
 176                
 177        tp = netdev_priv(dev);
 178        tp->setnselout = sk_isa_setnselout_pins;
 179                
 180        tp->sifreadb = sk_isa_sifreadb;
 181        tp->sifreadw = sk_isa_sifreadw;
 182        tp->sifwriteb = sk_isa_sifwriteb;
 183        tp->sifwritew = sk_isa_sifwritew;
 184        
 185        memcpy(tp->ProductID, isa_cardname, PROD_ID_SIZE + 1);
 186
 187        tp->tmspriv = NULL;
 188
 189        dev->netdev_ops = &sk_isa_netdev_ops;
 190
 191        if (dev->irq == 0)
 192        {
 193                for(j = 0; irqlist[j] != 0; j++)
 194                {
 195                        dev->irq = irqlist[j];
 196                        if (!request_irq(dev->irq, tms380tr_interrupt, 0, 
 197                                isa_cardname, dev))
 198                                break;
 199                }
 200                
 201                if(irqlist[j] == 0)
 202                {
 203                        printk(KERN_INFO "skisa.c: AutoSelect no IRQ available\n");
 204                        goto out3;
 205                }
 206        }
 207        else
 208        {
 209                for(j = 0; irqlist[j] != 0; j++)
 210                        if (irqlist[j] == dev->irq)
 211                                break;
 212                if (irqlist[j] == 0)
 213                {
 214                        printk(KERN_INFO "skisa.c: Illegal IRQ %d specified\n",
 215                                dev->irq);
 216                        goto out3;
 217                }
 218                if (request_irq(dev->irq, tms380tr_interrupt, 0, 
 219                        isa_cardname, dev))
 220                {
 221                        printk(KERN_INFO "skisa.c: Selected IRQ %d not available\n",
 222                                dev->irq);
 223                        goto out3;
 224                }
 225        }
 226
 227        if (dev->dma == 0)
 228        {
 229                for(j = 0; dmalist[j] != 0; j++)
 230                {
 231                        dev->dma = dmalist[j];
 232                        if (!request_dma(dev->dma, isa_cardname))
 233                                break;
 234                }
 235
 236                if(dmalist[j] == 0)
 237                {
 238                        printk(KERN_INFO "skisa.c: AutoSelect no DMA available\n");
 239                        goto out2;
 240                }
 241        }
 242        else
 243        {
 244                for(j = 0; dmalist[j] != 0; j++)
 245                        if (dmalist[j] == dev->dma)
 246                                break;
 247                if (dmalist[j] == 0)
 248                {
 249                        printk(KERN_INFO "skisa.c: Illegal DMA %d specified\n",
 250                                dev->dma);
 251                        goto out2;
 252                }
 253                if (request_dma(dev->dma, isa_cardname))
 254                {
 255                        printk(KERN_INFO "skisa.c: Selected DMA %d not available\n",
 256                                dev->dma);
 257                        goto out2;
 258                }
 259        }
 260
 261        err = register_netdev(dev);
 262        if (err)
 263                goto out;
 264
 265        printk(KERN_DEBUG "%s:    IO: %#4lx  IRQ: %d  DMA: %d\n",
 266               dev->name, dev->base_addr, dev->irq, dev->dma);
 267
 268        return 0;
 269out:
 270        free_dma(dev->dma);
 271out2:
 272        free_irq(dev->irq, dev);
 273out3:
 274        tmsdev_term(dev);
 275out4:
 276        release_region(dev->base_addr, SK_ISA_IO_EXTENT);
 277out5:
 278        return err;
 279}
 280
 281/*
 282 * Reads MAC address from adapter RAM, which should've read it from
 283 * the onboard ROM.  
 284 *
 285 * Calling this on a board that does not support it can be a very
 286 * dangerous thing.  The Madge board, for instance, will lock your
 287 * machine hard when this is called.  Luckily, its supported in a
 288 * separate driver.  --ASF
 289 */
 290static void sk_isa_read_eeprom(struct net_device *dev)
 291{
 292        int i;
 293        
 294        /* Address: 0000:0000 */
 295        sk_isa_sifwritew(dev, 0, SIFADX);
 296        sk_isa_sifwritew(dev, 0, SIFADR);       
 297        
 298        /* Read six byte MAC address data */
 299        dev->addr_len = 6;
 300        for(i = 0; i < 6; i++)
 301                dev->dev_addr[i] = sk_isa_sifreadw(dev, SIFINC) >> 8;
 302}
 303
 304static unsigned short sk_isa_setnselout_pins(struct net_device *dev)
 305{
 306        return 0;
 307}
 308
 309static int sk_isa_open(struct net_device *dev)
 310{  
 311        struct net_local *tp = netdev_priv(dev);
 312        unsigned short val = 0;
 313        unsigned short oldval;
 314        int i;
 315
 316        val = 0;
 317        for(i = 0; irqlist[i] != 0; i++)
 318        {
 319                if(irqlist[i] == dev->irq)
 320                        break;
 321        }
 322
 323        val |= CYCLE_TIME << 2;
 324        val |= i << 4;
 325        i = dev->dma - 5;
 326        val |= i;
 327        if(tp->DataRate == SPEED_4)
 328                val |= LINE_SPEED_BIT;
 329        else
 330                val &= ~LINE_SPEED_BIT;
 331        oldval = sk_isa_sifreadb(dev, POSREG);
 332        /* Leave cycle bits alone */
 333        oldval |= 0xf3;
 334        val &= oldval;
 335        sk_isa_sifwriteb(dev, val, POSREG);
 336
 337        return tms380tr_open(dev);
 338}
 339
 340#define ISATR_MAX_ADAPTERS 3
 341
 342static int io[ISATR_MAX_ADAPTERS];
 343static int irq[ISATR_MAX_ADAPTERS];
 344static int dma[ISATR_MAX_ADAPTERS];
 345
 346MODULE_LICENSE("GPL");
 347
 348module_param_array(io, int, NULL, 0);
 349module_param_array(irq, int, NULL, 0);
 350module_param_array(dma, int, NULL, 0);
 351
 352static struct platform_device *sk_isa_dev[ISATR_MAX_ADAPTERS];
 353
 354static struct platform_driver sk_isa_driver = {
 355        .driver         = {
 356                .name   = "skisa",
 357        },
 358};
 359
 360static int __init sk_isa_init(void)
 361{
 362        struct net_device *dev;
 363        struct platform_device *pdev;
 364        int i, num = 0, err = 0;
 365
 366        sk_isa_netdev_ops = tms380tr_netdev_ops;
 367        sk_isa_netdev_ops.ndo_open = sk_isa_open;
 368        sk_isa_netdev_ops.ndo_stop = tms380tr_close;
 369
 370        err = platform_driver_register(&sk_isa_driver);
 371        if (err)
 372                return err;
 373
 374        for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
 375                dev = alloc_trdev(sizeof(struct net_local));
 376                if (!dev)
 377                        continue;
 378
 379                dev->base_addr = io[i];
 380                dev->irq = irq[i];
 381                dev->dma = dma[i];
 382                pdev = platform_device_register_simple("skisa",
 383                        i, NULL, 0);
 384                if (IS_ERR(pdev)) {
 385                        free_netdev(dev);
 386                        continue;
 387                }
 388                err = setup_card(dev, &pdev->dev);
 389                if (!err) {
 390                        sk_isa_dev[i] = pdev;
 391                        platform_set_drvdata(sk_isa_dev[i], dev);
 392                        ++num;
 393                } else {
 394                        platform_device_unregister(pdev);
 395                        free_netdev(dev);
 396                }
 397        }
 398
 399        printk(KERN_NOTICE "skisa.c: %d cards found.\n", num);
 400        /* Probe for cards. */
 401        if (num == 0) {
 402                printk(KERN_NOTICE "skisa.c: No cards found.\n");
 403                platform_driver_unregister(&sk_isa_driver);
 404                return -ENODEV;
 405        }
 406        return 0;
 407}
 408
 409static void __exit sk_isa_cleanup(void)
 410{
 411        struct net_device *dev;
 412        int i;
 413
 414        for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
 415                struct platform_device *pdev = sk_isa_dev[i];
 416
 417                if (!pdev)
 418                        continue;
 419                dev = platform_get_drvdata(pdev);
 420                unregister_netdev(dev);
 421                release_region(dev->base_addr, SK_ISA_IO_EXTENT);
 422                free_irq(dev->irq, dev);
 423                free_dma(dev->dma);
 424                tmsdev_term(dev);
 425                free_netdev(dev);
 426                platform_set_drvdata(pdev, NULL);
 427                platform_device_unregister(pdev);
 428        }
 429        platform_driver_unregister(&sk_isa_driver);
 430}
 431
 432module_init(sk_isa_init);
 433module_exit(sk_isa_cleanup);
 434
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.