Commit c71dac64 authored by Petko Manolov's avatar Petko Manolov Committed by Greg Kroah-Hartman

USB pegasus driver

fix problem which cause hotplug/unplug crash the kernel
parent f0c3878e
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
/* /*
* Version Information * 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_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
static int loopback = 0; static int loopback = 0;
static int mii_mode = 0; static int mii_mode = 0;
static int multicast_filter_limit = 32; static int multicast_filter_limit = 32;
static DECLARE_MUTEX(gsem);
static struct usb_eth_dev usb_dev_id[] = { static struct usb_eth_dev usb_dev_id[] = {
#define PEGASUS_DEV(pn, vid, pid, flags) \ #define PEGASUS_DEV(pn, vid, pid, flags) \
...@@ -741,6 +742,7 @@ static int pegasus_open(struct net_device *net) ...@@ -741,6 +742,7 @@ static int pegasus_open(struct net_device *net)
pegasus_t *pegasus = (pegasus_t *)net->priv; pegasus_t *pegasus = (pegasus_t *)net->priv;
int res; int res;
down(&pegasus->sem);
FILL_BULK_URB( pegasus->rx_urb, pegasus->usb, FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1), usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_buff, PEGASUS_MAX_MTU, pegasus->rx_buff, PEGASUS_MAX_MTU,
...@@ -759,11 +761,15 @@ static int pegasus_open(struct net_device *net) ...@@ -759,11 +761,15 @@ static int pegasus_open(struct net_device *net)
pegasus->flags |= PEGASUS_RUNNING; pegasus->flags |= PEGASUS_RUNNING;
if ( (res = enable_net_traffic(net, pegasus->usb)) ) { if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
err("can't enable_net_traffic() - %d", res); err("can't enable_net_traffic() - %d", res);
return -EIO; res = -EIO;
goto exit;
} }
set_carrier(net); set_carrier(net);
res = 0;
exit:
up(&pegasus->sem);
return 0; return res;
} }
...@@ -771,6 +777,7 @@ static int pegasus_close( struct net_device *net ) ...@@ -771,6 +777,7 @@ static int pegasus_close( struct net_device *net )
{ {
pegasus_t *pegasus = net->priv; pegasus_t *pegasus = net->priv;
down(&pegasus->sem);
pegasus->flags &= ~PEGASUS_RUNNING; pegasus->flags &= ~PEGASUS_RUNNING;
netif_stop_queue( net ); netif_stop_queue( net );
if ( !(pegasus->flags & PEGASUS_UNPLUG) ) if ( !(pegasus->flags & PEGASUS_UNPLUG) )
...@@ -782,6 +789,7 @@ static int pegasus_close( struct net_device *net ) ...@@ -782,6 +789,7 @@ static int pegasus_close( struct net_device *net )
#ifdef PEGASUS_USE_INTR #ifdef PEGASUS_USE_INTR
usb_unlink_urb( pegasus->intr_urb ); usb_unlink_urb( pegasus->intr_urb );
#endif #endif
up(&pegasus->sem);
return 0; return 0;
} }
...@@ -868,23 +876,32 @@ static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd ) ...@@ -868,23 +876,32 @@ static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
{ {
__u16 *data = (__u16 *)&rq->ifr_data; __u16 *data = (__u16 *)&rq->ifr_data;
pegasus_t *pegasus = net->priv; pegasus_t *pegasus = net->priv;
int res;
down(&pegasus->sem);
switch(cmd) { switch(cmd) {
case SIOCETHTOOL: case SIOCETHTOOL:
return pegasus_ethtool_ioctl(net, rq->ifr_data); res = pegasus_ethtool_ioctl(net, rq->ifr_data);
break;
case SIOCDEVPRIVATE: case SIOCDEVPRIVATE:
data[0] = pegasus->phy; data[0] = pegasus->phy;
case SIOCDEVPRIVATE+1: case SIOCDEVPRIVATE+1:
read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]); read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
return 0; res = 0;
break;
case SIOCDEVPRIVATE+2: case SIOCDEVPRIVATE+2:
if ( !capable(CAP_NET_ADMIN) ) if ( !capable(CAP_NET_ADMIN) ) {
up(&pegasus->sem);
return -EPERM; return -EPERM;
}
write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]); write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
return 0; res = 0;
break;
default: default:
return -EOPNOTSUPP; res = -EOPNOTSUPP;
} }
up(&pegasus->sem);
return res;
} }
...@@ -953,10 +970,10 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum, ...@@ -953,10 +970,10 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
err("usb_set_configuration() failed"); err("usb_set_configuration() failed");
return NULL; return NULL;
} }
down(&gsem);
if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) { if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
err("out of memory allocating device structure"); err("out of memory allocating device structure");
return NULL; goto exit;
} }
usb_inc_dev_use( dev ); usb_inc_dev_use( dev );
...@@ -967,20 +984,23 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum, ...@@ -967,20 +984,23 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->ctrl_urb) { if (!pegasus->ctrl_urb) {
kfree (pegasus); kfree (pegasus);
return NULL; pegasus = NULL;
goto exit;
} }
pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL); pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->rx_urb) { if (!pegasus->rx_urb) {
usb_free_urb (pegasus->ctrl_urb); usb_free_urb (pegasus->ctrl_urb);
kfree (pegasus); kfree (pegasus);
return NULL; pegasus = NULL;
goto exit;
} }
pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL); pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->tx_urb) { if (!pegasus->tx_urb) {
usb_free_urb (pegasus->rx_urb); usb_free_urb (pegasus->rx_urb);
usb_free_urb (pegasus->ctrl_urb); usb_free_urb (pegasus->ctrl_urb);
kfree (pegasus); kfree (pegasus);
return NULL; pegasus = NULL;
goto exit;
} }
pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL); pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->intr_urb) { if (!pegasus->intr_urb) {
...@@ -988,7 +1008,8 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum, ...@@ -988,7 +1008,8 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
usb_free_urb (pegasus->rx_urb); usb_free_urb (pegasus->rx_urb);
usb_free_urb (pegasus->ctrl_urb); usb_free_urb (pegasus->ctrl_urb);
kfree (pegasus); kfree (pegasus);
return NULL; pegasus = NULL;
goto exit;
} }
net = init_etherdev( NULL, 0 ); net = init_etherdev( NULL, 0 );
...@@ -997,9 +1018,11 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum, ...@@ -997,9 +1018,11 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
usb_free_urb (pegasus->rx_urb); usb_free_urb (pegasus->rx_urb);
usb_free_urb (pegasus->ctrl_urb); usb_free_urb (pegasus->ctrl_urb);
kfree( pegasus ); kfree( pegasus );
return NULL; pegasus = NULL;
goto exit;
} }
init_MUTEX(&pegasus->sem);
pegasus->usb = dev; pegasus->usb = dev;
pegasus->net = net; pegasus->net = net;
SET_MODULE_OWNER(net); SET_MODULE_OWNER(net);
...@@ -1027,7 +1050,7 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum, ...@@ -1027,7 +1050,7 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
kfree(pegasus->net); kfree(pegasus->net);
kfree(pegasus); kfree(pegasus);
pegasus = NULL; pegasus = NULL;
return NULL; goto exit;
} }
info( "%s: %s", net->name, usb_dev_id[dev_index].name ); info( "%s: %s", net->name, usb_dev_id[dev_index].name );
...@@ -1044,7 +1067,8 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum, ...@@ -1044,7 +1067,8 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
warn( "can't locate MII phy, using default" ); warn( "can't locate MII phy, using default" );
pegasus->phy = 1; pegasus->phy = 1;
} }
exit:
up(&gsem);
return pegasus; return pegasus;
} }
......
...@@ -101,7 +101,7 @@ typedef struct pegasus { ...@@ -101,7 +101,7 @@ typedef struct pegasus {
struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb; struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
struct usb_ctrlrequest dr; struct usb_ctrlrequest dr;
wait_queue_head_t ctrl_wait; wait_queue_head_t ctrl_wait;
struct semaphore ctrl_sem; struct semaphore sem;
unsigned char rx_buff[PEGASUS_MAX_MTU]; unsigned char rx_buff[PEGASUS_MAX_MTU];
unsigned char tx_buff[PEGASUS_MAX_MTU]; unsigned char tx_buff[PEGASUS_MAX_MTU];
unsigned char intr_buff[8]; unsigned char intr_buff[8];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment