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

📄 fmv18x.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	struct net_local *lp = (struct net_local *)dev->priv;	int ioaddr = dev->base_addr;	unsigned long flags;			printk(KERN_WARNING "%s: transmit timed out with status %04x, %s?\n", dev->name,		   htons(inw(ioaddr + TX_STATUS)),		   inb(ioaddr + TX_STATUS) & 0x80		   ? "IRQ conflict" : "network cable problem");	printk(KERN_WARNING "%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",		   dev->name, htons(inw(ioaddr + 0)),		   htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),		   htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),		   htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),		   htons(inw(ioaddr +14)));	printk(KERN_WARNING "eth card: %04x %04x\n",		htons(inw(ioaddr+FJ_STATUS0)),		htons(inw(ioaddr+FJ_CONFIG0)));	lp->stats.tx_errors++;	/* ToDo: We should try to restart the adaptor... */	save_flags(flags);	cli();	/* Initialize LAN Controller and LAN Card */	outb(0xda, ioaddr + CONFIG_0);   /* Initialize LAN Controller */	outb(0x00, ioaddr + CONFIG_1);   /* Stand by mode */	outb(0x00, ioaddr + FJ_CONFIG1); /* Disable IRQ of LAN Card */	outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure */	net_open(dev);	restore_flags(flags);}static int net_send_packet(struct sk_buff *skb, struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	int ioaddr = dev->base_addr;	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;	unsigned char *buf = skb->data;	/* Block a transmit from overlapping.  */		netif_stop_queue(dev);		if (length > ETH_FRAME_LEN) {		if (net_debug)			printk("%s: Attempting to send a large packet (%d bytes).\n",				dev->name, length);		return 1;	}	if (net_debug > 4)		printk("%s: Transmitting a packet of length %lu.\n", dev->name,			   (unsigned long)skb->len);	/* We may not start transmitting unless we finish transferring	   a packet into the Tx queue. During executing the following	   codes we possibly catch a Tx interrupt. Thus we flag off	   tx_queue_ready, so that we prevent the interrupt routine	   (net_interrupt) to start transmitting. */	lp->tx_queue_ready = 0;	{		outw(length, ioaddr + DATAPORT);		outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);		lp->tx_queue++;		lp->tx_queue_len += length + 2;	}	lp->tx_queue_ready = 1;	if (lp->tx_started == 0) {		/* If the Tx is idle, always trigger a transmit. */		outb(0x80 | lp->tx_queue, ioaddr + TX_START);		lp->tx_queue = 0;		lp->tx_queue_len = 0;		dev->trans_start = jiffies;		lp->tx_started = 1;		netif_wake_queue(dev);	} else if (lp->tx_queue_len < 4096 - 1502)		/* Yes, there is room for one more packet. */		netif_wake_queue(dev);	dev_kfree_skb(skb);	return 0;}/* The typical workload of the driver:   Handle the network interface interrupts. */static voidnet_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	struct net_local *lp;	int ioaddr, status;	ioaddr = dev->base_addr;	lp = (struct net_local *)dev->priv;	status = inw(ioaddr + TX_STATUS);	outw(status, ioaddr + TX_STATUS);	if (net_debug > 4)		printk("%s: Interrupt with status %04x.\n", dev->name, status);	if (lp->rx_started == 0 &&		(status & 0xff00 || (inb(ioaddr + RX_MODE) & 0x40) == 0)) {		/* Got a packet(s).		   We cannot execute net_rx more than once at the same time for		   the same device. During executing net_rx, we possibly catch a		   Tx interrupt. Thus we flag on rx_started, so that we prevent		   the interrupt routine (net_interrupt) to dive into net_rx		   again. */		lp->rx_started = 1;		outb(0x00, ioaddr + RX_INTR);	/* Disable RX intr. */		net_rx(dev);		outb(0x81, ioaddr + RX_INTR);	/* Enable  RX intr. */		lp->rx_started = 0;	}	if (status & 0x00ff) {		if (status & 0x02) {			/* More than 16 collisions occurred */			if (net_debug > 4)				printk("%s: 16 Collision occur during Txing.\n", dev->name);			/* Cancel sending a packet. */			outb(0x03, ioaddr + COL16CNTL);			lp->stats.collisions++;		}		if (status & 0x82) {			lp->stats.tx_packets++;			if (lp->tx_queue && lp->tx_queue_ready) {				outb(0x80 | lp->tx_queue, ioaddr + TX_START);				lp->tx_queue = 0;				lp->tx_queue_len = 0;				dev->trans_start = jiffies;				netif_wake_queue(dev);	/* Inform upper layers. */			} else {				lp->tx_started = 0;				netif_wake_queue(dev);	/* Inform upper layers. */			}		}	}	return;}/* We have a good packet(s), get it/them out of the buffers. */static void net_rx(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	int ioaddr = dev->base_addr;	int boguscount = 5;	while ((inb(ioaddr + RX_MODE) & 0x40) == 0) {		/* Clear PKT_RDY bit: by agy 19940922 */		/* outb(0x80, ioaddr + RX_STATUS); */		ushort status = inw(ioaddr + DATAPORT);		if (net_debug > 4)			printk("%s: Rxing packet mode %02x status %04x.\n",				   dev->name, inb(ioaddr + RX_MODE), status);#ifndef final_version		if (status == 0) {			outb(0x05, ioaddr + 14);			break;		}#endif		if ((status & 0xF0) != 0x20) {	/* There was an error. */			lp->stats.rx_errors++;			if (status & 0x08) lp->stats.rx_length_errors++;			if (status & 0x04) lp->stats.rx_frame_errors++;			if (status & 0x02) lp->stats.rx_crc_errors++;			if (status & 0x01) lp->stats.rx_over_errors++;		} else {			ushort pkt_len = inw(ioaddr + DATAPORT);			/* Malloc up new buffer. */			struct sk_buff *skb;			if (pkt_len > 1550) {				printk("%s: The FMV-18x claimed a very large packet, size %d.\n",					   dev->name, pkt_len);				outb(0x05, ioaddr + 14);				lp->stats.rx_errors++;				break;			}			skb = dev_alloc_skb(pkt_len+3);			if (skb == NULL) {				printk("%s: Memory squeeze, dropping packet (len %d).\n",					   dev->name, pkt_len);				outb(0x05, ioaddr + 14);				lp->stats.rx_dropped++;				break;			}			skb->dev = dev;			skb_reserve(skb,2);			insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1);			if (net_debug > 5) {				int i;				printk("%s: Rxed packet of length %d: ", dev->name, pkt_len);				for (i = 0; i < 14; i++)					printk(" %02x", skb->data[i]);				printk(".\n");			}			skb->protocol=eth_type_trans(skb, dev);			netif_rx(skb);			lp->stats.rx_packets++;		}		if (--boguscount <= 0)			break;	}	/* If any worth-while packets have been received, dev_rint()	   has done a mark_bh(NET_BH) for us and will work on them	   when we get to the bottom-half routine. */	{		int i;		for (i = 0; i < 20; i++) {			if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40)				break;			(void)inw(ioaddr + DATAPORT);				/* dummy status read */			outb(0x05, ioaddr + 14);		}		if (net_debug > 5 && i > 0)			printk("%s: Exint Rx packet with mode %02x after %d ticks.\n",				   dev->name, inb(ioaddr + RX_MODE), i);	}	return;}/* The inverse routine to net_open(). */static int net_close(struct net_device *dev){	int ioaddr = dev->base_addr;	((struct net_local *)dev->priv)->open_time = 0;	netif_stop_queue(dev);		/* Set configuration register 0 to disable Tx and Rx. */	outb(0xda, ioaddr + CONFIG_0);	/* Update the statistics -- ToDo. */	/* Power-down the chip.  Green, green, green! */	outb(0x00, ioaddr + CONFIG_1);	/* Set the ethernet adaptor disable IRQ */	outb(0x00, ioaddr + FJ_CONFIG1);	return 0;}/* Get the current statistics.	This may be called with the card open or   closed. */static struct net_device_stats *net_get_stats(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	return &lp->stats;}/* Set or clear the multicast filter for this adaptor.   num_addrs == -1	Promiscuous mode, receive all packets   num_addrs == 0	Normal mode, clear multicast list   num_addrs > 0	Multicast mode, receive normal and MC packets, and do			best-effort filtering. */ static void set_multicast_list(struct net_device *dev){	short ioaddr = dev->base_addr;	if (dev->mc_count || dev->flags&(IFF_PROMISC|IFF_ALLMULTI))	{		/*		 *	We must make the kernel realise we had to move		 *	into promisc mode or we start all out war on		 *	the cable. - AC		 */		dev->flags|=IFF_PROMISC;		outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */	}	else		outb(2, ioaddr + RX_MODE);	/* Disable promiscuous, use normal mode */}#ifdef MODULEstatic struct net_device dev_fmv18x;static int io = 0x220;static int irq;MODULE_PARM(io, "i");MODULE_PARM(irq, "i");MODULE_PARM(net_debug, "i");int init_module(void){	if (io == 0)		printk("fmv18x: You should not use auto-probing with insmod!\n");	dev_fmv18x.base_addr	= io;	dev_fmv18x.irq		= irq;	dev_fmv18x.init		= fmv18x_probe;	if (register_netdev(&dev_fmv18x) != 0) {		printk("fmv18x: register_netdev() returned non-zero.\n");		return -EIO;	}	return 0;}voidcleanup_module(void){	unregister_netdev(&dev_fmv18x);	kfree(dev_fmv18x.priv);	dev_fmv18x.priv = NULL;	/* If we don't do this, we can't re-insmod it later. */	free_irq(dev_fmv18x.irq, &dev_fmv18x);	release_region(dev_fmv18x.base_addr, FMV18X_IO_EXTENT);}#endif /* MODULE *//* * Local variables: *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c fmv18x.c" *  version-control: t *  kept-new-versions: 5 *  tab-width: 4 *  c-indent-level: 4 * End: */

⌨️ 快捷键说明

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