Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Linux ARCnet driver - COM20020 PCMCIA support
0003  *
0004  * Written 1994-1999 by Avery Pennarun,
0005  *    based on an ISA version by David Woodhouse.
0006  * Derived from ibmtr_cs.c by Steve Kipisz (pcmcia-cs 3.1.4)
0007  *    which was derived from pcnet_cs.c by David Hinds.
0008  * Some additional portions derived from skeleton.c by Donald Becker.
0009  *
0010  * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
0011  *  for sponsoring the further development of this driver.
0012  *
0013  * **********************
0014  *
0015  * The original copyright of skeleton.c was as follows:
0016  *
0017  * skeleton.c Written 1993 by Donald Becker.
0018  * Copyright 1993 United States Government as represented by the
0019  * Director, National Security Agency.  This software may only be used
0020  * and distributed according to the terms of the GNU General Public License as
0021  * modified by SRC, incorporated herein by reference.
0022  *
0023  * **********************
0024  * Changes:
0025  * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
0026  * - reorganize kmallocs in com20020_attach, checking all for failure
0027  *   and releasing the previous allocations if one fails
0028  * **********************
0029  *
0030  * For more details, see drivers/net/arcnet.c
0031  *
0032  * **********************
0033  */
0034 
0035 #define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
0036 
0037 #include <linux/kernel.h>
0038 #include <linux/ptrace.h>
0039 #include <linux/slab.h>
0040 #include <linux/string.h>
0041 #include <linux/timer.h>
0042 #include <linux/delay.h>
0043 #include <linux/module.h>
0044 #include <linux/netdevice.h>
0045 #include <linux/io.h>
0046 #include <pcmcia/cistpl.h>
0047 #include <pcmcia/ds.h>
0048 
0049 #include "arcdevice.h"
0050 #include "com20020.h"
0051 
0052 static void regdump(struct net_device *dev)
0053 {
0054 #ifdef DEBUG
0055     int ioaddr = dev->base_addr;
0056     int count;
0057 
0058     netdev_dbg(dev, "register dump:\n");
0059     for (count = 0; count < 16; count++) {
0060         if (!(count % 16))
0061             pr_cont("%04X:", ioaddr + count);
0062         pr_cont(" %02X", arcnet_inb(ioaddr, count));
0063     }
0064     pr_cont("\n");
0065 
0066     netdev_dbg(dev, "buffer0 dump:\n");
0067     /* set up the address register */
0068     count = 0;
0069     arcnet_outb((count >> 8) | RDDATAflag | AUTOINCflag,
0070             ioaddr, COM20020_REG_W_ADDR_HI);
0071     arcnet_outb(count & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);
0072 
0073     for (count = 0; count < 256 + 32; count++) {
0074         if (!(count % 16))
0075             pr_cont("%04X:", count);
0076 
0077         /* copy the data */
0078         pr_cont(" %02X", arcnet_inb(ioaddr, COM20020_REG_RW_MEMDATA));
0079     }
0080     pr_cont("\n");
0081 #endif
0082 }
0083 
0084 /*====================================================================*/
0085 
0086 /* Parameters that can be set with 'insmod' */
0087 
0088 static int node;
0089 static int timeout = 3;
0090 static int backplane;
0091 static int clockp;
0092 static int clockm;
0093 
0094 module_param(node, int, 0);
0095 module_param(timeout, int, 0);
0096 module_param(backplane, int, 0);
0097 module_param(clockp, int, 0);
0098 module_param(clockm, int, 0);
0099 
0100 MODULE_LICENSE("GPL");
0101 
0102 /*====================================================================*/
0103 
0104 static int com20020_config(struct pcmcia_device *link);
0105 static void com20020_release(struct pcmcia_device *link);
0106 
0107 static void com20020_detach(struct pcmcia_device *p_dev);
0108 
0109 /*====================================================================*/
0110 
0111 static int com20020_probe(struct pcmcia_device *p_dev)
0112 {
0113     struct com20020_dev *info;
0114     struct net_device *dev;
0115     struct arcnet_local *lp;
0116 
0117     dev_dbg(&p_dev->dev, "com20020_attach()\n");
0118 
0119     /* Create new network device */
0120     info = kzalloc(sizeof(*info), GFP_KERNEL);
0121     if (!info)
0122         goto fail_alloc_info;
0123 
0124     dev = alloc_arcdev("");
0125     if (!dev)
0126         goto fail_alloc_dev;
0127 
0128     lp = netdev_priv(dev);
0129     lp->timeout = timeout;
0130     lp->backplane = backplane;
0131     lp->clockp = clockp;
0132     lp->clockm = clockm & 3;
0133     lp->hw.owner = THIS_MODULE;
0134 
0135     /* fill in our module parameters as defaults */
0136     arcnet_set_addr(dev, node);
0137 
0138     p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
0139     p_dev->resource[0]->end = 16;
0140     p_dev->config_flags |= CONF_ENABLE_IRQ;
0141 
0142     info->dev = dev;
0143     p_dev->priv = info;
0144 
0145     return com20020_config(p_dev);
0146 
0147 fail_alloc_dev:
0148     kfree(info);
0149 fail_alloc_info:
0150     return -ENOMEM;
0151 } /* com20020_attach */
0152 
0153 static void com20020_detach(struct pcmcia_device *link)
0154 {
0155     struct com20020_dev *info = link->priv;
0156     struct net_device *dev = info->dev;
0157 
0158     dev_dbg(&link->dev, "detach...\n");
0159 
0160     dev_dbg(&link->dev, "com20020_detach\n");
0161 
0162     dev_dbg(&link->dev, "unregister...\n");
0163 
0164     unregister_netdev(dev);
0165 
0166     /* this is necessary because we register our IRQ separately
0167      * from card services.
0168      */
0169     if (dev->irq)
0170         free_irq(dev->irq, dev);
0171 
0172     com20020_release(link);
0173 
0174     /* Unlink device structure, free bits */
0175     dev_dbg(&link->dev, "unlinking...\n");
0176     if (link->priv) {
0177         dev = info->dev;
0178         if (dev) {
0179             dev_dbg(&link->dev, "kfree...\n");
0180             free_arcdev(dev);
0181         }
0182         dev_dbg(&link->dev, "kfree2...\n");
0183         kfree(info);
0184     }
0185 
0186 } /* com20020_detach */
0187 
0188 static int com20020_config(struct pcmcia_device *link)
0189 {
0190     struct arcnet_local *lp;
0191     struct com20020_dev *info;
0192     struct net_device *dev;
0193     int i, ret;
0194     int ioaddr;
0195 
0196     info = link->priv;
0197     dev = info->dev;
0198 
0199     dev_dbg(&link->dev, "config...\n");
0200 
0201     dev_dbg(&link->dev, "com20020_config\n");
0202 
0203     dev_dbg(&link->dev, "baseport1 is %Xh\n",
0204         (unsigned int)link->resource[0]->start);
0205 
0206     i = -ENODEV;
0207     link->io_lines = 16;
0208 
0209     if (!link->resource[0]->start) {
0210         for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) {
0211             link->resource[0]->start = ioaddr;
0212             i = pcmcia_request_io(link);
0213             if (i == 0)
0214                 break;
0215         }
0216     } else {
0217         i = pcmcia_request_io(link);
0218     }
0219 
0220     if (i != 0) {
0221         dev_dbg(&link->dev, "requestIO failed totally!\n");
0222         goto failed;
0223     }
0224 
0225     ioaddr = dev->base_addr = link->resource[0]->start;
0226     dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
0227 
0228     dev_dbg(&link->dev, "request IRQ %d\n",
0229         link->irq);
0230     if (!link->irq) {
0231         dev_dbg(&link->dev, "requestIRQ failed totally!\n");
0232         goto failed;
0233     }
0234 
0235     dev->irq = link->irq;
0236 
0237     ret = pcmcia_enable_device(link);
0238     if (ret)
0239         goto failed;
0240 
0241     if (com20020_check(dev)) {
0242         regdump(dev);
0243         goto failed;
0244     }
0245 
0246     lp = netdev_priv(dev);
0247     lp->card_name = "PCMCIA COM20020";
0248     lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
0249 
0250     SET_NETDEV_DEV(dev, &link->dev);
0251 
0252     i = com20020_found(dev, 0); /* calls register_netdev */
0253 
0254     if (i != 0) {
0255         dev_notice(&link->dev,
0256                "com20020_found() failed\n");
0257         goto failed;
0258     }
0259 
0260     netdev_dbg(dev, "port %#3lx, irq %d\n",
0261            dev->base_addr, dev->irq);
0262     return 0;
0263 
0264 failed:
0265     dev_dbg(&link->dev, "com20020_config failed...\n");
0266     com20020_release(link);
0267     return -ENODEV;
0268 } /* com20020_config */
0269 
0270 static void com20020_release(struct pcmcia_device *link)
0271 {
0272     dev_dbg(&link->dev, "com20020_release\n");
0273     pcmcia_disable_device(link);
0274 }
0275 
0276 static int com20020_suspend(struct pcmcia_device *link)
0277 {
0278     struct com20020_dev *info = link->priv;
0279     struct net_device *dev = info->dev;
0280 
0281     if (link->open)
0282         netif_device_detach(dev);
0283 
0284     return 0;
0285 }
0286 
0287 static int com20020_resume(struct pcmcia_device *link)
0288 {
0289     struct com20020_dev *info = link->priv;
0290     struct net_device *dev = info->dev;
0291 
0292     if (link->open) {
0293         int ioaddr = dev->base_addr;
0294         struct arcnet_local *lp = netdev_priv(dev);
0295 
0296         arcnet_outb(lp->config | 0x80, ioaddr, COM20020_REG_W_CONFIG);
0297         udelay(5);
0298         arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
0299     }
0300 
0301     return 0;
0302 }
0303 
0304 static const struct pcmcia_device_id com20020_ids[] = {
0305     PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
0306                 "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
0307     PCMCIA_DEVICE_PROD_ID12("SoHard AG",
0308                 "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
0309     PCMCIA_DEVICE_NULL
0310 };
0311 MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
0312 
0313 static struct pcmcia_driver com20020_cs_driver = {
0314     .owner      = THIS_MODULE,
0315     .name       = "com20020_cs",
0316     .probe      = com20020_probe,
0317     .remove     = com20020_detach,
0318     .id_table   = com20020_ids,
0319     .suspend    = com20020_suspend,
0320     .resume     = com20020_resume,
0321 };
0322 module_pcmcia_driver(com20020_cs_driver);