# 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.225 -> 1.226 # drivers/usb/pegasus.h 1.8 -> 1.9 # drivers/usb/pegasus.c 1.12 -> 1.13 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/03/22 petkan@mastika. 1.226 # 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 Fri Mar 22 15:47:39 2002 +++ b/drivers/usb/pegasus.c Fri Mar 22 15:47:39 2002 @@ -57,7 +57,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.4.25 (2002/03/06)" +#define DRIVER_VERSION "v0.4.26 (2002/03/21)" #define DRIVER_AUTHOR "Petko Manolov " #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" @@ -69,6 +69,7 @@ static int loopback = 0; static int mii_mode = 1; 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 @@ 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,12 +761,16 @@ 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); - - return 0; + res = 0; +exit: + up(&pegasus->sem); + + return res; } @@ -772,6 +778,7 @@ { pegasus_t *pegasus = net->priv; + down(&pegasus->sem); pegasus->flags &= ~PEGASUS_RUNNING; netif_stop_queue( net ); if ( !(pegasus->flags & PEGASUS_UNPLUG) ) @@ -783,7 +790,8 @@ #ifdef PEGASUS_USE_INTR usb_unlink_urb( pegasus->intr_urb ); #endif - + up(&pegasus->sem); + return 0; } @@ -869,23 +877,33 @@ { __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; } @@ -955,9 +973,10 @@ 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 ); @@ -968,20 +987,23 @@ pegasus->ctrl_urb = usb_alloc_urb(0); if (!pegasus->ctrl_urb) { kfree (pegasus); - return NULL; + pegasus = NULL; + goto exit; } pegasus->rx_urb = usb_alloc_urb(0); 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); 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); if (!pegasus->intr_urb) { @@ -989,7 +1011,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 ); @@ -998,9 +1021,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); @@ -1028,7 +1053,7 @@ kfree(pegasus->net); kfree(pegasus); pegasus = NULL; - return NULL; + goto exit; } info( "%s: %s", net->name, usb_dev_id[dev_index].name ); @@ -1046,6 +1071,8 @@ 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 Fri Mar 22 15:47:39 2002 +++ b/drivers/usb/pegasus.h Fri Mar 22 15:47:39 2002 @@ -102,7 +102,7 @@ struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb; devrequest dr; wait_queue_head_t ctrl_wait; - struct semaphore ctrl_sem; + struct semaphore sem; unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]); unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]); unsigned char ALIGN(intr_buff[8]);