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