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

📄 smc9194.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 4 页
字号:
}/* * This is our template.  Fill the rest in at run-time */static const struct ethtool_cmd ecmd_template = {	supported:	SUPPORTED_10baseT_Half |			SUPPORTED_10baseT_Full |			SUPPORTED_TP |			SUPPORTED_AUI,	speed:		SPEED_10,	autoneg:	AUTONEG_DISABLE,	maxtxpkt:	1,	maxrxpkt:	1,	transceiver:	XCVR_INTERNAL,};static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct smc_local *smc = dev->priv;	u32 etcmd;	int ret = -EINVAL;	if (cmd != SIOCETHTOOL)		return -EOPNOTSUPP;	if (get_user(etcmd, (u32 *)rq->ifr_data))		return -EFAULT;	switch (etcmd) {	case ETHTOOL_GSET: {		struct ethtool_cmd ecmd = ecmd_template;		ecmd.cmd = etcmd;		ecmd.port = smc->port;		ecmd.duplex = smc->duplex;		ret = copy_to_user(rq->ifr_data, &ecmd, sizeof(ecmd))				? -EFAULT : 0;		break;	}	case ETHTOOL_SSET: {		struct ethtool_cmd ecmd;		ret = -EPERM;		if (!capable(CAP_NET_ADMIN))			break;		ret = -EFAULT;		if (copy_from_user(&ecmd, rq->ifr_data, sizeof(ecmd)))			break;		/*		 * Sanity-check the arguments.		 */		ret = -EINVAL;		if (ecmd.autoneg != AUTONEG_DISABLE)			break;		if (ecmd.speed != SPEED_10)			break;		if (ecmd.duplex != DUPLEX_HALF && ecmd.duplex != DUPLEX_FULL)			break;		if (ecmd.port != PORT_TP && ecmd.port != PORT_AUI)			break;		smc->port   = ecmd.port;		smc->duplex = ecmd.duplex;		if (netif_running(dev))			smc_set_port(dev);		ret = 0;		break;	}	case ETHTOOL_GDRVINFO: {		struct ethtool_drvinfo edrv;		memset(&edrv, 0, sizeof(edrv));		edrv.cmd = etcmd;		strcpy(edrv.driver, DRV_NAME);		strcpy(edrv.version, DRV_VERSION);		sprintf(edrv.bus_info, "ISA:%8.8lx:%d",			dev->base_addr, dev->irq);		ret = copy_to_user(rq->ifr_data, &edrv, sizeof(edrv))				? -EFAULT : 0;		break;	}	}	return ret;}/*-------------------------------------------------------- . Called by the kernel to send a packet out into the void . of the net.  This routine is largely based on . skeleton.c, from Becker. .--------------------------------------------------------*/static void smc_timeout(struct net_device *dev){	/* If we get here, some higher level has decided we are broken.	   There should really be a "kick me" function call instead. */	printk(KERN_WARNING "%s: transmit timed out\n", dev->name);	/* "kick" the adaptor */	smc_reset(dev);	smc_enable(dev);	dev->trans_start = jiffies;	/* clear anything saved */	((struct smc_local *)dev->priv)->saved_skb = NULL;	netif_wake_queue(dev);}/*-------------------------------------------------------------------- . . This is the main routine of the driver, to handle the device when . it needs some attention. . . So: .   first, save state of the chipset .   branch off into routines to handle each case, and acknowledge .	    each to the interrupt register .   and finally restore state. . ---------------------------------------------------------------------*/static void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs){	struct net_device *dev 	= dev_id;	u_int ioaddr 		= dev->base_addr;	struct smc_local *lp 	= (struct smc_local *)dev->priv;	byte	status;	word	card_stats;	byte	mask;	int	timeout;	/* state registers */	word	saved_bank;	word	saved_pointer;	PRINTK3(("%s: SMC interrupt started\n", dev->name));	saved_bank = smc_inw(ioaddr, BANK_SELECT);	SMC_SELECT_BANK(2);	saved_pointer = smc_inw(ioaddr, POINTER);	mask = smc_inb(ioaddr, INT_MASK);	/* clear all interrupts */	SMC_SET_INT(0);	/* set a timeout value, so I don't stay here forever */	timeout = 4;	PRINTK2((KERN_WARNING "%s: MASK IS %x\n", dev->name, mask));	do {		/* read the status flag, and mask it */		status = smc_inb(ioaddr, INTERRUPT) & mask;		if (!status)			break;		PRINTK3((KERN_WARNING "%s: handling interrupt status %x\n",			dev->name, status));		if (status & IM_RCV_INT) {			/* Got a packet(s). */			PRINTK2((KERN_WARNING "%s: receive interrupt\n",				dev->name));			smc_rcv(dev);		} else if (status & IM_TX_INT) {			PRINTK2((KERN_WARNING "%s: TX ERROR handled\n",				dev->name));			smc_tx(dev);			smc_outb(IM_TX_INT, ioaddr, INTERRUPT);		} else if (status & IM_TX_EMPTY_INT) {			/* update stats */			SMC_SELECT_BANK(0);			card_stats = smc_inw(ioaddr, COUNTER);			/* single collisions */			lp->stats.collisions += card_stats & 0xF;			card_stats >>= 4;			/* multiple collisions */			lp->stats.collisions += card_stats & 0xF;			/* these are for when linux supports these statistics */			SMC_SELECT_BANK(2);			PRINTK2((KERN_WARNING "%s: TX_BUFFER_EMPTY handled\n",				dev->name));			smc_outb(IM_TX_EMPTY_INT, ioaddr, INTERRUPT);			mask &= ~IM_TX_EMPTY_INT;			lp->stats.tx_packets += lp->packets_waiting;			lp->packets_waiting = 0;		} else if (status & IM_ALLOC_INT) {			PRINTK2((KERN_DEBUG "%s: Allocation interrupt\n",				dev->name));			/* clear this interrupt so it doesn't happen again */			mask &= ~IM_ALLOC_INT;			smc_hardware_send_packet(dev);			/* enable xmit interrupts based on this */			mask |= (IM_TX_EMPTY_INT | IM_TX_INT);			/* and let the card send more packets to me */			netif_wake_queue(dev);						PRINTK2(("%s: Handoff done successfully.\n",				dev->name));		} else if (status & IM_RX_OVRN_INT) {			lp->stats.rx_errors++;			lp->stats.rx_fifo_errors++;			smc_outb(IM_RX_OVRN_INT, ioaddr, INTERRUPT);		} else if (status & IM_EPH_INT) {			PRINTK(("%s: UNSUPPORTED: EPH INTERRUPT\n",				dev->name));		} else if (status & IM_ERCV_INT) {			PRINTK(("%s: UNSUPPORTED: ERCV INTERRUPT\n",				dev->name));			smc_outb(IM_ERCV_INT, ioaddr, INTERRUPT);		}	} while (timeout --);	/* restore state register */	SMC_SELECT_BANK(2);	SMC_SET_INT(mask);	PRINTK3((KERN_WARNING "%s: MASK is now %x\n", dev->name, mask));	smc_outw(saved_pointer, ioaddr, POINTER);	SMC_SELECT_BANK(saved_bank);	PRINTK3(("%s: Interrupt done\n", dev->name));	return;}/*------------------------------------------------------------- . . smc_rcv - receive a packet from the card . . There is (at least) a packet waiting to be read from . chip-memory. . . o Read the status . o If an error, record it . o otherwise, read in the packet --------------------------------------------------------------*/static void smc_rcv(struct net_device *dev){	struct smc_local *lp = (struct smc_local *)dev->priv;	u_int 	ioaddr = dev->base_addr;	int 	packet_number;	word	status;	word	packet_length;	/* assume bank 2 */	packet_number = smc_inw(ioaddr, FIFO_PORTS);	if (packet_number & FP_RXEMPTY) {		/* we got called , but nothing was on the FIFO */		PRINTK(("%s: WARNING: smc_rcv with nothing on FIFO.\n",			dev->name));		/* don't need to restore anything */		return;	}	/*  start reading from the start of the packet */	smc_outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr, POINTER);	/* First two words are status and packet_length */	status 		= smc_inw(ioaddr, DATA_1);	packet_length 	= smc_inw(ioaddr, DATA_1);	packet_length &= 0x07ff;  /* mask off top bits */	PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length));	/*	 . the packet length contains 3 extra words :	 . status, length, and an extra word with an odd byte .	*/	packet_length -= 6;	if (!(status & RS_ERRORS)){		/* do stuff to make a new packet */		struct sk_buff  * skb;		byte		* data;		/* read one extra byte */		if (status & RS_ODDFRAME)			packet_length++;		/* set multicast stats */		if (status & RS_MULTICAST)			lp->stats.multicast++;		skb = dev_alloc_skb(packet_length + 5);		if (skb == NULL) {			printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",				dev->name);			lp->stats.rx_dropped++;			goto done;		}		/*		 ! This should work without alignment, but it could be		 ! in the worse case		*/		skb_reserve(skb, 2);   /* 16 bit alignment */		skb->dev = dev;		data = skb_put(skb, packet_length);		smc_ins(ioaddr, DATA_1, data, packet_length);		print_packet(data, packet_length);		skb->protocol = eth_type_trans(skb, dev);		netif_rx(skb);		dev->last_rx = jiffies;		lp->stats.rx_packets++;		lp->stats.rx_bytes += packet_length;	} else {		/* error ... */		lp->stats.rx_errors++;		if (status & RS_ALGNERR)			lp->stats.rx_frame_errors++;		if (status & (RS_TOOSHORT | RS_TOOLONG))			lp->stats.rx_length_errors++;		if (status & RS_BADCRC)			lp->stats.rx_crc_errors++;	}done:	/*  error or good, tell the card to get rid of this packet */	smc_outw(MC_RELEASE, ioaddr, MMU_CMD);}/************************************************************************* . smc_tx . . Purpose:  Handle a transmit error message.   This will only be called .   when an error, because of the AUTO_RELEASE mode. . . Algorithm: .	Save pointer and packet no .	Get the packet no from the top of the queue .	check if it's valid (if not, is this an error???) .	read the status word .	record the error .	(resend?  Not really, since we don't want old packets around) .	Restore saved values ************************************************************************/static void smc_tx(struct net_device * dev){	u_int ioaddr = dev->base_addr;	struct smc_local *lp = (struct smc_local *)dev->priv;	byte saved_packet;	byte packet_no;	word tx_status;	/* assume bank 2 */	saved_packet = smc_inb(ioaddr, PNR_ARR);	packet_no = smc_inw(ioaddr, FIFO_PORTS);	packet_no &= 0x7F;	/* select this as the packet to read from */	smc_outb(packet_no, ioaddr, PNR_ARR);	/* read the first word from this packet */	smc_outw(PTR_AUTOINC | PTR_READ, ioaddr, POINTER);	tx_status = smc_inw(ioaddr, DATA_1);	PRINTK3(("%s: TX DONE STATUS: %4x\n", dev->name, tx_status));	lp->stats.tx_errors++;	if (tx_status & TS_LOSTCAR)		lp->stats.tx_carrier_errors++;	if (tx_status & TS_LATCOL) {		printk(KERN_DEBUG "%s: Late collision occurred on "			"last xmit.\n", dev->name);		lp->stats.tx_window_errors++;	}#if 0		if (tx_status & TS_16COL) { ... }#endif	if (tx_status & TS_SUCCESS) {		printk("%s: Successful packet caused interrupt\n",			dev->name);	}	/* re-enable transmit */	SMC_SELECT_BANK(0);	smc_outw(smc_inw(ioaddr, TCR) | TCR_ENABLE, ioaddr, TCR);	/* kill the packet */	SMC_SELECT_BANK(2);	smc_outw(MC_FREEPKT, ioaddr, MMU_CMD);	/* one less packet waiting for me */	lp->packets_waiting--;	smc_outb(saved_packet, ioaddr, PNR_ARR);	return;}/*---------------------------------------------------- . smc_close . . this makes the board clean up everything that it can . and not talk to the outside world.   Caused by . an 'ifconfig ethX down' . -----------------------------------------------------*/static int smc_close(struct net_device *dev){	netif_stop_queue(dev);	/* clear everything */	smc_shutdown(dev);	/* Update the statistics here. */	return 0;}/*------------------------------------------------------------ . Get the current statistics. . This may be called with the card open or closed. .-------------------------------------------------------------*/static struct net_device_stats* smc_query_statistics(struct net_device *dev) {	struct smc_local *lp = (struct smc_local *)dev->priv;	return &lp->stats;}/*----------------------------------------------------------- . smc_set_multicast_list . . This routine will, depending on the values passed to it, . either make it accept multicast packets, go into . promiscuous mode (for TCPDUMP and cousins) or accept . a select set of multicast packets*/static void smc_set_multicast_list(struct net_device *dev){	u_int ioaddr = dev->base_addr;	SMC_SELECT_BANK(0);	if (dev->flags & IFF_PROMISC)		smc_outw(smc_inw(ioaddr, RCR) | RCR_PROMISC, ioaddr, RCR);/* BUG?  I never disable promiscuous mode if multicasting was turned on.   Now, I turn off promiscuous mode, but I don't do anything to multicasting   when promiscuous mode is turned on.*/	/* Here, I am setting this to accept all multicast packets.	   I don't need to zero the multicast table, because the flag is	   checked before the table is	*/	else if (dev->flags & IFF_ALLMULTI)		smc_outw(smc_inw(ioaddr, RCR) | RCR_ALMUL, ioaddr, RCR);	/* We just get all multicast packets even if we only want them	 . from one source.  This will be changed at some future	 . point. */	else if (dev->mc_count) {		/* support hardware multicasting */		/* be sure I get rid of flags I might have set */		smc_outw(smc_inw(ioaddr, RCR) & ~(RCR_PROMISC | RCR_ALMUL),			ioaddr, RCR);		/* NOTE: this has to set the bank, so make sure it is the		   last thing called.  The bank is set to zero at the top */		smc_setmulticast(dev, dev->mc_count, dev->mc_list);	}	else {		smc_outw(smc_inw(ioaddr, RCR) & ~(RCR_PROMISC | RCR_ALMUL),			ioaddr, RCR);		/*		  since I'm disabling all multicast entirely, I need to		  clear the multicast list		*/		SMC_SELECT_BANK(3);		smc_outw(0, ioaddr, MULTICAST1);		smc_outw(0, ioaddr, MULTICAST2);		smc_outw(0, ioaddr, MULTICAST3);		smc_outw(0, ioaddr, MULTICAST4);	}}#ifdef MODULEstatic struct net_device devSMC9194;static int io;static int irq;static int ifport;MODULE_LICENSE("GPL");MODULE_PARM(io, "i");MODULE_PARM(irq, "i");MODULE_PARM(ifport, "i");MODULE_PARM_DESC(io, "SMC 99194 I/O base address");MODULE_PARM_DESC(irq, "SMC 99194 IRQ number");MODULE_PARM_DESC(ifport, "SMC 99194 interface port (0-default, 1-TP, 2-AUI)");int init_module(void){	if (io == 0)		printk(KERN_WARNING CARDNAME			": You shouldn't use auto-probing with insmod!\n");	/*	 * Note: dev->if_port has changed to be 2.4 compliant.	 * We keep the ifport insmod parameter the same though.	 */	switch (ifport) {	case 1: devSMC9194.if_port = IF_PORT_10BASET;	break;	case 2: devSMC9194.if_port = IF_PORT_AUI;	break;	default: devSMC9194.if_port = 0;		break;	}	/* copy the parameters from insmod into the device structure */	devSMC9194.base_addr = io;	devSMC9194.irq       = irq;	devSMC9194.init      = smc_init;	return register_netdev(&devSMC9194);}void cleanup_module(void){	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	unregister_netdev(&devSMC9194);	free_irq(devSMC9194.irq, &devSMC9194);	release_region(devSMC9194.base_addr, SMC_IO_EXTENT);	if (devSMC9194.priv)		kfree(devSMC9194.priv);}#endif /* MODULE */

⌨️ 快捷键说明

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