Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.4.19 /drivers/usb/pegasus.c

Filename:/drivers/usb/pegasus.c
Lines Added:261
Lines Deleted:86
Also changed in: (Previous) 2.4.19-rc5  2.4.19-rc4  2.4.19-rc3  2.4.19-rc2  2.4.19-rc1  2.4.19-pre10 
(Following) 2.4.20-pre2  2.4.20-pre1-ac3  2.4.20-pre3  2.4.20-pre4  2.4.20-pre4-ac1  2.4.20-pre4-ac2 

Location
[  2.4.19
  [  drivers
    [  usb
       o  pegasus.c

Patch

diff -urN linux-2.4.18/drivers/usb/pegasus.c linux-2.4.19/drivers/usb/pegasus.c
--- linux-2.4.18/drivers/usb/pegasus.c   Mon Feb 25 11:38:07 2002
+++ linux-2.4.19/drivers/usb/pegasus.c   Fri Aug  2 17:39:45 2002
@@ -1,7 +1,7 @@
 /*
 **   Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
 **
-**   Copyright (c) 1999-2001 Petko Manolov (pmanolov@lnxw.com)
+**   Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
 **   
 **
 **   ChangeLog:
@@ -21,6 +21,7 @@
 **         TODO: suppressing HCD warnings spewage on disconnect.
 **      v0.4.13   Ethernet address is now set at probe(), not at open()
 **         time as this seems to break dhcpd. 
+**      v0.4.25   ethtool support added.
 */
 
 /*
@@ -46,23 +47,29 @@
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
 #include <linux/usb.h>
 #include <linux/module.h>
+#include <asm/uaccess.h>
 #include "pegasus.h"
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.22 (2001/12/07)"
-#define DRIVER_AUTHOR "Petko Manolov <pmanolov@lnxw.com>"
+#define DRIVER_VERSION "v0.4.26 (2002/03/21)"
+#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
 #define   PEGASUS_USE_INTR
 #define   PEGASUS_WRITE_EEPROM
+#define   BMSR_MEDIA   (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
+         BMSR_100FULL | BMSR_ANEGCAPABLE)
 
 static int loopback = 0;
-static int mii_mode = 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)   \
@@ -94,7 +101,7 @@
 
 static int update_eth_regs_async( pegasus_t * );
 /* Aargh!!! I _really_ hate such tweaks */
-static void ctrl_callback( urb_t *urb )
+static void ctrl_callback( struct urb *urb )
 {
    pegasus_t   *pegasus = urb->context;
 
@@ -102,7 +109,7 @@
       return;
 
    switch ( urb->status ) {
-      case USB_ST_NOERROR:
+      case 0:
          if ( pegasus->flags & ETH_REGS_CHANGE ) {
             pegasus->flags &= ~ETH_REGS_CHANGE;
             pegasus->flags |= ETH_REGS_CHANGED;
@@ -110,12 +117,12 @@
             return;
          }
          break;
-      case USB_ST_URB_PENDING:
+      case -EINPROGRESS:
          return;
-      case USB_ST_URB_KILLED:
+      case -ENOENT:
          break;
       default:
-         warn( __FUNCTION__ " status %d", urb->status);
+         warn("%s: status %d", __FUNCTION__, urb->status);
    }
    pegasus->flags &= ~ETH_REGS_CHANGED;
    wake_up(&pegasus->ctrl_wait );
@@ -147,9 +154,9 @@
    pegasus->dr.value = cpu_to_le16 (0);
    pegasus->dr.index = cpu_to_le16p(&indx);
    pegasus->dr.length = cpu_to_le16p(&size);
-   pegasus->ctrl_urb.transfer_buffer_length = size;
+   pegasus->ctrl_urb->transfer_buffer_length = size;
 
-   FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+   FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
            usb_rcvctrlpipe(pegasus->usb,0),
            (char *)&pegasus->dr,
            buffer, size, ctrl_callback, pegasus );
@@ -157,8 +164,8 @@
    add_wait_queue( &pegasus->ctrl_wait, &wait );
    set_current_state( TASK_UNINTERRUPTIBLE );
 
-   if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
-      err( __FUNCTION__ " BAD CTRLs %d", ret);
+   if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
+      err("%s: BAD CTRLs %d", __FUNCTION__, ret);
       goto out;
    }
 
@@ -197,9 +204,9 @@
    pegasus->dr.value = cpu_to_le16 (0);
    pegasus->dr.index = cpu_to_le16p( &indx );
    pegasus->dr.length = cpu_to_le16p( &size );
-   pegasus->ctrl_urb.transfer_buffer_length = size;
+   pegasus->ctrl_urb->transfer_buffer_length = size;
 
-   FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+   FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
            usb_sndctrlpipe(pegasus->usb,0),
            (char *)&pegasus->dr,
            buffer, size, ctrl_callback, pegasus );
@@ -207,8 +214,8 @@
    add_wait_queue( &pegasus->ctrl_wait, &wait );
    set_current_state( TASK_UNINTERRUPTIBLE );
 
-   if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
-      err( __FUNCTION__ " BAD CTRL %d", ret);
+   if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
+      err("%s: BAD CTRL %d", __FUNCTION__, ret);
       goto out;
    }
    
@@ -247,9 +254,9 @@
    pegasus->dr.value = cpu_to_le16p( &dat);
    pegasus->dr.index = cpu_to_le16p( &indx );
    pegasus->dr.length = cpu_to_le16( 1 );
-   pegasus->ctrl_urb.transfer_buffer_length = 1;
+   pegasus->ctrl_urb->transfer_buffer_length = 1;
 
-   FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+   FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
            usb_sndctrlpipe(pegasus->usb,0),
            (char *)&pegasus->dr,
            buffer, 1, ctrl_callback, pegasus );
@@ -257,8 +264,8 @@
    add_wait_queue( &pegasus->ctrl_wait, &wait );
    set_current_state( TASK_UNINTERRUPTIBLE );
 
-   if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
-      err( __FUNCTION__ " BAD CTRL %d", ret);
+   if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
+      err("%s: BAD CTRL %d", __FUNCTION__, ret);
       goto out;
    }
 
@@ -280,15 +287,15 @@
    pegasus->dr.value = 0;
    pegasus->dr.index =  cpu_to_le16(EthCtrl0);
    pegasus->dr.length = cpu_to_le16(3);
-   pegasus->ctrl_urb.transfer_buffer_length = 3;
+   pegasus->ctrl_urb->transfer_buffer_length = 3;
 
-   FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+   FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
            usb_sndctrlpipe(pegasus->usb,0),
            (char *)&pegasus->dr,
            pegasus->eth_regs, 3, ctrl_callback, pegasus );
 
-   if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) )
-      err( __FUNCTION__ " BAD CTRL %d, flags %x",ret,pegasus->flags );
+   if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) )
+      err("%s: BAD CTRL %d, flgs %x",__FUNCTION__,ret,pegasus->flags);
 
    return   ret;
 }
@@ -313,7 +320,7 @@
       *regd = le16_to_cpu(regdi);
       return   0;
    }
-   warn( __FUNCTION__ " failed" );
+   warn("%s: failed", __FUNCTION__);
    
    return 1;
 }
@@ -335,7 +342,7 @@
    }
    if ( i < REG_TIMEOUT )
       return   0;
-   warn( __FUNCTION__ " failed" );
+   warn("%s: failed", __FUNCTION__);
 
    return 1;
 }
@@ -361,7 +368,7 @@
       *retdata = le16_to_cpu (retdatai);
       return   0;
    }
-   warn( __FUNCTION__ " failed" );
+   warn("%s: failed", __FUNCTION__);
 
    return -1;
 }
@@ -405,7 +412,7 @@
    disable_eprom_write( pegasus );
    if ( i < REG_TIMEOUT )
       return   0;
-   warn( __FUNCTION__ " failed" );
+   warn("%s: failed", __FUNCTION__);
    return   -1;
 }
 #endif   /* PEGASUS_WRITE_EEPROM */
@@ -455,14 +462,18 @@
    if ( i == REG_TIMEOUT )
       return 1;
 
-   if ( usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
-        usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK ) {
+   if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
+       usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
       __u16   auxmode;
 
-      read_mii_word( pegasus, 0, 0x1b, &auxmode );
-      write_mii_word( pegasus, 0, 0x1b, auxmode | 4 );
+      read_mii_word(pegasus, 1, 0x1b, &auxmode);
+      write_mii_word(pegasus, 1, 0x1b, auxmode | 4);
+   }
+   if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
+      __u16   auxmode;
+      read_mii_word(pegasus, 3, 0x1b, &auxmode);
+      write_mii_word(pegasus, 3, 0x1b, auxmode | 4);
    }
-
    return   0;
 }
 
@@ -473,22 +484,22 @@
    __u8   data[4];
    pegasus_t *pegasus = dev->priv;
 
-
-   if ( read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr) ) 
-      return 1;
-   if ( !(bmsr & 0x20) && !loopback ) 
+   /* read twice 'cos this is a latch bit */
+   read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr);
+   read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr);
+   if ( !(bmsr & 4) && !loopback ) 
       warn( "%s: link NOT established (0x%x) - check the cable.",
          dev->name, bmsr );
-   if ( read_mii_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) )
+   if ( read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart) )
       return 2;
    if ( !(linkpart & 1) )
       warn( "link partner stat %x", linkpart );
 
    data[0] = 0xc9;
    data[1] = 0;
-   if ( linkpart & (ANLPA_100TX_FD | ANLPA_10T_FD) )
+   if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL) )
       data[1] |= 0x20; /* set full duplex */
-   if ( linkpart & (ANLPA_100TX_FD | ANLPA_100TX_HD) )
+   if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF) )
       data[1] |= 0x10; /* set 100 Mbps */
    if ( mii_mode )
       data[1] = 0;
@@ -526,9 +537,9 @@
    pegasus->flags |= PEGASUS_RX_BUSY;
 
    switch ( urb->status ) {
-      case USB_ST_NOERROR:
+      case 0:
          break;
-      case USB_ST_NORESPONSE:
+      case -ETIMEDOUT:
          dbg( "reset MAC" );
          pegasus->flags &= ~PEGASUS_RX_BUSY;
          break;
@@ -569,12 +580,12 @@
    pegasus->stats.rx_bytes += pkt_len;
 
 goon:
-   FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,
+   FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
          usb_rcvbulkpipe(pegasus->usb, 1),
          pegasus->rx_buff, PEGASUS_MAX_MTU, 
          read_bulk_callback, pegasus );
-   if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
-      warn( __FUNCTION__ " failed submint rx_urb %d", res);
+   if ( (res = usb_submit_urb(pegasus->rx_urb)) )
+      warn("%s: failed submint rx_urb %d", __FUNCTION__, res);
    pegasus->flags &= ~PEGASUS_RX_BUSY;
 }
 
@@ -607,9 +618,9 @@
       return;
       
    switch ( urb->status ) {
-      case USB_ST_NOERROR:
+      case 0:
          break;
-      case USB_ST_URB_KILLED:
+      case -ENOENT:
          return;
       default:
          info("intr status %d", urb->status);
@@ -639,8 +650,8 @@
       return;
       
    warn("%s: Tx timed out.", net->name);
-   pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
-   usb_unlink_urb( &pegasus->tx_urb );
+   pegasus->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+   usb_unlink_urb( pegasus->tx_urb );
    pegasus->stats.tx_errors++;
 }
 
@@ -656,12 +667,12 @@
       
    ((__u16 *)pegasus->tx_buff)[0] = cpu_to_le16( l16 );
    memcpy(pegasus->tx_buff+2, skb->data, skb->len);
-   FILL_BULK_URB( &pegasus->tx_urb, pegasus->usb,
+   FILL_BULK_URB( pegasus->tx_urb, pegasus->usb,
          usb_sndbulkpipe(pegasus->usb, 2),
          pegasus->tx_buff, PEGASUS_MAX_MTU, 
          write_bulk_callback, pegasus );
-   pegasus->tx_urb.transfer_buffer_length = count;
-   if ((res = usb_submit_urb(&pegasus->tx_urb))) {
+   pegasus->tx_urb->transfer_buffer_length = count;
+   if ((res = usb_submit_urb(pegasus->tx_urb))) {
       warn("failed tx_urb %d", res);
       pegasus->stats.tx_errors++;
       netif_start_queue( net );
@@ -708,33 +719,56 @@
 }
 
 
+static void set_carrier(struct net_device *net)
+{
+   pegasus_t   *pegasus;
+   short      tmp;
+
+   pegasus = net->priv;
+   read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
+   if (tmp & BMSR_LSTATUS)
+      netif_carrier_on(net);
+   else
+      netif_carrier_off(net);
+   
+}
+
+
 static int pegasus_open(struct net_device *net)
 {
    pegasus_t *pegasus = (pegasus_t *)net->priv;
    int   res;
 
-   if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
-      err("can't enable_net_traffic() - %d", res);
-      return -EIO;
-   }
-   FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,
+
+   down(&pegasus->sem);
+   FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
          usb_rcvbulkpipe(pegasus->usb, 1),
          pegasus->rx_buff, PEGASUS_MAX_MTU, 
          read_bulk_callback, pegasus );
-   if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
-      warn( __FUNCTION__ " failed rx_urb %d", res );
+   if ( (res = usb_submit_urb(pegasus->rx_urb)) )
+      warn("%s: failed rx_urb %d", __FUNCTION__, res);
 #ifdef   PEGASUS_USE_INTR
-   FILL_INT_URB( &pegasus->intr_urb, pegasus->usb,
+   FILL_INT_URB( pegasus->intr_urb, pegasus->usb,
          usb_rcvintpipe(pegasus->usb, 3),
          pegasus->intr_buff, sizeof(pegasus->intr_buff),
          intr_callback, pegasus, pegasus->intr_interval );
-   if ( (res = usb_submit_urb(&pegasus->intr_urb)) )
-      warn( __FUNCTION__ " failed intr_urb %d", res);
+   if ( (res = usb_submit_urb(pegasus->intr_urb)) )
+      warn("%s: failed intr_urb %d", __FUNCTION__, res);
 #endif
    netif_start_queue( net );
    pegasus->flags |= PEGASUS_RUNNING;
+   if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
+      err("can't enable_net_traffic() - %d", res);
+      res = -EIO;
+      goto exit;
+   }
 
-   return 0;
+   set_carrier(net);
+   res = 0;
+exit:
+   up(&pegasus->sem);
+   
+   return res;
 }
 
 
@@ -742,41 +776,132 @@
 {
    pegasus_t   *pegasus = net->priv;
 
+   down(&pegasus->sem);
    pegasus->flags &= ~PEGASUS_RUNNING;
    netif_stop_queue( net );
    if ( !(pegasus->flags & PEGASUS_UNPLUG) )
       disable_net_traffic( pegasus );
 
-   usb_unlink_urb( &pegasus->rx_urb );
-   usb_unlink_urb( &pegasus->tx_urb );
-   usb_unlink_urb( &pegasus->ctrl_urb );
+   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 );
+   usb_unlink_urb( pegasus->intr_urb );
 #endif
-
+   up(&pegasus->sem);
+   
    return 0;
 }
 
 
+static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
+{
+   pegasus_t   *pegasus;
+   int      cmd;
+   char      tmp[128];
+
+   pegasus = net->priv;
+   if (get_user(cmd, (int *)uaddr))
+      return -EFAULT;
+   switch (cmd) {
+   case ETHTOOL_GDRVINFO: {
+      struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+      strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
+      strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+      sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum,
+              pegasus->usb->devnum);
+      strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
+      if (copy_to_user(uaddr, &info, sizeof(info)))
+         return -EFAULT;
+      return 0;
+   }
+   case ETHTOOL_GSET: {
+      struct ethtool_cmd ecmd;
+      short   lpa, bmcr;
+
+      if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
+         return -EFAULT;
+      ecmd.supported = (SUPPORTED_10baseT_Half |
+                       SUPPORTED_10baseT_Full |
+                       SUPPORTED_100baseT_Half |
+                       SUPPORTED_100baseT_Full |
+                       SUPPORTED_Autoneg |
+                       SUPPORTED_TP |
+                       SUPPORTED_MII);
+      ecmd.port = PORT_TP;
+      ecmd.transceiver = XCVR_INTERNAL;
+      ecmd.phy_address = pegasus->phy;
+      read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
+      read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
+      if (bmcr & BMCR_ANENABLE) {
+         ecmd.autoneg = AUTONEG_ENABLE;
+         ecmd.speed = lpa & (LPA_100HALF|LPA_100FULL) ?
+                           SPEED_100 : SPEED_10;
+         if (ecmd.speed == SPEED_100)
+            ecmd.duplex = lpa & LPA_100FULL ?
+                          DUPLEX_FULL : DUPLEX_HALF;
+         else
+            ecmd.duplex = lpa & LPA_10FULL ?
+                          DUPLEX_FULL : DUPLEX_HALF;
+      } else {
+         ecmd.autoneg = AUTONEG_DISABLE;
+         ecmd.speed = bmcr & BMCR_SPEED100 ? 
+                      SPEED_100 : SPEED_10;
+         ecmd.duplex = bmcr & BMCR_FULLDPLX ?
+                       DUPLEX_FULL : DUPLEX_HALF;
+      }
+      if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
+         return -EFAULT;
+      
+      return 0;
+   }
+   case ETHTOOL_SSET: {
+      return -EOPNOTSUPP;
+   }
+   case ETHTOOL_GLINK: {
+      struct ethtool_value edata = {ETHTOOL_GLINK};
+      edata.data = netif_carrier_ok(net);
+      if (copy_to_user(uaddr, &edata, sizeof(edata)))
+         return -EFAULT;
+      return 0;
+   }
+   default:
+      return -EOPNOTSUPP;
+   }
+}
+
+
 static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
 {
    __u16 *data = (__u16 *)&rq->ifr_data;
    pegasus_t   *pegasus = net->priv;
+   int   res;
 
+   down(&pegasus->sem);
    switch(cmd) {
-      case SIOCDEVPRIVATE:
-         data[0] = pegasus->phy;
-      case SIOCDEVPRIVATE+1:
-         read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
-         return 0;
-      case SIOCDEVPRIVATE+2:
-         if ( !capable(CAP_NET_ADMIN) )
-            return -EPERM;
-         write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
-         return 0;
-      default:
-         return -EOPNOTSUPP;
+   case SIOCETHTOOL:
+      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]);
+      res = 0;
+      break;
+   case SIOCDEVPRIVATE+2:
+      if ( !capable(CAP_NET_ADMIN) ) {
+         up(&pegasus->sem);
+         return -EPERM;
+      }
+      write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
+      res = 0;
+      break;
+   default:
+      res = -EOPNOTSUPP;
    }
+   up(&pegasus->sem);
+
+   return res;
 }
 
 
@@ -800,7 +925,7 @@
    }
 
    pegasus->flags |= ETH_REGS_CHANGE;
-   ctrl_callback( &pegasus->ctrl_urb );
+   ctrl_callback( pegasus->ctrl_urb );
 
    netif_wake_queue(net);
 }
@@ -846,9 +971,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 );
@@ -856,12 +982,48 @@
    pegasus->dev_index = dev_index;
    init_waitqueue_head( &pegasus->ctrl_wait );
 
+   pegasus->ctrl_urb = usb_alloc_urb(0);
+   if (!pegasus->ctrl_urb) {
+      kfree (pegasus);
+      pegasus = NULL;
+      goto exit;
+   }
+   pegasus->rx_urb = usb_alloc_urb(0);
+   if (!pegasus->rx_urb) {
+      usb_free_urb (pegasus->ctrl_urb);
+      kfree (pegasus);
+      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);
+      pegasus = NULL;
+      goto exit;
+   }
+   pegasus->intr_urb = usb_alloc_urb(0);
+   if (!pegasus->intr_urb) {
+      usb_free_urb (pegasus->tx_urb);
+      usb_free_urb (pegasus->rx_urb);
+      usb_free_urb (pegasus->ctrl_urb);
+      kfree (pegasus);
+      pegasus = NULL;
+      goto exit;
+   }
+
    net = init_etherdev( NULL, 0 );
    if ( !net ) {
+      usb_free_urb (pegasus->tx_urb);
+      usb_free_urb (pegasus->rx_urb);
+      usb_free_urb (pegasus->ctrl_urb);
       kfree( pegasus );
-      return   NULL;
+      return NULL;
    }
-   
+
+   init_MUTEX(&pegasus->sem);
+   down(&pegasus->sem);
    pegasus->usb = dev;
    pegasus->net = net;
    SET_MODULE_OWNER(net);
@@ -883,10 +1045,13 @@
    if ( reset_mac(pegasus) ) {
       err("can't reset MAC");
       unregister_netdev( pegasus->net );
+      usb_free_urb (pegasus->tx_urb);
+      usb_free_urb (pegasus->rx_urb);
+      usb_free_urb (pegasus->ctrl_urb);
       kfree(pegasus->net);
       kfree(pegasus);
       pegasus = NULL;
-      return NULL;
+      goto exit;
    }
 
    info( "%s: %s", net->name, usb_dev_id[dev_index].name );
@@ -904,6 +1069,8 @@
       pegasus->phy = 1;
    }
 
+exit:
+   up(&pegasus->sem);
    return pegasus;
 }
 
@@ -920,6 +1087,14 @@
    pegasus->flags |= PEGASUS_UNPLUG;
    unregister_netdev( pegasus->net );
    usb_dec_dev_use( dev );
+   usb_unlink_urb(pegasus->intr_urb);
+   usb_unlink_urb(pegasus->tx_urb);
+   usb_unlink_urb(pegasus->rx_urb);
+   usb_unlink_urb(pegasus->ctrl_urb);
+   usb_free_urb(pegasus->intr_urb);
+   usb_free_urb(pegasus->tx_urb);
+   usb_free_urb(pegasus->rx_urb);
+   usb_free_urb(pegasus->ctrl_urb);
    kfree( pegasus->net );
    kfree( pegasus );
    pegasus = NULL;


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.