libertas: cope with both old and new mesh TLV values
authorDavid Woodhouse <dwmw2@infradead.org>
Thu, 13 Dec 2007 04:29:13 +0000 (23:29 -0500)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 23:07:06 +0000 (15:07 -0800)
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/main.c

index ddf15271244f77dafae51f4df3bfb310061bd6b1..c4299ae1774eabad3acd2a0dfc3c5586894b847d 100644 (file)
@@ -1121,14 +1121,14 @@ int lbs_mesh_config(struct lbs_private *priv, int enable)
        memset(&cmd, 0, sizeof(cmd));
        cmd.action = cpu_to_le16(enable);
        cmd.channel = cpu_to_le16(priv->curbssparams.channel);
-       cmd.type = cpu_to_le16(0x100 + 37);
+       cmd.type = cpu_to_le16(priv->mesh_tlv);
        
        if (enable) {
                cmd.length = cpu_to_le16(priv->mesh_ssid_len);
                memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len);
        }
-       lbs_deb_cmd("mesh config channel %d SSID %s\n",
-                   priv->curbssparams.channel,
+       lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n",
+                   enable, priv->mesh_tlv, priv->curbssparams.channel,
                    escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
        return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd);
 }
index 60a6a51d0dcbe46886772fec7d224fb3384412b7..e6f553d5d2cf42aef067f1ac61502de7e270743b 100644 (file)
@@ -206,6 +206,8 @@ struct lbs_private {
 
        /** current ssid/bssid related parameters*/
        struct current_bss_params curbssparams;
+
+       uint16_t mesh_tlv;
        u8 mesh_ssid[IW_ESSID_MAX_SIZE + 1];
        u8 mesh_ssid_len;
 
index 5e2f3296be34ada73f5d83a45f647eba737ab181..2409df85c2e06b52bb4632b865f61387924db743 100644 (file)
@@ -1171,8 +1171,33 @@ int lbs_start_card(struct lbs_private *priv)
        }
        if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
                lbs_pr_err("cannot register lbs_rtap attribute\n");
-       if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
-               lbs_pr_err("cannot register lbs_mesh attribute\n");
+
+       /* Enable mesh, if supported, and work out which TLV it uses.
+          0x100 + 291 is an unofficial value used in 5.110.20.pXX
+          0x100 + 37 is the official value used in 5.110.21.pXX
+          but we check them in that order because 20.pXX doesn't 
+          give an error -- it just silently fails. */
+
+       /* 5.110.20.pXX firmware will fail the command if the channel
+          doesn't match the existing channel. But only if the TLV
+          is correct. If the channel is wrong, _BOTH_ versions will
+          give an error to 0x100+291, and allow 0x100+37 to succeed.
+          It's just that 5.110.20.pXX will not have done anything
+          useful */
+
+       lbs_update_channel(priv);
+       priv->mesh_tlv = 0x100 + 291;
+       if (lbs_mesh_config(priv, 1)) {
+               priv->mesh_tlv = 0x100 + 37;
+               if (lbs_mesh_config(priv, 1))
+                       priv->mesh_tlv = 0;
+       }
+       if (priv->mesh_tlv) {
+               lbs_add_mesh(priv);
+
+               if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
+                       lbs_pr_err("cannot register lbs_mesh attribute\n");
+       }
 
        lbs_debugfs_init_one(priv, dev);
 
@@ -1201,7 +1226,8 @@ int lbs_stop_card(struct lbs_private *priv)
 
        lbs_debugfs_remove_one(priv);
        device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
-       device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
+       if (priv->mesh_tlv)
+               device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
 
        /* Flush pending command nodes */
        spin_lock_irqsave(&priv->driver_lock, flags);