linux/drivers/net/arcnet/com20020.c
<<
>>
Prefs
   1/*
   2 * Linux ARCnet driver - COM20020 chipset support
   3 * 
   4 * Written 1997 by David Woodhouse.
   5 * Written 1994-1999 by Avery Pennarun.
   6 * Written 1999 by Martin Mares <mj@ucw.cz>.
   7 * Derived from skeleton.c by Donald Becker.
   8 *
   9 * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
  10 *  for sponsoring the further development of this driver.
  11 *
  12 * **********************
  13 *
  14 * The original copyright of skeleton.c was as follows:
  15 *
  16 * skeleton.c Written 1993 by Donald Becker.
  17 * Copyright 1993 United States Government as represented by the
  18 * Director, National Security Agency.  This software may only be used
  19 * and distributed according to the terms of the GNU General Public License as
  20 * modified by SRC, incorporated herein by reference.
  21 *
  22 * **********************
  23 *
  24 * For more details, see drivers/net/arcnet.c
  25 *
  26 * **********************
  27 */
  28#include <linux/module.h>
  29#include <linux/kernel.h>
  30#include <linux/types.h>
  31#include <linux/ioport.h>
  32#include <linux/errno.h>
  33#include <linux/delay.h>
  34#include <linux/netdevice.h>
  35#include <linux/init.h>
  36#include <linux/interrupt.h>
  37#include <linux/arcdevice.h>
  38#include <linux/com20020.h>
  39
  40#include <asm/io.h>
  41
  42#define VERSION "arcnet: COM20020 chipset support (by David Woodhouse et al.)\n"
  43
  44static char *clockrates[] =
  45{"10 Mb/s", "Reserved", "5 Mb/s",
  46 "2.5 Mb/s", "1.25Mb/s", "625 Kb/s", "312.5 Kb/s",
  47 "156.25 Kb/s", "Reserved", "Reserved", "Reserved"};
  48
  49static void com20020_command(struct net_device *dev, int command);
  50static int com20020_status(struct net_device *dev);
  51static void com20020_setmask(struct net_device *dev, int mask);
  52static int com20020_reset(struct net_device *dev, int really_reset);
  53static void com20020_copy_to_card(struct net_device *dev, int bufnum,
  54                                  int offset, void *buf, int count);
  55static void com20020_copy_from_card(struct net_device *dev, int bufnum,
  56                                    int offset, void *buf, int count);
  57static void com20020_set_mc_list(struct net_device *dev);
  58static void com20020_close(struct net_device *);
  59
  60static void com20020_copy_from_card(struct net_device *dev, int bufnum,
  61                                    int offset, void *buf, int count)
  62{
  63        int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset;
  64
  65        /* set up the address register */
  66        outb((ofs >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
  67        outb(ofs & 0xff, _ADDR_LO);
  68
  69        /* copy the data */
  70        TIME("insb", count, insb(_MEMDATA, buf, count));
  71}
  72
  73
  74static void com20020_copy_to_card(struct net_device *dev, int bufnum,
  75                                  int offset, void *buf, int count)
  76{
  77        int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset;
  78
  79        /* set up the address register */
  80        outb((ofs >> 8) | AUTOINCflag, _ADDR_HI);
  81        outb(ofs & 0xff, _ADDR_LO);
  82
  83        /* copy the data */
  84        TIME("outsb", count, outsb(_MEMDATA, buf, count));
  85}
  86
  87
  88/* Reset the card and check some basic stuff during the detection stage. */
  89int com20020_check(struct net_device *dev)
  90{
  91        int ioaddr = dev->base_addr, status;
  92        struct arcnet_local *lp = netdev_priv(dev);
  93
  94        ARCRESET0;
  95        mdelay(RESETtime);
  96
  97        lp->setup = lp->clockm ? 0 : (lp->clockp << 1);
  98        lp->setup2 = (lp->clockm << 4) | 8;
  99
 100        /* CHECK: should we do this for SOHARD cards ? */
 101        /* Enable P1Mode for backplane mode */
 102        lp->setup = lp->setup | P1MODE;
 103
 104        SET_SUBADR(SUB_SETUP1);
 105        outb(lp->setup, _XREG);
 106
 107        if (lp->clockm != 0)
 108        {
 109                SET_SUBADR(SUB_SETUP2);
 110                outb(lp->setup2, _XREG);
 111        
 112                /* must now write the magic "restart operation" command */
 113                mdelay(1);
 114                outb(0x18, _COMMAND);
 115        }
 116
 117        lp->config = 0x21 | (lp->timeout << 3) | (lp->backplane << 2);
 118        /* set node ID to 0x42 (but transmitter is disabled, so it's okay) */
 119        SETCONF;
 120        outb(0x42, ioaddr + BUS_ALIGN*7);
 121
 122        status = ASTATUS();
 123
 124        if ((status & 0x99) != (NORXflag | TXFREEflag | RESETflag)) {
 125                BUGMSG(D_NORMAL, "status invalid (%Xh).\n", status);
 126                return -ENODEV;
 127        }
 128        BUGMSG(D_INIT_REASONS, "status after reset: %X\n", status);
 129
 130        /* Enable TX */
 131        outb(0x39, _CONFIG);
 132        outb(inb(ioaddr + BUS_ALIGN*8), ioaddr + BUS_ALIGN*7);
 133
 134        ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
 135
 136        status = ASTATUS();
 137        BUGMSG(D_INIT_REASONS, "status after reset acknowledged: %X\n",
 138               status);
 139
 140        /* Read first location of memory */
 141        outb(0 | RDDATAflag | AUTOINCflag, _ADDR_HI);
 142        outb(0, _ADDR_LO);
 143
 144        if ((status = inb(_MEMDATA)) != TESTvalue) {
 145                BUGMSG(D_NORMAL, "Signature byte not found (%02Xh != D1h).\n",
 146                       status);
 147                return -ENODEV;
 148        }
 149        return 0;
 150}
 151
 152const struct net_device_ops com20020_netdev_ops = {
 153        .ndo_open       = arcnet_open,
 154        .ndo_stop       = arcnet_close,
 155        .ndo_start_xmit = arcnet_send_packet,
 156        .ndo_tx_timeout = arcnet_timeout,
 157        .ndo_set_rx_mode = com20020_set_mc_list,
 158};
 159
 160/* Set up the struct net_device associated with this card.  Called after
 161 * probing succeeds.
 162 */
 163int com20020_found(struct net_device *dev, int shared)
 164{
 165        struct arcnet_local *lp;
 166        int ioaddr = dev->base_addr;
 167
 168        /* Initialize the rest of the device structure. */
 169
 170        lp = netdev_priv(dev);
 171
 172        lp->hw.owner = THIS_MODULE;
 173        lp->hw.command = com20020_command;
 174        lp->hw.status = com20020_status;
 175        lp->hw.intmask = com20020_setmask;
 176        lp->hw.reset = com20020_reset;
 177        lp->hw.copy_to_card = com20020_copy_to_card;
 178        lp->hw.copy_from_card = com20020_copy_from_card;
 179        lp->hw.close = com20020_close;
 180
 181        if (!dev->dev_addr[0])
 182                dev->dev_addr[0] = inb(ioaddr + BUS_ALIGN*8);   /* FIXME: do this some other way! */
 183
 184        SET_SUBADR(SUB_SETUP1);
 185        outb(lp->setup, _XREG);
 186
 187        if (lp->card_flags & ARC_CAN_10MBIT)
 188        {
 189                SET_SUBADR(SUB_SETUP2);
 190                outb(lp->setup2, _XREG);
 191        
 192                /* must now write the magic "restart operation" command */
 193                mdelay(1);
 194                outb(0x18, _COMMAND);
 195        }
 196
 197        lp->config = 0x20 | (lp->timeout << 3) | (lp->backplane << 2) | 1;
 198        /* Default 0x38 + register: Node ID */
 199        SETCONF;
 200        outb(dev->dev_addr[0], _XREG);
 201
 202        /* reserve the irq */
 203        if (request_irq(dev->irq, arcnet_interrupt, shared,
 204                        "arcnet (COM20020)", dev)) {
 205                BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
 206                return -ENODEV;
 207        }
 208
 209        dev->base_addr = ioaddr;
 210
 211        BUGMSG(D_NORMAL, "%s: station %02Xh found at %03lXh, IRQ %d.\n",
 212               lp->card_name, dev->dev_addr[0], dev->base_addr, dev->irq);
 213
 214        if (lp->backplane)
 215                BUGMSG(D_NORMAL, "Using backplane mode.\n");
 216
 217        if (lp->timeout != 3)
 218                BUGMSG(D_NORMAL, "Using extended timeout value of %d.\n", lp->timeout);
 219
 220        BUGMSG(D_NORMAL, "Using CKP %d - data rate %s.\n",
 221               lp->setup >> 1, 
 222               clockrates[3 - ((lp->setup2 & 0xF0) >> 4) + ((lp->setup & 0x0F) >> 1)]);
 223
 224        if (register_netdev(dev)) {
 225                free_irq(dev->irq, dev);
 226                return -EIO;
 227        }
 228        return 0;
 229}
 230
 231
 232/* 
 233 * Do a hardware reset on the card, and set up necessary registers.
 234 * 
 235 * This should be called as little as possible, because it disrupts the
 236 * token on the network (causes a RECON) and requires a significant delay.
 237 *
 238 * However, it does make sure the card is in a defined state.
 239 */
 240static int com20020_reset(struct net_device *dev, int really_reset)
 241{
 242        struct arcnet_local *lp = netdev_priv(dev);
 243        u_int ioaddr = dev->base_addr;
 244        u_char inbyte;
 245
 246        BUGMSG(D_DEBUG, "%s: %d: %s: dev: %p, lp: %p, dev->name: %s\n",
 247                __FILE__,__LINE__,__func__,dev,lp,dev->name);
 248        BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n",
 249               dev->name, ASTATUS());
 250
 251        BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 252        lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2);
 253        /* power-up defaults */
 254        SETCONF;
 255        BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 256
 257        if (really_reset) {
 258                /* reset the card */
 259                ARCRESET;
 260                mdelay(RESETtime * 2);  /* COM20020 seems to be slower sometimes */
 261        }
 262        /* clear flags & end reset */
 263        BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 264        ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
 265
 266        /* verify that the ARCnet signature byte is present */
 267        BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 268
 269        com20020_copy_from_card(dev, 0, 0, &inbyte, 1);
 270        BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 271        if (inbyte != TESTvalue) {
 272                BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 273                BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
 274                return 1;
 275        }
 276        /* enable extended (512-byte) packets */
 277        ACOMMAND(CONFIGcmd | EXTconf);
 278        BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
 279
 280        /* done!  return success. */
 281        return 0;
 282}
 283
 284
 285static void com20020_setmask(struct net_device *dev, int mask)
 286{
 287        u_int ioaddr = dev->base_addr;
 288        BUGMSG(D_DURING, "Setting mask to %x at %x\n",mask,ioaddr);
 289        AINTMASK(mask);
 290}
 291
 292
 293static void com20020_command(struct net_device *dev, int cmd)
 294{
 295        u_int ioaddr = dev->base_addr;
 296        ACOMMAND(cmd);
 297}
 298
 299
 300static int com20020_status(struct net_device *dev)
 301{
 302        u_int ioaddr = dev->base_addr;
 303
 304        return ASTATUS() + (ADIAGSTATUS()<<8);
 305}
 306
 307static void com20020_close(struct net_device *dev)
 308{
 309        struct arcnet_local *lp = netdev_priv(dev);
 310        int ioaddr = dev->base_addr;
 311
 312        /* disable transmitter */
 313        lp->config &= ~TXENcfg;
 314        SETCONF;
 315}
 316
 317/* Set or clear the multicast filter for this adaptor.
 318 * num_addrs == -1    Promiscuous mode, receive all packets
 319 * num_addrs == 0       Normal mode, clear multicast list
 320 * num_addrs > 0        Multicast mode, receive normal and MC packets, and do
 321 *                      best-effort filtering.
 322 *      FIXME - do multicast stuff, not just promiscuous.
 323 */
 324static void com20020_set_mc_list(struct net_device *dev)
 325{
 326        struct arcnet_local *lp = netdev_priv(dev);
 327        int ioaddr = dev->base_addr;
 328
 329        if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) {      /* Enable promiscuous mode */
 330                if (!(lp->setup & PROMISCset))
 331                        BUGMSG(D_NORMAL, "Setting promiscuous flag...\n");
 332                SET_SUBADR(SUB_SETUP1);
 333                lp->setup |= PROMISCset;
 334                outb(lp->setup, _XREG);
 335        } else
 336                /* Disable promiscuous mode, use normal mode */
 337        {
 338                if ((lp->setup & PROMISCset))
 339                        BUGMSG(D_NORMAL, "Resetting promiscuous flag...\n");
 340                SET_SUBADR(SUB_SETUP1);
 341                lp->setup &= ~PROMISCset;
 342                outb(lp->setup, _XREG);
 343        }
 344}
 345
 346#if defined(CONFIG_ARCNET_COM20020_PCI_MODULE) || \
 347    defined(CONFIG_ARCNET_COM20020_ISA_MODULE) || \
 348    defined(CONFIG_ARCNET_COM20020_CS_MODULE)
 349EXPORT_SYMBOL(com20020_check);
 350EXPORT_SYMBOL(com20020_found);
 351EXPORT_SYMBOL(com20020_netdev_ops);
 352#endif
 353
 354MODULE_LICENSE("GPL");
 355
 356#ifdef MODULE
 357
 358static int __init com20020_module_init(void)
 359{
 360        BUGLVL(D_NORMAL) printk(VERSION);
 361        return 0;
 362}
 363
 364static void __exit com20020_module_exit(void)
 365{
 366}
 367module_init(com20020_module_init);
 368module_exit(com20020_module_exit);
 369#endif                          /* MODULE */
 370