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

📄 plip.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Handle the parallel port interrupts. */static voidplip_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct net_device *dev = dev_id;	struct net_local *nl;	struct plip_local *rcv;	unsigned char c0;	if (dev == NULL) {		printk(KERN_DEBUG "plip_interrupt: irq %d for unknown device.\n", irq);		return;	}	nl = (struct net_local *)dev->priv;	rcv = &nl->rcv_data;	spin_lock_irq (&nl->lock);	c0 = read_status(dev);	if ((c0 & 0xf8) != 0xc0) {		if ((dev->irq != -1) && (net_debug > 1))			printk(KERN_DEBUG "%s: spurious interrupt\n", dev->name);		spin_unlock_irq (&nl->lock);		return;	}	if (net_debug > 3)		printk(KERN_DEBUG "%s: interrupt.\n", dev->name);	switch (nl->connection) {	case PLIP_CN_CLOSING:		netif_wake_queue (dev);	case PLIP_CN_NONE:	case PLIP_CN_SEND:		dev->last_rx = jiffies;		rcv->state = PLIP_PK_TRIGGER;		nl->connection = PLIP_CN_RECEIVE;		nl->timeout_count = 0;		queue_task(&nl->immediate, &tq_immediate);		mark_bh(IMMEDIATE_BH);		break;	case PLIP_CN_RECEIVE:		/* May occur because there is race condition		   around test and set of dev->interrupt.		   Ignore this interrupt. */		break;	case PLIP_CN_ERROR:		printk(KERN_ERR "%s: receive interrupt in error state\n", dev->name);		break;	}	spin_unlock_irq(&nl->lock);}static intplip_tx_packet(struct sk_buff *skb, struct net_device *dev){	struct net_local *nl = (struct net_local *)dev->priv;	struct plip_local *snd = &nl->snd_data;	if (netif_queue_stopped(dev))		return 1;	/* We may need to grab the bus */	if (!nl->port_owner) {		if (parport_claim(nl->pardev))			return 1;		nl->port_owner = 1;	}	netif_stop_queue (dev);		if (skb->len > dev->mtu + dev->hard_header_len) {		printk(KERN_WARNING "%s: packet too big, %d.\n", dev->name, (int)skb->len);		netif_start_queue (dev);		return 1;	}	if (net_debug > 2)		printk(KERN_DEBUG "%s: send request\n", dev->name);	spin_lock_irq(&nl->lock);	dev->trans_start = jiffies;	snd->skb = skb;	snd->length.h = skb->len;	snd->state = PLIP_PK_TRIGGER;	if (nl->connection == PLIP_CN_NONE) {		nl->connection = PLIP_CN_SEND;		nl->timeout_count = 0;	}	queue_task(&nl->immediate, &tq_immediate);	mark_bh(IMMEDIATE_BH);	spin_unlock_irq(&nl->lock);		return 0;}static voidplip_rewrite_address(struct net_device *dev, struct ethhdr *eth){	struct in_device *in_dev;	if ((in_dev=dev->ip_ptr) != NULL) {		/* Any address will do - we take the first */		struct in_ifaddr *ifa=in_dev->ifa_list;		if (ifa != NULL) {			memcpy(eth->h_source, dev->dev_addr, 6);			memset(eth->h_dest, 0xfc, 2);			memcpy(eth->h_dest+2, &ifa->ifa_address, 4);		}	}}static intplip_hard_header(struct sk_buff *skb, struct net_device *dev,                 unsigned short type, void *daddr,	         void *saddr, unsigned len){	struct net_local *nl = (struct net_local *)dev->priv;	int ret;	if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0)		plip_rewrite_address (dev, (struct ethhdr *)skb->data);	return ret;}int plip_hard_header_cache(struct neighbour *neigh,                           struct hh_cache *hh){	struct net_local *nl = (struct net_local *)neigh->dev->priv;	int ret;		if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0)	{		struct ethhdr *eth = (struct ethhdr*)(((u8*)hh->hh_data) + 2);		plip_rewrite_address (neigh->dev, eth);	}		return ret;}                          /* Open/initialize the board.  This is called (in the current kernel)   sometime after booting when the 'ifconfig' program is run.   This routine gets exclusive access to the parallel port by allocating   its IRQ line. */static intplip_open(struct net_device *dev){	struct net_local *nl = (struct net_local *)dev->priv;	struct in_device *in_dev;	/* Grab the port */	if (!nl->port_owner) {		if (parport_claim(nl->pardev)) return -EAGAIN;		nl->port_owner = 1;	}	nl->should_relinquish = 0;	/* Clear the data port. */	write_data (dev, 0x00);	/* Enable rx interrupt. */	enable_parport_interrupts (dev);	if (dev->irq == -1)	{		atomic_set (&nl->kill_timer, 0);		queue_task (&nl->timer, &tq_timer);	}	/* Initialize the state machine. */	nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE;	nl->rcv_data.skb = nl->snd_data.skb = NULL;	nl->connection = PLIP_CN_NONE;	nl->is_deferred = 0;	/* Fill in the MAC-level header.	   We used to abuse dev->broadcast to store the point-to-point	   MAC address, but we no longer do it. Instead, we fetch the	   interface address whenever it is needed, which is cheap enough	   because we use the hh_cache. Actually, abusing dev->broadcast	   didn't work, because when using plip_open the point-to-point	   address isn't yet known.	   PLIP doesn't have a real MAC address, but we need it to be	   DOS compatible, and to properly support taps (otherwise,	   when the device address isn't identical to the address of a	   received frame, the kernel incorrectly drops it).             */	if ((in_dev=dev->ip_ptr) != NULL) {		/* Any address will do - we take the first. We already		   have the first two bytes filled with 0xfc, from		   plip_init_dev(). */		struct in_ifaddr *ifa=in_dev->ifa_list;		if (ifa != NULL) {			memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);		}	}	netif_start_queue (dev);	return 0;}/* The inverse routine to plip_open (). */static intplip_close(struct net_device *dev){	struct net_local *nl = (struct net_local *)dev->priv;	struct plip_local *snd = &nl->snd_data;	struct plip_local *rcv = &nl->rcv_data;	netif_stop_queue (dev);	DISABLE(dev->irq);	synchronize_irq();	if (dev->irq == -1)	{		init_MUTEX_LOCKED (&nl->killed_timer_sem);		atomic_set (&nl->kill_timer, 1);		down (&nl->killed_timer_sem);	}#ifdef NOTDEF	outb(0x00, PAR_DATA(dev));#endif	nl->is_deferred = 0;	nl->connection = PLIP_CN_NONE;	if (nl->port_owner) {		parport_release(nl->pardev);		nl->port_owner = 0;	}	snd->state = PLIP_PK_DONE;	if (snd->skb) {		dev_kfree_skb(snd->skb);		snd->skb = NULL;	}	rcv->state = PLIP_PK_DONE;	if (rcv->skb) {		kfree_skb(rcv->skb);		rcv->skb = NULL;	}#ifdef NOTDEF	/* Reset. */	outb(0x00, PAR_CONTROL(dev));#endif	return 0;}static intplip_preempt(void *handle){	struct net_device *dev = (struct net_device *)handle;	struct net_local *nl = (struct net_local *)dev->priv;	/* Stand our ground if a datagram is on the wire */	if (nl->connection != PLIP_CN_NONE) {		nl->should_relinquish = 1;		return 1;	}	nl->port_owner = 0;	/* Remember that we released the bus */	return 0;}static voidplip_wakeup(void *handle){	struct net_device *dev = (struct net_device *)handle;	struct net_local *nl = (struct net_local *)dev->priv;	if (nl->port_owner) {		/* Why are we being woken up? */		printk(KERN_DEBUG "%s: why am I being woken up?\n", dev->name);		if (!parport_claim(nl->pardev))			/* bus_owner is already set (but why?) */			printk(KERN_DEBUG "%s: I'm broken.\n", dev->name);		else			return;	}		if (!(dev->flags & IFF_UP))		/* Don't need the port when the interface is down */		return;	if (!parport_claim(nl->pardev)) {		nl->port_owner = 1;		/* Clear the data port. */		write_data (dev, 0x00);	}	return;}static struct net_device_stats *plip_get_stats(struct net_device *dev){	struct net_local *nl = (struct net_local *)dev->priv;	struct net_device_stats *r = &nl->enet_stats;	return r;}static intplip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct net_local *nl = (struct net_local *) dev->priv;	struct plipconf *pc = (struct plipconf *) &rq->ifr_data;	switch(pc->pcmd) {	case PLIP_GET_TIMEOUT:		pc->trigger = nl->trigger;		pc->nibble  = nl->nibble;		break;	case PLIP_SET_TIMEOUT:		if(!capable(CAP_NET_ADMIN))			return -EPERM;		nl->trigger = pc->trigger;		nl->nibble  = pc->nibble;		break;	default:		return -EOPNOTSUPP;	}	return 0;}static int parport[PLIP_MAX] = { [0 ... PLIP_MAX-1] = -1 };static int timid = 0;MODULE_PARM(parport, "1-" __MODULE_STRING(PLIP_MAX) "i");MODULE_PARM(timid, "1i");static struct net_device *dev_plip[PLIP_MAX] = { NULL, };static int inline plip_searchfor(int list[], int a){	int i;	for (i = 0; i < PLIP_MAX && list[i] != -1; i++) {		if (list[i] == a) return 1;	}	return 0;}/* plip_attach() is called (by the parport code) when a port is * available to use. */static void plip_attach (struct parport *port){	static int i = 0;	if ((parport[0] == -1 && (!timid || !port->devices)) || 	    plip_searchfor(parport, port->number)) {		if (i == PLIP_MAX) {			printk(KERN_ERR "plip: too many devices\n");			return;		}		dev_plip[i] = kmalloc(sizeof(struct net_device),				      GFP_KERNEL);		if (!dev_plip[i]) {			printk(KERN_ERR "plip: memory squeeze\n");			return;		}		memset(dev_plip[i], 0, sizeof(struct net_device));		sprintf(dev_plip[i]->name, "plip%d", i);		dev_plip[i]->priv = port;		if (plip_init_dev(dev_plip[i],port) ||		    register_netdev(dev_plip[i])) {			kfree(dev_plip[i]);			dev_plip[i] = NULL;		} else {			i++;		}	}}/* plip_detach() is called (by the parport code) when a port is * no longer available to use. */static void plip_detach (struct parport *port){	/* Nothing to do */}static struct parport_driver plip_driver = {	name:	"plip",	attach:	plip_attach,	detach:	plip_detach};static void __exit plip_cleanup_module (void){	int i;	parport_unregister_driver (&plip_driver);	for (i=0; i < PLIP_MAX; i++) {		if (dev_plip[i]) {			struct net_local *nl =				(struct net_local *)dev_plip[i]->priv;			unregister_netdev(dev_plip[i]);			if (nl->port_owner)				parport_release(nl->pardev);			parport_unregister_device(nl->pardev);			kfree(dev_plip[i]->priv);			kfree(dev_plip[i]);			dev_plip[i] = NULL;		}	}}#ifndef MODULEstatic int parport_ptr = 0;static int __init plip_setup(char *str){	int ints[4];	str = get_options(str, ARRAY_SIZE(ints), ints);	/* Ugh. */	if (!strncmp(str, "parport", 7)) {		int n = simple_strtoul(str+7, NULL, 10);		if (parport_ptr < PLIP_MAX)			parport[parport_ptr++] = n;		else			printk(KERN_INFO "plip: too many ports, %s ignored.\n",			       str);	} else if (!strcmp(str, "timid")) {		timid = 1;	} else {		if (ints[0] == 0 || ints[1] == 0) {			/* disable driver on "plip=" or "plip=0" */			parport[0] = -2;		} else {			printk(KERN_WARNING "warning: 'plip=0x%x' ignored\n", 			       ints[1]);		}	}	return 1;}__setup("plip=", plip_setup);#endif /* !MODULE */static int __init plip_init (void){	if (parport[0] == -2)		return 0;	if (parport[0] != -1 && timid) {		printk(KERN_WARNING "plip: warning, ignoring `timid' since specific ports given.\n");		timid = 0;	}	if (parport_register_driver (&plip_driver)) {		printk (KERN_WARNING "plip: couldn't register driver\n");		return 1;	}	return 0;}module_init(plip_init);module_exit(plip_cleanup_module);/* * Local variables: * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -c plip.c" * End: */

⌨️ 快捷键说明

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