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

📄 plip.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: plip.c,v 1.3.6.2 1997/04/16 15:07:56 phil Exp $ *//* PLIP: A parallel port "network" driver for Linux. *//* This driver is for parallel port with 5-bit cable (LapLink (R) cable). *//* * Authors:	Donald Becker,  <becker@super.org> *		Tommy Thorn, <thorn@daimi.aau.dk> *		Tanabe Hiroyasu, <hiro@sanpo.t.u-tokyo.ac.jp> *		Alan Cox, <gw4pts@gw4pts.ampr.org> *		Peter Bauer, <100136.3530@compuserve.com> *		Niibe Yutaka, <gniibe@mri.co.jp> * *		Modularization and ifreq/ifmap support by Alan Cox. *		Rewritten by Niibe Yutaka. *              parport-sharing awareness code by Philip Blundell. *		SMP locking by Niibe Yutaka. * * Fixes: *		Niibe Yutaka *		  - Module initialization. *		  - MTU fix. *		  - Make sure other end is OK, before sending a packet. *		  - Fix immediate timer problem. * *		Al Viro *		  - Changed {enable,disable}_irq handling to make it work *		    with new ("stack") semantics. * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. *//* * Original version and the name 'PLIP' from Donald Becker <becker@super.org> * inspired by Russ Nelson's parallel port packet driver. * * NOTE: *     Tanabe Hiroyasu had changed the protocol, and it was in Linux v1.0. *     Because of the necessity to communicate to DOS machines with the *     Crynwr packet driver, Peter Bauer changed the protocol again *     back to original protocol. * *     This version follows original PLIP protocol. *     So, this PLIP can't communicate the PLIP of Linux v1.0. *//* *     To use with DOS box, please do (Turn on ARP switch): *	# ifconfig plip[0-2] arp */static const char *version = "NET3 PLIP version 2.3-parport gniibe@mri.co.jp\n";/*  Sources:	Ideas and protocols came from Russ Nelson's <nelson@crynwr.com>	"parallel.asm" parallel port packet driver.  The "Crynwr" parallel port standard specifies the following protocol:    Trigger by sending '0x08' (this cause interrupt on other end)    count-low octet    count-high octet    ... data octets    checksum octet  Each octet is sent as <wait for rx. '0x1?'> <send 0x10+(octet&0x0F)>			<wait for rx. '0x0?'> <send 0x00+((octet>>4)&0x0F)>  The packet is encapsulated as if it were ethernet.  The cable used is a de facto standard parallel null cable -- sold as  a "LapLink" cable by various places.  You'll need a 12-conductor cable to  make one yourself.  The wiring is:    SLCTIN	17 - 17    GROUND	25 - 25    D0->ERROR	2 - 15		15 - 2    D1->SLCT	3 - 13		13 - 3    D2->PAPOUT	4 - 12		12 - 4    D3->ACK	5 - 10		10 - 5    D4->BUSY	6 - 11		11 - 6  Do not connect the other pins.  They are    D5,D6,D7 are 7,8,9    STROBE is 1, FEED is 14, INIT is 16    extra grounds are 18,19,20,21,22,23,24*/#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/string.h>#include <linux/ptrace.h>#include <linux/if_ether.h>#include <asm/system.h>#include <asm/io.h>#include <linux/in.h>#include <linux/errno.h>#include <linux/delay.h>#include <linux/lp.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/inetdevice.h>#include <linux/skbuff.h>#include <linux/if_plip.h>#include <linux/tqueue.h>#include <linux/ioport.h>#include <asm/bitops.h>#include <asm/irq.h>#include <asm/byteorder.h>#include <asm/spinlock.h>#include <linux/parport.h>/* Maximum number of devices to support. */#define PLIP_MAX  8/* Use 0 for production, 1 for verification, >2 for debug */#ifndef NET_DEBUG#define NET_DEBUG 1#endifstatic unsigned int net_debug = NET_DEBUG;#define ENABLE(irq) enable_irq(irq)#define DISABLE(irq) disable_irq(irq)/* In micro second */#define PLIP_DELAY_UNIT		   1/* Connection time out = PLIP_TRIGGER_WAIT * PLIP_DELAY_UNIT usec */#define PLIP_TRIGGER_WAIT	 500/* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */#define PLIP_NIBBLE_WAIT        3000#define PAR_INTR_ON		(LP_PINITP|LP_PSELECP|LP_PINTEN)#define PAR_INTR_OFF		(LP_PINITP|LP_PSELECP)#define PAR_DATA(dev)		((dev)->base_addr+0)#define PAR_STATUS(dev)		((dev)->base_addr+1)#define PAR_CONTROL(dev)	((dev)->base_addr+2)/* Bottom halfs */static void plip_kick_bh(struct device *dev);static void plip_bh(struct device *dev);/* Interrupt handler */static void plip_interrupt(int irq, void *dev_id, struct pt_regs *regs);/* Functions for DEV methods */static int plip_rebuild_header(struct sk_buff *skb);static int plip_tx_packet(struct sk_buff *skb, struct device *dev);static int plip_open(struct device *dev);static int plip_close(struct device *dev);static struct net_device_stats *plip_get_stats(struct device *dev);static int plip_config(struct device *dev, struct ifmap *map);static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);static int plip_preempt(void *handle);static void plip_wakeup(void *handle);enum plip_connection_state {	PLIP_CN_NONE=0,	PLIP_CN_RECEIVE,	PLIP_CN_SEND,	PLIP_CN_CLOSING,	PLIP_CN_ERROR};enum plip_packet_state {	PLIP_PK_DONE=0,	PLIP_PK_TRIGGER,	PLIP_PK_LENGTH_LSB,	PLIP_PK_LENGTH_MSB,	PLIP_PK_DATA,	PLIP_PK_CHECKSUM};enum plip_nibble_state {	PLIP_NB_BEGIN,	PLIP_NB_1,	PLIP_NB_2,};struct plip_local {	enum plip_packet_state state;	enum plip_nibble_state nibble;	union {		struct {#if defined(__LITTLE_ENDIAN)			unsigned char lsb;			unsigned char msb;#elif defined(__BIG_ENDIAN)			unsigned char msb;			unsigned char lsb;#else#error	"Please fix the endianness defines in <asm/byteorder.h>"#endif		} b;		unsigned short h;	} length;	unsigned short byte;	unsigned char  checksum;	unsigned char  data;	struct sk_buff *skb;};struct net_local {	struct net_device_stats enet_stats;	struct tq_struct immediate;	struct tq_struct deferred;	struct plip_local snd_data;	struct plip_local rcv_data;	struct pardevice *pardev;	unsigned long  trigger;	unsigned long  nibble;	enum plip_connection_state connection;	unsigned short timeout_count;	int is_deferred;	int port_owner;	int should_relinquish;	int (*orig_rebuild_header)(struct sk_buff *skb);	spinlock_t lock;};/* Entry point of PLIP driver.   Probe the hardware, and register/initialize the driver.   PLIP is rather weird, because of the way it interacts with the parport   system.  It is _not_ initialised from Space.c.  Instead, plip_init()   is called, and that function makes up a "struct device" for each port, and   then calls us here.   */__initfunc(intplip_init_dev(struct device *dev, struct parport *pb)){	struct net_local *nl;	struct pardevice *pardev;	dev->irq = pb->irq;	dev->base_addr = pb->base;	if (pb->irq == -1) {		printk(KERN_INFO "plip: %s has no IRQ.\n", pb->name);		return -ENODEV;	}	pardev = parport_register_device(pb, dev->name, plip_preempt,					 plip_wakeup, plip_interrupt, 					 0, dev);	if (!pardev)		return -ENODEV;	printk(KERN_INFO "%s", version);	printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d\n", dev->name,	       dev->base_addr, dev->irq);	/* Fill in the generic fields of the device structure. */	ether_setup(dev);	/* Then, override parts of it */	dev->hard_start_xmit	= plip_tx_packet;	dev->open		= plip_open;	dev->stop		= plip_close;	dev->get_stats 		= plip_get_stats;	dev->set_config		= plip_config;	dev->do_ioctl		= plip_ioctl;	dev->tx_queue_len	= 10;	dev->flags	        = IFF_POINTOPOINT|IFF_NOARP;	memset(dev->dev_addr, 0xfc, ETH_ALEN);	/* Set the private structure */	dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);	if (dev->priv == NULL) {		printk(KERN_ERR "%s: out of memory\n", dev->name);		parport_unregister_device(pardev);		return -ENOMEM;	}	memset(dev->priv, 0, sizeof(struct net_local));	nl = (struct net_local *) dev->priv;	nl->orig_rebuild_header = dev->rebuild_header;	dev->rebuild_header 	= plip_rebuild_header;	nl->pardev = pardev; 	nl->port_owner = 0;	/* Initialize constants */	nl->trigger	= PLIP_TRIGGER_WAIT;	nl->nibble	= PLIP_NIBBLE_WAIT;	/* Initialize task queue structures */	nl->immediate.next = NULL;	nl->immediate.sync = 0;	nl->immediate.routine = (void *)(void *)plip_bh;	nl->immediate.data = dev;	nl->deferred.next = NULL;	nl->deferred.sync = 0;	nl->deferred.routine = (void *)(void *)plip_kick_bh;	nl->deferred.data = dev;	spin_lock_init(&nl->lock);	return 0;}/* Bottom half handler for the delayed request.   This routine is kicked by do_timer().   Request `plip_bh' to be invoked. */static voidplip_kick_bh(struct device *dev){	struct net_local *nl = (struct net_local *)dev->priv;	if (nl->is_deferred) {		queue_task(&nl->immediate, &tq_immediate);		mark_bh(IMMEDIATE_BH);	}}/* Forward declarations of internal routines */static int plip_none(struct device *, struct net_local *,		     struct plip_local *, struct plip_local *);static int plip_receive_packet(struct device *, struct net_local *,			       struct plip_local *, struct plip_local *);static int plip_send_packet(struct device *, struct net_local *,			    struct plip_local *, struct plip_local *);static int plip_connection_close(struct device *, struct net_local *,				 struct plip_local *, struct plip_local *);static int plip_error(struct device *, struct net_local *,		      struct plip_local *, struct plip_local *);static int plip_bh_timeout_error(struct device *dev, struct net_local *nl,				 struct plip_local *snd,				 struct plip_local *rcv,				 int error);#define OK        0#define TIMEOUT   1#define ERROR     2#define HS_TIMEOUT	3typedef int (*plip_func)(struct device *dev, struct net_local *nl,			 struct plip_local *snd, struct plip_local *rcv);static plip_func connection_state_table[] ={	plip_none,	plip_receive_packet,	plip_send_packet,	plip_connection_close,	plip_error};/* Bottom half handler of PLIP. */static voidplip_bh(struct 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;	plip_func f;	int r;	nl->is_deferred = 0;	f = connection_state_table[nl->connection];	if ((r = (*f)(dev, nl, snd, rcv)) != OK	    && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {		nl->is_deferred = 1;		queue_task(&nl->deferred, &tq_timer);	}}static intplip_bh_timeout_error(struct device *dev, struct net_local *nl,		      struct plip_local *snd, struct plip_local *rcv,		      int error){	unsigned char c0;	/*	 * This is tricky. If we got here from the beginning of send (either	 * with ERROR or HS_TIMEOUT) we have IRQ enabled. Otherwise it's	 * already disabled. With the old variant of {enable,disable}_irq()	 * extra disable_irq() was a no-op. Now it became mortal - it's	 * unbalanced and thus we'll never re-enable IRQ (until rmmod plip,	 * that is). So we have to treat HS_TIMEOUT and ERROR from send	 * in a special way.	 */	spin_lock_irq(&nl->lock);	if (nl->connection == PLIP_CN_SEND) {		if (error != ERROR) { /* Timeout */			nl->timeout_count++;			if ((error == HS_TIMEOUT			     && nl->timeout_count <= 10)			    || nl->timeout_count <= 3) {				spin_unlock_irq(&nl->lock);				/* Try again later */				return TIMEOUT;			}			c0 = inb(PAR_STATUS(dev));			printk(KERN_WARNING "%s: transmit timeout(%d,%02x)\n",			       dev->name, snd->state, c0);		} else			error = HS_TIMEOUT;		nl->enet_stats.tx_errors++;		nl->enet_stats.tx_aborted_errors++;	} else if (nl->connection == PLIP_CN_RECEIVE) {		if (rcv->state == PLIP_PK_TRIGGER) {			/* Transmission was interrupted. */			spin_unlock_irq(&nl->lock);			return OK;		}		if (error != ERROR) { /* Timeout */			if (++nl->timeout_count <= 3) {				spin_unlock_irq(&nl->lock);				/* Try again later */				return TIMEOUT;			}			c0 = inb(PAR_STATUS(dev));			printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n",			       dev->name, rcv->state, c0);		}		nl->enet_stats.rx_dropped++;	}	rcv->state = PLIP_PK_DONE;

⌨️ 快捷键说明

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