# 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 " #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];