⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ibmlana.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
				priv->stat.rx_bytes += rda.length;#endif				/* pass to the upper layers */				netif_rx(skb);			}		}		/* otherwise check error status bits and increase statistics */		else {			priv->stat.rx_errors++;			if (rda.status & RCREG_FAER)				priv->stat.rx_frame_errors++;			if (rda.status & RCREG_CRCR)				priv->stat.rx_crc_errors++;		}		/* descriptor processed, will become new last descriptor in queue */		rda.link = 1;		rda.inuse = 1;		IBMLANA_TOIO(dev->mem_start + rdaaddr, &rda,			     sizeof(rda_t));		/* set up link and EOL = 0 in currently last descriptor. Only write		   the link field since the SONIC may currently already access the		   other fields. */		IBMLANA_TOIO(dev->mem_start + lrdaaddr + 20, &rdaaddr, 4);		/* advance indices */		priv->lastrxdescr = priv->nextrxdescr;		if ((++priv->nextrxdescr) >= priv->rxbufcnt)			priv->nextrxdescr = 0;	}}/* transmit interrupt */static void irqtx_handler(struct IBMLANA_NETDEV *dev){	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;	tda_t tda;	/* fetch descriptor (we forgot the size ;-) */	IBMLANA_FROMIO(&tda,		       dev->mem_start + priv->tdastart +		       (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));	/* update statistics */	priv->stat.tx_packets++;#if (LINUX_VERSION_CODE >= 0x020119)	priv->stat.tx_bytes += tda.length;#endif	/* update our pointers */	priv->txused[priv->currtxdescr] = 0;	priv->txusedcnt--;	/* if there are more descriptors present in RAM, start them */	if (priv->txusedcnt > 0)		StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT);	/* tell the upper layer we can go on transmitting */#if LINUX_VERSION_CODE >= 0x02032a	netif_wake_queue(dev);#else	dev->tbusy = 0;	mark_bh(NET_BH);#endif}static void irqtxerr_handler(struct IBMLANA_NETDEV *dev){	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;	tda_t tda;	/* fetch descriptor to check status */	IBMLANA_FROMIO(&tda,		       dev->mem_start + priv->tdastart +		       (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));	/* update statistics */	priv->stat.tx_errors++;	if (tda.status & (TCREG_NCRS | TCREG_CRSL))		priv->stat.tx_carrier_errors++;	if (tda.status & TCREG_EXC)		priv->stat.tx_aborted_errors++;	if (tda.status & TCREG_OWC)		priv->stat.tx_window_errors++;	if (tda.status & TCREG_FU)		priv->stat.tx_fifo_errors++;	/* update our pointers */	priv->txused[priv->currtxdescr] = 0;	priv->txusedcnt--;	/* if there are more descriptors present in RAM, start them */	if (priv->txusedcnt > 0)		StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT);	/* tell the upper layer we can go on transmitting */#if LINUX_VERSION_CODE >= 0x02032a	netif_wake_queue(dev);#else	dev->tbusy = 0;	mark_bh(NET_BH);#endif}/* general interrupt entry */static void irq_handler(int irq, void *device, struct pt_regs *regs){	struct IBMLANA_NETDEV *dev = (struct IBMLANA_NETDEV *) device;	u16 ival;	/* in case we're not meant... */	if (!(inb(dev->base_addr + BCMREG) & BCMREG_IPEND))		return;#if (LINUX_VERSION_CODE >= 0x02032a)#if 0	set_bit(LINK_STATE_RXSEM, &dev->state);#endif#else	dev->interrupt = 1;#endif	/* loop through the interrupt bits until everything is clear */	while (1) {		ival = inw(dev->base_addr + SONIC_ISREG);		if (ival & ISREG_RBE) {			irqrbe_handler(dev);			outw(ISREG_RBE, dev->base_addr + SONIC_ISREG);		}		if (ival & ISREG_PKTRX) {			irqrx_handler(dev);			outw(ISREG_PKTRX, dev->base_addr + SONIC_ISREG);		}		if (ival & ISREG_TXDN) {			irqtx_handler(dev);			outw(ISREG_TXDN, dev->base_addr + SONIC_ISREG);		}		if (ival & ISREG_TXER) {			irqtxerr_handler(dev);			outw(ISREG_TXER, dev->base_addr + SONIC_ISREG);		}		break;	}#if (LINUX_VERSION_CODE >= 0x02032a)#if 0	clear_bit(LINK_STATE_RXSEM, &dev->state);#endif#else	dev->interrupt = 0;#endif}/* ------------------------------------------------------------------------ * driver methods * ------------------------------------------------------------------------ *//* MCA info */static int ibmlana_getinfo(char *buf, int slot, void *d){	int len = 0, i;	struct IBMLANA_NETDEV *dev = (struct IBMLANA_NETDEV *) d;	ibmlana_priv *priv;	/* can't say anything about an uninitialized device... */	if (dev == NULL)		return len;	if (dev->priv == NULL)		return len;	priv = (ibmlana_priv *) dev->priv;	/* print info */	len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);	len += sprintf(buf + len, "I/O: %#lx\n", dev->base_addr);	len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,		       dev->mem_end - 1);	len +=	    sprintf(buf + len, "Transceiver: %s\n",		    MediaNames[priv->medium]);	len += sprintf(buf + len, "Device: %s\n", dev->name);	len += sprintf(buf + len, "MAC address:");	for (i = 0; i < 6; i++)		len += sprintf(buf + len, " %02x", dev->dev_addr[i]);	buf[len++] = '\n';	buf[len] = 0;	return len;}/* open driver.  Means also initialization and start of LANCE */static int ibmlana_open(struct IBMLANA_NETDEV *dev){	int result;	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;	/* register resources - only necessary for IRQ */	result =	    request_irq(priv->realirq, irq_handler,			SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);	if (result != 0) {		printk("%s: failed to register irq %d\n", dev->name,		       dev->irq);		return result;	}	dev->irq = priv->realirq;	/* set up the card and SONIC */	InitBoard(dev);	/* initialize operational flags */#if (LINUX_VERSION_CODE >= 0x02032a)	netif_start_queue(dev);#else	dev->interrupt = 0;	dev->tbusy = 0;	dev->start = 1;	MOD_INC_USE_COUNT;#endif	return 0;}/* close driver.  Shut down board and free allocated resources */static int ibmlana_close(struct IBMLANA_NETDEV *dev){	/* turn off board */	/* release resources */	if (dev->irq != 0)		free_irq(dev->irq, dev);	dev->irq = 0;#if (LINUX_VERSION_CODE < 0x02032a)	MOD_DEC_USE_COUNT;#endif	return 0;}/* transmit a block. */static int ibmlana_tx(struct sk_buff *skb, struct IBMLANA_NETDEV *dev){	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;	int retval = 0, tmplen, addr;	unsigned long flags;	tda_t tda;	int baddr;	/* if we get called with a NULL descriptor, the Ethernet layer thinks 	   our card is stuck an we should reset it.  We'll do this completely: */	if (skb == NULL) {		printk("%s: Resetting SONIC\n", dev->name);		StopSONIC(dev);		InitBoard(dev);		return 0;	/* don't try to free the block here ;-) */	}	/* find out if there are free slots for a frame to transmit. If not,	   the upper layer is in deep desperation and we simply ignore the frame. */	if (priv->txusedcnt >= TXBUFCNT) {		retval = -EIO;		priv->stat.tx_dropped++;		goto tx_done;	}	/* copy the frame data into the next free transmit buffer - fillup missing */	tmplen = skb->len;	if (tmplen < 60)		tmplen = 60;	baddr = priv->txbufstart + (priv->nexttxdescr * PKTSIZE);	IBMLANA_TOIO(dev->mem_start + baddr, skb->data, skb->len);	/* copy filler into RAM - in case we're filling up... 	   we're filling a bit more than necessary, but that doesn't harm	   since the buffer is far larger... 	   Sorry Linus for the filler string but I couldn't resist ;-) */	if (tmplen > skb->len) {		char *fill = "NetBSD is a nice OS too! ";		unsigned int destoffs = skb->len, l = strlen(fill);		while (destoffs < tmplen) {			IBMLANA_TOIO(dev->mem_start + baddr + destoffs,				     fill, l);			destoffs += l;		}	}	/* set up the new frame descriptor */	addr = priv->tdastart + (priv->nexttxdescr * sizeof(tda_t));	IBMLANA_FROMIO(&tda, dev->mem_start + addr, sizeof(tda_t));	tda.length = tda.fraglength = tmplen;	IBMLANA_TOIO(dev->mem_start + addr, &tda, sizeof(tda_t));	/* if there were no active descriptors, trigger the SONIC */	save_flags(flags);	cli();	priv->txusedcnt++;	priv->txused[priv->nexttxdescr] = 1;	/* are all transmission slots used up ? */	if (priv->txusedcnt >= TXBUFCNT)#if (LINUX_VERSION_CODE >= 0x02032a)		netif_stop_queue(dev);#else		dev->tbusy = 1;#endif	if (priv->txusedcnt == 1)		StartTx(dev, priv->nexttxdescr);	priv->nexttxdescr = (priv->nexttxdescr + 1) % TXBUFCNT;	restore_flags(flags);      tx_done:	/* When did that change exactly ? */#if (LINUX_VERSION_CODE >= 0x20200)	dev_kfree_skb(skb);#else	dev_kfree_skb(skb, FREE_WRITE);#endif	return retval;}/* return pointer to Ethernet statistics */static struct net_device_stats *ibmlana_stats(struct IBMLANA_NETDEV *dev){	ibmlana_priv *priv = (ibmlana_priv *) dev->priv;	return &(priv->stat);}/* we don't support runtime reconfiguration, since am MCA card can   be unambigously identified by its POS registers. */static int ibmlana_config(struct IBMLANA_NETDEV *dev, struct ifmap *map){	return 0;}/* switch receiver mode. */static void ibmlana_set_multicast_list(struct IBMLANA_NETDEV *dev){	/* first stop the SONIC... */	StopSONIC(dev);	/* ...then reinit it with the new flags */	InitBoard(dev);}/* ------------------------------------------------------------------------ * hardware check * ------------------------------------------------------------------------ */static int startslot;		/* counts through slots when probing multiple devices */int ibmlana_probe(struct IBMLANA_NETDEV *dev){	int force_detect = 0;	int slot, z;	int base = 0, irq = 0, iobase = 0, memlen = 0;	ibmlana_priv *priv;	ibmlana_medium medium;#if (LINUX_VERSION_CODE >= 0x02032a)	SET_MODULE_OWNER(dev);#endif	/* can't work without an MCA bus ;-) */	if (MCA_bus == 0)		return -ENODEV;	/* start address of 1 --> forced detection */	if (dev->mem_start == 1)		force_detect = 1;	/* search through slots */	if (dev != NULL) {		base = dev->mem_start;		irq = dev->irq;	}	slot = mca_find_adapter(IBM_LANA_ID, startslot);	while (slot != -1) {		/* deduce card addresses */		getaddrs(slot, &base, &memlen, &iobase, &irq, &medium);#if (LINUX_VERSION_CODE >= 0x20300)		/* slot already in use ? */		if (mca_is_adapter_used(slot)) {			slot = mca_find_adapter(IBM_LANA_ID, slot + 1);			continue;		}#endif		/* were we looking for something different ? */		if ((dev->irq != 0) || (dev->mem_start != 0)) {			if ((dev->irq != 0) && (dev->irq != irq)) {				slot =				    mca_find_adapter(IBM_LANA_ID,						     slot + 1);				continue;			}			if ((dev->mem_start != 0)			    && (dev->mem_start != base)) {				slot =				    mca_find_adapter(IBM_LANA_ID,						     slot + 1);				continue;			}		}		/* found something that matches */		break;	}	/* nothing found ? */	if (slot == -1)		return ((base != 0) || (irq != 0)) ? -ENXIO : -ENODEV;	/* announce success */	printk("%s: IBM LAN Adapter/A found in slot %d\n", dev->name,	       slot + 1);	/* try to obtain I/O range */	if (!request_region(iobase, IBM_LANA_IORANGE, dev->name)) {		printk("%s: cannot allocate I/O range at %#x!\n", dev->name, iobase);		startslot = slot + 1;		return -EBUSY;	}	/* make procfs entries */	mca_set_adapter_name(slot, "IBM LAN Adapter/A");	mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmlana_getinfo, dev);#if (LINUX_VERSION_CODE >= 0x20200)	mca_mark_as_used(slot);#endif	/* allocate structure */	priv = dev->priv =	    (ibmlana_priv *) kmalloc(sizeof(ibmlana_priv), GFP_KERNEL);	if (!priv) {		release_region(iobase, IBM_LANA_IORANGE);		return -ENOMEM;	}	priv->slot = slot;	priv->realirq = irq;	priv->medium = medium;	memset(&(priv->stat), 0, sizeof(struct net_device_stats));	/* set base + irq for this device (irq not allocated so far) */	dev->irq = 0;	dev->mem_start = base;	dev->mem_end = base + memlen;	dev->base_addr = iobase;	/* set methods */	dev->open = ibmlana_open;	dev->stop = ibmlana_close;	dev->set_config = ibmlana_config;	dev->hard_start_xmit = ibmlana_tx;	dev->do_ioctl = NULL;	dev->get_stats = ibmlana_stats;	dev->set_multicast_list = ibmlana_set_multicast_list;	dev->flags |= IFF_MULTICAST;	/* generic setup */	ether_setup(dev);	/* copy out MAC address */	for (z = 0; z < sizeof(dev->dev_addr); z++)		dev->dev_addr[z] = inb(dev->base_addr + MACADDRPROM + z);	/* print config */	printk("%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, "	       "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",	       dev->name, priv->realirq, dev->base_addr,	       dev->mem_start, dev->mem_end - 1,	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);	printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]);	/* reset board */	ResetBoard(dev);	/* next probe will start at next slot */	startslot = slot + 1;	return 0;}/* ------------------------------------------------------------------------ * modularization support * ------------------------------------------------------------------------ */#ifdef MODULE#define DEVMAX 5static struct IBMLANA_NETDEV moddevs[DEVMAX];static int irq;static int io;MODULE_PARM(irq, "i");MODULE_PARM(io, "i");int init_module(void){	int z, res;	startslot = 0;	for (z = 0; z < DEVMAX; z++) {		moddevs[z].init = ibmlana_probe;		moddevs[z].irq = irq;		moddevs[z].base_addr = io;		res = register_netdev(moddevs + z);		if (res != 0)			return (z > 0) ? 0 : -EIO;	}	return 0;}void cleanup_module(void){	struct IBMLANA_NETDEV *dev;	ibmlana_priv *priv;	int z;	if (MOD_IN_USE) {		printk("cannot unload, module in use\n");		return;	}	for (z = 0; z < DEVMAX; z++) {		dev = moddevs + z;		if (dev->priv != NULL) {			priv = (ibmlana_priv *) dev->priv;			/*DeinitBoard(dev); */			if (dev->irq != 0)				free_irq(dev->irq, dev);			dev->irq = 0;			release_region(dev->base_addr, IBM_LANA_IORANGE);			unregister_netdev(dev);#if (LINUX_VERSION_CODE >= 0x20200)			mca_mark_as_unused(priv->slot);#endif			mca_set_adapter_name(priv->slot, "");			mca_set_adapter_procfn(priv->slot, NULL, NULL);			kfree(dev->priv);			dev->priv = NULL;		}	}}#endif				/* MODULE */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -