brintos

brintos / linux-shallow public Read only

0
0
Text · 12.8 KiB · a0053e3 Raw
420 lines · c
1/*2 * Linux ARCnet driver - COM20020 chipset support3 *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 the18 * Director, National Security Agency.  This software may only be used19 * and distributed according to the terms of the GNU General Public License as20 * modified by SRC, incorporated herein by reference.21 *22 * **********************23 *24 * For more details, see drivers/net/arcnet.c25 *26 * **********************27 */28 29#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt30 31#include <linux/module.h>32#include <linux/kernel.h>33#include <linux/types.h>34#include <linux/ioport.h>35#include <linux/errno.h>36#include <linux/delay.h>37#include <linux/netdevice.h>38#include <linux/init.h>39#include <linux/interrupt.h>40#include <linux/io.h>41 42#include "arcdevice.h"43#include "com20020.h"44 45static const char * const clockrates[] = {46	"XXXXXXX", "XXXXXXXX", "XXXXXX", "2.5 Mb/s",47	"1.25Mb/s", "625 Kb/s", "312.5 Kb/s", "156.25 Kb/s",48	"Reserved", "Reserved", "Reserved"49};50 51static void com20020_command(struct net_device *dev, int command);52static int com20020_status(struct net_device *dev);53static void com20020_setmask(struct net_device *dev, int mask);54static int com20020_reset(struct net_device *dev, int really_reset);55static void com20020_copy_to_card(struct net_device *dev, int bufnum,56				  int offset, void *buf, int count);57static void com20020_copy_from_card(struct net_device *dev, int bufnum,58				    int offset, void *buf, int count);59static void com20020_set_mc_list(struct net_device *dev);60static void com20020_close(struct net_device *);61 62static void com20020_copy_from_card(struct net_device *dev, int bufnum,63				    int offset, void *buf, int count)64{65	int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset;66 67	/* set up the address register */68	arcnet_outb((ofs >> 8) | RDDATAflag | AUTOINCflag,69		    ioaddr, COM20020_REG_W_ADDR_HI);70	arcnet_outb(ofs & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);71 72	/* copy the data */73	TIME(dev, "insb", count,74	     arcnet_insb(ioaddr, COM20020_REG_RW_MEMDATA, buf, count));75}76 77static void com20020_copy_to_card(struct net_device *dev, int bufnum,78				  int offset, void *buf, int count)79{80	int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset;81 82	/* set up the address register */83	arcnet_outb((ofs >> 8) | AUTOINCflag, ioaddr, COM20020_REG_W_ADDR_HI);84	arcnet_outb(ofs & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);85 86	/* copy the data */87	TIME(dev, "outsb", count,88	     arcnet_outsb(ioaddr, COM20020_REG_RW_MEMDATA, buf, count));89}90 91/* Reset the card and check some basic stuff during the detection stage. */92int com20020_check(struct net_device *dev)93{94	int ioaddr = dev->base_addr, status;95	struct arcnet_local *lp = netdev_priv(dev);96 97	arcnet_outb(XTOcfg(3) | RESETcfg, ioaddr, COM20020_REG_W_CONFIG);98	udelay(5);99	arcnet_outb(XTOcfg(3), ioaddr, COM20020_REG_W_CONFIG);100	mdelay(RESETtime);101 102	lp->setup = lp->clockm ? 0 : (lp->clockp << 1);103	lp->setup2 = (lp->clockm << 4) | 8;104 105	/* CHECK: should we do this for SOHARD cards ? */106	/* Enable P1Mode for backplane mode */107	lp->setup = lp->setup | P1MODE;108 109	com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);110	arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);111 112	if (lp->clockm != 0) {113		com20020_set_subaddress(lp, ioaddr, SUB_SETUP2);114		arcnet_outb(lp->setup2, ioaddr, COM20020_REG_W_XREG);115 116		/* must now write the magic "restart operation" command */117		mdelay(1);118		arcnet_outb(STARTIOcmd, ioaddr, COM20020_REG_W_COMMAND);119	}120 121	lp->config = (lp->timeout << 3) | (lp->backplane << 2) | SUB_NODE;122	/* set node ID to 0x42 (but transmitter is disabled, so it's okay) */123	arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);124	arcnet_outb(0x42, ioaddr, COM20020_REG_W_XREG);125 126	status = arcnet_inb(ioaddr, COM20020_REG_R_STATUS);127 128	if ((status & 0x99) != (NORXflag | TXFREEflag | RESETflag)) {129		arc_printk(D_NORMAL, dev, "status invalid (%Xh).\n", status);130		return -ENODEV;131	}132	arc_printk(D_INIT_REASONS, dev, "status after reset: %X\n", status);133 134	arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,135		    ioaddr, COM20020_REG_W_COMMAND);136	status = arcnet_inb(ioaddr, COM20020_REG_R_STATUS);137	arc_printk(D_INIT_REASONS, dev, "status after reset acknowledged: %X\n",138		   status);139 140	/* Read first location of memory */141	arcnet_outb(0 | RDDATAflag | AUTOINCflag,142		    ioaddr, COM20020_REG_W_ADDR_HI);143	arcnet_outb(0, ioaddr, COM20020_REG_W_ADDR_LO);144 145	status = arcnet_inb(ioaddr, COM20020_REG_RW_MEMDATA);146	if (status != TESTvalue) {147		arc_printk(D_NORMAL, dev, "Signature byte not found (%02Xh != D1h).\n",148			   status);149		return -ENODEV;150	}151	return 0;152}153 154static int com20020_set_hwaddr(struct net_device *dev, void *addr)155{156	int ioaddr = dev->base_addr;157	struct arcnet_local *lp = netdev_priv(dev);158	struct sockaddr *hwaddr = addr;159 160	dev_addr_set(dev, hwaddr->sa_data);161	com20020_set_subaddress(lp, ioaddr, SUB_NODE);162	arcnet_outb(dev->dev_addr[0], ioaddr, COM20020_REG_W_XREG);163 164	return 0;165}166 167static int com20020_netdev_open(struct net_device *dev)168{169	int ioaddr = dev->base_addr;170	struct arcnet_local *lp = netdev_priv(dev);171 172	lp->config |= TXENcfg;173	arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);174 175	return arcnet_open(dev);176}177 178static int com20020_netdev_close(struct net_device *dev)179{180	int ioaddr = dev->base_addr;181	struct arcnet_local *lp = netdev_priv(dev);182 183	arcnet_close(dev);184 185	/* disable transmitter */186	lp->config &= ~TXENcfg;187	arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);188	return 0;189}190 191const struct net_device_ops com20020_netdev_ops = {192	.ndo_open	= com20020_netdev_open,193	.ndo_stop	= com20020_netdev_close,194	.ndo_start_xmit = arcnet_send_packet,195	.ndo_tx_timeout = arcnet_timeout,196	.ndo_set_mac_address = com20020_set_hwaddr,197	.ndo_set_rx_mode = com20020_set_mc_list,198};199 200/* Set up the struct net_device associated with this card.  Called after201 * probing succeeds.202 */203int com20020_found(struct net_device *dev, int shared)204{205	struct arcnet_local *lp;206	int ioaddr = dev->base_addr;207 208	/* Initialize the rest of the device structure. */209 210	lp = netdev_priv(dev);211 212	lp->hw.owner = THIS_MODULE;213	lp->hw.command = com20020_command;214	lp->hw.status = com20020_status;215	lp->hw.intmask = com20020_setmask;216	lp->hw.reset = com20020_reset;217	lp->hw.copy_to_card = com20020_copy_to_card;218	lp->hw.copy_from_card = com20020_copy_from_card;219	lp->hw.close = com20020_close;220 221	/* FIXME: do this some other way! */222	if (!dev->dev_addr[0])223		arcnet_set_addr(dev, arcnet_inb(ioaddr, 8));224 225	com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);226	arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);227 228	if (lp->card_flags & ARC_CAN_10MBIT) {229		com20020_set_subaddress(lp, ioaddr, SUB_SETUP2);230		arcnet_outb(lp->setup2, ioaddr, COM20020_REG_W_XREG);231 232		/* must now write the magic "restart operation" command */233		mdelay(1);234		arcnet_outb(STARTIOcmd, ioaddr, COM20020_REG_W_COMMAND);235	}236 237	lp->config = (lp->timeout << 3) | (lp->backplane << 2) | SUB_NODE;238	/* Default 0x38 + register: Node ID */239	arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);240	arcnet_outb(dev->dev_addr[0], ioaddr, COM20020_REG_W_XREG);241 242	/* reserve the irq */243	if (request_irq(dev->irq, arcnet_interrupt, shared,244			"arcnet (COM20020)", dev)) {245		arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", dev->irq);246		return -ENODEV;247	}248 249	arc_printk(D_NORMAL, dev, "%s: station %02Xh found at %03lXh, IRQ %d.\n",250		   lp->card_name, dev->dev_addr[0], dev->base_addr, dev->irq);251 252	if (lp->backplane)253		arc_printk(D_NORMAL, dev, "Using backplane mode.\n");254 255	if (lp->timeout != 3)256		arc_printk(D_NORMAL, dev, "Using extended timeout value of %d\n",257			   lp->timeout);258 259	arc_printk(D_NORMAL, dev, "Using CKP %d - data rate %s\n",260		   lp->setup >> 1,261		   clockrates[3 -262			      ((lp->setup2 & 0xF0) >> 4) +263			      ((lp->setup & 0x0F) >> 1)]);264			/* The clockrates array index looks very fragile.265			 * It seems like it could have negative indexing.266			 */267 268	if (register_netdev(dev)) {269		free_irq(dev->irq, dev);270		return -EIO;271	}272	return 0;273}274 275/* Do a hardware reset on the card, and set up necessary registers.276 *277 * This should be called as little as possible, because it disrupts the278 * token on the network (causes a RECON) and requires a significant delay.279 *280 * However, it does make sure the card is in a defined state.281 */282static int com20020_reset(struct net_device *dev, int really_reset)283{284	struct arcnet_local *lp = netdev_priv(dev);285	u_int ioaddr = dev->base_addr;286	u_char inbyte;287 288	arc_printk(D_DEBUG, dev, "%s: %d: %s: dev: %p, lp: %p, dev->name: %s\n",289		   __FILE__, __LINE__, __func__, dev, lp, dev->name);290	arc_printk(D_INIT, dev, "Resetting %s (status=%02Xh)\n",291		   dev->name, arcnet_inb(ioaddr, COM20020_REG_R_STATUS));292 293	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);294	lp->config |= (lp->timeout << 3) | (lp->backplane << 2);295	/* power-up defaults */296	arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);297	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);298 299	if (really_reset) {300		/* reset the card */301		arcnet_outb(lp->config | RESETcfg, ioaddr, COM20020_REG_W_CONFIG);302		udelay(5);303		arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);304		mdelay(RESETtime * 2);305				/* COM20020 seems to be slower sometimes */306	}307	/* clear flags & end reset */308	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);309	arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,310		    ioaddr, COM20020_REG_W_COMMAND);311 312	/* verify that the ARCnet signature byte is present */313	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);314 315	com20020_copy_from_card(dev, 0, 0, &inbyte, 1);316	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);317	if (inbyte != TESTvalue) {318		arc_printk(D_DEBUG, dev, "%s: %d: %s\n",319			   __FILE__, __LINE__, __func__);320		arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n");321		return 1;322	}323	/* enable extended (512-byte) packets */324	arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM20020_REG_W_COMMAND);325 326	arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);327 328	/* done!  return success. */329	return 0;330}331 332static void com20020_setmask(struct net_device *dev, int mask)333{334	u_int ioaddr = dev->base_addr;335 336	arc_printk(D_DURING, dev, "Setting mask to %x at %x\n", mask, ioaddr);337	arcnet_outb(mask, ioaddr, COM20020_REG_W_INTMASK);338}339 340static void com20020_command(struct net_device *dev, int cmd)341{342	u_int ioaddr = dev->base_addr;343 344	arcnet_outb(cmd, ioaddr, COM20020_REG_W_COMMAND);345}346 347static int com20020_status(struct net_device *dev)348{349	u_int ioaddr = dev->base_addr;350 351	return arcnet_inb(ioaddr, COM20020_REG_R_STATUS) +352		(arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT) << 8);353}354 355static void com20020_close(struct net_device *dev)356{357	struct arcnet_local *lp = netdev_priv(dev);358	int ioaddr = dev->base_addr;359 360	/* disable transmitter */361	lp->config &= ~TXENcfg;362	arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);363}364 365/* Set or clear the multicast filter for this adaptor.366 * num_addrs == -1    Promiscuous mode, receive all packets367 * num_addrs == 0       Normal mode, clear multicast list368 * num_addrs > 0        Multicast mode, receive normal and MC packets, and do369 *                      best-effort filtering.370 *      FIXME - do multicast stuff, not just promiscuous.371 */372static void com20020_set_mc_list(struct net_device *dev)373{374	struct arcnet_local *lp = netdev_priv(dev);375	int ioaddr = dev->base_addr;376 377	if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) {378		/* Enable promiscuous mode */379		if (!(lp->setup & PROMISCset))380			arc_printk(D_NORMAL, dev, "Setting promiscuous flag...\n");381		com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);382		lp->setup |= PROMISCset;383		arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);384	} else {385		/* Disable promiscuous mode, use normal mode */386		if ((lp->setup & PROMISCset))387			arc_printk(D_NORMAL, dev, "Resetting promiscuous flag...\n");388		com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);389		lp->setup &= ~PROMISCset;390		arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);391	}392}393 394#if defined(CONFIG_ARCNET_COM20020_PCI_MODULE) || \395    defined(CONFIG_ARCNET_COM20020_ISA_MODULE) || \396    defined(CONFIG_ARCNET_COM20020_CS_MODULE)397EXPORT_SYMBOL(com20020_check);398EXPORT_SYMBOL(com20020_found);399EXPORT_SYMBOL(com20020_netdev_ops);400#endif401 402MODULE_DESCRIPTION("ARCnet COM20020 chipset core driver");403MODULE_LICENSE("GPL");404 405#ifdef MODULE406 407static int __init com20020_module_init(void)408{409	if (BUGLVL(D_NORMAL))410		pr_info("%s\n", "COM20020 chipset support (by David Woodhouse et al.)");411	return 0;412}413 414static void __exit com20020_module_exit(void)415{416}417module_init(com20020_module_init);418module_exit(com20020_module_exit);419#endif				/* MODULE */420