patch-2.4.0-test11 linux/drivers/usb/pegasus.c

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

diff -u --recursive --new-file v2.4.0-test10/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c
@@ -40,7 +40,6 @@
  */
 
 
-#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
@@ -48,162 +47,44 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/usb.h>
-
-
-static const char *version = __FILE__ ": v0.4.13 2000/10/13 (C) 1999-2000 Petko Manolov (petkan@dce.bg)";
+#include <linux/module.h>
+#include "pegasus.h"
 
 
 #define	PEGASUS_USE_INTR
+#define	PEGASUS_WRITE_EEPROM
 
+static const char *version = __FILE__ ": v0.4.17 2000/11/13 (C) 1999-2000 Petko Manolov (petkan@dce.bg)";
 
-#define	PEGASUS_II		0x80000000
-#define	HAS_HOME_PNA		0x40000000
 
-#define	PEGASUS_MTU		1500
-#define	PEGASUS_MAX_MTU		1536
+static int loopback = 0;
+static int mii_mode = 0;
+static int multicast_filter_limit = 32;
 
-#define	EPROM_WRITE		0x01
-#define	EPROM_READ		0x02
-#define	EPROM_DONE		0x04
-#define	EPROM_WR_ENABLE		0x10
-#define	EPROM_LOAD		0x20
-
-#define	MII_BMCR		0x00
-#define	MII_BMSR		0x01
-#define	BMSR_MEDIA		0x7808
-#define	MII_ANLPA		0x05
-#define	ANLPA_100TX_FD		0x0100
-#define	ANLPA_100TX_HD		0x0080
-#define	ANLPA_10T_FD		0x0040
-#define	ANLPA_10T_HD		0x0020
-#define	PHY_DONE		0x80
-#define	PHY_READ		0x40
-#define	PHY_WRITE		0x20
-#define	DEFAULT_GPIO_RESET	0x24
-#define	LINKSYS_GPIO_RESET	0x24
-#define	DEFAULT_GPIO_SET	0x26
-
-#define	PEGASUS_PRESENT		0x00000001
-#define	PEGASUS_RUNNING		0x00000002
-#define	PEGASUS_TX_BUSY		0x00000004
-#define	PEGASUS_RX_BUSY		0x00000008
-#define	CTRL_URB_RUNNING	0x00000010
-#define	CTRL_URB_SLEEP		0x00000020
-#define	PEGASUS_UNPLUG		0x00000040
-#define	ETH_REGS_CHANGE		0x40000000
-#define	ETH_REGS_CHANGED	0x80000000
-
-#define	RX_MULTICAST		2
-#define	RX_PROMISCUOUS		4
-
-#define	REG_TIMEOUT		(HZ)
-#define	PEGASUS_TX_TIMEOUT	(HZ*10)
-
-#define	TX_UNDERRUN		0x80
-#define	EXCESSIVE_COL		0x40
-#define	LATE_COL		0x20
-#define	NO_CARRIER		0x10
-#define	LOSS_CARRIER		0x08
-#define	JABBER_TIMEOUT		0x04
-
-#define	PEGASUS_REQT_READ	0xc0
-#define	PEGASUS_REQT_WRITE	0x40
-#define	PEGASUS_REQ_GET_REGS	0xf0
-#define	PEGASUS_REQ_SET_REGS	0xf1
-#define	PEGASUS_REQ_SET_REG	PEGASUS_REQ_SET_REGS
-#define	NUM_CTRL_URBS		0x10
-#define	ALIGN(x)		x __attribute__((aligned(L1_CACHE_BYTES)))
-
-enum pegasus_registers {
-	EthCtrl0 = 0,
-	EthCtrl1 = 1,
-	EthCtrl2 = 2,
-	EthID = 0x10,
-	Reg1d = 0x1d,
-	EpromOffset = 0x20,
-	EpromData = 0x21,	/* 0x21 low, 0x22 high byte */
-	EpromCtrl = 0x23,
-	PhyAddr = 0x25,
-	PhyData = 0x26, 	/* 0x26 low, 0x27 high byte */
-	PhyCtrl = 0x28,
-	UsbStst = 0x2a,
-	EthTxStat0 = 0x2b,
-	EthTxStat1 = 0x2c,
-	EthRxStat = 0x2d,
-	Reg7b = 0x7b,
-	Gpio0 = 0x7e,
-	Gpio1 = 0x7f,
-	Reg81 = 0x81,
+static struct usb_eth_dev usb_dev_id[] = {
+#define	PEGASUS_DEV(pn, vid, pid, flags)	\
+	{name:pn, vendor:vid, device:pid, private:flags},
+#include "pegasus.h"
+#undef	PEGASUS_DEV
+	{NULL, 0, 0, 0}
 };
 
-
-typedef struct pegasus {
-	struct usb_device	*usb;
-	struct net_device	*net;
-	struct net_device_stats	stats;
-	unsigned		flags;
-	unsigned		features;
-	int			intr_interval;
-	struct urb		ctrl_urb, rx_urb, tx_urb, intr_urb;
-	devrequest		dr;
-	wait_queue_head_t	ctrl_wait;
-	struct semaphore	ctrl_sem;
-	unsigned char		ALIGN(rx_buff[PEGASUS_MAX_MTU]);
-	unsigned char		ALIGN(tx_buff[PEGASUS_MAX_MTU]);
-	unsigned char		ALIGN(intr_buff[8]);
-	__u8			eth_regs[4];
-	__u8			phy;
-	__u8			gpio_res;
-} pegasus_t;
-
-struct usb_eth_dev {
-	char	*name;
-	__u16	vendor;
-	__u16	device;
-	__u32	private; /* LSB is gpio reset value */
+static struct usb_device_id pegasus_ids[] = {
+#define	PEGASUS_DEV(pn, vid, pid, flags) {idVendor:vid, idProduct:pid},
+#include "pegasus.h"
+#undef	PEGASUS_DEV
+	{ }
 };
 
 
-static int loopback = 0;
-static int mii_mode = 0;
-static int multicast_filter_limit = 32;
-
-
 MODULE_AUTHOR("Petko Manolov <petkan@dce.bg>");
 MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver");
 MODULE_PARM(loopback, "i");
-MODULE_PARM(mode, "i");
+MODULE_PARM(mii_mode, "i");
 MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)");
-MODULE_PARM_DESC(mode, "Enable HomePNA mode (bit 0) - default = MII mode = 0");
+MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0");
 
-
-static struct usb_eth_dev usb_dev_id[] = {
-	{"Billionton USB-100", 0x08dd, 0x0986, DEFAULT_GPIO_RESET},
-	{"Corega FEter USB-TX", 0x7aa, 0x0004, DEFAULT_GPIO_RESET},
-	{"MELCO/BUFFALO LUA-TX", 0x0411, 0x0001, DEFAULT_GPIO_RESET},
-	{"D-Link DSB-650TX", 0x2001, 0x4001, LINKSYS_GPIO_RESET},
-	{"D-Link DSB-650TX", 0x2001, 0x4002, LINKSYS_GPIO_RESET},
-	{"D-Link DSB-650TX(PNA)", 0x2001, 0x4003,
-		HAS_HOME_PNA | DEFAULT_GPIO_RESET},
-	{"D-Link DSB-650", 0x2001, 0xabc1, DEFAULT_GPIO_RESET},
-	{"D-Link DU-E10", 0x07b8, 0xabc1, DEFAULT_GPIO_RESET},
-	{"D-Link DU-E100", 0x07b8, 0x4002, DEFAULT_GPIO_RESET},
-	{"Linksys USB10TX", 0x066b, 0x2202, LINKSYS_GPIO_RESET},
-	{"Linksys USB100TX", 0x066b, 0x2203, LINKSYS_GPIO_RESET},
-	{"Linksys USB100TX", 0x066b, 0x2204, HAS_HOME_PNA | LINKSYS_GPIO_RESET},
-	{"Linksys USB Ethernet Adapter", 0x066b, 0x2206, LINKSYS_GPIO_RESET},
-	{"SMC 202 USB Ethernet", 0x0707, 0x0200, DEFAULT_GPIO_RESET},
-	{"ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)", 0x07a6, 0x0986, 
-		HAS_HOME_PNA | DEFAULT_GPIO_RESET},
-	{"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, 
-		DEFAULT_GPIO_RESET},
-	{"IO DATA USB ET/TX", 0x04bb, 0x0904, DEFAULT_GPIO_RESET},
-	{"LANEED USB Ethernet LD-USB/TX", 0x056e, 0x4002, DEFAULT_GPIO_RESET},
-	{"SOHOware NUB100 Ethernet", 0x15e8, 0x9100, DEFAULT_GPIO_RESET},
-	{"ADMtek ADM8511 \"Pegasus II\" USB Ethernet", 0x07a6, 0x8511, 
-		PEGASUS_II | DEFAULT_GPIO_RESET},
-	{NULL, 0, 0, 0}
-};
+MODULE_DEVICE_TABLE (usb, pegasus_ids);
 
 
 static int update_eth_regs_async( pegasus_t * );
@@ -243,7 +124,7 @@
 {
 	int	ret;
 
-	if ( pegasus->flags & ETH_REGS_CHANGED ) {
+	while ( pegasus->flags & ETH_REGS_CHANGED ) {
 		pegasus->flags |= CTRL_URB_SLEEP;
 		interruptible_sleep_on( &pegasus->ctrl_wait );
 	}
@@ -274,7 +155,7 @@
 {
 	int	ret;
 
-	if ( pegasus->flags & ETH_REGS_CHANGED ) {
+	while ( pegasus->flags & ETH_REGS_CHANGED ) {
 		pegasus->flags |= CTRL_URB_SLEEP ;
 		interruptible_sleep_on( &pegasus->ctrl_wait );
 	}
@@ -305,7 +186,7 @@
 {
 	int	ret;
 
-	if ( pegasus->flags & ETH_REGS_CHANGED ) {
+	while ( pegasus->flags & ETH_REGS_CHANGED ) {
 		pegasus->flags |= CTRL_URB_SLEEP;
 		interruptible_sleep_on( &pegasus->ctrl_wait );
 	}
@@ -354,7 +235,7 @@
 }
 
 
-static int read_phy_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd )
+static int read_mii_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd )
 {
 	int	i;
 	__u8	data[4] = { phy, 0, 0, indx };
@@ -377,7 +258,7 @@
 }
 
 
-static int write_phy_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd )
+static int write_mii_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd )
 {
 	int	i;
 	__u8	data[4] = { phy, 0, 0, indx };
@@ -505,6 +386,15 @@
 	}
 	if ( i == REG_TIMEOUT )
 		return 1;
+
+	if ( usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
+	     usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK1 ) {
+		__u16	auxmode;
+
+		read_mii_word( pegasus, 0, 0x1b, &auxmode );
+		write_mii_word( pegasus, 0, 0x1b, auxmode | 4 );
+	}
+
 	return	0;
 }
 
@@ -516,13 +406,13 @@
 	pegasus_t *pegasus = dev->priv;
 
 
-	if ( read_phy_word(pegasus, pegasus->phy, MII_BMSR, &bmsr) ) 
-		return 2;
+	if ( read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr) ) 
+		return 1;
 	if ( !(bmsr & 0x20) && !loopback ) 
 		warn( "%s: link NOT established (0x%x) - check the cable.",
 			dev->name, bmsr );
-	if ( read_phy_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) )
-		return 4;
+	if ( read_mii_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) )
+		return 2;
 	if ( !(linkpart & 1) )
 		warn( "link partner stat %x", linkpart );
 
@@ -536,7 +426,7 @@
 		data[1] = 0;
 	data[2] = (loopback & 1) ? 0x09 : 0x01;
 
-	*(unsigned *)pegasus->eth_regs = *(unsigned *)data;
+	memcpy( pegasus->eth_regs, data, sizeof(data) );
 
 	set_registers( pegasus, EthCtrl0, 3, data );
 
@@ -562,23 +452,29 @@
 
 	if ( pegasus->flags & PEGASUS_RX_BUSY ) {
 		pegasus->stats.rx_errors++;
+		dbg("pegasus Rx busy");
 		return;
 	}
 	pegasus->flags |= PEGASUS_RX_BUSY;
 
-	rx_status = *(int *)(pegasus->rx_buff + count - 4);
-
-	if (urb->status) {
-		dbg("%s: RX status %d", net->name, urb->status);
-		goto goon;
+	switch ( urb->status ) {
+		case USB_ST_NOERROR:
+			break;
+		case USB_ST_NORESPONSE:
+			dbg( "reset MAC" );
+			pegasus->flags &= ~PEGASUS_RX_BUSY;
+			break;
+		default:
+			dbg( "%s: RX status %d", net->name, urb->status );
+			goto goon;
 	}
 
 	if ( !count )
 		goto goon;
 
+	rx_status = *(int *)(pegasus->rx_buff + count - 4);
 	if ( rx_status & 0x000e0000 ) {
-
-		dbg("%s: error receiving packet %x", net->name, rx_status & 0xe0000);
+		dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000);
 		pegasus->stats.rx_errors++;
 		if ( rx_status & 0x060000 )
 			pegasus->stats.rx_length_errors++;
@@ -586,7 +482,6 @@
 			pegasus->stats.rx_crc_errors++;
 		if ( rx_status & 0x100000 )
 			pegasus->stats.rx_frame_errors++;
-
 		goto goon;
 	}
 
@@ -629,6 +524,7 @@
 	if ( urb->status )
 		info("%s: TX status %d", pegasus->net->name, urb->status);
 
+	pegasus->net->trans_start = jiffies;
 	netif_wake_queue( pegasus->net );
 }
 
@@ -641,6 +537,16 @@
 
 	if ( !pegasus )
 		return;
+		
+	switch ( urb->status ) {
+		case USB_ST_NOERROR:
+			break;
+		case USB_ST_URB_KILLED:
+			return;
+		default:
+			info("intr status %d", urb->status);
+	}
+
 	d = urb->transfer_buffer;
 	net = pegasus->net;
 	if ( d[0] & 0xfc ) {
@@ -654,31 +560,23 @@
 		if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )
 			pegasus->stats.tx_carrier_errors++;
 	}
-	switch ( urb->status ) {
-		case USB_ST_NOERROR:
-			break;
-		case USB_ST_URB_KILLED:
-			break;
-		default:
-			info("intr status %d", urb->status);
-	}
 }
 #endif
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,48)
 static void pegasus_tx_timeout( struct net_device *net )
 {
 	pegasus_t *pegasus = net->priv;
 
 	if ( !pegasus )
 		return;
-	
-	usb_unlink_urb( &pegasus->tx_urb );
+		
 	warn("%s: Tx timed out.", net->name);
+	pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
+	usb_unlink_urb( &pegasus->tx_urb );
 	pegasus->stats.tx_errors++;
-	net->trans_start = jiffies;
-
-	netif_wake_queue( net );
 }
+#endif
 
 
 static int pegasus_start_xmit( struct sk_buff *skb, struct net_device *net )
@@ -696,7 +594,6 @@
 			pegasus->tx_buff, PEGASUS_MAX_MTU, 
 			write_bulk_callback, pegasus );
 	pegasus->tx_urb.transfer_buffer_length = count;
-	pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
 	if ((res = usb_submit_urb(&pegasus->tx_urb))) {
 		warn("failed tx_urb %d", res);
 		pegasus->stats.tx_errors++;
@@ -732,6 +629,14 @@
 	__u8	data[2];
 
 	read_eprom_word( pegasus, 4, (__u16 *)data );
+	if ( data[1] < 0x80 ) {
+		info( "intr interval will be changed from %ums to %ums",
+		     data[1], 0x80 );
+		data[1] = 0x80;
+#ifdef	PEGASUS_WRITE_EEPROM
+		write_eprom_word( pegasus, 4, *(__u16 *)data );
+#endif
+	}
 	pegasus->intr_interval = data[1];
 }
 
@@ -754,7 +659,6 @@
 	if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
 		warn( __FUNCTION__ " failed rx_urb %d", res );
 #ifdef	PEGASUS_USE_INTR
-	get_interrupt_interval( pegasus );
 	FILL_INT_URB( &pegasus->intr_urb, pegasus->usb,
 			usb_rcvintpipe(pegasus->usb, 3),
 			pegasus->intr_buff, sizeof(pegasus->intr_buff),
@@ -781,8 +685,9 @@
 	usb_unlink_urb( &pegasus->rx_urb );
 	usb_unlink_urb( &pegasus->tx_urb );
 	usb_unlink_urb( &pegasus->ctrl_urb );
+#ifdef	PEGASUS_USE_INTR
 	usb_unlink_urb( &pegasus->intr_urb );
-
+#endif
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -798,12 +703,12 @@
 		case SIOCDEVPRIVATE:
 			data[0] = pegasus->phy;
 		case SIOCDEVPRIVATE+1:
-			read_phy_word(pegasus, data[0], data[1]&0x1f, &data[3]);
+			read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
 			return 0;
 		case SIOCDEVPRIVATE+2:
 			if ( !capable(CAP_NET_ADMIN) )
 				return -EPERM;
-			write_phy_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
+			write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
 			return 0;
 		default:
 			return -EOPNOTSUPP;
@@ -838,34 +743,20 @@
 }
 
 
-static int check_device_ids( __u16 vendor, __u16 product )
-{
-	int i=0;
-	
-	while ( usb_dev_id[i].name ) {
-		if ( (usb_dev_id[i].vendor == vendor) && 
-			(usb_dev_id[i].device == product) )
-			return i;
-		i++;
-	}
-	return	-1;
-}
-
-
 static __u8 mii_phy_probe( pegasus_t *pegasus )
 {
 	int	i;
 	__u16	tmp;
 
 	for ( i=0; i < 32; i++ ) {
-		read_phy_word( pegasus, i, MII_BMSR, &tmp );
+		read_mii_word( pegasus, i, MII_BMSR, &tmp );
 		if ( tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0 )
 			continue;
 		else
 			return	i;
 	}
 
-	return	0;
+	return	0xff;
 }
 
 
@@ -880,15 +771,12 @@
 }
 
 
-static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum )
+static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
+			     const struct usb_device_id *id)
 {
-	struct net_device *net;
-	pegasus_t *pegasus;
-	int	dev_indx;
-
-	if ( (dev_indx = check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct)) == -1 ) {
-		return NULL;
-	}
+	struct net_device	*net;
+	pegasus_t		*pegasus;
+	int			dev_index = id - pegasus_ids;
 
 	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
 		err("usb_set_configuration() failed");
@@ -902,7 +790,7 @@
 
 	usb_inc_dev_use( dev );
 	memset(pegasus, 0, sizeof(struct pegasus));
-	init_MUTEX( &pegasus-> ctrl_sem );
+	pegasus->dev_index = dev_index;
 	init_waitqueue_head( &pegasus->ctrl_wait );
 
 	net = init_etherdev( NULL, 0 );
@@ -926,7 +814,10 @@
 	net->get_stats = pegasus_netdev_stats;
 	net->mtu = PEGASUS_MTU;
 
-	pegasus->features = usb_dev_id[dev_indx].private;
+	pegasus->features = usb_dev_id[dev_index].private;
+#ifdef	PEGASUS_USE_INTR
+	get_interrupt_interval( pegasus );
+#endif
 	if ( reset_mac(pegasus) ) {
 		err("can't reset MAC");
 		unregister_netdev( pegasus->net );
@@ -935,21 +826,21 @@
 		return NULL;
 	}
 
+	info( "%s: %s", net->name, usb_dev_id[dev_index].name );
+
 	set_ethernet_addr( pegasus );
-	
+
 	if ( pegasus->features & PEGASUS_II ) {
 		info( "setup Pegasus II specific registers" );
 		setup_pegasus_II( pegasus );
 	}
 	
 	pegasus->phy = mii_phy_probe( pegasus );
-	if ( !pegasus->phy ) {
+	if ( pegasus->phy == 0xff ) {
 		warn( "can't locate MII phy, using default" );
 		pegasus->phy = 1;
 	}
 
-	info( "%s: %s", net->name, usb_dev_id[dev_indx].name );
-
 	return pegasus;
 }
 
@@ -975,6 +866,7 @@
 	name:		"pegasus",
 	probe:		pegasus_probe,
 	disconnect:	pegasus_disconnect,
+	id_table:	pegasus_ids,
 };
 
 int __init pegasus_init(void)

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