# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.557   -> 1.558  
#	drivers/usb/pegasus.h	1.11    -> 1.12   
#	drivers/usb/pegasus.c	1.19    -> 1.20   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/03/22	petkan@mastika.	1.558
# USB pegasus driver
# 
# fix problem which cause hotplug/unplug crash the kernel
# --------------------------------------------
#
diff -Nru a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
--- a/drivers/usb/pegasus.c	Wed Apr  3 16:39:45 2002
+++ b/drivers/usb/pegasus.c	Wed Apr  3 16:39:45 2002
@@ -59,7 +59,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.5.1 (2002/03/06)"
+#define DRIVER_VERSION "v0.5.2 (2002/03/21)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
@@ -71,6 +71,7 @@
 static int loopback = 0;
 static int mii_mode = 0;
 static int multicast_filter_limit = 32;
+static DECLARE_MUTEX(gsem);
 
 static struct usb_eth_dev usb_dev_id[] = {
 #define	PEGASUS_DEV(pn, vid, pid, flags)	\
@@ -741,6 +742,7 @@
 	pegasus_t *pegasus = (pegasus_t *)net->priv;
 	int	res;
 
+	down(&pegasus->sem);
 	FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
 			usb_rcvbulkpipe(pegasus->usb, 1),
 			pegasus->rx_buff, PEGASUS_MAX_MTU, 
@@ -759,11 +761,15 @@
 	pegasus->flags |= PEGASUS_RUNNING;
 	if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
 		err("can't enable_net_traffic() - %d", res);
-		return -EIO;
+		res = -EIO;
+		goto exit;
 	}
 	set_carrier(net);
+	res = 0;
+exit:
+	up(&pegasus->sem);
 
-	return 0;
+	return res;
 }
 
 
@@ -771,6 +777,7 @@
 {
 	pegasus_t	*pegasus = net->priv;
 
+	down(&pegasus->sem);
 	pegasus->flags &= ~PEGASUS_RUNNING;
 	netif_stop_queue( net );
 	if ( !(pegasus->flags & PEGASUS_UNPLUG) )
@@ -782,6 +789,7 @@
 #ifdef	PEGASUS_USE_INTR
 	usb_unlink_urb( pegasus->intr_urb );
 #endif
+	up(&pegasus->sem);
 
 	return 0;
 }
@@ -868,23 +876,32 @@
 {
 	__u16 *data = (__u16 *)&rq->ifr_data;
 	pegasus_t	*pegasus = net->priv;
+	int	res;
 
+	down(&pegasus->sem);
 	switch(cmd) {
 	case SIOCETHTOOL:
-		return pegasus_ethtool_ioctl(net, rq->ifr_data);
+		res = pegasus_ethtool_ioctl(net, rq->ifr_data);
+		break;
 	case SIOCDEVPRIVATE:
 		data[0] = pegasus->phy;
 	case SIOCDEVPRIVATE+1:
 		read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
-		return 0;
+		res = 0;
+		break;
 	case SIOCDEVPRIVATE+2:
-		if ( !capable(CAP_NET_ADMIN) )
+		if ( !capable(CAP_NET_ADMIN) ) {
+			up(&pegasus->sem);
 			return -EPERM;
+		}
 		write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
-		return 0;
+		res = 0;
+		break;
 	default:
-		return -EOPNOTSUPP;
+		res = -EOPNOTSUPP;
 	}
+	up(&pegasus->sem);
+	return res;
 }
 
 
@@ -953,10 +970,10 @@
 		err("usb_set_configuration() failed");
 		return NULL;
 	}
-
+	down(&gsem);
 	if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
 		err("out of memory allocating device structure");
-		return NULL;
+		goto exit;
 	}
 
 	usb_inc_dev_use( dev );
@@ -967,20 +984,23 @@
 	pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!pegasus->ctrl_urb) {
 		kfree (pegasus);
-		return NULL;
+		pegasus = NULL;
+		goto exit;
 	}
 	pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!pegasus->rx_urb) {
 		usb_free_urb (pegasus->ctrl_urb);
 		kfree (pegasus);
-		return NULL;
+		pegasus = NULL;
+		goto exit;
 	}
 	pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!pegasus->tx_urb) {
 		usb_free_urb (pegasus->rx_urb);
 		usb_free_urb (pegasus->ctrl_urb);
 		kfree (pegasus);
-		return NULL;
+		pegasus = NULL;
+		goto exit;
 	}
 	pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!pegasus->intr_urb) {
@@ -988,7 +1008,8 @@
 		usb_free_urb (pegasus->rx_urb);
 		usb_free_urb (pegasus->ctrl_urb);
 		kfree (pegasus);
-		return NULL;
+		pegasus = NULL;
+		goto exit;
 	}
 
 	net = init_etherdev( NULL, 0 );
@@ -997,9 +1018,11 @@
 		usb_free_urb (pegasus->rx_urb);
 		usb_free_urb (pegasus->ctrl_urb);
 		kfree( pegasus );
-		return	NULL;
+		pegasus = NULL;
+		goto exit;
 	}
-	
+
+	init_MUTEX(&pegasus->sem);
 	pegasus->usb = dev;
 	pegasus->net = net;
 	SET_MODULE_OWNER(net);
@@ -1027,7 +1050,7 @@
 		kfree(pegasus->net);
 		kfree(pegasus);
 		pegasus = NULL;
-		return NULL;
+		goto exit;
 	}
 
 	info( "%s: %s", net->name, usb_dev_id[dev_index].name );
@@ -1044,7 +1067,8 @@
 		warn( "can't locate MII phy, using default" );
 		pegasus->phy = 1;
 	}
-
+exit:
+	up(&gsem);
 	return pegasus;
 }
 
diff -Nru a/drivers/usb/pegasus.h b/drivers/usb/pegasus.h
--- a/drivers/usb/pegasus.h	Wed Apr  3 16:39:45 2002
+++ b/drivers/usb/pegasus.h	Wed Apr  3 16:39:45 2002
@@ -101,7 +101,7 @@
 	struct urb		*ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
 	struct usb_ctrlrequest	dr;
 	wait_queue_head_t	ctrl_wait;
-	struct semaphore	ctrl_sem;
+	struct semaphore	sem;
 	unsigned char		rx_buff[PEGASUS_MAX_MTU];
 	unsigned char		tx_buff[PEGASUS_MAX_MTU];
 	unsigned char		intr_buff[8];
