patch-2.3.99-pre1 linux/drivers/usb/pegasus.c

Next file: linux/drivers/usb/serial/Makefile
Previous file: linux/drivers/usb/ov511.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.51/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c
@@ -1,578 +1,474 @@
 /*
-**
 **	Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
 **
-**	Copyleft (L) 1999 Petko Manolov - Petkan (petkan@spct.net)
-** 	
+**	Copyright (R) 1999,2000 Petko Manolov - Petkan (petkan@spct.net)
+**
 **	Distribute under GPL version 2 or later.
 */
 
-
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/usb.h>
-
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/usb.h>
 
-#if LINUX_VERSION_CODE<0x2032d || !defined(__KERNEL__) || !defined(__OPTIMIZE__)
-#error You can not compile this driver on this kernel with this C options!
-#endif
-
-
-#define	ADMTEK_VENDOR_ID	0x07a6
-#define	ADMTEK_HPNA_PEGASUS	0x0986
-
-#define	HPNA_MTU		1500
-#define MAX_MTU			1536
 
-#define	TX_TIMEOUT		(HZ*5)
-#define	SOMETHING		(jiffies + TX_TIMEOUT)
+static const char *version = __FILE__ ": v0.3.3 2000/03/13 Written by Petko Manolov (petkan@spct.net)\n";
 
 
-static const char version[] = "pegasus.c: v0.2.27 2000/02/29 Written by Petko Manolov (petkan@spct.net)\n";
+#define	ADMTEK_VENDOR_ID		0x07a6
+#define	ADMTEK_DEVICE_ID_PEGASUS	0x0986
 
+#define	PEGASUS_MTU		1500
+#define PEGASUS_MAX_MTU		1536
+#define	PEGASUS_TX_TIMEOUT	(HZ*5)
+#define	ALIGN(x)		x __attribute__((aligned(16)))
 
-typedef struct usb_hpna
-{
-	struct usb_device	*usb_dev;
-	struct net_device	*net_dev;
-	int			present;
-	int			active;
-	void			*irq_handler;
-	struct list_head	list;
+struct pegasus {
+	struct usb_device	*usb;
+	struct net_device	*net;
 	struct net_device_stats	stats;
-	spinlock_t		hpna_lock;
-	struct timer_list	timer;
-
-	unsigned int		rx_pipe;
-	unsigned char *		rx_buff;
-	urb_t 			rx_urb;
-
-	unsigned int		tx_pipe;
-	unsigned char *		tx_buff;
-	urb_t 			tx_urb;
-	struct sk_buff *	tx_skbuff;
-
-	__u8			intr_ival;
-	unsigned int		intr_pipe;
-	unsigned char 		intr_buff[8];
-	urb_t 			intr_urb;
-} usb_hpna_t;
-
-
-usb_hpna_t	usb_dev_hpna;
-static int	loopback = 0;
-int		multicast_filter_limit = 32;
-static LIST_HEAD(hpna_list);
+	spinlock_t		pegasus_lock;
+	struct urb		rx_urb, tx_urb, intr_urb;
+	unsigned char		ALIGN(rx_buff[PEGASUS_MAX_MTU]); 
+	unsigned char		ALIGN(tx_buff[PEGASUS_MAX_MTU]); 
+	unsigned char		ALIGN(intr_buff[8]);
+};
 
+static int loopback = 0;
+static int multicast_filter_limit = 32;
 
 MODULE_AUTHOR("Petko Manolov <petkan@spct.net>");
-MODULE_DESCRIPTION("ADMtek \"Pegasus\" USB Ethernet driver");
+MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver");
 MODULE_PARM(loopback, "i");
 
 
-
-/*** vendor specific commands ***/
-static __inline__ int	hpna_get_registers( struct usb_device *dev, __u16 indx, __u16 size, void *data )
-{
-	return	usb_control_msg(dev, usb_rcvctrlpipe(dev,0), 0xf0, 0xc0, 0,
-				indx, data, size, HZ);
-}
-
-
-static __inline__ int	hpna_set_register( struct usb_device *dev, __u16 indx, __u8 value )
-{
-	__u8	data = value;
-	return	usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40,
-				data, indx, &data, 1, HZ);
-}
-
-
-static __inline__ int	hpna_set_registers( struct usb_device *dev, __u16 indx, __u16 size, void *data )
-{
-	return	usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40, 0,
-				indx, data, size, HZ);
-}
-
-
-static int read_phy_word( struct usb_device *dev, __u8 index, __u16 *regdata )
-{
-	int	i;
-	__u8	data[4];
-
-	data[0] = 1;
-	data[1] = 0;
-	data[2] = 0;
-	data[3] = 0x40 + index;
-	hpna_set_registers( dev, 0x25, 4, data );
-	for ( i=0; i<100; i++ ) {
-		hpna_get_registers( dev, 0x25, 4, data );
-		if ( data[3] & 0x80 ) {
-			*regdata = *(__u16 *)(data+1);
-			return	0;
+#define pegasus_get_registers(dev, indx, size, data)\
+	usb_control_msg(dev, usb_rcvctrlpipe(dev,0), 0xf0, 0xc0, 0, indx, data, size, HZ);
+#define pegasus_set_registers(dev, indx, size, data)\
+	usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40, 0, indx, data, size, HZ);
+#define pegasus_set_register(dev, indx, value)	\
+	{ __u8	data = value;			\
+	usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40, data, indx, &data, 1, HZ);}
+
+
+static int pegasus_read_phy_word(struct usb_device *dev, __u8 index, __u16 *regdata)
+{
+	int i;
+	__u8 data[4] = { 1, 0, 0, 0x40 + index };
+
+	pegasus_set_registers(dev, 0x25, 4, data);
+	for (i = 0; i < 100; i++) {
+		pegasus_get_registers(dev, 0x26, 3, data);
+		if (data[2] & 0x80) {
+			*regdata = *(__u16 *)(data);
+			return 0;
 		}
 		udelay(100);
 	}
+
 	warn("read_phy_word() failed");
-	return	1;
+	return 1;
 }
 
-
-static int write_phy_word( struct usb_device *dev, __u8 index, __u16 regdata )
+static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regdata)
 {
-	int	i;
-	__u8	data[4];
+	int i;
+	__u8 data[4] = { 1, regdata, regdata >> 8, 0x20 + index };
 
-	data[0] = 1;
-	data[1] = regdata;
-	data[2] = regdata >> 8;
-	data[3] = 0x20 + index;
-	hpna_set_registers( dev, 0x25, 4, data );
-	for ( i=0; i<100; i++ ) {
-		hpna_get_registers( dev, 0x28, 1, data );
-		if ( data[0] & 0x80 ) {
-			return	0;
-		}
+	pegasus_set_registers(dev, 0x25, 4, data);
+	for (i = 0; i < 100; i++) {
+		pegasus_get_registers(dev, 0x28, 1, data);
+		if (data[0] & 0x80)
+			return 0;
 		udelay(100);
 	}
+
 	warn("write_phy_word() failed");
-	return	1;
+	return 1;
 }
 
-
-int read_srom_word( struct usb_device *dev, __u8 index, __u16 *retdata)
+static int pegasus_read_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata)
 {
-	int	i;
-	__u8	data[4];
+	int i;
+	__u8 data[4] = { index, 0, 0, 0x02 };
 
-	data[0] = index;
-	data[1] = data[2] = 0;
-	data[3] = 0x02;
-	hpna_set_registers(dev, 0x20, 4, data);
-	for ( i=0; i<100; i++ ) {
-		hpna_get_registers(dev, 0x23, 1, data);
-		if ( data[0] & 4 ) {
-			hpna_get_registers(dev, 0x21, 2, data);
+	pegasus_set_registers(dev, 0x20, 4, data);
+	for (i = 0; i < 100; i++) {
+		pegasus_get_registers(dev, 0x23, 1, data);
+		if (data[0] & 4) {
+			pegasus_get_registers(dev, 0x21, 2, data);
 			*retdata = *(__u16 *)data;
-			return	0;		
+			return 0;
 		}
 	}
+
 	warn("read_srom_word() failed");
-	return	1;
+	return 1;
 }
-/*** end ***/
 
-
-
-
-int get_node_id( struct usb_device *dev, __u8 *id )
+static int pegasus_get_node_id(struct usb_device *dev, __u8 *id)
 {
-	int	i;
-
-	for ( i=0; i<3; i++ ) {
-		if ( read_srom_word(dev, i, (__u16 *)&id[i*2] ) )
-			return	1;
-	}
-	return	0;
+	int i;
+	for (i = 0; i < 3; i++)
+		if (pegasus_read_srom_word(dev, i, (__u16 *)&id[i * 2]))
+			return 1;
+	return 0;
 }
 
-
-static int reset_mac( struct usb_device *dev )
+static int pegasus_reset_mac(struct usb_device *dev)
 {
-	__u8	data = 0x8;
-	int	i;
-	
-	hpna_set_register( dev, 1, 0x08 );
-	for ( i=0; i<100; i++ ) {
-		hpna_get_registers( dev, 1, 1, &data);
-		if ( !(data & 0x08) ) {
-			if ( loopback & 1 )
-				return	0;
-			else if ( loopback & 2 ) {
-				write_phy_word( dev, 0, 0x4000 );
-				/*return	0;*/
-			}
-			hpna_set_register( dev, 0x7e, 0x24 );
-			hpna_set_register( dev, 0x7e, 0x27 );
-			return	0;
+	__u8 data = 0x8;
+	int i;
+
+	pegasus_set_register(dev, 1, data);
+	for (i = 0; i < 100; i++) {
+		pegasus_get_registers(dev, 1, 1, &data);
+		if (~data & 0x08) {
+			if (loopback & 1) 
+				return 0;
+			if (loopback & 2) 
+				pegasus_write_phy_word(dev, 0, 0x4000);
+			pegasus_set_register(dev, 0x7e, 0x24);
+			pegasus_set_register(dev, 0x7e, 0x27);
+			return 0;
 		}
 	}
+
 	return 1;
 }
 
-
-int start_net( struct net_device *dev, struct usb_device *usb_dev )
+static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
 {
-	__u16	partmedia, temp;
-	__u8	node_id[6];
-	__u8	data[4];
-	
-	if ( get_node_id(usb_dev, node_id) )
-		return	1;
-	hpna_set_registers(usb_dev, 0x10, 6, node_id);
+	__u16 partmedia, temp;
+	__u8 node_id[6];
+	__u8 data[4];
+
+	if (pegasus_get_node_id(usb, node_id)) 
+		return 1;
+
+	pegasus_set_registers(usb, 0x10, 6, node_id);
 	memcpy(dev->dev_addr, node_id, 6);
-	if ( read_phy_word(usb_dev, 1, &temp) )
-		return	2;
-	if ( !(temp & 4) ) {
-		if ( loopback )
-			goto ok;
+	if (pegasus_read_phy_word(usb, 1, &temp)) 
+		return 2;
+
+	if ((~temp & 4) && !loopback) {
 		err("link NOT established - %x", temp);
-		return	3;
+		return 3;
 	}
-ok:
-	if ( read_phy_word(usb_dev, 5, &partmedia) )
-		return	4;
-	temp = partmedia;
-	partmedia &= 0x1f;
-	if ( partmedia != 1 ) {
-		err("party FAIL %x", temp);
-		return	5;
-	}
-	partmedia = temp;
-	if ( partmedia & 0x100 )
-		data[1] = 0x30;
-	else {
-		if ( partmedia & 0x80 )
-			data[1] = 0x10;
-		else 
-			data[1] = 0;
+
+	if (pegasus_read_phy_word(usb, 5, &partmedia))
+		return 4;
+
+	if ((partmedia & 0x1f) != 1) {
+		err("party FAIL %x", partmedia);
+		return 5;
 	}
-	
+
 	data[0] = 0xc9;
-	data[2] = (loopback & 1) ? 0x08 : 0x00; 
-	
-	hpna_set_registers(usb_dev, 0, 3, data);
-	
-	return	0;
-}
+	data[1] = (partmedia & 0x100) ? 0x30 : ((partmedia & 0x80) ? 0x10 : 0);
+	data[2] = (loopback & 1) ? 0x08 : 0x00;
 
+	pegasus_set_registers(usb, 0, 3, data);
 
-static void hpna_read_irq( purb_t urb )
-{
-	struct net_device *net_dev = urb->context;
-	usb_hpna_t *hpna = net_dev->priv;
-	int	count = urb->actual_length, res;
-	int	rx_status = *(int *)(hpna->rx_buff + count - 4);
+	return 0;
+}
 
+static void pegasus_read_bulk(struct urb *urb)
+{
+	struct pegasus *pegasus = urb->context;
+	struct net_device *net = pegasus->net;
+	int count = urb->actual_length, res;
+	int rx_status = *(int *)(pegasus->rx_buff + count - 4);
+	struct sk_buff	*skb;
+	__u16 pkt_len;
 
-	if ( urb->status ) {
-		info( "%s: RX status %d\n", net_dev->name, urb->status );
+	if (urb->status) {
+		info("%s: RX status %d", net->name, urb->status);
 		goto goon;
 	}
 
-	if ( !count )
+	if (!count)
 		goto goon;
-/*	if ( rx_status & 0x00010000 )
+#if 0
+	if (rx_status & 0x00010000)
 		goto goon;
-*/	
-	if ( rx_status & 0x000e0000 ) {
-		dbg("%s: error receiving packet %x",
-			net_dev->name, rx_status & 0xe0000);
-		hpna->stats.rx_errors++;
-		if(rx_status & 0x060000) hpna->stats.rx_length_errors++;
-		if(rx_status & 0x080000) hpna->stats.rx_crc_errors++;
-		if(rx_status & 0x100000) hpna->stats.rx_frame_errors++;
-	} else {
-		struct sk_buff	*skb;
-		__u16 		pkt_len = (rx_status & 0xfff) - 8;
+#endif
+	if (rx_status & 0x000e0000) {
 
+		dbg("%s: error receiving packet %x", net->name, rx_status & 0xe0000);
+		pegasus->stats.rx_errors++;
+		if(rx_status & 0x060000) pegasus->stats.rx_length_errors++;
+		if(rx_status & 0x080000) pegasus->stats.rx_crc_errors++;
+		if(rx_status & 0x100000) pegasus->stats.rx_frame_errors++;
 
-		if((skb = dev_alloc_skb(pkt_len+2)) != NULL ) {
-			skb->dev = net_dev;
-			skb_reserve(skb, 2);
-			eth_copy_and_sum(skb, hpna->rx_buff, pkt_len, 0);
-			skb_put(skb, pkt_len);
-		} else
-			goto	goon;
-		skb->protocol = eth_type_trans(skb, net_dev);
-		netif_rx(skb);
-		hpna->stats.rx_packets++;
-		hpna->stats.rx_bytes += pkt_len;
+		goto goon;
 	}
+
+	pkt_len = (rx_status & 0xfff) - 8;
+
+	if(!(skb = dev_alloc_skb(pkt_len+2)))
+		goto goon;
+
+	skb->dev = net;
+	skb_reserve(skb, 2);
+	eth_copy_and_sum(skb, pegasus->rx_buff, pkt_len, 0);
+	skb_put(skb, pkt_len);
+
+	skb->protocol = eth_type_trans(skb, net);
+	netif_rx(skb);
+	pegasus->stats.rx_packets++;
+	pegasus->stats.rx_bytes += pkt_len;
+
 goon:
-	if ( (res = usb_submit_urb( &hpna->rx_urb )) )
-		warn("failed rx_urb %d", res);
+	if ((res = usb_submit_urb(&pegasus->rx_urb)))
+		warn("(prb)failed rx_urb %d", res);
 }
 
-
-static void hpna_irq( urb_t *urb)
+static void pegasus_irq(urb_t *urb)
 {
-	if( urb->status ) {
+	if(urb->status) {
 		__u8	*d = urb->transfer_buffer;
 		printk("txst0 %x, txst1 %x, rxst %x, rxlst0 %x, rxlst1 %x, wakest %x",
-			d[0], d[1], d[2], d[3], d[4], d[5] );
+			d[0], d[1], d[2], d[3], d[4], d[5]);
 	}
 }
 
-
-static void hpna_write_irq( purb_t urb )
+static void pegasus_write_bulk(struct urb *urb)
 {
-	struct net_device *net_dev = urb->context;
-	usb_hpna_t *hpna = net_dev->priv;
+	struct pegasus *pegasus = urb->context;
 
+	spin_lock(&pegasus->pegasus_lock);
 
-	spin_lock( &hpna->hpna_lock );
-	
-	if ( urb->status ) 
-		info("%s: TX status %d\n", net_dev->name, urb->status);
-	netif_wake_queue( net_dev );
+	if (urb->status)
+		info("%s: TX status %d", pegasus->net->name, urb->status);
+	netif_wake_queue(pegasus->net);
 
-	spin_unlock( &hpna->hpna_lock );
+	spin_unlock(&pegasus->pegasus_lock);
 }
 
-
-static void tx_timeout( struct net_device *dev )
+static void pegasus_tx_timeout(struct net_device *net)
 {
-	usb_hpna_t	*hpna = dev->priv;
+	struct pegasus *pegasus = net->priv;
 
-	warn( "%s: Tx timed out. Reseting...", dev->name );
-	hpna->stats.tx_errors++;
-	dev->trans_start = jiffies;
-	netif_wake_queue( dev );
-}
+	warn("%s: Tx timed out. Reseting...", net->name);
+	pegasus->stats.tx_errors++;
+	net->trans_start = jiffies;
 
+	netif_wake_queue(net);
+}
 
-static int hpna_start_xmit( struct sk_buff *skb, struct net_device *net_dev )
+static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
 {
-	usb_hpna_t	*hpna = (usb_hpna_t *)net_dev->priv;
-	int		count = skb->len+2 % 64 ? skb->len+2 : skb->len+3;
-	int		res;
+	struct pegasus	*pegasus = net->priv;
+	int count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3;
+	int res;
 
-	spin_lock( &hpna->hpna_lock );
+	spin_lock(&pegasus->pegasus_lock);
 
-	netif_stop_queue( net_dev );
-	((__u16 *)hpna->tx_buff)[0] = skb->len;
-	memcpy(hpna->tx_buff+2, skb->data, skb->len);
-	(&hpna->tx_urb)->transfer_buffer_length = count;
-	if ( (res = usb_submit_urb( &hpna->tx_urb )) ) {
+	netif_stop_queue(net);
+
+	((__u16 *)pegasus->tx_buff)[0] = skb->len;
+	memcpy(pegasus->tx_buff+2, skb->data, skb->len);
+	(&pegasus->tx_urb)->transfer_buffer_length = count;
+
+	if ((res = usb_submit_urb(&pegasus->tx_urb))) {
 		warn("failed tx_urb %d", res);
-		hpna->stats.tx_errors++;
-		netif_start_queue( net_dev );
+		pegasus->stats.tx_errors++;
+		netif_start_queue(net);
 	} else {
-		hpna->stats.tx_packets++;
-		hpna->stats.tx_bytes += skb->len;
-		net_dev->trans_start = jiffies;
+		pegasus->stats.tx_packets++;
+		pegasus->stats.tx_bytes += skb->len;
+		net->trans_start = jiffies;
 	}
-	dev_kfree_skb( skb );
-	spin_unlock( &hpna->hpna_lock );
-	return	0;
-}
 
+	dev_kfree_skb(skb);
 
-static struct net_device_stats *hpna_netdev_stats( struct net_device *dev )
-{
-	return	&((usb_hpna_t *)dev->priv)->stats;
+	spin_unlock(&pegasus->pegasus_lock);
+
+	return 0;
 }
 
-static int hpna_open( struct net_device *net_dev )
+static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
 {
-	usb_hpna_t *hpna = (usb_hpna_t *)net_dev->priv;
-	int	res;
+	return &((struct pegasus *)dev->priv)->stats;
+}
 
-	if ( hpna->active )
-		return	-EBUSY;
-	else
-		hpna->active = 1;
+static int pegasus_open(struct net_device *net)
+{
+	struct pegasus *pegasus = (struct pegasus *)net->priv;
+	int res;
 
-	if ( start_net(net_dev, hpna->usb_dev) ) {
-		err("can't start_net()");
-		return	-EIO;
+	if ((res = pegasus_start_net(net, pegasus->usb))) {
+		err("can't start_net() - %d", res);
+		return -EIO;
 	}
 
-	if ( (res = usb_submit_urb( &hpna->rx_urb )) )
-		warn("failed rx_urb %d", res);
+	if ((res = usb_submit_urb(&pegasus->rx_urb)))
+		warn("(open)failed rx_urb %d", res);
 
-/*	usb_submit_urb( &hpna->intr_urb );*/
-	netif_start_queue( net_dev );
+/*	usb_submit_urb(&pegasus->intr_urb);*/
+	netif_start_queue(net);
 
 	MOD_INC_USE_COUNT;
 
 	return 0;
 }
 
-
-static int hpna_close( struct net_device *net_dev )
+static int pegasus_close(struct net_device *net)
 {
-	usb_hpna_t	*hpna = net_dev->priv;
-
+	struct pegasus	*pegasus = net->priv;
 
-	netif_stop_queue( net_dev );
+	netif_stop_queue(net);
 
-	usb_unlink_urb( &hpna->rx_urb );
-	usb_unlink_urb( &hpna->tx_urb );
-/*	usb_unlink_urb( hpna->intr_urb );*/
-
-	hpna->active = 0;
+	usb_unlink_urb(&pegasus->rx_urb);
+	usb_unlink_urb(&pegasus->tx_urb);
+/*	usb_unlink_urb(&pegasus->intr_urb); */
 
 	MOD_DEC_USE_COUNT;
 
 	return 0;
 }
 
-
-static int hpna_ioctl( struct net_device *dev, struct ifreq *rq, int cmd )
+static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
 {
-	__u16	*data = (__u16 *)&rq->ifr_data;
-	usb_hpna_t	*hpna = dev->priv;
+	__u16 *data = (__u16 *)&rq->ifr_data;
+	struct pegasus	*pegasus = net->priv;
 
-	switch( cmd ) {
-		case SIOCDEVPRIVATE: 
+	switch(cmd) {
+		case SIOCDEVPRIVATE:
 			data[0] = 1;
 		case SIOCDEVPRIVATE+1:
-			read_phy_word(hpna->usb_dev, data[1] & 0x1f, &data[3]);
-			return	0;
+			pegasus_read_phy_word(pegasus->usb, data[1] & 0x1f, &data[3]);
+			return 0;
 		case SIOCDEVPRIVATE+2:
-			if ( !capable(CAP_NET_ADMIN) )
-				return	-EPERM;
-			write_phy_word(hpna->usb_dev, data[1] & 0x1f, data[2]);
-			return	0;
+			if (!capable(CAP_NET_ADMIN))
+				return -EPERM;
+			pegasus_write_phy_word(pegasus->usb, data[1] & 0x1f, data[2]);
+			return 0;
 		default:
-			return	-EOPNOTSUPP;
+			return -EOPNOTSUPP;
 	}
 }
 
-
-static void set_rx_mode( struct net_device *net_dev )
+static void pegasus_set_rx_mode(struct net_device *net)
 {
-	usb_hpna_t	*hpna=net_dev->priv;
+	struct pegasus *pegasus = net->priv;
 
-	netif_stop_queue( net_dev );
-	
-	if ( net_dev->flags & IFF_PROMISC ) {
-		info("%s: Promiscuous mode enabled", net_dev->name);
-		hpna_set_register( hpna->usb_dev, 2, 0x04 );
-	} else if ((net_dev->mc_count > multicast_filter_limit) ||
-			(net_dev->flags & IFF_ALLMULTI)) {
-		hpna_set_register(hpna->usb_dev, 0, 0xfa);
-		hpna_set_register(hpna->usb_dev, 2, 0);
+	netif_stop_queue(net);
+
+	if (net->flags & IFF_PROMISC) {
+		info("%s: Promiscuous mode enabled", net->name);
+		pegasus_set_register(pegasus->usb, 2, 0x04);
+	} else if ((net->mc_count > multicast_filter_limit) ||
+			(net->flags & IFF_ALLMULTI)) {
+		pegasus_set_register(pegasus->usb, 0, 0xfa);
+		pegasus_set_register(pegasus->usb, 2, 0);
 	} else {
-		dbg("%s: set Rx mode", net_dev->name);
+		dbg("%s: set Rx mode", net->name);
 	}
 
-	netif_wake_queue( net_dev );
+	netif_wake_queue(net);
 }
 
-
-static void * usb_hpna_probe( struct usb_device *dev, unsigned int ifnum )
+static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
 {
-	struct net_device 		*net_dev;
-	usb_hpna_t			*hpna = &usb_dev_hpna;
-
+	struct net_device *net;
+	struct pegasus *pegasus;
 
-
-	if ( dev->descriptor.idVendor != ADMTEK_VENDOR_ID ||
-	     dev->descriptor.idProduct != ADMTEK_HPNA_PEGASUS ) {
-		return	NULL;
+	if (dev->descriptor.idVendor != ADMTEK_VENDOR_ID ||
+		dev->descriptor.idProduct != ADMTEK_DEVICE_ID_PEGASUS) {
+		return NULL;
 	}
 
-	printk("USB HPNA Pegasus found\n");
-
-	if ( usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
 		err("usb_set_configuration() failed");
 		return NULL;
 	}
 
-	hpna->usb_dev = dev;
-
-	hpna->rx_pipe = usb_rcvbulkpipe(hpna->usb_dev, 1);
-	hpna->tx_pipe = usb_sndbulkpipe(hpna->usb_dev, 2);
-	hpna->intr_pipe = usb_rcvintpipe(hpna->usb_dev, 0);
+	if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
+		err("out of memory allocating device structure");
+		return NULL;
+	}
+	memset(pegasus, 0, sizeof(struct pegasus));
 
-	if ( reset_mac(dev) ) {
+	if (pegasus_reset_mac(dev)) {
 		err("can't reset MAC");
+		kfree(pegasus);
+		return NULL;
 	}
-
-	hpna->present = 1;
-
-	if(!(hpna->rx_buff=kmalloc(MAX_MTU, GFP_KERNEL))) {
-		err("not enough mem for out buff");
-		return	NULL;
-	}
-	if(!(hpna->tx_buff=kmalloc(MAX_MTU, GFP_KERNEL))) {
-		kfree_s(hpna->rx_buff, MAX_MTU);
-		err("not enough mem for out buff");
-		return	NULL;
-	}
-
-	net_dev = init_etherdev( 0, 0 );
-	hpna->net_dev = net_dev;
-	net_dev->priv = hpna;
-	net_dev->open = hpna_open;
-	net_dev->stop = hpna_close;
-	net_dev->watchdog_timeo = TX_TIMEOUT;
-	net_dev->tx_timeout = tx_timeout;
-	net_dev->do_ioctl = hpna_ioctl; 
-	net_dev->hard_start_xmit = hpna_start_xmit;
-	net_dev->set_multicast_list = set_rx_mode;
-	net_dev->get_stats = hpna_netdev_stats; 
-	net_dev->mtu = HPNA_MTU;
-	hpna->hpna_lock = SPIN_LOCK_UNLOCKED;
-	
-	FILL_BULK_URB( &hpna->rx_urb, hpna->usb_dev, hpna->rx_pipe, 
-			hpna->rx_buff, MAX_MTU, hpna_read_irq, net_dev );
-	FILL_BULK_URB( &hpna->tx_urb, hpna->usb_dev, hpna->tx_pipe, 
-			hpna->tx_buff, MAX_MTU, hpna_write_irq, net_dev );
-	FILL_INT_URB( &hpna->intr_urb, hpna->usb_dev, hpna->intr_pipe,
-			hpna->intr_buff, 8, hpna_irq, net_dev, 250 );
-	
-/*	list_add( &hpna->list, &hpna_list );*/
 	
-	return	net_dev; 
+	net = init_etherdev(0, 0);
+	net->priv = pegasus;
+	net->open = pegasus_open;
+	net->stop = pegasus_close;
+	net->watchdog_timeo = PEGASUS_TX_TIMEOUT;
+	net->tx_timeout = pegasus_tx_timeout;
+	net->do_ioctl = pegasus_ioctl;
+	net->hard_start_xmit = pegasus_start_xmit;
+	net->set_multicast_list = pegasus_set_rx_mode;
+	net->get_stats = pegasus_netdev_stats;
+	net->mtu = PEGASUS_MTU;
+
+	pegasus->usb = dev;
+	pegasus->net = net;
+	pegasus->pegasus_lock = SPIN_LOCK_UNLOCKED;
+
+	FILL_BULK_URB(&pegasus->rx_urb, dev, usb_rcvbulkpipe(dev, 1),
+			pegasus->rx_buff, PEGASUS_MAX_MTU, pegasus_read_bulk, 
+			pegasus);
+	FILL_BULK_URB(&pegasus->tx_urb, dev, usb_sndbulkpipe(dev, 2),
+			pegasus->tx_buff, PEGASUS_MAX_MTU, pegasus_write_bulk,
+			pegasus);
+	FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 0),
+			pegasus->intr_buff, 8, pegasus_irq, pegasus, 250);
+
+
+	printk(KERN_INFO "%s: ADMtek AN986 Pegasus usb device\n", net->name);
+
+	return pegasus;
 }
 
-
-static void usb_hpna_disconnect( struct usb_device *dev, void *ptr )
+static void pegasus_disconnect(struct usb_device *dev, void *ptr)
 {
-	struct net_device	*net_dev = ptr;
-	struct usb_hpna		*hpna = net_dev->priv;
+	struct pegasus *pegasus = ptr;
 
+	if (!pegasus) {
+		warn("unregistering non-existant device");
+		return;
+	}
 
-	if ( net_dev->flags & IFF_UP )
-		dev_close(net_dev);
-	
-	unregister_netdev( net_dev );
+	if (pegasus->net->flags & IFF_UP)
+		dev_close(pegasus->net);
 
-	if ( !hpna ) /* should never happen */
-		return;
-		
-	usb_unlink_urb( &hpna->rx_urb );
-	usb_unlink_urb( &hpna->tx_urb );
-/*	usb_unlink_urb( &hpna->intr_urb );*/
-	kfree_s(hpna->rx_buff, MAX_MTU);
-	kfree_s(hpna->tx_buff, MAX_MTU);
+	unregister_netdev(pegasus->net);
 
-	hpna->usb_dev = NULL;
-	hpna->present = 0;
+	usb_unlink_urb(&pegasus->rx_urb);
+	usb_unlink_urb(&pegasus->tx_urb);
+/*	usb_unlink_urb(&pegasus->intr_urb);*/
 
-	printk("USB HPNA disconnected\n");
+	kfree(pegasus);
 }
 
-
-static struct usb_driver usb_hpna_driver = {
-	"ADMtek \"Pegasus\" USB Ethernet",
-	usb_hpna_probe,
-	usb_hpna_disconnect,
-	{NULL, NULL}
+static struct usb_driver pegasus_driver = {
+	name:		"pegasus",
+	probe:		pegasus_probe,
+	disconnect:	pegasus_disconnect,
 };
 
-
-
-static int  __init start_hpna( void )
+int __init pegasus_init(void)
 {
 	printk( version );
-	return	usb_register( &usb_hpna_driver );
+	return usb_register(&pegasus_driver);
 }
 
-
-static void __exit stop_hpna( void )
+void __exit pegasus_exit(void)
 {
-	usb_deregister( &usb_hpna_driver );
+	usb_deregister(&pegasus_driver);
 }
 
-
-module_init( start_hpna );
-module_exit( stop_hpna );
+module_init(pegasus_init);
+module_exit(pegasus_exit);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)