Update firmware detection code.  This will now reliably detect
Intersil firmwares past verison 1.x, a serious flaw in the previous
code.  It cleans up the code, and reduces the size of the private
structure by using single bits for the various firmware feature flags.

Signed-off-by: David Gibson <[EMAIL PROTECTED]>

Index: working-2.6/drivers/net/wireless/orinoco.c
===================================================================
--- working-2.6.orig/drivers/net/wireless/orinoco.c     2005-02-24 
14:50:57.300439064 +1100
+++ working-2.6/drivers/net/wireless/orinoco.c  2005-02-24 14:50:59.879047056 
+1100
@@ -2047,39 +2047,54 @@
 /* Initialization                                                   */
 /********************************************************************/
 
-struct sta_id {
+struct comp_id {
        u16 id, variant, major, minor;
 } __attribute__ ((packed));
 
-static int determine_firmware_type(struct net_device *dev, struct sta_id 
*sta_id)
+static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
 {
-       /* FIXME: this is fundamentally broken */
-       unsigned int firmver = ((u32)sta_id->major << 16) | sta_id->minor;
-       
-       if (sta_id->variant == 1)
+       if (nic_id->id < 0x8000)
                return FIRMWARE_TYPE_AGERE;
-       else if ((sta_id->variant == 2) &&
-                  ((firmver == 0x10001) || (firmver == 0x20001)))
+       else if (nic_id->id == 0x8000 && nic_id->major == 0)
                return FIRMWARE_TYPE_SYMBOL;
        else
                return FIRMWARE_TYPE_INTERSIL;
 }
 
-static void determine_firmware(struct net_device *dev)
+/* Set priv->firmware type, determine firmware properties */
+static int determine_firmware(struct net_device *dev)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        hermes_t *hw = &priv->hw;
        int err;
-       struct sta_id sta_id;
+       struct comp_id nic_id, sta_id;
        unsigned int firmver;
        char tmp[SYMBOL_MAX_VER_LEN+1];
 
+       /* Get the hardware version */
+       err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
+       if (err) {
+               printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
+                      dev->name, err);
+               return err;
+       }
+
+       le16_to_cpus(&nic_id.id);
+       le16_to_cpus(&nic_id.variant);
+       le16_to_cpus(&nic_id.major);
+       le16_to_cpus(&nic_id.minor);
+       printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
+              dev->name, nic_id.id, nic_id.variant,
+              nic_id.major, nic_id.minor);
+
+       priv->firmware_type = determine_firmware_type(&nic_id);
+
        /* Get the firmware version */
        err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
        if (err) {
-               printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly 
guessing capabilities...\n",
+               printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
                       dev->name, err);
-               memset(&sta_id, 0, sizeof(sta_id));
+               return err;
        }
 
        le16_to_cpus(&sta_id.id);
@@ -2090,8 +2105,23 @@
               dev->name, sta_id.id, sta_id.variant,
               sta_id.major, sta_id.minor);
 
-       if (! priv->firmware_type)
-               priv->firmware_type = determine_firmware_type(dev, &sta_id);
+       switch (sta_id.id) {
+       case 0x15:
+               printk(KERN_ERR "%s: Primary firmware is active\n",
+                      dev->name);
+               return -ENODEV;
+       case 0x14b:
+               printk(KERN_ERR "%s: Tertiary firmware is active\n",
+                      dev->name);
+               return -ENODEV;
+       case 0x1f:      /* Intersil, Agere, Symbol Spectrum24 */
+       case 0x21:      /* Symbol Spectrum24 Trilogy */
+               break;
+       default:
+               printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
+                      dev->name);
+               break;
+       }
 
        /* Default capabilities */
        priv->has_sensitivity = 1;
@@ -2107,9 +2137,8 @@
        case FIRMWARE_TYPE_AGERE:
                /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
                   ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
-               printk(KERN_DEBUG "%s: Looks like a Lucent/Agere firmware "
-                      "version %d.%02d\n", dev->name,
-                      sta_id.major, sta_id.minor);
+               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+                        "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
 
                firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
 
@@ -2152,14 +2181,15 @@
                        tmp[SYMBOL_MAX_VER_LEN] = '\0';
                }
 
-               printk(KERN_DEBUG "%s: Looks like a Symbol firmware "
-                      "version [%s] (parsing to %X)\n", dev->name,
-                      tmp, firmver);
+               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+                        "Symbol %s", tmp);
 
                priv->has_ibss = (firmver >= 0x20000);
                priv->has_wep = (firmver >= 0x15012);
                priv->has_big_wep = (firmver >= 0x20000);
-               priv->has_pm = (firmver >= 0x20000) && (firmver < 0x22000);
+               priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || 
+                              (firmver >= 0x29000 && firmver < 0x30000) ||
+                              firmver >= 0x31000;
                priv->has_preamble = (firmver >= 0x20000);
                priv->ibss_port = 4;
                /* Tested with Intel firmware : 0x20015 => Jean II */
@@ -2171,9 +2201,9 @@
                 * different and less well tested */
                /* D-Link MAC : 00:40:05:* */
                /* Addtron MAC : 00:90:D1:* */
-               printk(KERN_DEBUG "%s: Looks like an Intersil firmware "
-                      "version %d.%d.%d\n", dev->name,
-                      sta_id.major, sta_id.minor, sta_id.variant);
+               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+                        "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
+                        sta_id.variant);
 
                firmver = ((unsigned long)sta_id.major << 16) |
                        ((unsigned long)sta_id.minor << 8) | sta_id.variant;
@@ -2191,9 +2221,11 @@
                        priv->ibss_port = 1;
                }
                break;
-       default:
-               break;
        }
+       printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
+              priv->fw_name);
+
+       return 0;
 }
 
 static int orinoco_init(struct net_device *dev)
@@ -2219,7 +2251,12 @@
                goto out;
        }
 
-       determine_firmware(dev);
+       err = determine_firmware(dev);
+       if (err != 0) {
+               printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
+                      dev->name);
+               goto out;
+       }
 
        if (priv->has_port3)
                printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", 
dev->name);
Index: working-2.6/drivers/net/wireless/orinoco.h
===================================================================
--- working-2.6.orig/drivers/net/wireless/orinoco.h     2005-02-24 
14:50:53.167067432 +1100
+++ working-2.6/drivers/net/wireless/orinoco.h  2005-02-24 14:50:59.879047056 
+1100
@@ -30,6 +30,12 @@
        char data[ORINOCO_MAX_KEY_SIZE];
 } __attribute__ ((packed));
 
+typedef enum {
+       FIRMWARE_TYPE_AGERE,
+       FIRMWARE_TYPE_INTERSIL,
+       FIRMWARE_TYPE_SYMBOL
+} fwtype_t;
+
 struct orinoco_private {
        void *card;     /* Pointer to card dependent structure */
        int (*hard_reset)(struct orinoco_private *);
@@ -53,19 +59,22 @@
        u16 txfid;
 
        /* Capabilities of the hardware/firmware */
-       int firmware_type;
-#define FIRMWARE_TYPE_AGERE 1
-#define FIRMWARE_TYPE_INTERSIL 2
-#define FIRMWARE_TYPE_SYMBOL 3
-       int has_ibss, has_port3, ibss_port;
-       int has_wep, has_big_wep;
-       int has_mwo;
-       int has_pm;
-       int has_preamble;
-       int has_sensitivity;
+       fwtype_t firmware_type;
+       char fw_name[32];
+       int ibss_port;
        int nicbuf_size;
        u16 channel_mask;
-       int broken_disableport;
+
+       /* Boolean capabilities */
+       unsigned int has_ibss:1;
+       unsigned int has_port3:1;
+       unsigned int has_wep:1;
+       unsigned int has_big_wep:1;
+       unsigned int has_mwo:1;
+       unsigned int has_pm:1;
+       unsigned int has_preamble:1;
+       unsigned int has_sensitivity:1;
+       unsigned int broken_disableport:1;
 
        /* Configuration paramaters */
        u32 iw_mode;
Index: working-2.6/drivers/net/wireless/orinoco_pci.c
===================================================================
--- working-2.6.orig/drivers/net/wireless/orinoco_pci.c 2005-02-24 
14:50:47.830878656 +1100
+++ working-2.6/drivers/net/wireless/orinoco_pci.c      2005-02-24 
14:50:59.880046904 +1100
@@ -251,10 +251,6 @@
                goto fail;
        }
 
-       /* Override the normal firmware detection - the Prism 2.5 PCI
-        * cards look like Lucent firmware but are actually Intersil */
-       priv->firmware_type = FIRMWARE_TYPE_INTERSIL;
-
        err = register_netdev(dev);
        if (err) {
                printk(KERN_ERR PFX "Failed to register net device\n");

-- 
David Gibson                    | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au  | minimalist.  NOT _the_ _other_ _way_
                                | _around_!
http://www.ozlabs.org/people/dgibson
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to