linux/drivers/net/arcnet/com20020_cs.c
<<
>>
Prefs
   1/*
   2 * Linux ARCnet driver - COM20020 PCMCIA support
   3 * 
   4 * Written 1994-1999 by Avery Pennarun,
   5 *    based on an ISA version by David Woodhouse.
   6 * Derived from ibmtr_cs.c by Steve Kipisz (pcmcia-cs 3.1.4)
   7 *    which was derived from pcnet_cs.c by David Hinds.
   8 * Some additional portions derived from skeleton.c by Donald Becker.
   9 *
  10 * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
  11 *  for sponsoring the further development of this driver.
  12 *
  13 * **********************
  14 *
  15 * The original copyright of skeleton.c was as follows:
  16 *
  17 * skeleton.c Written 1993 by Donald Becker.
  18 * Copyright 1993 United States Government as represented by the
  19 * Director, National Security Agency.  This software may only be used
  20 * and distributed according to the terms of the GNU General Public License as
  21 * modified by SRC, incorporated herein by reference.
  22 * 
  23 * **********************
  24 * Changes:
  25 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
  26 * - reorganize kmallocs in com20020_attach, checking all for failure
  27 *   and releasing the previous allocations if one fails
  28 * **********************
  29 * 
  30 * For more details, see drivers/net/arcnet.c
  31 *
  32 * **********************
  33 */
  34#include <linux/kernel.h>
  35#include <linux/init.h>
  36#include <linux/ptrace.h>
  37#include <linux/slab.h>
  38#include <linux/string.h>
  39#include <linux/timer.h>
  40#include <linux/delay.h>
  41#include <linux/module.h>
  42#include <linux/netdevice.h>
  43#include <linux/arcdevice.h>
  44#include <linux/com20020.h>
  45
  46#include <pcmcia/cistpl.h>
  47#include <pcmcia/ds.h>
  48
  49#include <asm/io.h>
  50
  51#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n"
  52
  53
  54static void regdump(struct net_device *dev)
  55{
  56#ifdef DEBUG
  57    int ioaddr = dev->base_addr;
  58    int count;
  59    
  60    netdev_dbg(dev, "register dump:\n");
  61    for (count = ioaddr; count < ioaddr + 16; count++)
  62    {
  63        if (!(count % 16))
  64            pr_cont("%04X:", count);
  65        pr_cont(" %02X", inb(count));
  66    }
  67    pr_cont("\n");
  68    
  69    netdev_dbg(dev, "buffer0 dump:\n");
  70        /* set up the address register */
  71        count = 0;
  72        outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
  73        outb(count & 0xff, _ADDR_LO);
  74    
  75    for (count = 0; count < 256+32; count++)
  76    {
  77        if (!(count % 16))
  78            pr_cont("%04X:", count);
  79        
  80        /* copy the data */
  81        pr_cont(" %02X", inb(_MEMDATA));
  82    }
  83    pr_cont("\n");
  84#endif
  85}
  86
  87
  88
  89/*====================================================================*/
  90
  91/* Parameters that can be set with 'insmod' */
  92
  93static int node;
  94static int timeout = 3;
  95static int backplane;
  96static int clockp;
  97static int clockm;
  98
  99module_param(node, int, 0);
 100module_param(timeout, int, 0);
 101module_param(backplane, int, 0);
 102module_param(clockp, int, 0);
 103module_param(clockm, int, 0);
 104
 105MODULE_LICENSE("GPL");
 106
 107/*====================================================================*/
 108
 109static int com20020_config(struct pcmcia_device *link);
 110static void com20020_release(struct pcmcia_device *link);
 111
 112static void com20020_detach(struct pcmcia_device *p_dev);
 113
 114/*====================================================================*/
 115
 116typedef struct com20020_dev_t {
 117    struct net_device       *dev;
 118} com20020_dev_t;
 119
 120static int com20020_probe(struct pcmcia_device *p_dev)
 121{
 122    com20020_dev_t *info;
 123    struct net_device *dev;
 124    struct arcnet_local *lp;
 125
 126    dev_dbg(&p_dev->dev, "com20020_attach()\n");
 127
 128    /* Create new network device */
 129    info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
 130    if (!info)
 131        goto fail_alloc_info;
 132
 133    dev = alloc_arcdev("");
 134    if (!dev)
 135        goto fail_alloc_dev;
 136
 137    lp = netdev_priv(dev);
 138    lp->timeout = timeout;
 139    lp->backplane = backplane;
 140    lp->clockp = clockp;
 141    lp->clockm = clockm & 3;
 142    lp->hw.owner = THIS_MODULE;
 143
 144    /* fill in our module parameters as defaults */
 145    dev->dev_addr[0] = node;
 146
 147    p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
 148    p_dev->resource[0]->end = 16;
 149    p_dev->config_flags |= CONF_ENABLE_IRQ;
 150
 151    info->dev = dev;
 152    p_dev->priv = info;
 153
 154    return com20020_config(p_dev);
 155
 156fail_alloc_dev:
 157    kfree(info);
 158fail_alloc_info:
 159    return -ENOMEM;
 160} /* com20020_attach */
 161
 162static void com20020_detach(struct pcmcia_device *link)
 163{
 164    struct com20020_dev_t *info = link->priv;
 165    struct net_device *dev = info->dev;
 166
 167    dev_dbg(&link->dev, "detach...\n");
 168
 169    dev_dbg(&link->dev, "com20020_detach\n");
 170
 171    dev_dbg(&link->dev, "unregister...\n");
 172
 173    unregister_netdev(dev);
 174
 175    /*
 176     * this is necessary because we register our IRQ separately
 177     * from card services.
 178     */
 179    if (dev->irq)
 180            free_irq(dev->irq, dev);
 181
 182    com20020_release(link);
 183
 184    /* Unlink device structure, free bits */
 185    dev_dbg(&link->dev, "unlinking...\n");
 186    if (link->priv)
 187    {
 188        dev = info->dev;
 189        if (dev)
 190        {
 191            dev_dbg(&link->dev, "kfree...\n");
 192            free_netdev(dev);
 193        }
 194        dev_dbg(&link->dev, "kfree2...\n");
 195        kfree(info);
 196    }
 197
 198} /* com20020_detach */
 199
 200static int com20020_config(struct pcmcia_device *link)
 201{
 202    struct arcnet_local *lp;
 203    com20020_dev_t *info;
 204    struct net_device *dev;
 205    int i, ret;
 206    int ioaddr;
 207
 208    info = link->priv;
 209    dev = info->dev;
 210
 211    dev_dbg(&link->dev, "config...\n");
 212
 213    dev_dbg(&link->dev, "com20020_config\n");
 214
 215    dev_dbg(&link->dev, "baseport1 is %Xh\n",
 216            (unsigned int) link->resource[0]->start);
 217
 218    i = -ENODEV;
 219    link->io_lines = 16;
 220
 221    if (!link->resource[0]->start)
 222    {
 223        for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
 224        {
 225            link->resource[0]->start = ioaddr;
 226            i = pcmcia_request_io(link);
 227            if (i == 0)
 228                break;
 229        }
 230    }
 231    else
 232        i = pcmcia_request_io(link);
 233    
 234    if (i != 0)
 235    {
 236        dev_dbg(&link->dev, "requestIO failed totally!\n");
 237        goto failed;
 238    }
 239        
 240    ioaddr = dev->base_addr = link->resource[0]->start;
 241    dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
 242
 243    dev_dbg(&link->dev, "request IRQ %d\n",
 244            link->irq);
 245    if (!link->irq)
 246    {
 247        dev_dbg(&link->dev, "requestIRQ failed totally!\n");
 248        goto failed;
 249    }
 250
 251    dev->irq = link->irq;
 252
 253    ret = pcmcia_enable_device(link);
 254    if (ret)
 255            goto failed;
 256
 257    if (com20020_check(dev))
 258    {
 259        regdump(dev);
 260        goto failed;
 261    }
 262    
 263    lp = netdev_priv(dev);
 264    lp->card_name = "PCMCIA COM20020";
 265    lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
 266
 267    SET_NETDEV_DEV(dev, &link->dev);
 268
 269    i = com20020_found(dev, 0); /* calls register_netdev */
 270    
 271    if (i != 0) {
 272        dev_notice(&link->dev,
 273                   "com20020_found() failed\n");
 274        goto failed;
 275    }
 276
 277    netdev_dbg(dev, "port %#3lx, irq %d\n",
 278               dev->base_addr, dev->irq);
 279    return 0;
 280
 281failed:
 282    dev_dbg(&link->dev, "com20020_config failed...\n");
 283    com20020_release(link);
 284    return -ENODEV;
 285} /* com20020_config */
 286
 287static void com20020_release(struct pcmcia_device *link)
 288{
 289        dev_dbg(&link->dev, "com20020_release\n");
 290        pcmcia_disable_device(link);
 291}
 292
 293static int com20020_suspend(struct pcmcia_device *link)
 294{
 295        com20020_dev_t *info = link->priv;
 296        struct net_device *dev = info->dev;
 297
 298        if (link->open)
 299                netif_device_detach(dev);
 300
 301        return 0;
 302}
 303
 304static int com20020_resume(struct pcmcia_device *link)
 305{
 306        com20020_dev_t *info = link->priv;
 307        struct net_device *dev = info->dev;
 308
 309        if (link->open) {
 310                int ioaddr = dev->base_addr;
 311                struct arcnet_local *lp = netdev_priv(dev);
 312                ARCRESET;
 313        }
 314
 315        return 0;
 316}
 317
 318static const struct pcmcia_device_id com20020_ids[] = {
 319        PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
 320                        "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
 321        PCMCIA_DEVICE_PROD_ID12("SoHard AG",
 322                        "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
 323        PCMCIA_DEVICE_NULL
 324};
 325MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
 326
 327static struct pcmcia_driver com20020_cs_driver = {
 328        .owner          = THIS_MODULE,
 329        .name           = "com20020_cs",
 330        .probe          = com20020_probe,
 331        .remove         = com20020_detach,
 332        .id_table       = com20020_ids,
 333        .suspend        = com20020_suspend,
 334        .resume         = com20020_resume,
 335};
 336module_pcmcia_driver(com20020_cs_driver);
 337