linux-bk/drivers/net/daynaport.c
<<
>>
Prefs
   1/* daynaport.c: A Macintosh 8390 based ethernet driver for linux. */
   2/*
   3        Derived from code:
   4        
   5        Written 1993-94 by Donald Becker.
   6
   7        Copyright 1993 United States Government as represented by the
   8        Director, National Security Agency.
   9
  10        This software may be used and distributed according to the terms
  11        of the GNU General Public License, incorporated herein by reference.
  12
  13            TODO:
  14
  15            The block output routines may be wrong for non Dayna
  16            cards
  17
  18                Fix this driver so that it will attempt to use the info
  19                (i.e. iobase, iosize) given to it by the new and improved
  20                NuBus code.
  21
  22                Despite its misleading filename, this driver is not Dayna-specific
  23                anymore. */
  24/* Cabletron E6100 card support added by Tony Mantler (eek@escape.ca) April 1999 */
  25
  26static const char *version =
  27        "daynaport.c: v0.02 1999-05-17 Alan Cox (Alan.Cox@linux.org) and others\n";
  28static int version_printed;
  29
  30#include <linux/module.h>
  31#include <linux/init.h>
  32#include <linux/kernel.h>
  33#include <linux/sched.h>
  34#include <linux/errno.h>
  35#include <linux/string.h>
  36#include <linux/nubus.h>
  37#include <asm/io.h>
  38#include <asm/system.h>
  39#include <asm/hwtest.h>
  40#include <asm/macints.h>
  41#include <linux/delay.h>
  42
  43#include <linux/netdevice.h>
  44#include <linux/etherdevice.h>
  45#include "8390.h"
  46
  47static int ns8390_probe1(struct net_device *dev, int word16, char *name, int id,
  48                                  int prom, struct nubus_dev *ndev);
  49
  50static int ns8390_open(struct net_device *dev);
  51static void ns8390_no_reset(struct net_device *dev);
  52static int ns8390_close_card(struct net_device *dev);
  53
  54/* Interlan */
  55static void interlan_reset(struct net_device *dev);
  56
  57/* Dayna */
  58static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
  59                                                int ring_page);
  60static void dayna_block_input(struct net_device *dev, int count,
  61                                                  struct sk_buff *skb, int ring_offset);
  62static void dayna_block_output(struct net_device *dev, int count,
  63                                                   const unsigned char *buf, const int start_page);
  64
  65/* Sane (32-bit chunk memory read/write) */
  66static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
  67                                                int ring_page);
  68static void sane_block_input(struct net_device *dev, int count,
  69                                                  struct sk_buff *skb, int ring_offset);
  70static void sane_block_output(struct net_device *dev, int count,
  71                                                   const unsigned char *buf, const int start_page);
  72
  73/* Slow Sane (16-bit chunk memory read/write) */
  74static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
  75                                                int ring_page);
  76static void slow_sane_block_input(struct net_device *dev, int count,
  77                                                  struct sk_buff *skb, int ring_offset);
  78static void slow_sane_block_output(struct net_device *dev, int count,
  79                                                   const unsigned char *buf, const int start_page);
  80
  81
  82#define WD_START_PG     0x00    /* First page of TX buffer */
  83#define WD03_STOP_PG    0x20    /* Last page +1 of RX ring */
  84#define WD13_STOP_PG    0x40    /* Last page +1 of RX ring */
  85
  86#define CABLETRON_RX_START_PG          0x00    /* First page of RX buffer */
  87#define CABLETRON_RX_STOP_PG           0x30    /* Last page +1 of RX ring */
  88#define CABLETRON_TX_START_PG          CABLETRON_RX_STOP_PG  /* First page of TX buffer */
  89
  90
  91#define DAYNA_MAC_BASE          0xf0007
  92#define DAYNA_8390_BASE         0x80000 /* 3 */
  93#define DAYNA_8390_MEM          0x00000
  94#define DAYNA_MEMSIZE           0x04000 /* First word of each long ! */
  95
  96#define APPLE_8390_BASE         0xE0000
  97#define APPLE_8390_MEM          0xD0000
  98#define APPLE_MEMSIZE           8192    /* FIXME: need to dynamically check */
  99
 100#define KINETICS_MAC_BASE       0xf0004 /* first byte of each long */
 101#define KINETICS_8390_BASE      0x80000
 102#define KINETICS_8390_MEM       0x00000 /* first word of each long */
 103#define KINETICS_MEMSIZE        8192    /* FIXME: need to dynamically check */
 104/*#define KINETICS_MEMSIZE      (0x10000/2) * CSA: on the board I have, at least */
 105
 106#define CABLETRON_8390_BASE             0x90000 
 107#define CABLETRON_8390_MEM              0x00000
 108
 109static int test_8390(volatile char *ptr, int scale)
 110{
 111        int regd;
 112        int v;
 113        
 114        if(hwreg_present(&ptr[0x00])==0)
 115                return -EIO;
 116        if(hwreg_present(&ptr[0x0D<<scale])==0)
 117                return -EIO;
 118        if(hwreg_present(&ptr[0x0D<<scale])==0)
 119                return -EIO;
 120        ptr[0x00]=E8390_NODMA+E8390_PAGE1+E8390_STOP;
 121        regd=ptr[0x0D<<scale];
 122        ptr[0x0D<<scale]=0xFF;
 123        ptr[0x00]=E8390_NODMA+E8390_PAGE0;
 124        v=ptr[0x0D<<scale];
 125        if(ptr[0x0D<<scale]!=0)
 126        {
 127                ptr[0x0D<<scale]=regd;
 128                return -ENODEV;
 129        }
 130/*      printk("NS8390 found at %p scaled %d\n", ptr,scale);*/
 131        return 0;
 132}
 133/*
 134 *    Identify the species of NS8390 card/driver we need
 135 */
 136
 137enum mac8390_type {
 138        NS8390_DAYNA,
 139        NS8390_INTERLAN,
 140        NS8390_KINETICS,
 141        NS8390_APPLE,
 142        NS8390_FARALLON,
 143        NS8390_ASANTE,
 144        NS8390_CABLETRON
 145};
 146
 147static int __init ns8390_ident(struct nubus_dev* ndev)
 148{
 149        /* This really needs to be tested and tested hard.  */
 150                
 151        /* Summary of what we know so far --
 152         * SW: 0x0104 -- asante,    16 bit, back4_offsets
 153         * SW: 0x010b -- daynaport, 16 bit, fwrd4_offsets
 154         * SW: 0x010c -- farallon,  16 bit, back4_offsets, no long word access
 155         * SW: 0x011a -- focus,     [no details yet]
 156         * SW: ?????? -- interlan,  16 bit, back4_offsets, funny reset
 157         * SW: ?????? -- kinetics,   8 bit, back4_offsets
 158         * -- so i've this hypothesis going that says DrSW&1 says whether the
 159         *    map is forward or backwards -- and maybe DrSW&256 says what the
 160         *    register spacing is -- for all cards that report a DrSW in some
 161         *    range.
 162         *    This would allow the "apple compatible" driver to drive many
 163         *    seemingly different types of cards.  More DrSW info is needed
 164         *    to investigate this properly. [CSA, 21-May-1999]
 165         */
 166        /* Dayna ex Kinetics board */
 167        if(ndev->dr_sw == NUBUS_DRSW_DAYNA)
 168                return NS8390_DAYNA;
 169        if(ndev->dr_sw == NUBUS_DRSW_ASANTE)
 170                return NS8390_ASANTE;
 171        if(ndev->dr_sw == NUBUS_DRSW_FARALLON) /* farallon or sonic systems */
 172                return NS8390_FARALLON;
 173        if(ndev->dr_sw == NUBUS_DRSW_KINETICS)
 174                return NS8390_KINETICS;
 175        /* My ATI Engineering card with this combination crashes the */
 176        /* driver trying to xmit packets. Best not touch it for now. */
 177        /*     - 1999-05-20 (funaho@jurai.org)                       */
 178        if(ndev->dr_sw == NUBUS_DRSW_FOCUS)
 179                return -1;
 180
 181        /* Check the HW on this one, because it shares the same DrSW as
 182           the on-board SONIC chips */
 183        if(ndev->dr_hw == NUBUS_DRHW_CABLETRON)
 184                return NS8390_CABLETRON;
 185        /* does anyone have one of these? */
 186        if(ndev->dr_hw == NUBUS_DRHW_INTERLAN)
 187                return NS8390_INTERLAN;
 188
 189        /* FIXME: what do genuine Apple boards look like? */
 190        return -1;
 191}
 192
 193/*
 194 *      Memory probe for 8390 cards
 195 */
 196 
 197static int __init apple_8390_mem_probe(volatile unsigned short *p)
 198{
 199        int i, j;
 200        /*
 201         *      Algorithm.
 202         *      1.      Check each block size of memory doesn't fault
 203         *      2.      Write a value to it
 204         *      3.      Check all previous blocks are unaffected
 205         */
 206        
 207        for(i=0;i<2;i++)
 208        {
 209                volatile unsigned short *m=p+4096*i;
 210                /* Unwriteable - we have a fully decoded card and the
 211                   RAM end located */
 212                   
 213                if(hwreg_present(m)==0)
 214                        return 8192*i;
 215                        
 216                *m=0xA5A0|i;
 217                
 218                for(j=0;j<i;j++)
 219                {
 220                        /* Partial decode and wrap ? */
 221                        if(p[4096*j]!=(0xA5A0|j))
 222                        {
 223                                /* This is the first misdecode, so it had
 224                                   one less page than we tried */
 225                                return 8192*i;
 226                        }
 227                        j++;
 228                }
 229                /* Ok it still decodes.. move on 8K */
 230        }
 231        /* 
 232         *      We don't look past 16K. That should cover most cards
 233         *      and above 16K there isnt really any gain.
 234         */
 235        return 16384;
 236 }
 237                
 238/*
 239 *    Probe for 8390 cards.  
 240 *    The ns8390_probe1() routine initializes the card and fills the
 241 *    station address field.
 242 *
 243 *    The NuBus interface has changed!  We now scan for these somewhat
 244 *    like how the PCI and Zorro drivers do.  It's not clear whether
 245 *    this is actually better, but it makes things more consistent.
 246 *
 247 *    dev->mem_start points
 248 *    at the memory ring, dev->mem_end gives the end of it.
 249 */
 250
 251int __init mac8390_probe(struct net_device *dev)
 252{
 253        static int slots;
 254        volatile unsigned short *i;
 255        volatile unsigned char *p;
 256        int plen;
 257        int id;
 258        static struct nubus_dev* ndev;
 259
 260        /* Find the first card that hasn't already been seen */
 261        while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
 262                                                                   NUBUS_TYPE_ETHERNET, ndev)) != NULL) {
 263                /* Have we seen it already? */
 264                if (slots & (1<<ndev->board->slot))
 265                        continue;
 266                slots |= 1<<ndev->board->slot;
 267
 268                /* Is it one of ours? */
 269                if ((id = ns8390_ident(ndev)) != -1)
 270                        break;
 271        }
 272
 273        /* Hm.  No more cards, then */
 274        if (ndev == NULL)
 275                return -ENODEV;
 276
 277        dev = init_etherdev(dev, 0);
 278        if (!dev)
 279                return -ENOMEM;
 280        SET_MODULE_OWNER(dev);
 281
 282        if (!version_printed) {
 283                printk(KERN_INFO "%s", version);
 284                version_printed = 1;
 285        }
 286
 287        /*
 288         *      Dayna specific init
 289         */
 290        if(id==NS8390_DAYNA)
 291        {
 292                dev->base_addr = (int)(ndev->board->slot_addr+DAYNA_8390_BASE);
 293                dev->mem_start = (int)(ndev->board->slot_addr+DAYNA_8390_MEM);
 294                dev->mem_end = dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
 295        
 296                printk(KERN_INFO "%s: daynaport. testing board: ", dev->name);
 297                        
 298                printk("memory - ");    
 299                        
 300                i = (void *)dev->mem_start;
 301                memset((void *)i,0xAA, DAYNA_MEMSIZE);
 302                while(i<(volatile unsigned short *)dev->mem_end)
 303                {
 304                        if(*i!=0xAAAA)
 305                                goto membad;
 306                        *i=0x5678; /* make sure we catch byte smearing */
 307                        if(*i!=0x5678)
 308                                goto membad;
 309                        i+=2;   /* Skip a word */
 310                }
 311                        
 312                printk("controller - ");
 313                        
 314                p=(void *)dev->base_addr;
 315                plen=0;
 316                        
 317                while(plen<0x3FF00)
 318                {
 319                        if(test_8390(p,0)==0)
 320                                break;
 321                        if(test_8390(p,1)==0)
 322                                break;
 323                        if(test_8390(p,2)==0)
 324                                break;
 325                        if(test_8390(p,3)==0)
 326                                break;
 327                        plen++;
 328                        p++;
 329                }
 330                if(plen==0x3FF00)
 331                        goto membad;
 332                printk("OK\n");
 333                dev->irq = SLOT2IRQ(ndev->board->slot);
 334                if(ns8390_probe1(dev, 0, "dayna", id, -1, ndev)==0)
 335                        return 0;
 336        }
 337        /* Cabletron */
 338        if (id==NS8390_CABLETRON) {
 339                int memsize = 16<<10; /* fix this */
 340                  
 341                dev->base_addr=(int)(ndev->board->slot_addr+CABLETRON_8390_BASE);
 342                dev->mem_start=(int)(ndev->board->slot_addr+CABLETRON_8390_MEM);
 343                dev->mem_end=dev->mem_start+memsize;
 344                dev->irq = SLOT2IRQ(ndev->board->slot);
 345                  
 346                /* The base address is unreadable if 0x00 has been written to the command register */
 347                /* Reset the chip by writing E8390_NODMA+E8390_PAGE0+E8390_STOP just to be sure */
 348                i = (void *)dev->base_addr;
 349                *i = 0x21;
 350                  
 351                printk(KERN_INFO "%s: cabletron: testing board: ", dev->name);
 352                printk("%dK memory - ", memsize>>10);           
 353                i=(void *)dev->mem_start;
 354                while(i<(volatile unsigned short *)(dev->mem_start+memsize))
 355                {
 356                        *i=0xAAAA;
 357                        if(*i!=0xAAAA)
 358                                goto membad;
 359                        *i=0x5555;
 360                        if(*i!=0x5555)
 361                                goto membad;
 362                        i+=2;   /* Skip a word */
 363                }
 364                printk("OK\n");
 365                  
 366                if(ns8390_probe1(dev, 1, "cabletron", id, -1, ndev)==0)
 367                        return 0;
 368        }
 369        /* Apple, Farallon, Asante */
 370        if(id==NS8390_APPLE || id==NS8390_FARALLON || id==NS8390_ASANTE)
 371        {
 372                int memsize;
 373                        
 374                dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE);
 375                dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM);
 376                        
 377                memsize = apple_8390_mem_probe((void *)dev->mem_start);
 378                        
 379                dev->mem_end=dev->mem_start+memsize;
 380                dev->irq = SLOT2IRQ(ndev->board->slot);
 381                        
 382                switch(id)
 383                {
 384                case NS8390_FARALLON:
 385                        printk(KERN_INFO "%s: farallon: testing board: ", dev->name);
 386                        break;
 387                case NS8390_ASANTE:
 388                        printk(KERN_INFO "%s: asante: testing board: ", dev->name);
 389                        break;
 390                case NS8390_APPLE:
 391                default:
 392                        printk(KERN_INFO "%s: apple/clone: testing board: ", dev->name);
 393                        break;
 394                }
 395                        
 396                printk("%dK memory - ", memsize>>10);           
 397                        
 398                i=(void *)dev->mem_start;
 399                memset((void *)i,0xAA, memsize);
 400                while(i<(volatile unsigned short *)dev->mem_end)
 401                {
 402                        if(*i!=0xAAAA)
 403                                goto membad;
 404                        *i=0x5555;
 405                        if(*i!=0x5555)
 406                                goto membad;
 407                        i+=2;   /* Skip a word */
 408                }
 409                printk("OK\n");
 410                        
 411                switch (id)
 412                {
 413                case NS8390_FARALLON:
 414                        if(ns8390_probe1(dev, 1, "farallon", id, -1, ndev)==0)
 415                                return 0;
 416                        break;
 417                case NS8390_ASANTE:
 418                        if(ns8390_probe1(dev, 1, "asante", id, -1, ndev)==0)
 419                                return 0;
 420                        break;
 421                case NS8390_APPLE:
 422                default:
 423                        if(ns8390_probe1(dev, 1, "apple/clone", id, -1, ndev)==0)
 424                                return 0;
 425                        break;
 426                }
 427        }
 428        /* Interlan */
 429        if(id==NS8390_INTERLAN)
 430        {
 431                /* As apple and asante */
 432                dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE);
 433                dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM);
 434                dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
 435                dev->irq = SLOT2IRQ(ndev->board->slot);
 436                if(ns8390_probe1(dev, 1, "interlan", id, -1, ndev)==0)
 437                        return 0;
 438        }
 439        /* Kinetics (Shiva Etherport) */
 440        if(id==NS8390_KINETICS)
 441        {
 442                dev->base_addr=(int)(ndev->board->slot_addr+KINETICS_8390_BASE);
 443                dev->mem_start=(int)(ndev->board->slot_addr+KINETICS_8390_MEM);
 444                dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */
 445                dev->irq = SLOT2IRQ(ndev->board->slot);
 446                if(ns8390_probe1(dev, 0, "kinetics", id, -1, ndev)==0)
 447                        return 0;
 448        }
 449
 450        /* We should hopefully not get here */
 451        printk(KERN_ERR "Probe unsuccessful.\n");
 452        return -ENODEV;
 453
 454 membad:
 455        printk(KERN_ERR "failed at %p in %p - %p.\n", i,
 456                   (void *)dev->mem_start, (void *)dev->mem_end);
 457        return -ENODEV;
 458}
 459
 460static int __init mac8390_ethernet_addr(struct nubus_dev* ndev, unsigned char addr[6])
 461{
 462        struct nubus_dir dir;
 463        struct nubus_dirent ent;
 464
 465        /* Get the functional resource for this device */
 466        if (nubus_get_func_dir(ndev, &dir) == -1)
 467                return -1;
 468        if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1)
 469                return -1;
 470        
 471        nubus_get_rsrc_mem(addr, &ent, 6);
 472        return 0;
 473}
 474
 475static int __init ns8390_probe1(struct net_device *dev, int word16, char *model_name,
 476                                int type, int promoff, struct nubus_dev *ndev)
 477{
 478        static u32 fwrd4_offsets[16]={
 479                0,      4,      8,      12,
 480                16,     20,     24,     28,
 481                32,     36,     40,     44,
 482                48,     52,     56,     60
 483        };
 484        static u32 back4_offsets[16]={
 485                60,     56,     52,     48,
 486                44,     40,     36,     32,
 487                28,     24,     20,     16,
 488                12,     8,      4,      0
 489        };
 490        static u32 fwrd2_offsets[16]={
 491                0,      2,      4,      6,
 492                8,     10,     12,     14,
 493                16,    18,     20,     22,
 494                24,    26,     28,     30
 495        };
 496
 497        unsigned char *prom = (unsigned char*) ndev->board->slot_addr + promoff;
 498
 499        /* Allocate dev->priv and fill in 8390 specific dev fields. */
 500        if (ethdev_init(dev)) 
 501        {       
 502                printk ("%s: unable to get memory for dev->priv.\n", dev->name);
 503                return -ENOMEM;
 504        }
 505
 506        /* OK, we are certain this is going to work.  Setup the device. */
 507
 508        ei_status.name = model_name;
 509        ei_status.word16 = word16;
 510
 511       if (type==NS8390_CABLETRON) {
 512               /* Cabletron card puts the RX buffer before the TX buffer */
 513               ei_status.tx_start_page = CABLETRON_TX_START_PG;
 514               ei_status.rx_start_page = CABLETRON_RX_START_PG;
 515               ei_status.stop_page = CABLETRON_RX_STOP_PG;
 516               ei_status.rmem_start = dev->mem_start;
 517               ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
 518       } else {
 519               ei_status.tx_start_page = WD_START_PG;
 520               ei_status.rx_start_page = WD_START_PG + TX_PAGES;
 521               ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
 522               ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
 523               ei_status.rmem_end = dev->mem_end;
 524       }
 525        
 526        if(promoff==-1)         /* Use nubus resources ? */
 527        {
 528                if(mac8390_ethernet_addr(ndev, dev->dev_addr))
 529                {
 530                  printk("mac_ns8390: MAC address not in resources!\n");
 531                  return -ENODEV;
 532                }
 533        }
 534        else                    /* Pull it off the card */
 535        {
 536                int i=0;
 537                int x=1;
 538                /* These should go in the end I hope */
 539                if(type==NS8390_DAYNA)
 540                        x=2;
 541                if(type==NS8390_INTERLAN || type==NS8390_KINETICS)
 542                        x=4;
 543                while(i<6)
 544                {
 545                        dev->dev_addr[i]=*prom;
 546                        prom+=x;
 547                        if(i)
 548                                printk(":");
 549                        printk("%02X",dev->dev_addr[i++]);
 550                }
 551        }
 552
 553        printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
 554                   dev->name, ndev->board->name, ndev->board->slot, model_name);
 555        printk(KERN_INFO "MAC ");
 556        {
 557                int i;
 558                for (i = 0; i < 6; i++) {
 559                        printk("%2.2x", dev->dev_addr[i]);
 560                        if (i < 5)
 561                                printk(":");
 562                }
 563        }
 564        printk(" IRQ %d, shared memory at %#lx-%#lx.\n",
 565                   dev->irq, dev->mem_start, dev->mem_end-1);
 566
 567        switch(type)
 568        {
 569                case NS8390_DAYNA:      /* Dayna card */
 570                case NS8390_KINETICS:   /* Kinetics --  8 bit config, but 16 bit mem */
 571                        /* 16 bit, 4 word offsets */
 572                        ei_status.reset_8390 = &ns8390_no_reset;
 573                        ei_status.block_input = &dayna_block_input;
 574                        ei_status.block_output = &dayna_block_output;
 575                        ei_status.get_8390_hdr = &dayna_get_8390_hdr;
 576                        ei_status.reg_offset = fwrd4_offsets;
 577                        break;
 578                case NS8390_CABLETRON: /* Cabletron */
 579                        /*              16 bit card, register map is short forward */
 580                        ei_status.reset_8390 = &ns8390_no_reset;
 581                        /* Ctron card won't accept 32bit values read or written to it */
 582                        ei_status.block_input = &slow_sane_block_input;
 583                        ei_status.block_output = &slow_sane_block_output;
 584                        ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
 585                        ei_status.reg_offset = fwrd2_offsets;
 586                        break;
 587                case NS8390_FARALLON:
 588                case NS8390_APPLE:      /* Apple/Asante/Farallon */
 589                        /*      16 bit card, register map is reversed */
 590                        ei_status.reset_8390 = &ns8390_no_reset;
 591                        ei_status.block_input = &slow_sane_block_input;
 592                        ei_status.block_output = &slow_sane_block_output;
 593                        ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
 594                        ei_status.reg_offset = back4_offsets;
 595                        break;
 596                case NS8390_ASANTE:
 597                        /*      16 bit card, register map is reversed */
 598                        ei_status.reset_8390 = &ns8390_no_reset;
 599                        ei_status.block_input = &sane_block_input;
 600                        ei_status.block_output = &sane_block_output;
 601                        ei_status.get_8390_hdr = &sane_get_8390_hdr;
 602                        ei_status.reg_offset = back4_offsets;
 603                        break;
 604                case NS8390_INTERLAN:   /* Interlan */
 605                        /*      16 bit card, map is forward */
 606                        ei_status.reset_8390 = &interlan_reset;
 607                        ei_status.block_input = &sane_block_input;
 608                        ei_status.block_output = &sane_block_output;
 609                        ei_status.get_8390_hdr = &sane_get_8390_hdr;
 610                        ei_status.reg_offset = back4_offsets;
 611                        break;
 612#if 0 /* i think this suffered code rot.  my kinetics card has much
 613           * different settings.  -- CSA [22-May-1999] */
 614                case NS8390_KINETICS:   /* Kinetics */
 615                        /*      8bit card, map is forward */
 616                        ei_status.reset_8390 = &ns8390_no_reset;
 617                        ei_status.block_input = &sane_block_input;
 618                        ei_status.block_output = &sane_block_output;
 619                        ei_status.get_8390_hdr = &sane_get_8390_hdr;
 620                        ei_status.reg_offset = back4_offsets;
 621                        break;
 622#endif
 623                default:
 624                        panic("Detected a card I can't drive - whoops\n");
 625        }
 626        dev->open = &ns8390_open;
 627        dev->stop = &ns8390_close_card;
 628
 629        NS8390_init(dev, 0);
 630
 631        return 0;
 632}
 633
 634static int ns8390_open(struct net_device *dev)
 635{
 636        int ret;
 637
 638        ei_open(dev);
 639
 640        /* At least on my card (a Focus Enhancements PDS card) I start */
 641        /* getting interrupts right away, so the driver needs to be    */
 642        /* completely initialized before enabling the interrupt.        */
 643        /*                             - funaho@jurai.org (1999-05-17) */
 644
 645        /* Non-slow interrupt, works around issues with the SONIC driver */
 646        ret = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev); 
 647        if (ret) {
 648                printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
 649                return ret;
 650        }
 651        return 0;
 652}
 653
 654static void ns8390_no_reset(struct net_device *dev)
 655{
 656        if (ei_debug > 1) 
 657                printk("Need to reset the NS8390 t=%lu...", jiffies);
 658        ei_status.txing = 0;
 659        if (ei_debug > 1) printk("reset not supported\n");
 660}
 661
 662static int ns8390_close_card(struct net_device *dev)
 663{
 664        if (ei_debug > 1)
 665                printk("%s: Shutting down ethercard.\n", dev->name);
 666        free_irq(dev->irq, dev);
 667        ei_close(dev);
 668        return 0;
 669}
 670
 671/*
 672 *    Interlan Specific Code Starts Here
 673 */
 674
 675static void interlan_reset(struct net_device *dev)
 676{
 677        unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq));
 678        if (ei_debug > 1) 
 679                printk("Need to reset the NS8390 t=%lu...", jiffies);
 680        ei_status.txing = 0;
 681        /* This write resets the card */
 682        target[0xC0000]=0;
 683        if (ei_debug > 1) printk("reset complete\n");
 684        return;
 685}
 686
 687/*
 688 *    Daynaport code (some is used by other drivers)
 689 */
 690
 691
 692/* Grab the 8390 specific header. Similar to the block_input routine, but
 693   we don't need to be concerned with ring wrap as the header will be at
 694   the start of a page, so we optimize accordingly. */
 695
 696
 697/* Block input and output are easy on shared memory ethercards, and trivial
 698   on the Daynaport card where there is no choice of how to do it.
 699   The only complications are that the ring buffer wraps.
 700*/
 701
 702static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
 703{
 704        volatile unsigned short *ptr;
 705        unsigned short *target=to;
 706        from<<=1;       /* word, skip overhead */
 707        ptr=(unsigned short *)(dev->mem_start+from);
 708        /*
 709         * Leading byte?
 710         */
 711        if (from&2) {
 712                *((char *)target)++ = *(((char *)ptr++)-1);
 713                count--;
 714        }
 715        while(count>=2)
 716        {
 717                *target++=*ptr++;       /* Copy and */
 718                ptr++;                  /* skip cruft */
 719                count-=2;
 720        }
 721        /*
 722         *      Trailing byte ?
 723         */
 724        if(count)
 725        {
 726                /* Big endian */
 727                unsigned short v=*ptr;
 728                *((char *)target)=v>>8;
 729        }
 730}
 731
 732static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count)
 733{
 734        volatile unsigned short *ptr;
 735        const unsigned short *src=from;
 736        to<<=1; /* word, skip overhead */
 737        ptr=(unsigned short *)(dev->mem_start+to);
 738        /*
 739         * Leading byte?
 740         */
 741        if (to&2) { /* avoid a byte write (stomps on other data) */
 742                ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++;
 743                ptr++;
 744                count--;
 745        }
 746        while(count>=2)
 747        {
 748                *ptr++=*src++;          /* Copy and */
 749                ptr++;                  /* skip cruft */
 750                count-=2;
 751        }
 752        /*
 753         *      Trailing byte ?
 754         */
 755        if(count)
 756        {
 757                /* Big endian */
 758                unsigned short v=*src;
 759                /* card doesn't like byte writes */
 760                *ptr=(*ptr&0x00FF)|(v&0xFF00);
 761        }
 762}
 763
 764static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 765{
 766        unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
 767        dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4);
 768        /* Register endianism - fix here rather than 8390.c */
 769        hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
 770}
 771
 772static void dayna_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
 773{
 774        unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
 775        unsigned long xfer_start = xfer_base+dev->mem_start;
 776
 777        /*
 778         *      Note the offset maths is done in card memory space which
 779         *      is word per long onto our space.
 780         */
 781         
 782        if (xfer_start + count > ei_status.rmem_end) 
 783        {
 784                /* We must wrap the input move. */
 785                int semi_count = ei_status.rmem_end - xfer_start;
 786                dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
 787                count -= semi_count;
 788                dayna_memcpy_fromcard(dev, skb->data + semi_count, 
 789                        ei_status.rmem_start - dev->mem_start, count);
 790        }
 791        else
 792        {
 793                dayna_memcpy_fromcard(dev, skb->data, xfer_base, count);
 794        }
 795}
 796
 797static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf,
 798                                int start_page)
 799{
 800        long shmem = (start_page - WD_START_PG)<<8;
 801        
 802        dayna_memcpy_tocard(dev, shmem, buf, count);
 803}
 804
 805/*
 806 *      Cards with full width memory
 807 */
 808
 809
 810static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 811{
 812        unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
 813        memcpy((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
 814        /* Register endianism - fix here rather than 8390.c */
 815        hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
 816}
 817
 818static void sane_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
 819{
 820        unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
 821        unsigned long xfer_start = xfer_base+dev->mem_start;
 822
 823        if (xfer_start + count > ei_status.rmem_end) 
 824        {
 825                /* We must wrap the input move. */
 826                int semi_count = ei_status.rmem_end - xfer_start;
 827                memcpy(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
 828                count -= semi_count;
 829                memcpy(skb->data + semi_count, 
 830                        (char *)ei_status.rmem_start, count);
 831        }
 832        else
 833        {
 834                memcpy(skb->data, (char *)dev->mem_start+xfer_base, count);
 835        }
 836}
 837
 838
 839static void sane_block_output(struct net_device *dev, int count, const unsigned char *buf,
 840                                int start_page)
 841{
 842        long shmem = (start_page - WD_START_PG)<<8;
 843        
 844        memcpy((char *)dev->mem_start+shmem, buf, count);
 845}
 846
 847static void word_memcpy_tocard(void *tp, const void *fp, int count)
 848{
 849        volatile unsigned short *to = tp;
 850        const unsigned short *from = fp;
 851        
 852        count++;
 853        count/=2;
 854        
 855        while(count--)
 856                *to++=*from++;
 857}
 858
 859static void word_memcpy_fromcard(void *tp, const void *fp, int count)
 860{
 861        unsigned short *to = tp;
 862        const volatile unsigned short *from = fp;
 863        
 864        count++;
 865        count/=2;
 866        
 867        while(count--)
 868                *to++=*from++;
 869}
 870
 871static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 872{
 873        unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
 874        word_memcpy_fromcard((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
 875        /* Register endianism - fix here rather than 8390.c */
 876        hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
 877}
 878
 879static void slow_sane_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
 880{
 881        unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
 882        unsigned long xfer_start = xfer_base+dev->mem_start;
 883
 884        if (xfer_start + count > ei_status.rmem_end) 
 885        {
 886                /* We must wrap the input move. */
 887                int semi_count = ei_status.rmem_end - xfer_start;
 888                word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
 889                count -= semi_count;
 890                word_memcpy_fromcard(skb->data + semi_count, 
 891                        (char *)ei_status.rmem_start, count);
 892        }
 893        else
 894        {
 895                word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, count);
 896        }
 897}
 898
 899static void slow_sane_block_output(struct net_device *dev, int count, const unsigned char *buf,
 900                                int start_page)
 901{
 902        long shmem = (start_page - WD_START_PG)<<8;
 903        
 904        word_memcpy_tocard((char *)dev->mem_start+shmem, buf, count);
 905#if 0
 906        long shmem = (start_page - WD_START_PG)<<8;
 907        volatile unsigned short *to=(unsigned short *)(dev->mem_start+shmem);
 908        volatile int p;
 909        unsigned short *bp=(unsigned short *)buf;
 910        
 911        count=(count+1)/2;
 912        
 913        while(count--)
 914        {
 915                *to++=*bp++;
 916                for(p=0;p<10;p++)
 917                        p++;
 918        }
 919#endif  
 920}
 921
 922MODULE_LICENSE("GPL");
 923
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.