Back to home page

OSCL-LXR

 
 

    


0001 /* Encapsulate basic setting changes and retrieval on Hermes hardware
0002  *
0003  * See copyright notice in main.c
0004  */
0005 #include <linux/kernel.h>
0006 #include <linux/device.h>
0007 #include <linux/if_arp.h>
0008 #include <linux/ieee80211.h>
0009 #include <linux/wireless.h>
0010 #include <net/cfg80211.h>
0011 #include "hermes.h"
0012 #include "hermes_rid.h"
0013 #include "orinoco.h"
0014 
0015 #include "hw.h"
0016 
0017 #define SYMBOL_MAX_VER_LEN  (14)
0018 
0019 /* Symbol firmware has a bug allocating buffers larger than this */
0020 #define TX_NICBUF_SIZE_BUG  1585
0021 
0022 /********************************************************************/
0023 /* Data tables                                                      */
0024 /********************************************************************/
0025 
0026 /* This tables gives the actual meanings of the bitrate IDs returned
0027  * by the firmware. */
0028 static const struct {
0029     int bitrate; /* in 100s of kilobits */
0030     int automatic;
0031     u16 agere_txratectrl;
0032     u16 intersil_txratectrl;
0033 } bitrate_table[] = {
0034     {110, 1,  3, 15}, /* Entry 0 is the default */
0035     {10,  0,  1,  1},
0036     {10,  1,  1,  1},
0037     {20,  0,  2,  2},
0038     {20,  1,  6,  3},
0039     {55,  0,  4,  4},
0040     {55,  1,  7,  7},
0041     {110, 0,  5,  8},
0042 };
0043 #define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
0044 
0045 /* Firmware version encoding */
0046 struct comp_id {
0047     u16 id, variant, major, minor;
0048 } __packed;
0049 
0050 static inline enum fwtype determine_firmware_type(struct comp_id *nic_id)
0051 {
0052     if (nic_id->id < 0x8000)
0053         return FIRMWARE_TYPE_AGERE;
0054     else if (nic_id->id == 0x8000 && nic_id->major == 0)
0055         return FIRMWARE_TYPE_SYMBOL;
0056     else
0057         return FIRMWARE_TYPE_INTERSIL;
0058 }
0059 
0060 /* Set priv->firmware type, determine firmware properties
0061  * This function can be called before we have registerred with netdev,
0062  * so all errors go out with dev_* rather than printk
0063  *
0064  * If non-NULL stores a firmware description in fw_name.
0065  * If non-NULL stores a HW version in hw_ver
0066  *
0067  * These are output via generic cfg80211 ethtool support.
0068  */
0069 int determine_fw_capabilities(struct orinoco_private *priv,
0070                   char *fw_name, size_t fw_name_len,
0071                   u32 *hw_ver)
0072 {
0073     struct device *dev = priv->dev;
0074     struct hermes *hw = &priv->hw;
0075     int err;
0076     struct comp_id nic_id, sta_id;
0077     unsigned int firmver;
0078     char tmp[SYMBOL_MAX_VER_LEN + 1] __attribute__((aligned(2)));
0079 
0080     /* Get the hardware version */
0081     err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
0082     if (err) {
0083         dev_err(dev, "Cannot read hardware identity: error %d\n",
0084             err);
0085         return err;
0086     }
0087 
0088     le16_to_cpus(&nic_id.id);
0089     le16_to_cpus(&nic_id.variant);
0090     le16_to_cpus(&nic_id.major);
0091     le16_to_cpus(&nic_id.minor);
0092     dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
0093          nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
0094 
0095     if (hw_ver)
0096         *hw_ver = (((nic_id.id & 0xff) << 24) |
0097                ((nic_id.variant & 0xff) << 16) |
0098                ((nic_id.major & 0xff) << 8) |
0099                (nic_id.minor & 0xff));
0100 
0101     priv->firmware_type = determine_firmware_type(&nic_id);
0102 
0103     /* Get the firmware version */
0104     err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
0105     if (err) {
0106         dev_err(dev, "Cannot read station identity: error %d\n",
0107             err);
0108         return err;
0109     }
0110 
0111     le16_to_cpus(&sta_id.id);
0112     le16_to_cpus(&sta_id.variant);
0113     le16_to_cpus(&sta_id.major);
0114     le16_to_cpus(&sta_id.minor);
0115     dev_info(dev, "Station identity  %04x:%04x:%04x:%04x\n",
0116          sta_id.id, sta_id.variant, sta_id.major, sta_id.minor);
0117 
0118     switch (sta_id.id) {
0119     case 0x15:
0120         dev_err(dev, "Primary firmware is active\n");
0121         return -ENODEV;
0122     case 0x14b:
0123         dev_err(dev, "Tertiary firmware is active\n");
0124         return -ENODEV;
0125     case 0x1f:  /* Intersil, Agere, Symbol Spectrum24 */
0126     case 0x21:  /* Symbol Spectrum24 Trilogy */
0127         break;
0128     default:
0129         dev_notice(dev, "Unknown station ID, please report\n");
0130         break;
0131     }
0132 
0133     /* Default capabilities */
0134     priv->has_sensitivity = 1;
0135     priv->has_mwo = 0;
0136     priv->has_preamble = 0;
0137     priv->has_port3 = 1;
0138     priv->has_ibss = 1;
0139     priv->has_wep = 0;
0140     priv->has_big_wep = 0;
0141     priv->has_alt_txcntl = 0;
0142     priv->has_ext_scan = 0;
0143     priv->has_wpa = 0;
0144     priv->do_fw_download = 0;
0145 
0146     /* Determine capabilities from the firmware version */
0147     switch (priv->firmware_type) {
0148     case FIRMWARE_TYPE_AGERE:
0149         /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
0150            ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
0151         if (fw_name)
0152             snprintf(fw_name, fw_name_len, "Lucent/Agere %d.%02d",
0153                  sta_id.major, sta_id.minor);
0154 
0155         firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
0156 
0157         priv->has_ibss = (firmver >= 0x60006);
0158         priv->has_wep = (firmver >= 0x40020);
0159         priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
0160                       Gold cards from the others? */
0161         priv->has_mwo = (firmver >= 0x60000);
0162         priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
0163         priv->ibss_port = 1;
0164         priv->has_hostscan = (firmver >= 0x8000a);
0165         priv->do_fw_download = 1;
0166         priv->broken_monitor = (firmver >= 0x80000);
0167         priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
0168         priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
0169         priv->has_wpa = (firmver >= 0x9002a);
0170         /* Tested with Agere firmware :
0171          *  1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
0172          * Tested CableTron firmware : 4.32 => Anton */
0173         break;
0174     case FIRMWARE_TYPE_SYMBOL:
0175         /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
0176         /* Intel MAC : 00:02:B3:* */
0177         /* 3Com MAC : 00:50:DA:* */
0178         memset(tmp, 0, sizeof(tmp));
0179         /* Get the Symbol firmware version */
0180         err = hw->ops->read_ltv_pr(hw, USER_BAP,
0181                     HERMES_RID_SECONDARYVERSION_SYMBOL,
0182                     SYMBOL_MAX_VER_LEN, NULL, &tmp);
0183         if (err) {
0184             dev_warn(dev, "Error %d reading Symbol firmware info. "
0185                  "Wildly guessing capabilities...\n", err);
0186             firmver = 0;
0187             tmp[0] = '\0';
0188         } else {
0189             /* The firmware revision is a string, the format is
0190              * something like : "V2.20-01".
0191              * Quick and dirty parsing... - Jean II
0192              */
0193             firmver = ((tmp[1] - '0') << 16)
0194                 | ((tmp[3] - '0') << 12)
0195                 | ((tmp[4] - '0') << 8)
0196                 | ((tmp[6] - '0') << 4)
0197                 | (tmp[7] - '0');
0198 
0199             tmp[SYMBOL_MAX_VER_LEN] = '\0';
0200         }
0201 
0202         if (fw_name)
0203             snprintf(fw_name, fw_name_len, "Symbol %s", tmp);
0204 
0205         priv->has_ibss = (firmver >= 0x20000);
0206         priv->has_wep = (firmver >= 0x15012);
0207         priv->has_big_wep = (firmver >= 0x20000);
0208         priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
0209                    (firmver >= 0x29000 && firmver < 0x30000) ||
0210                    firmver >= 0x31000;
0211         priv->has_preamble = (firmver >= 0x20000);
0212         priv->ibss_port = 4;
0213 
0214         /* Symbol firmware is found on various cards, but
0215          * there has been no attempt to check firmware
0216          * download on non-spectrum_cs based cards.
0217          *
0218          * Given that the Agere firmware download works
0219          * differently, we should avoid doing a firmware
0220          * download with the Symbol algorithm on non-spectrum
0221          * cards.
0222          *
0223          * For now we can identify a spectrum_cs based card
0224          * because it has a firmware reset function.
0225          */
0226         priv->do_fw_download = (priv->stop_fw != NULL);
0227 
0228         priv->broken_disableport = (firmver == 0x25013) ||
0229                 (firmver >= 0x30000 && firmver <= 0x31000);
0230         priv->has_hostscan = (firmver >= 0x31001) ||
0231                      (firmver >= 0x29057 && firmver < 0x30000);
0232         /* Tested with Intel firmware : 0x20015 => Jean II */
0233         /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
0234         break;
0235     case FIRMWARE_TYPE_INTERSIL:
0236         /* D-Link, Linksys, Adtron, ZoomAir, and many others...
0237          * Samsung, Compaq 100/200 and Proxim are slightly
0238          * different and less well tested */
0239         /* D-Link MAC : 00:40:05:* */
0240         /* Addtron MAC : 00:90:D1:* */
0241         if (fw_name)
0242             snprintf(fw_name, fw_name_len, "Intersil %d.%d.%d",
0243                  sta_id.major, sta_id.minor, sta_id.variant);
0244 
0245         firmver = ((unsigned long)sta_id.major << 16) |
0246             ((unsigned long)sta_id.minor << 8) | sta_id.variant;
0247 
0248         priv->has_ibss = (firmver >= 0x000700); /* FIXME */
0249         priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
0250         priv->has_pm = (firmver >= 0x000700);
0251         priv->has_hostscan = (firmver >= 0x010301);
0252 
0253         if (firmver >= 0x000800)
0254             priv->ibss_port = 0;
0255         else {
0256             dev_notice(dev, "Intersil firmware earlier than v0.8.x"
0257                    " - several features not supported\n");
0258             priv->ibss_port = 1;
0259         }
0260         break;
0261     }
0262     if (fw_name)
0263         dev_info(dev, "Firmware determined as %s\n", fw_name);
0264 
0265 #ifndef CONFIG_HERMES_PRISM
0266     if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
0267         dev_err(dev, "Support for Prism chipset is not enabled\n");
0268         return -ENODEV;
0269     }
0270 #endif
0271 
0272     return 0;
0273 }
0274 
0275 /* Read settings from EEPROM into our private structure.
0276  * MAC address gets dropped into callers buffer
0277  * Can be called before netdev registration.
0278  */
0279 int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
0280 {
0281     struct device *dev = priv->dev;
0282     struct hermes_idstring nickbuf;
0283     struct hermes *hw = &priv->hw;
0284     int len;
0285     int err;
0286     u16 reclen;
0287 
0288     /* Get the MAC address */
0289     err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
0290                 ETH_ALEN, NULL, dev_addr);
0291     if (err) {
0292         dev_warn(dev, "Failed to read MAC address!\n");
0293         goto out;
0294     }
0295 
0296     dev_dbg(dev, "MAC address %pM\n", dev_addr);
0297 
0298     /* Get the station name */
0299     err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
0300                 sizeof(nickbuf), &reclen, &nickbuf);
0301     if (err) {
0302         dev_err(dev, "failed to read station name\n");
0303         goto out;
0304     }
0305     if (nickbuf.len)
0306         len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
0307     else
0308         len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
0309     memcpy(priv->nick, &nickbuf.val, len);
0310     priv->nick[len] = '\0';
0311 
0312     dev_dbg(dev, "Station name \"%s\"\n", priv->nick);
0313 
0314     /* Get allowed channels */
0315     err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CHANNELLIST,
0316                   &priv->channel_mask);
0317     if (err) {
0318         dev_err(dev, "Failed to read channel list!\n");
0319         goto out;
0320     }
0321 
0322     /* Get initial AP density */
0323     err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
0324                   &priv->ap_density);
0325     if (err || priv->ap_density < 1 || priv->ap_density > 3)
0326         priv->has_sensitivity = 0;
0327 
0328     /* Get initial RTS threshold */
0329     err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
0330                   &priv->rts_thresh);
0331     if (err) {
0332         dev_err(dev, "Failed to read RTS threshold!\n");
0333         goto out;
0334     }
0335 
0336     /* Get initial fragmentation settings */
0337     if (priv->has_mwo)
0338         err = hermes_read_wordrec_pr(hw, USER_BAP,
0339                       HERMES_RID_CNFMWOROBUST_AGERE,
0340                       &priv->mwo_robust);
0341     else
0342         err = hermes_read_wordrec_pr(hw, USER_BAP,
0343                       HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
0344                       &priv->frag_thresh);
0345     if (err) {
0346         dev_err(dev, "Failed to read fragmentation settings!\n");
0347         goto out;
0348     }
0349 
0350     /* Power management setup */
0351     if (priv->has_pm) {
0352         priv->pm_on = 0;
0353         priv->pm_mcast = 1;
0354         err = hermes_read_wordrec_pr(hw, USER_BAP,
0355                       HERMES_RID_CNFMAXSLEEPDURATION,
0356                       &priv->pm_period);
0357         if (err) {
0358             dev_err(dev, "Failed to read power management "
0359                 "period!\n");
0360             goto out;
0361         }
0362         err = hermes_read_wordrec_pr(hw, USER_BAP,
0363                       HERMES_RID_CNFPMHOLDOVERDURATION,
0364                       &priv->pm_timeout);
0365         if (err) {
0366             dev_err(dev, "Failed to read power management "
0367                 "timeout!\n");
0368             goto out;
0369         }
0370     }
0371 
0372     /* Preamble setup */
0373     if (priv->has_preamble) {
0374         err = hermes_read_wordrec_pr(hw, USER_BAP,
0375                       HERMES_RID_CNFPREAMBLE_SYMBOL,
0376                       &priv->preamble);
0377         if (err) {
0378             dev_err(dev, "Failed to read preamble setup\n");
0379             goto out;
0380         }
0381     }
0382 
0383     /* Retry settings */
0384     err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
0385                   &priv->short_retry_limit);
0386     if (err) {
0387         dev_err(dev, "Failed to read short retry limit\n");
0388         goto out;
0389     }
0390 
0391     err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
0392                   &priv->long_retry_limit);
0393     if (err) {
0394         dev_err(dev, "Failed to read long retry limit\n");
0395         goto out;
0396     }
0397 
0398     err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
0399                   &priv->retry_lifetime);
0400     if (err) {
0401         dev_err(dev, "Failed to read max retry lifetime\n");
0402         goto out;
0403     }
0404 
0405 out:
0406     return err;
0407 }
0408 
0409 /* Can be called before netdev registration */
0410 int orinoco_hw_allocate_fid(struct orinoco_private *priv)
0411 {
0412     struct device *dev = priv->dev;
0413     struct hermes *hw = &priv->hw;
0414     int err;
0415 
0416     err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
0417     if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
0418         /* Try workaround for old Symbol firmware bug */
0419         priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
0420         err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
0421 
0422         dev_warn(dev, "Firmware ALLOC bug detected "
0423              "(old Symbol firmware?). Work around %s\n",
0424              err ? "failed!" : "ok.");
0425     }
0426 
0427     return err;
0428 }
0429 
0430 int orinoco_get_bitratemode(int bitrate, int automatic)
0431 {
0432     int ratemode = -1;
0433     int i;
0434 
0435     if ((bitrate != 10) && (bitrate != 20) &&
0436         (bitrate != 55) && (bitrate != 110))
0437         return ratemode;
0438 
0439     for (i = 0; i < BITRATE_TABLE_SIZE; i++) {
0440         if ((bitrate_table[i].bitrate == bitrate) &&
0441             (bitrate_table[i].automatic == automatic)) {
0442             ratemode = i;
0443             break;
0444         }
0445     }
0446     return ratemode;
0447 }
0448 
0449 void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic)
0450 {
0451     BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE));
0452 
0453     *bitrate = bitrate_table[ratemode].bitrate * 100000;
0454     *automatic = bitrate_table[ratemode].automatic;
0455 }
0456 
0457 int orinoco_hw_program_rids(struct orinoco_private *priv)
0458 {
0459     struct net_device *dev = priv->ndev;
0460     struct wireless_dev *wdev = netdev_priv(dev);
0461     struct hermes *hw = &priv->hw;
0462     int err;
0463     struct hermes_idstring idbuf;
0464 
0465     /* Set the MAC address */
0466     err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
0467                  HERMES_BYTES_TO_RECLEN(ETH_ALEN),
0468                  dev->dev_addr);
0469     if (err) {
0470         printk(KERN_ERR "%s: Error %d setting MAC address\n",
0471                dev->name, err);
0472         return err;
0473     }
0474 
0475     /* Set up the link mode */
0476     err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
0477                    priv->port_type);
0478     if (err) {
0479         printk(KERN_ERR "%s: Error %d setting port type\n",
0480                dev->name, err);
0481         return err;
0482     }
0483     /* Set the channel/frequency */
0484     if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) {
0485         err = hermes_write_wordrec(hw, USER_BAP,
0486                        HERMES_RID_CNFOWNCHANNEL,
0487                        priv->channel);
0488         if (err) {
0489             printk(KERN_ERR "%s: Error %d setting channel %d\n",
0490                    dev->name, err, priv->channel);
0491             return err;
0492         }
0493     }
0494 
0495     if (priv->has_ibss) {
0496         u16 createibss;
0497 
0498         if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
0499             printk(KERN_WARNING "%s: This firmware requires an "
0500                    "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
0501             /* With wvlan_cs, in this case, we would crash.
0502              * hopefully, this driver will behave better...
0503              * Jean II */
0504             createibss = 0;
0505         } else {
0506             createibss = priv->createibss;
0507         }
0508 
0509         err = hermes_write_wordrec(hw, USER_BAP,
0510                        HERMES_RID_CNFCREATEIBSS,
0511                        createibss);
0512         if (err) {
0513             printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
0514                    dev->name, err);
0515             return err;
0516         }
0517     }
0518 
0519     /* Set the desired BSSID */
0520     err = __orinoco_hw_set_wap(priv);
0521     if (err) {
0522         printk(KERN_ERR "%s: Error %d setting AP address\n",
0523                dev->name, err);
0524         return err;
0525     }
0526 
0527     /* Set the desired ESSID */
0528     idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
0529     memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
0530     /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
0531     err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
0532             HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2),
0533             &idbuf);
0534     if (err) {
0535         printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
0536                dev->name, err);
0537         return err;
0538     }
0539     err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
0540             HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2),
0541             &idbuf);
0542     if (err) {
0543         printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
0544                dev->name, err);
0545         return err;
0546     }
0547 
0548     /* Set the station name */
0549     idbuf.len = cpu_to_le16(strlen(priv->nick));
0550     memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
0551     err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
0552                  HERMES_BYTES_TO_RECLEN(strlen(priv->nick) + 2),
0553                  &idbuf);
0554     if (err) {
0555         printk(KERN_ERR "%s: Error %d setting nickname\n",
0556                dev->name, err);
0557         return err;
0558     }
0559 
0560     /* Set AP density */
0561     if (priv->has_sensitivity) {
0562         err = hermes_write_wordrec(hw, USER_BAP,
0563                        HERMES_RID_CNFSYSTEMSCALE,
0564                        priv->ap_density);
0565         if (err) {
0566             printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
0567                    "Disabling sensitivity control\n",
0568                    dev->name, err);
0569 
0570             priv->has_sensitivity = 0;
0571         }
0572     }
0573 
0574     /* Set RTS threshold */
0575     err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
0576                    priv->rts_thresh);
0577     if (err) {
0578         printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
0579                dev->name, err);
0580         return err;
0581     }
0582 
0583     /* Set fragmentation threshold or MWO robustness */
0584     if (priv->has_mwo)
0585         err = hermes_write_wordrec(hw, USER_BAP,
0586                        HERMES_RID_CNFMWOROBUST_AGERE,
0587                        priv->mwo_robust);
0588     else
0589         err = hermes_write_wordrec(hw, USER_BAP,
0590                        HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
0591                        priv->frag_thresh);
0592     if (err) {
0593         printk(KERN_ERR "%s: Error %d setting fragmentation\n",
0594                dev->name, err);
0595         return err;
0596     }
0597 
0598     /* Set bitrate */
0599     err = __orinoco_hw_set_bitrate(priv);
0600     if (err) {
0601         printk(KERN_ERR "%s: Error %d setting bitrate\n",
0602                dev->name, err);
0603         return err;
0604     }
0605 
0606     /* Set power management */
0607     if (priv->has_pm) {
0608         err = hermes_write_wordrec(hw, USER_BAP,
0609                        HERMES_RID_CNFPMENABLED,
0610                        priv->pm_on);
0611         if (err) {
0612             printk(KERN_ERR "%s: Error %d setting up PM\n",
0613                    dev->name, err);
0614             return err;
0615         }
0616 
0617         err = hermes_write_wordrec(hw, USER_BAP,
0618                        HERMES_RID_CNFMULTICASTRECEIVE,
0619                        priv->pm_mcast);
0620         if (err) {
0621             printk(KERN_ERR "%s: Error %d setting up PM\n",
0622                    dev->name, err);
0623             return err;
0624         }
0625         err = hermes_write_wordrec(hw, USER_BAP,
0626                        HERMES_RID_CNFMAXSLEEPDURATION,
0627                        priv->pm_period);
0628         if (err) {
0629             printk(KERN_ERR "%s: Error %d setting up PM\n",
0630                    dev->name, err);
0631             return err;
0632         }
0633         err = hermes_write_wordrec(hw, USER_BAP,
0634                        HERMES_RID_CNFPMHOLDOVERDURATION,
0635                        priv->pm_timeout);
0636         if (err) {
0637             printk(KERN_ERR "%s: Error %d setting up PM\n",
0638                    dev->name, err);
0639             return err;
0640         }
0641     }
0642 
0643     /* Set preamble - only for Symbol so far... */
0644     if (priv->has_preamble) {
0645         err = hermes_write_wordrec(hw, USER_BAP,
0646                        HERMES_RID_CNFPREAMBLE_SYMBOL,
0647                        priv->preamble);
0648         if (err) {
0649             printk(KERN_ERR "%s: Error %d setting preamble\n",
0650                    dev->name, err);
0651             return err;
0652         }
0653     }
0654 
0655     /* Set up encryption */
0656     if (priv->has_wep || priv->has_wpa) {
0657         err = __orinoco_hw_setup_enc(priv);
0658         if (err) {
0659             printk(KERN_ERR "%s: Error %d activating encryption\n",
0660                    dev->name, err);
0661             return err;
0662         }
0663     }
0664 
0665     if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
0666         /* Enable monitor mode */
0667         dev->type = ARPHRD_IEEE80211;
0668         err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
0669                         HERMES_TEST_MONITOR, 0, NULL);
0670     } else {
0671         /* Disable monitor mode */
0672         dev->type = ARPHRD_ETHER;
0673         err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
0674                         HERMES_TEST_STOP, 0, NULL);
0675     }
0676     if (err)
0677         return err;
0678 
0679     /* Reset promiscuity / multicast*/
0680     priv->promiscuous = 0;
0681     priv->mc_count = 0;
0682 
0683     /* Record mode change */
0684     wdev->iftype = priv->iw_mode;
0685 
0686     return 0;
0687 }
0688 
0689 /* Get tsc from the firmware */
0690 int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
0691 {
0692     struct hermes *hw = &priv->hw;
0693     int err = 0;
0694     u8 tsc_arr[4][ORINOCO_SEQ_LEN];
0695 
0696     if ((key < 0) || (key >= 4))
0697         return -EINVAL;
0698 
0699     err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
0700                 sizeof(tsc_arr), NULL, &tsc_arr);
0701     if (!err)
0702         memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
0703 
0704     return err;
0705 }
0706 
0707 int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
0708 {
0709     struct hermes *hw = &priv->hw;
0710     int ratemode = priv->bitratemode;
0711     int err = 0;
0712 
0713     if (ratemode >= BITRATE_TABLE_SIZE) {
0714         printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
0715                priv->ndev->name, ratemode);
0716         return -EINVAL;
0717     }
0718 
0719     switch (priv->firmware_type) {
0720     case FIRMWARE_TYPE_AGERE:
0721         err = hermes_write_wordrec(hw, USER_BAP,
0722                 HERMES_RID_CNFTXRATECONTROL,
0723                 bitrate_table[ratemode].agere_txratectrl);
0724         break;
0725     case FIRMWARE_TYPE_INTERSIL:
0726     case FIRMWARE_TYPE_SYMBOL:
0727         err = hermes_write_wordrec(hw, USER_BAP,
0728                 HERMES_RID_CNFTXRATECONTROL,
0729                 bitrate_table[ratemode].intersil_txratectrl);
0730         break;
0731     default:
0732         BUG();
0733     }
0734 
0735     return err;
0736 }
0737 
0738 int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate)
0739 {
0740     struct hermes *hw = &priv->hw;
0741     int i;
0742     int err = 0;
0743     u16 val;
0744 
0745     err = hermes_read_wordrec(hw, USER_BAP,
0746                   HERMES_RID_CURRENTTXRATE, &val);
0747     if (err)
0748         return err;
0749 
0750     switch (priv->firmware_type) {
0751     case FIRMWARE_TYPE_AGERE: /* Lucent style rate */
0752         /* Note : in Lucent firmware, the return value of
0753          * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s,
0754          * and therefore is totally different from the
0755          * encoding of HERMES_RID_CNFTXRATECONTROL.
0756          * Don't forget that 6Mb/s is really 5.5Mb/s */
0757         if (val == 6)
0758             *bitrate = 5500000;
0759         else
0760             *bitrate = val * 1000000;
0761         break;
0762     case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
0763     case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
0764         for (i = 0; i < BITRATE_TABLE_SIZE; i++)
0765             if (bitrate_table[i].intersil_txratectrl == val) {
0766                 *bitrate = bitrate_table[i].bitrate * 100000;
0767                 break;
0768             }
0769 
0770         if (i >= BITRATE_TABLE_SIZE) {
0771             printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
0772                    priv->ndev->name, val);
0773             err = -EIO;
0774         }
0775 
0776         break;
0777     default:
0778         BUG();
0779     }
0780 
0781     return err;
0782 }
0783 
0784 /* Set fixed AP address */
0785 int __orinoco_hw_set_wap(struct orinoco_private *priv)
0786 {
0787     int roaming_flag;
0788     int err = 0;
0789     struct hermes *hw = &priv->hw;
0790 
0791     switch (priv->firmware_type) {
0792     case FIRMWARE_TYPE_AGERE:
0793         /* not supported */
0794         break;
0795     case FIRMWARE_TYPE_INTERSIL:
0796         if (priv->bssid_fixed)
0797             roaming_flag = 2;
0798         else
0799             roaming_flag = 1;
0800 
0801         err = hermes_write_wordrec(hw, USER_BAP,
0802                        HERMES_RID_CNFROAMINGMODE,
0803                        roaming_flag);
0804         break;
0805     case FIRMWARE_TYPE_SYMBOL:
0806         err = HERMES_WRITE_RECORD(hw, USER_BAP,
0807                       HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
0808                       &priv->desired_bssid);
0809         break;
0810     }
0811     return err;
0812 }
0813 
0814 /* Change the WEP keys and/or the current keys.  Can be called
0815  * either from __orinoco_hw_setup_enc() or directly from
0816  * orinoco_ioctl_setiwencode().  In the later case the association
0817  * with the AP is not broken (if the firmware can handle it),
0818  * which is needed for 802.1x implementations. */
0819 int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
0820 {
0821     struct hermes *hw = &priv->hw;
0822     int err = 0;
0823     int i;
0824 
0825     switch (priv->firmware_type) {
0826     case FIRMWARE_TYPE_AGERE:
0827     {
0828         struct orinoco_key keys[ORINOCO_MAX_KEYS];
0829 
0830         memset(&keys, 0, sizeof(keys));
0831         for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
0832             int len = min(priv->keys[i].key_len,
0833                       ORINOCO_MAX_KEY_SIZE);
0834             memcpy(&keys[i].data, priv->keys[i].key, len);
0835             if (len > SMALL_KEY_SIZE)
0836                 keys[i].len = cpu_to_le16(LARGE_KEY_SIZE);
0837             else if (len > 0)
0838                 keys[i].len = cpu_to_le16(SMALL_KEY_SIZE);
0839             else
0840                 keys[i].len = cpu_to_le16(0);
0841         }
0842 
0843         err = HERMES_WRITE_RECORD(hw, USER_BAP,
0844                       HERMES_RID_CNFWEPKEYS_AGERE,
0845                       &keys);
0846         if (err)
0847             return err;
0848         err = hermes_write_wordrec(hw, USER_BAP,
0849                        HERMES_RID_CNFTXKEY_AGERE,
0850                        priv->tx_key);
0851         if (err)
0852             return err;
0853         break;
0854     }
0855     case FIRMWARE_TYPE_INTERSIL:
0856     case FIRMWARE_TYPE_SYMBOL:
0857         {
0858             int keylen;
0859 
0860             /* Force uniform key length to work around
0861              * firmware bugs */
0862             keylen = priv->keys[priv->tx_key].key_len;
0863 
0864             if (keylen > LARGE_KEY_SIZE) {
0865                 printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
0866                        priv->ndev->name, priv->tx_key, keylen);
0867                 return -E2BIG;
0868             } else if (keylen > SMALL_KEY_SIZE)
0869                 keylen = LARGE_KEY_SIZE;
0870             else if (keylen > 0)
0871                 keylen = SMALL_KEY_SIZE;
0872             else
0873                 keylen = 0;
0874 
0875             /* Write all 4 keys */
0876             for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
0877                 u8 key[LARGE_KEY_SIZE] = { 0 };
0878 
0879                 memcpy(key, priv->keys[i].key,
0880                        priv->keys[i].key_len);
0881 
0882                 err = hw->ops->write_ltv(hw, USER_BAP,
0883                         HERMES_RID_CNFDEFAULTKEY0 + i,
0884                         HERMES_BYTES_TO_RECLEN(keylen),
0885                         key);
0886                 if (err)
0887                     return err;
0888             }
0889 
0890             /* Write the index of the key used in transmission */
0891             err = hermes_write_wordrec(hw, USER_BAP,
0892                         HERMES_RID_CNFWEPDEFAULTKEYID,
0893                         priv->tx_key);
0894             if (err)
0895                 return err;
0896         }
0897         break;
0898     }
0899 
0900     return 0;
0901 }
0902 
0903 int __orinoco_hw_setup_enc(struct orinoco_private *priv)
0904 {
0905     struct hermes *hw = &priv->hw;
0906     int err = 0;
0907     int master_wep_flag;
0908     int auth_flag;
0909     int enc_flag;
0910 
0911     /* Setup WEP keys */
0912     if (priv->encode_alg == ORINOCO_ALG_WEP)
0913         __orinoco_hw_setup_wepkeys(priv);
0914 
0915     if (priv->wep_restrict)
0916         auth_flag = HERMES_AUTH_SHARED_KEY;
0917     else
0918         auth_flag = HERMES_AUTH_OPEN;
0919 
0920     if (priv->wpa_enabled)
0921         enc_flag = 2;
0922     else if (priv->encode_alg == ORINOCO_ALG_WEP)
0923         enc_flag = 1;
0924     else
0925         enc_flag = 0;
0926 
0927     switch (priv->firmware_type) {
0928     case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
0929         if (priv->encode_alg == ORINOCO_ALG_WEP) {
0930             /* Enable the shared-key authentication. */
0931             err = hermes_write_wordrec(hw, USER_BAP,
0932                     HERMES_RID_CNFAUTHENTICATION_AGERE,
0933                     auth_flag);
0934         }
0935         err = hermes_write_wordrec(hw, USER_BAP,
0936                        HERMES_RID_CNFWEPENABLED_AGERE,
0937                        enc_flag);
0938         if (err)
0939             return err;
0940 
0941         if (priv->has_wpa) {
0942             /* Set WPA key management */
0943             err = hermes_write_wordrec(hw, USER_BAP,
0944                   HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE,
0945                   priv->key_mgmt);
0946             if (err)
0947                 return err;
0948         }
0949 
0950         break;
0951 
0952     case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
0953     case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
0954         if (priv->encode_alg == ORINOCO_ALG_WEP) {
0955             if (priv->wep_restrict ||
0956                 (priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
0957                 master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
0958                           HERMES_WEP_EXCL_UNENCRYPTED;
0959             else
0960                 master_wep_flag = HERMES_WEP_PRIVACY_INVOKED;
0961 
0962             err = hermes_write_wordrec(hw, USER_BAP,
0963                            HERMES_RID_CNFAUTHENTICATION,
0964                            auth_flag);
0965             if (err)
0966                 return err;
0967         } else
0968             master_wep_flag = 0;
0969 
0970         if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
0971             master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
0972 
0973         /* Master WEP setting : on/off */
0974         err = hermes_write_wordrec(hw, USER_BAP,
0975                        HERMES_RID_CNFWEPFLAGS_INTERSIL,
0976                        master_wep_flag);
0977         if (err)
0978             return err;
0979 
0980         break;
0981     }
0982 
0983     return 0;
0984 }
0985 
0986 /* key must be 32 bytes, including the tx and rx MIC keys.
0987  * rsc must be NULL or up to 8 bytes
0988  * tsc must be NULL or up to 8 bytes
0989  */
0990 int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
0991                   int set_tx, const u8 *key, size_t key_len,
0992                   const u8 *rsc, size_t rsc_len,
0993                   const u8 *tsc, size_t tsc_len)
0994 {
0995     struct {
0996         __le16 idx;
0997         u8 rsc[ORINOCO_SEQ_LEN];
0998         struct {
0999             u8 key[TKIP_KEYLEN];
1000             u8 tx_mic[MIC_KEYLEN];
1001             u8 rx_mic[MIC_KEYLEN];
1002         } tkip;
1003         u8 tsc[ORINOCO_SEQ_LEN];
1004     } __packed buf;
1005     struct hermes *hw = &priv->hw;
1006     int ret;
1007     int err;
1008     int k;
1009     u16 xmitting;
1010 
1011     key_idx &= 0x3;
1012 
1013     if (set_tx)
1014         key_idx |= 0x8000;
1015 
1016     buf.idx = cpu_to_le16(key_idx);
1017     if (key_len != sizeof(buf.tkip))
1018         return -EINVAL;
1019     memcpy(&buf.tkip, key, sizeof(buf.tkip));
1020 
1021     if (rsc_len > sizeof(buf.rsc))
1022         rsc_len = sizeof(buf.rsc);
1023 
1024     if (tsc_len > sizeof(buf.tsc))
1025         tsc_len = sizeof(buf.tsc);
1026 
1027     memset(buf.rsc, 0, sizeof(buf.rsc));
1028     memset(buf.tsc, 0, sizeof(buf.tsc));
1029 
1030     if (rsc != NULL)
1031         memcpy(buf.rsc, rsc, rsc_len);
1032 
1033     if (tsc != NULL)
1034         memcpy(buf.tsc, tsc, tsc_len);
1035     else
1036         buf.tsc[4] = 0x10;
1037 
1038     /* Wait up to 100ms for tx queue to empty */
1039     for (k = 100; k > 0; k--) {
1040         udelay(1000);
1041         ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
1042                       &xmitting);
1043         if (ret || !xmitting)
1044             break;
1045     }
1046 
1047     if (k == 0)
1048         ret = -ETIMEDOUT;
1049 
1050     err = HERMES_WRITE_RECORD(hw, USER_BAP,
1051                   HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE,
1052                   &buf);
1053 
1054     return ret ? ret : err;
1055 }
1056 
1057 int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx)
1058 {
1059     struct hermes *hw = &priv->hw;
1060     int err;
1061 
1062     err = hermes_write_wordrec(hw, USER_BAP,
1063                    HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
1064                    key_idx);
1065     if (err)
1066         printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n",
1067                priv->ndev->name, err, key_idx);
1068     return err;
1069 }
1070 
1071 int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
1072                     struct net_device *dev,
1073                     int mc_count, int promisc)
1074 {
1075     struct hermes *hw = &priv->hw;
1076     int err = 0;
1077 
1078     if (promisc != priv->promiscuous) {
1079         err = hermes_write_wordrec(hw, USER_BAP,
1080                        HERMES_RID_CNFPROMISCUOUSMODE,
1081                        promisc);
1082         if (err) {
1083             printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
1084                    priv->ndev->name, err);
1085         } else
1086             priv->promiscuous = promisc;
1087     }
1088 
1089     /* If we're not in promiscuous mode, then we need to set the
1090      * group address if either we want to multicast, or if we were
1091      * multicasting and want to stop */
1092     if (!promisc && (mc_count || priv->mc_count)) {
1093         struct netdev_hw_addr *ha;
1094         struct hermes_multicast mclist;
1095         int i = 0;
1096 
1097         netdev_for_each_mc_addr(ha, dev) {
1098             if (i == mc_count)
1099                 break;
1100             memcpy(mclist.addr[i++], ha->addr, ETH_ALEN);
1101         }
1102 
1103         err = hw->ops->write_ltv(hw, USER_BAP,
1104                    HERMES_RID_CNFGROUPADDRESSES,
1105                    HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
1106                    &mclist);
1107         if (err)
1108             printk(KERN_ERR "%s: Error %d setting multicast list.\n",
1109                    priv->ndev->name, err);
1110         else
1111             priv->mc_count = mc_count;
1112     }
1113     return err;
1114 }
1115 
1116 /* Return : < 0 -> error code ; >= 0 -> length */
1117 int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
1118              char buf[IW_ESSID_MAX_SIZE + 1])
1119 {
1120     struct hermes *hw = &priv->hw;
1121     int err = 0;
1122     struct hermes_idstring essidbuf;
1123     char *p = (char *)(&essidbuf.val);
1124     int len;
1125     unsigned long flags;
1126 
1127     if (orinoco_lock(priv, &flags) != 0)
1128         return -EBUSY;
1129 
1130     if (strlen(priv->desired_essid) > 0) {
1131         /* We read the desired SSID from the hardware rather
1132            than from priv->desired_essid, just in case the
1133            firmware is allowed to change it on us. I'm not
1134            sure about this */
1135         /* My guess is that the OWNSSID should always be whatever
1136          * we set to the card, whereas CURRENT_SSID is the one that
1137          * may change... - Jean II */
1138         u16 rid;
1139 
1140         *active = 1;
1141 
1142         rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
1143             HERMES_RID_CNFDESIREDSSID;
1144 
1145         err = hw->ops->read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
1146                     NULL, &essidbuf);
1147         if (err)
1148             goto fail_unlock;
1149     } else {
1150         *active = 0;
1151 
1152         err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
1153                     sizeof(essidbuf), NULL, &essidbuf);
1154         if (err)
1155             goto fail_unlock;
1156     }
1157 
1158     len = le16_to_cpu(essidbuf.len);
1159     BUG_ON(len > IW_ESSID_MAX_SIZE);
1160 
1161     memset(buf, 0, IW_ESSID_MAX_SIZE);
1162     memcpy(buf, p, len);
1163     err = len;
1164 
1165  fail_unlock:
1166     orinoco_unlock(priv, &flags);
1167 
1168     return err;
1169 }
1170 
1171 int orinoco_hw_get_freq(struct orinoco_private *priv)
1172 {
1173     struct hermes *hw = &priv->hw;
1174     int err = 0;
1175     u16 channel;
1176     int freq = 0;
1177     unsigned long flags;
1178 
1179     if (orinoco_lock(priv, &flags) != 0)
1180         return -EBUSY;
1181 
1182     err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL,
1183                   &channel);
1184     if (err)
1185         goto out;
1186 
1187     /* Intersil firmware 1.3.5 returns 0 when the interface is down */
1188     if (channel == 0) {
1189         err = -EBUSY;
1190         goto out;
1191     }
1192 
1193     if ((channel < 1) || (channel > NUM_CHANNELS)) {
1194         printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
1195                priv->ndev->name, channel);
1196         err = -EBUSY;
1197         goto out;
1198 
1199     }
1200     freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
1201 
1202  out:
1203     orinoco_unlock(priv, &flags);
1204 
1205     if (err > 0)
1206         err = -EBUSY;
1207     return err ? err : freq;
1208 }
1209 
1210 int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
1211                    int *numrates, s32 *rates, int max)
1212 {
1213     struct hermes *hw = &priv->hw;
1214     struct hermes_idstring list;
1215     unsigned char *p = (unsigned char *)&list.val;
1216     int err = 0;
1217     int num;
1218     int i;
1219     unsigned long flags;
1220 
1221     if (orinoco_lock(priv, &flags) != 0)
1222         return -EBUSY;
1223 
1224     err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
1225                 sizeof(list), NULL, &list);
1226     orinoco_unlock(priv, &flags);
1227 
1228     if (err)
1229         return err;
1230 
1231     num = le16_to_cpu(list.len);
1232     *numrates = num;
1233     num = min(num, max);
1234 
1235     for (i = 0; i < num; i++)
1236         rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
1237 
1238     return 0;
1239 }
1240 
1241 int orinoco_hw_trigger_scan(struct orinoco_private *priv,
1242                 const struct cfg80211_ssid *ssid)
1243 {
1244     struct net_device *dev = priv->ndev;
1245     struct hermes *hw = &priv->hw;
1246     unsigned long flags;
1247     int err = 0;
1248 
1249     if (orinoco_lock(priv, &flags) != 0)
1250         return -EBUSY;
1251 
1252     /* Scanning with port 0 disabled would fail */
1253     if (!netif_running(dev)) {
1254         err = -ENETDOWN;
1255         goto out;
1256     }
1257 
1258     /* In monitor mode, the scan results are always empty.
1259      * Probe responses are passed to the driver as received
1260      * frames and could be processed in software. */
1261     if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
1262         err = -EOPNOTSUPP;
1263         goto out;
1264     }
1265 
1266     if (priv->has_hostscan) {
1267         switch (priv->firmware_type) {
1268         case FIRMWARE_TYPE_SYMBOL:
1269             err = hermes_write_wordrec(hw, USER_BAP,
1270                         HERMES_RID_CNFHOSTSCAN_SYMBOL,
1271                         HERMES_HOSTSCAN_SYMBOL_ONCE |
1272                         HERMES_HOSTSCAN_SYMBOL_BCAST);
1273             break;
1274         case FIRMWARE_TYPE_INTERSIL: {
1275             __le16 req[3];
1276 
1277             req[0] = cpu_to_le16(0x3fff);   /* All channels */
1278             req[1] = cpu_to_le16(0x0001);   /* rate 1 Mbps */
1279             req[2] = 0;         /* Any ESSID */
1280             err = HERMES_WRITE_RECORD(hw, USER_BAP,
1281                           HERMES_RID_CNFHOSTSCAN, &req);
1282             break;
1283         }
1284         case FIRMWARE_TYPE_AGERE:
1285             if (ssid->ssid_len > 0) {
1286                 struct hermes_idstring idbuf;
1287                 size_t len = ssid->ssid_len;
1288 
1289                 idbuf.len = cpu_to_le16(len);
1290                 memcpy(idbuf.val, ssid->ssid, len);
1291 
1292                 err = hw->ops->write_ltv(hw, USER_BAP,
1293                            HERMES_RID_CNFSCANSSID_AGERE,
1294                            HERMES_BYTES_TO_RECLEN(len + 2),
1295                            &idbuf);
1296             } else
1297                 err = hermes_write_wordrec(hw, USER_BAP,
1298                            HERMES_RID_CNFSCANSSID_AGERE,
1299                            0);  /* Any ESSID */
1300             if (err)
1301                 break;
1302 
1303             if (priv->has_ext_scan) {
1304                 err = hermes_write_wordrec(hw, USER_BAP,
1305                         HERMES_RID_CNFSCANCHANNELS2GHZ,
1306                         0x7FFF);
1307                 if (err)
1308                     goto out;
1309 
1310                 err = hermes_inquire(hw,
1311                              HERMES_INQ_CHANNELINFO);
1312             } else
1313                 err = hermes_inquire(hw, HERMES_INQ_SCAN);
1314 
1315             break;
1316         }
1317     } else
1318         err = hermes_inquire(hw, HERMES_INQ_SCAN);
1319 
1320  out:
1321     orinoco_unlock(priv, &flags);
1322 
1323     return err;
1324 }
1325 
1326 /* Disassociate from node with BSSID addr */
1327 int orinoco_hw_disassociate(struct orinoco_private *priv,
1328                 u8 *addr, u16 reason_code)
1329 {
1330     struct hermes *hw = &priv->hw;
1331     int err;
1332 
1333     struct {
1334         u8 addr[ETH_ALEN];
1335         __le16 reason_code;
1336     } __packed buf;
1337 
1338     /* Currently only supported by WPA enabled Agere fw */
1339     if (!priv->has_wpa)
1340         return -EOPNOTSUPP;
1341 
1342     memcpy(buf.addr, addr, ETH_ALEN);
1343     buf.reason_code = cpu_to_le16(reason_code);
1344     err = HERMES_WRITE_RECORD(hw, USER_BAP,
1345                   HERMES_RID_CNFDISASSOCIATE,
1346                   &buf);
1347     return err;
1348 }
1349 
1350 int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
1351                  u8 *addr)
1352 {
1353     struct hermes *hw = &priv->hw;
1354     int err;
1355 
1356     err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
1357                 ETH_ALEN, NULL, addr);
1358 
1359     return err;
1360 }