Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Linux ARCnet driver - COM20020 chipset support
0003  *
0004  * Written 1997 by David Woodhouse.
0005  * Written 1994-1999 by Avery Pennarun.
0006  * Written 1999 by Martin Mares <mj@ucw.cz>.
0007  * Derived from skeleton.c by Donald Becker.
0008  *
0009  * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
0010  *  for sponsoring the further development of this driver.
0011  *
0012  * **********************
0013  *
0014  * The original copyright of skeleton.c was as follows:
0015  *
0016  * skeleton.c Written 1993 by Donald Becker.
0017  * Copyright 1993 United States Government as represented by the
0018  * Director, National Security Agency.  This software may only be used
0019  * and distributed according to the terms of the GNU General Public License as
0020  * modified by SRC, incorporated herein by reference.
0021  *
0022  * **********************
0023  *
0024  * For more details, see drivers/net/arcnet.c
0025  *
0026  * **********************
0027  */
0028 
0029 #define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
0030 
0031 #include <linux/module.h>
0032 #include <linux/kernel.h>
0033 #include <linux/types.h>
0034 #include <linux/ioport.h>
0035 #include <linux/errno.h>
0036 #include <linux/delay.h>
0037 #include <linux/netdevice.h>
0038 #include <linux/init.h>
0039 #include <linux/interrupt.h>
0040 #include <linux/io.h>
0041 
0042 #include "arcdevice.h"
0043 #include "com20020.h"
0044 
0045 static const char * const clockrates[] = {
0046     "XXXXXXX", "XXXXXXXX", "XXXXXX", "2.5 Mb/s",
0047     "1.25Mb/s", "625 Kb/s", "312.5 Kb/s", "156.25 Kb/s",
0048     "Reserved", "Reserved", "Reserved"
0049 };
0050 
0051 static void com20020_command(struct net_device *dev, int command);
0052 static int com20020_status(struct net_device *dev);
0053 static void com20020_setmask(struct net_device *dev, int mask);
0054 static int com20020_reset(struct net_device *dev, int really_reset);
0055 static void com20020_copy_to_card(struct net_device *dev, int bufnum,
0056                   int offset, void *buf, int count);
0057 static void com20020_copy_from_card(struct net_device *dev, int bufnum,
0058                     int offset, void *buf, int count);
0059 static void com20020_set_mc_list(struct net_device *dev);
0060 static void com20020_close(struct net_device *);
0061 
0062 static void com20020_copy_from_card(struct net_device *dev, int bufnum,
0063                     int offset, void *buf, int count)
0064 {
0065     int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset;
0066 
0067     /* set up the address register */
0068     arcnet_outb((ofs >> 8) | RDDATAflag | AUTOINCflag,
0069             ioaddr, COM20020_REG_W_ADDR_HI);
0070     arcnet_outb(ofs & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);
0071 
0072     /* copy the data */
0073     TIME(dev, "insb", count,
0074          arcnet_insb(ioaddr, COM20020_REG_RW_MEMDATA, buf, count));
0075 }
0076 
0077 static void com20020_copy_to_card(struct net_device *dev, int bufnum,
0078                   int offset, void *buf, int count)
0079 {
0080     int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset;
0081 
0082     /* set up the address register */
0083     arcnet_outb((ofs >> 8) | AUTOINCflag, ioaddr, COM20020_REG_W_ADDR_HI);
0084     arcnet_outb(ofs & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);
0085 
0086     /* copy the data */
0087     TIME(dev, "outsb", count,
0088          arcnet_outsb(ioaddr, COM20020_REG_RW_MEMDATA, buf, count));
0089 }
0090 
0091 /* Reset the card and check some basic stuff during the detection stage. */
0092 int com20020_check(struct net_device *dev)
0093 {
0094     int ioaddr = dev->base_addr, status;
0095     struct arcnet_local *lp = netdev_priv(dev);
0096 
0097     arcnet_outb(XTOcfg(3) | RESETcfg, ioaddr, COM20020_REG_W_CONFIG);
0098     udelay(5);
0099     arcnet_outb(XTOcfg(3), ioaddr, COM20020_REG_W_CONFIG);
0100     mdelay(RESETtime);
0101 
0102     lp->setup = lp->clockm ? 0 : (lp->clockp << 1);
0103     lp->setup2 = (lp->clockm << 4) | 8;
0104 
0105     /* CHECK: should we do this for SOHARD cards ? */
0106     /* Enable P1Mode for backplane mode */
0107     lp->setup = lp->setup | P1MODE;
0108 
0109     com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);
0110     arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);
0111 
0112     if (lp->clockm != 0) {
0113         com20020_set_subaddress(lp, ioaddr, SUB_SETUP2);
0114         arcnet_outb(lp->setup2, ioaddr, COM20020_REG_W_XREG);
0115 
0116         /* must now write the magic "restart operation" command */
0117         mdelay(1);
0118         arcnet_outb(STARTIOcmd, ioaddr, COM20020_REG_W_COMMAND);
0119     }
0120 
0121     lp->config = (lp->timeout << 3) | (lp->backplane << 2) | SUB_NODE;
0122     /* set node ID to 0x42 (but transmitter is disabled, so it's okay) */
0123     arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
0124     arcnet_outb(0x42, ioaddr, COM20020_REG_W_XREG);
0125 
0126     status = arcnet_inb(ioaddr, COM20020_REG_R_STATUS);
0127 
0128     if ((status & 0x99) != (NORXflag | TXFREEflag | RESETflag)) {
0129         arc_printk(D_NORMAL, dev, "status invalid (%Xh).\n", status);
0130         return -ENODEV;
0131     }
0132     arc_printk(D_INIT_REASONS, dev, "status after reset: %X\n", status);
0133 
0134     arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,
0135             ioaddr, COM20020_REG_W_COMMAND);
0136     status = arcnet_inb(ioaddr, COM20020_REG_R_STATUS);
0137     arc_printk(D_INIT_REASONS, dev, "status after reset acknowledged: %X\n",
0138            status);
0139 
0140     /* Read first location of memory */
0141     arcnet_outb(0 | RDDATAflag | AUTOINCflag,
0142             ioaddr, COM20020_REG_W_ADDR_HI);
0143     arcnet_outb(0, ioaddr, COM20020_REG_W_ADDR_LO);
0144 
0145     status = arcnet_inb(ioaddr, COM20020_REG_RW_MEMDATA);
0146     if (status != TESTvalue) {
0147         arc_printk(D_NORMAL, dev, "Signature byte not found (%02Xh != D1h).\n",
0148                status);
0149         return -ENODEV;
0150     }
0151     return 0;
0152 }
0153 
0154 static int com20020_set_hwaddr(struct net_device *dev, void *addr)
0155 {
0156     int ioaddr = dev->base_addr;
0157     struct arcnet_local *lp = netdev_priv(dev);
0158     struct sockaddr *hwaddr = addr;
0159 
0160     dev_addr_set(dev, hwaddr->sa_data);
0161     com20020_set_subaddress(lp, ioaddr, SUB_NODE);
0162     arcnet_outb(dev->dev_addr[0], ioaddr, COM20020_REG_W_XREG);
0163 
0164     return 0;
0165 }
0166 
0167 static int com20020_netdev_open(struct net_device *dev)
0168 {
0169     int ioaddr = dev->base_addr;
0170     struct arcnet_local *lp = netdev_priv(dev);
0171 
0172     lp->config |= TXENcfg;
0173     arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
0174 
0175     return arcnet_open(dev);
0176 }
0177 
0178 static int com20020_netdev_close(struct net_device *dev)
0179 {
0180     int ioaddr = dev->base_addr;
0181     struct arcnet_local *lp = netdev_priv(dev);
0182 
0183     arcnet_close(dev);
0184 
0185     /* disable transmitter */
0186     lp->config &= ~TXENcfg;
0187     arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
0188     return 0;
0189 }
0190 
0191 const struct net_device_ops com20020_netdev_ops = {
0192     .ndo_open   = com20020_netdev_open,
0193     .ndo_stop   = com20020_netdev_close,
0194     .ndo_start_xmit = arcnet_send_packet,
0195     .ndo_tx_timeout = arcnet_timeout,
0196     .ndo_set_mac_address = com20020_set_hwaddr,
0197     .ndo_set_rx_mode = com20020_set_mc_list,
0198 };
0199 
0200 /* Set up the struct net_device associated with this card.  Called after
0201  * probing succeeds.
0202  */
0203 int com20020_found(struct net_device *dev, int shared)
0204 {
0205     struct arcnet_local *lp;
0206     int ioaddr = dev->base_addr;
0207 
0208     /* Initialize the rest of the device structure. */
0209 
0210     lp = netdev_priv(dev);
0211 
0212     lp->hw.owner = THIS_MODULE;
0213     lp->hw.command = com20020_command;
0214     lp->hw.status = com20020_status;
0215     lp->hw.intmask = com20020_setmask;
0216     lp->hw.reset = com20020_reset;
0217     lp->hw.copy_to_card = com20020_copy_to_card;
0218     lp->hw.copy_from_card = com20020_copy_from_card;
0219     lp->hw.close = com20020_close;
0220 
0221     /* FIXME: do this some other way! */
0222     if (!dev->dev_addr[0])
0223         arcnet_set_addr(dev, arcnet_inb(ioaddr, 8));
0224 
0225     com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);
0226     arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);
0227 
0228     if (lp->card_flags & ARC_CAN_10MBIT) {
0229         com20020_set_subaddress(lp, ioaddr, SUB_SETUP2);
0230         arcnet_outb(lp->setup2, ioaddr, COM20020_REG_W_XREG);
0231 
0232         /* must now write the magic "restart operation" command */
0233         mdelay(1);
0234         arcnet_outb(STARTIOcmd, ioaddr, COM20020_REG_W_COMMAND);
0235     }
0236 
0237     lp->config = (lp->timeout << 3) | (lp->backplane << 2) | SUB_NODE;
0238     /* Default 0x38 + register: Node ID */
0239     arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
0240     arcnet_outb(dev->dev_addr[0], ioaddr, COM20020_REG_W_XREG);
0241 
0242     /* reserve the irq */
0243     if (request_irq(dev->irq, arcnet_interrupt, shared,
0244             "arcnet (COM20020)", dev)) {
0245         arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", dev->irq);
0246         return -ENODEV;
0247     }
0248 
0249     arc_printk(D_NORMAL, dev, "%s: station %02Xh found at %03lXh, IRQ %d.\n",
0250            lp->card_name, dev->dev_addr[0], dev->base_addr, dev->irq);
0251 
0252     if (lp->backplane)
0253         arc_printk(D_NORMAL, dev, "Using backplane mode.\n");
0254 
0255     if (lp->timeout != 3)
0256         arc_printk(D_NORMAL, dev, "Using extended timeout value of %d\n",
0257                lp->timeout);
0258 
0259     arc_printk(D_NORMAL, dev, "Using CKP %d - data rate %s\n",
0260            lp->setup >> 1,
0261            clockrates[3 -
0262                   ((lp->setup2 & 0xF0) >> 4) +
0263                   ((lp->setup & 0x0F) >> 1)]);
0264             /* The clockrates array index looks very fragile.
0265              * It seems like it could have negative indexing.
0266              */
0267 
0268     if (register_netdev(dev)) {
0269         free_irq(dev->irq, dev);
0270         return -EIO;
0271     }
0272     return 0;
0273 }
0274 
0275 /* Do a hardware reset on the card, and set up necessary registers.
0276  *
0277  * This should be called as little as possible, because it disrupts the
0278  * token on the network (causes a RECON) and requires a significant delay.
0279  *
0280  * However, it does make sure the card is in a defined state.
0281  */
0282 static int com20020_reset(struct net_device *dev, int really_reset)
0283 {
0284     struct arcnet_local *lp = netdev_priv(dev);
0285     u_int ioaddr = dev->base_addr;
0286     u_char inbyte;
0287 
0288     arc_printk(D_DEBUG, dev, "%s: %d: %s: dev: %p, lp: %p, dev->name: %s\n",
0289            __FILE__, __LINE__, __func__, dev, lp, dev->name);
0290     arc_printk(D_INIT, dev, "Resetting %s (status=%02Xh)\n",
0291            dev->name, arcnet_inb(ioaddr, COM20020_REG_R_STATUS));
0292 
0293     arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
0294     lp->config |= (lp->timeout << 3) | (lp->backplane << 2);
0295     /* power-up defaults */
0296     arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
0297     arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
0298 
0299     if (really_reset) {
0300         /* reset the card */
0301         arcnet_outb(lp->config | RESETcfg, ioaddr, COM20020_REG_W_CONFIG);
0302         udelay(5);
0303         arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
0304         mdelay(RESETtime * 2);
0305                 /* COM20020 seems to be slower sometimes */
0306     }
0307     /* clear flags & end reset */
0308     arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
0309     arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,
0310             ioaddr, COM20020_REG_W_COMMAND);
0311 
0312     /* verify that the ARCnet signature byte is present */
0313     arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
0314 
0315     com20020_copy_from_card(dev, 0, 0, &inbyte, 1);
0316     arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
0317     if (inbyte != TESTvalue) {
0318         arc_printk(D_DEBUG, dev, "%s: %d: %s\n",
0319                __FILE__, __LINE__, __func__);
0320         arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n");
0321         return 1;
0322     }
0323     /* enable extended (512-byte) packets */
0324     arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM20020_REG_W_COMMAND);
0325 
0326     arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
0327 
0328     /* done!  return success. */
0329     return 0;
0330 }
0331 
0332 static void com20020_setmask(struct net_device *dev, int mask)
0333 {
0334     u_int ioaddr = dev->base_addr;
0335 
0336     arc_printk(D_DURING, dev, "Setting mask to %x at %x\n", mask, ioaddr);
0337     arcnet_outb(mask, ioaddr, COM20020_REG_W_INTMASK);
0338 }
0339 
0340 static void com20020_command(struct net_device *dev, int cmd)
0341 {
0342     u_int ioaddr = dev->base_addr;
0343 
0344     arcnet_outb(cmd, ioaddr, COM20020_REG_W_COMMAND);
0345 }
0346 
0347 static int com20020_status(struct net_device *dev)
0348 {
0349     u_int ioaddr = dev->base_addr;
0350 
0351     return arcnet_inb(ioaddr, COM20020_REG_R_STATUS) +
0352         (arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT) << 8);
0353 }
0354 
0355 static void com20020_close(struct net_device *dev)
0356 {
0357     struct arcnet_local *lp = netdev_priv(dev);
0358     int ioaddr = dev->base_addr;
0359 
0360     /* disable transmitter */
0361     lp->config &= ~TXENcfg;
0362     arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
0363 }
0364 
0365 /* Set or clear the multicast filter for this adaptor.
0366  * num_addrs == -1    Promiscuous mode, receive all packets
0367  * num_addrs == 0       Normal mode, clear multicast list
0368  * num_addrs > 0        Multicast mode, receive normal and MC packets, and do
0369  *                      best-effort filtering.
0370  *      FIXME - do multicast stuff, not just promiscuous.
0371  */
0372 static void com20020_set_mc_list(struct net_device *dev)
0373 {
0374     struct arcnet_local *lp = netdev_priv(dev);
0375     int ioaddr = dev->base_addr;
0376 
0377     if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) {
0378         /* Enable promiscuous mode */
0379         if (!(lp->setup & PROMISCset))
0380             arc_printk(D_NORMAL, dev, "Setting promiscuous flag...\n");
0381         com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);
0382         lp->setup |= PROMISCset;
0383         arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);
0384     } else {
0385         /* Disable promiscuous mode, use normal mode */
0386         if ((lp->setup & PROMISCset))
0387             arc_printk(D_NORMAL, dev, "Resetting promiscuous flag...\n");
0388         com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);
0389         lp->setup &= ~PROMISCset;
0390         arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);
0391     }
0392 }
0393 
0394 #if defined(CONFIG_ARCNET_COM20020_PCI_MODULE) || \
0395     defined(CONFIG_ARCNET_COM20020_ISA_MODULE) || \
0396     defined(CONFIG_ARCNET_COM20020_CS_MODULE)
0397 EXPORT_SYMBOL(com20020_check);
0398 EXPORT_SYMBOL(com20020_found);
0399 EXPORT_SYMBOL(com20020_netdev_ops);
0400 #endif
0401 
0402 MODULE_LICENSE("GPL");
0403 
0404 #ifdef MODULE
0405 
0406 static int __init com20020_module_init(void)
0407 {
0408     if (BUGLVL(D_NORMAL))
0409         pr_info("%s\n", "COM20020 chipset support (by David Woodhouse et al.)");
0410     return 0;
0411 }
0412 
0413 static void __exit com20020_module_exit(void)
0414 {
0415 }
0416 module_init(com20020_module_init);
0417 module_exit(com20020_module_exit);
0418 #endif              /* MODULE */