Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Firmware I/O code for mac80211 Prism54 drivers
0004  *
0005  * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
0006  * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
0007  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
0008  *
0009  * Based on:
0010  * - the islsm (softmac prism54) driver, which is:
0011  *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
0012  * - stlc45xx driver
0013  *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
0014  */
0015 
0016 #include <linux/slab.h>
0017 #include <linux/firmware.h>
0018 #include <linux/etherdevice.h>
0019 #include <linux/export.h>
0020 
0021 #include <net/mac80211.h>
0022 
0023 #include "p54.h"
0024 #include "eeprom.h"
0025 #include "lmac.h"
0026 
0027 int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
0028 {
0029     struct p54_common *priv = dev->priv;
0030     struct exp_if *exp_if;
0031     struct bootrec *bootrec;
0032     u32 *data = (u32 *)fw->data;
0033     u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
0034     u8 *fw_version = NULL;
0035     size_t len;
0036     int i;
0037     int maxlen;
0038 
0039     if (priv->rx_start)
0040         return 0;
0041 
0042     while (data < end_data && *data)
0043         data++;
0044 
0045     while (data < end_data && !*data)
0046         data++;
0047 
0048     bootrec = (struct bootrec *) data;
0049 
0050     while (bootrec->data <= end_data && (bootrec->data +
0051            (len = le32_to_cpu(bootrec->len))) <= end_data) {
0052         u32 code = le32_to_cpu(bootrec->code);
0053         switch (code) {
0054         case BR_CODE_COMPONENT_ID:
0055             priv->fw_interface = be32_to_cpup((__be32 *)
0056                          bootrec->data);
0057             switch (priv->fw_interface) {
0058             case FW_LM86:
0059             case FW_LM20:
0060             case FW_LM87: {
0061                 char *iftype = (char *)bootrec->data;
0062                 wiphy_info(priv->hw->wiphy,
0063                        "p54 detected a LM%c%c firmware\n",
0064                        iftype[2], iftype[3]);
0065                 break;
0066                 }
0067             case FW_FMAC:
0068             default:
0069                 wiphy_err(priv->hw->wiphy,
0070                       "unsupported firmware\n");
0071                 return -ENODEV;
0072             }
0073             break;
0074         case BR_CODE_COMPONENT_VERSION:
0075             /* 24 bytes should be enough for all firmwares */
0076             if (strnlen((unsigned char *) bootrec->data, 24) < 24)
0077                 fw_version = (unsigned char *) bootrec->data;
0078             break;
0079         case BR_CODE_DESCR: {
0080             struct bootrec_desc *desc =
0081                 (struct bootrec_desc *)bootrec->data;
0082             priv->rx_start = le32_to_cpu(desc->rx_start);
0083             /* FIXME add sanity checking */
0084             priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
0085             priv->headroom = desc->headroom;
0086             priv->tailroom = desc->tailroom;
0087             priv->privacy_caps = desc->privacy_caps;
0088             priv->rx_keycache_size = desc->rx_keycache_size;
0089             if (le32_to_cpu(bootrec->len) == 11)
0090                 priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
0091             else
0092                 priv->rx_mtu = (size_t)
0093                     0x620 - priv->tx_hdr_len;
0094             maxlen = priv->tx_hdr_len + /* USB devices */
0095                  sizeof(struct p54_rx_data) +
0096                  4 + /* rx alignment */
0097                  IEEE80211_MAX_FRAG_THRESHOLD;
0098             if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
0099                 printk(KERN_INFO "p54: rx_mtu reduced from %d "
0100                        "to %d\n", priv->rx_mtu, maxlen);
0101                 priv->rx_mtu = maxlen;
0102             }
0103             break;
0104             }
0105         case BR_CODE_EXPOSED_IF:
0106             exp_if = (struct exp_if *) bootrec->data;
0107             for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
0108                 if (exp_if[i].if_id == cpu_to_le16(IF_ID_LMAC))
0109                     priv->fw_var = le16_to_cpu(exp_if[i].variant);
0110             break;
0111         case BR_CODE_DEPENDENT_IF:
0112             break;
0113         case BR_CODE_END_OF_BRA:
0114         case LEGACY_BR_CODE_END_OF_BRA:
0115             end_data = NULL;
0116             break;
0117         default:
0118             break;
0119         }
0120         bootrec = (struct bootrec *)&bootrec->data[len];
0121     }
0122 
0123     if (fw_version) {
0124         wiphy_info(priv->hw->wiphy,
0125                "FW rev %s - Softmac protocol %x.%x\n",
0126                fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
0127         snprintf(dev->wiphy->fw_version, sizeof(dev->wiphy->fw_version),
0128                 "%s - %x.%x", fw_version,
0129                 priv->fw_var >> 8, priv->fw_var & 0xff);
0130     }
0131 
0132     if (priv->fw_var < 0x500)
0133         wiphy_info(priv->hw->wiphy,
0134                "you are using an obsolete firmware. "
0135                "visit http://wireless.wiki.kernel.org/en/users/Drivers/p54 "
0136                "and grab one for \"kernel >= 2.6.28\"!\n");
0137 
0138     if (priv->fw_var >= 0x300) {
0139         /* Firmware supports QoS, use it! */
0140 
0141         if (priv->fw_var >= 0x500) {
0142             priv->tx_stats[P54_QUEUE_AC_VO].limit = 16;
0143             priv->tx_stats[P54_QUEUE_AC_VI].limit = 16;
0144             priv->tx_stats[P54_QUEUE_AC_BE].limit = 16;
0145             priv->tx_stats[P54_QUEUE_AC_BK].limit = 16;
0146         } else {
0147             priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
0148             priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
0149             priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
0150             priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
0151         }
0152         priv->hw->queues = P54_QUEUE_AC_NUM;
0153     }
0154 
0155     wiphy_info(priv->hw->wiphy,
0156            "cryptographic accelerator WEP:%s, TKIP:%s, CCMP:%s\n",
0157            (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : "no",
0158            (priv->privacy_caps &
0159             (BR_DESC_PRIV_CAP_TKIP | BR_DESC_PRIV_CAP_MICHAEL))
0160            ? "YES" : "no",
0161            (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)
0162            ? "YES" : "no");
0163 
0164     if (priv->rx_keycache_size) {
0165         /*
0166          * NOTE:
0167          *
0168          * The firmware provides at most 255 (0 - 254) slots
0169          * for keys which are then used to offload decryption.
0170          * As a result the 255 entry (aka 0xff) can be used
0171          * safely by the driver to mark keys that didn't fit
0172          * into the full cache. This trick saves us from
0173          * keeping a extra list for uploaded keys.
0174          */
0175 
0176         priv->used_rxkeys = bitmap_zalloc(priv->rx_keycache_size,
0177                           GFP_KERNEL);
0178         if (!priv->used_rxkeys)
0179             return -ENOMEM;
0180     }
0181 
0182     return 0;
0183 }
0184 EXPORT_SYMBOL_GPL(p54_parse_firmware);
0185 
0186 static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags,
0187                      u16 payload_len, u16 type, gfp_t memflags)
0188 {
0189     struct p54_hdr *hdr;
0190     struct sk_buff *skb;
0191     size_t frame_len = sizeof(*hdr) + payload_len;
0192 
0193     if (frame_len > P54_MAX_CTRL_FRAME_LEN)
0194         return NULL;
0195 
0196     if (unlikely(skb_queue_len(&priv->tx_pending) > 64))
0197         return NULL;
0198 
0199     skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
0200     if (!skb)
0201         return NULL;
0202     skb_reserve(skb, priv->tx_hdr_len);
0203 
0204     hdr = skb_put(skb, sizeof(*hdr));
0205     hdr->flags = cpu_to_le16(hdr_flags);
0206     hdr->len = cpu_to_le16(payload_len);
0207     hdr->type = cpu_to_le16(type);
0208     hdr->tries = hdr->rts_tries = 0;
0209     return skb;
0210 }
0211 
0212 int p54_download_eeprom(struct p54_common *priv, void *buf,
0213             u16 offset, u16 len)
0214 {
0215     struct p54_eeprom_lm86 *eeprom_hdr;
0216     struct sk_buff *skb;
0217     size_t eeprom_hdr_size;
0218     int ret = 0;
0219     long timeout;
0220 
0221     if (priv->fw_var >= 0x509)
0222         eeprom_hdr_size = sizeof(*eeprom_hdr);
0223     else
0224         eeprom_hdr_size = 0x4;
0225 
0226     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, eeprom_hdr_size +
0227                 len, P54_CONTROL_TYPE_EEPROM_READBACK,
0228                 GFP_KERNEL);
0229     if (unlikely(!skb))
0230         return -ENOMEM;
0231 
0232     mutex_lock(&priv->eeprom_mutex);
0233     priv->eeprom = buf;
0234     eeprom_hdr = skb_put(skb, eeprom_hdr_size + len);
0235 
0236     if (priv->fw_var < 0x509) {
0237         eeprom_hdr->v1.offset = cpu_to_le16(offset);
0238         eeprom_hdr->v1.len = cpu_to_le16(len);
0239     } else {
0240         eeprom_hdr->v2.offset = cpu_to_le32(offset);
0241         eeprom_hdr->v2.len = cpu_to_le16(len);
0242         eeprom_hdr->v2.magic2 = 0xf;
0243         memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
0244     }
0245 
0246     p54_tx(priv, skb);
0247 
0248     timeout = wait_for_completion_interruptible_timeout(
0249             &priv->eeprom_comp, HZ);
0250     if (timeout <= 0) {
0251         wiphy_err(priv->hw->wiphy,
0252             "device does not respond or signal received!\n");
0253         ret = -EBUSY;
0254     }
0255     priv->eeprom = NULL;
0256     mutex_unlock(&priv->eeprom_mutex);
0257     return ret;
0258 }
0259 
0260 int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set)
0261 {
0262     struct sk_buff *skb;
0263     struct p54_tim *tim;
0264 
0265     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
0266                 P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
0267     if (unlikely(!skb))
0268         return -ENOMEM;
0269 
0270     tim = skb_put(skb, sizeof(*tim));
0271     tim->count = 1;
0272     tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid);
0273     p54_tx(priv, skb);
0274     return 0;
0275 }
0276 
0277 int p54_sta_unlock(struct p54_common *priv, u8 *addr)
0278 {
0279     struct sk_buff *skb;
0280     struct p54_sta_unlock *sta;
0281 
0282     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
0283                 P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
0284     if (unlikely(!skb))
0285         return -ENOMEM;
0286 
0287     sta = skb_put(skb, sizeof(*sta));
0288     memcpy(sta->addr, addr, ETH_ALEN);
0289     p54_tx(priv, skb);
0290     return 0;
0291 }
0292 
0293 int p54_tx_cancel(struct p54_common *priv, __le32 req_id)
0294 {
0295     struct sk_buff *skb;
0296     struct p54_txcancel *cancel;
0297     u32 _req_id = le32_to_cpu(req_id);
0298 
0299     if (unlikely(_req_id < priv->rx_start || _req_id > priv->rx_end))
0300         return -EINVAL;
0301 
0302     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
0303                 P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
0304     if (unlikely(!skb))
0305         return -ENOMEM;
0306 
0307     cancel = skb_put(skb, sizeof(*cancel));
0308     cancel->req_id = req_id;
0309     p54_tx(priv, skb);
0310     return 0;
0311 }
0312 
0313 int p54_setup_mac(struct p54_common *priv)
0314 {
0315     struct sk_buff *skb;
0316     struct p54_setup_mac *setup;
0317     u16 mode;
0318 
0319     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
0320                 P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
0321     if (!skb)
0322         return -ENOMEM;
0323 
0324     setup = skb_put(skb, sizeof(*setup));
0325     if (!(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) {
0326         switch (priv->mode) {
0327         case NL80211_IFTYPE_STATION:
0328             mode = P54_FILTER_TYPE_STATION;
0329             break;
0330         case NL80211_IFTYPE_AP:
0331             mode = P54_FILTER_TYPE_AP;
0332             break;
0333         case NL80211_IFTYPE_ADHOC:
0334         case NL80211_IFTYPE_MESH_POINT:
0335             mode = P54_FILTER_TYPE_IBSS;
0336             break;
0337         case NL80211_IFTYPE_MONITOR:
0338             mode = P54_FILTER_TYPE_PROMISCUOUS;
0339             break;
0340         default:
0341             mode = P54_FILTER_TYPE_HIBERNATE;
0342             break;
0343         }
0344 
0345         /*
0346          * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
0347          * STSW45X0C LMAC API - page 12
0348          */
0349         if (priv->filter_flags & FIF_OTHER_BSS &&
0350             (mode != P54_FILTER_TYPE_PROMISCUOUS))
0351             mode |= P54_FILTER_TYPE_TRANSPARENT;
0352     } else {
0353         mode = P54_FILTER_TYPE_HIBERNATE;
0354     }
0355 
0356     setup->mac_mode = cpu_to_le16(mode);
0357     memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
0358     memcpy(setup->bssid, priv->bssid, ETH_ALEN);
0359     setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
0360     setup->rx_align = 0;
0361     if (priv->fw_var < 0x500) {
0362         setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
0363         memset(setup->v1.rts_rates, 0, 8);
0364         setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
0365         setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
0366         setup->v1.rxhw = cpu_to_le16(priv->rxhw);
0367         setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
0368         setup->v1.unalloc0 = cpu_to_le16(0);
0369     } else {
0370         setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
0371         setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
0372         setup->v2.rxhw = cpu_to_le16(priv->rxhw);
0373         setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
0374         setup->v2.truncate = cpu_to_le16(48896);
0375         setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
0376         setup->v2.sbss_offset = 0;
0377         setup->v2.mcast_window = 0;
0378         setup->v2.rx_rssi_threshold = 0;
0379         setup->v2.rx_ed_threshold = 0;
0380         setup->v2.ref_clock = cpu_to_le32(644245094);
0381         setup->v2.lpf_bandwidth = cpu_to_le16(65535);
0382         setup->v2.osc_start_delay = cpu_to_le16(65535);
0383     }
0384     p54_tx(priv, skb);
0385     priv->phy_idle = mode == P54_FILTER_TYPE_HIBERNATE;
0386     return 0;
0387 }
0388 
0389 int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
0390 {
0391     struct sk_buff *skb;
0392     struct p54_hdr *hdr;
0393     struct p54_scan_head *head;
0394     struct p54_iq_autocal_entry *iq_autocal;
0395     union p54_scan_body_union *body;
0396     struct p54_scan_tail_rate *rate;
0397     struct pda_rssi_cal_entry *rssi;
0398     struct p54_rssi_db_entry *rssi_data;
0399     unsigned int i;
0400     void *entry;
0401     __le16 freq = cpu_to_le16(priv->hw->conf.chandef.chan->center_freq);
0402 
0403     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
0404                 2 + sizeof(*iq_autocal) + sizeof(*body) +
0405                 sizeof(*rate) + 2 * sizeof(*rssi),
0406                 P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
0407     if (!skb)
0408         return -ENOMEM;
0409 
0410     head = skb_put(skb, sizeof(*head));
0411     memset(head->scan_params, 0, sizeof(head->scan_params));
0412     head->mode = cpu_to_le16(mode);
0413     head->dwell = cpu_to_le16(dwell);
0414     head->freq = freq;
0415 
0416     if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
0417         __le16 *pa_power_points = skb_put(skb, 2);
0418         *pa_power_points = cpu_to_le16(0x0c);
0419     }
0420 
0421     iq_autocal = skb_put(skb, sizeof(*iq_autocal));
0422     for (i = 0; i < priv->iq_autocal_len; i++) {
0423         if (priv->iq_autocal[i].freq != freq)
0424             continue;
0425 
0426         memcpy(iq_autocal, &priv->iq_autocal[i].params,
0427                sizeof(struct p54_iq_autocal_entry));
0428         break;
0429     }
0430     if (i == priv->iq_autocal_len)
0431         goto err;
0432 
0433     if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
0434         body = skb_put(skb, sizeof(body->longbow));
0435     else
0436         body = skb_put(skb, sizeof(body->normal));
0437 
0438     for (i = 0; i < priv->output_limit->entries; i++) {
0439         __le16 *entry_freq = (void *) (priv->output_limit->data +
0440                      priv->output_limit->entry_size * i);
0441 
0442         if (*entry_freq != freq)
0443             continue;
0444 
0445         if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
0446             memcpy(&body->longbow.power_limits,
0447                    (void *) entry_freq + sizeof(__le16),
0448                    priv->output_limit->entry_size);
0449         } else {
0450             struct pda_channel_output_limit *limits =
0451                    (void *) entry_freq;
0452 
0453             body->normal.val_barker = 0x38;
0454             body->normal.val_bpsk = body->normal.dup_bpsk =
0455                 limits->val_bpsk;
0456             body->normal.val_qpsk = body->normal.dup_qpsk =
0457                 limits->val_qpsk;
0458             body->normal.val_16qam = body->normal.dup_16qam =
0459                 limits->val_16qam;
0460             body->normal.val_64qam = body->normal.dup_64qam =
0461                 limits->val_64qam;
0462         }
0463         break;
0464     }
0465     if (i == priv->output_limit->entries)
0466         goto err;
0467 
0468     entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
0469     for (i = 0; i < priv->curve_data->entries; i++) {
0470         if (*((__le16 *)entry) != freq) {
0471             entry += priv->curve_data->entry_size;
0472             continue;
0473         }
0474 
0475         if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
0476             memcpy(&body->longbow.curve_data,
0477                 entry + sizeof(__le16),
0478                 priv->curve_data->entry_size);
0479         } else {
0480             struct p54_scan_body *chan = &body->normal;
0481             struct pda_pa_curve_data *curve_data =
0482                 (void *) priv->curve_data->data;
0483 
0484             entry += sizeof(__le16);
0485             chan->pa_points_per_curve = 8;
0486             memset(chan->curve_data, 0, sizeof(chan->curve_data));
0487             memcpy(chan->curve_data, entry,
0488                    sizeof(struct p54_pa_curve_data_sample) *
0489                    min((u8)8, curve_data->points_per_channel));
0490         }
0491         break;
0492     }
0493     if (i == priv->curve_data->entries)
0494         goto err;
0495 
0496     if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
0497         rate = skb_put(skb, sizeof(*rate));
0498         rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
0499         for (i = 0; i < sizeof(rate->rts_rates); i++)
0500             rate->rts_rates[i] = i;
0501     }
0502 
0503     rssi = skb_put(skb, sizeof(*rssi));
0504     rssi_data = p54_rssi_find(priv, le16_to_cpu(freq));
0505     rssi->mul = cpu_to_le16(rssi_data->mul);
0506     rssi->add = cpu_to_le16(rssi_data->add);
0507     if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
0508         /* Longbow frontend needs ever more */
0509         rssi = skb_put(skb, sizeof(*rssi));
0510         rssi->mul = cpu_to_le16(rssi_data->longbow_unkn);
0511         rssi->add = cpu_to_le16(rssi_data->longbow_unk2);
0512     }
0513 
0514     if (priv->fw_var >= 0x509) {
0515         rate = skb_put(skb, sizeof(*rate));
0516         rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
0517         for (i = 0; i < sizeof(rate->rts_rates); i++)
0518             rate->rts_rates[i] = i;
0519     }
0520 
0521     hdr = (struct p54_hdr *) skb->data;
0522     hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
0523 
0524     p54_tx(priv, skb);
0525     priv->cur_rssi = rssi_data;
0526     return 0;
0527 
0528 err:
0529     wiphy_err(priv->hw->wiphy, "frequency change to channel %d failed.\n",
0530           ieee80211_frequency_to_channel(
0531               priv->hw->conf.chandef.chan->center_freq));
0532 
0533     dev_kfree_skb_any(skb);
0534     return -EINVAL;
0535 }
0536 
0537 int p54_set_leds(struct p54_common *priv)
0538 {
0539     struct sk_buff *skb;
0540     struct p54_led *led;
0541 
0542     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
0543                 P54_CONTROL_TYPE_LED, GFP_ATOMIC);
0544     if (unlikely(!skb))
0545         return -ENOMEM;
0546 
0547     led = skb_put(skb, sizeof(*led));
0548     led->flags = cpu_to_le16(0x0003);
0549     led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
0550     led->delay[0] = cpu_to_le16(1);
0551     led->delay[1] = cpu_to_le16(0);
0552     p54_tx(priv, skb);
0553     return 0;
0554 }
0555 
0556 int p54_set_edcf(struct p54_common *priv)
0557 {
0558     struct sk_buff *skb;
0559     struct p54_edcf *edcf;
0560     u8 rtd;
0561 
0562     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
0563                 P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
0564     if (unlikely(!skb))
0565         return -ENOMEM;
0566 
0567     edcf = skb_put(skb, sizeof(*edcf));
0568     if (priv->use_short_slot) {
0569         edcf->slottime = 9;
0570         edcf->sifs = 0x10;
0571         edcf->eofpad = 0x00;
0572     } else {
0573         edcf->slottime = 20;
0574         edcf->sifs = 0x0a;
0575         edcf->eofpad = 0x06;
0576     }
0577     /*
0578      * calculate the extra round trip delay according to the
0579      * formula from 802.11-2007 17.3.8.6.
0580      */
0581     rtd = 3 * priv->coverage_class;
0582     edcf->slottime += rtd;
0583     edcf->round_trip_delay = cpu_to_le16(rtd);
0584     /* (see prism54/isl_oid.h for further details) */
0585     edcf->frameburst = cpu_to_le16(0);
0586     edcf->flags = 0;
0587     memset(edcf->mapping, 0, sizeof(edcf->mapping));
0588     memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
0589     p54_tx(priv, skb);
0590     return 0;
0591 }
0592 
0593 int p54_set_ps(struct p54_common *priv)
0594 {
0595     struct sk_buff *skb;
0596     struct p54_psm *psm;
0597     unsigned int i;
0598     u16 mode;
0599 
0600     if (priv->hw->conf.flags & IEEE80211_CONF_PS &&
0601         !priv->powersave_override)
0602         mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
0603                P54_PSM_CHECKSUM | P54_PSM_MCBC;
0604     else
0605         mode = P54_PSM_CAM;
0606 
0607     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
0608                 P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
0609     if (!skb)
0610         return -ENOMEM;
0611 
0612     psm = skb_put(skb, sizeof(*psm));
0613     psm->mode = cpu_to_le16(mode);
0614     psm->aid = cpu_to_le16(priv->aid);
0615     for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
0616         psm->intervals[i].interval =
0617             cpu_to_le16(priv->hw->conf.listen_interval);
0618         psm->intervals[i].periods = cpu_to_le16(1);
0619     }
0620 
0621     psm->beacon_rssi_skip_max = 200;
0622     psm->rssi_delta_threshold = 0;
0623     psm->nr = 1;
0624     psm->exclude[0] = WLAN_EID_TIM;
0625 
0626     p54_tx(priv, skb);
0627     priv->phy_ps = mode != P54_PSM_CAM;
0628     return 0;
0629 }
0630 
0631 int p54_init_xbow_synth(struct p54_common *priv)
0632 {
0633     struct sk_buff *skb;
0634     struct p54_xbow_synth *xbow;
0635 
0636     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
0637                 P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
0638     if (unlikely(!skb))
0639         return -ENOMEM;
0640 
0641     xbow = skb_put(skb, sizeof(*xbow));
0642     xbow->magic1 = cpu_to_le16(0x1);
0643     xbow->magic2 = cpu_to_le16(0x2);
0644     xbow->freq = cpu_to_le16(5390);
0645     memset(xbow->padding, 0, sizeof(xbow->padding));
0646     p54_tx(priv, skb);
0647     return 0;
0648 }
0649 
0650 int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len,
0651            u8 *addr, u8* key)
0652 {
0653     struct sk_buff *skb;
0654     struct p54_keycache *rxkey;
0655 
0656     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
0657                 P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
0658     if (unlikely(!skb))
0659         return -ENOMEM;
0660 
0661     rxkey = skb_put(skb, sizeof(*rxkey));
0662     rxkey->entry = slot;
0663     rxkey->key_id = idx;
0664     rxkey->key_type = algo;
0665     if (addr)
0666         memcpy(rxkey->mac, addr, ETH_ALEN);
0667     else
0668         eth_broadcast_addr(rxkey->mac);
0669 
0670     switch (algo) {
0671     case P54_CRYPTO_WEP:
0672     case P54_CRYPTO_AESCCMP:
0673         rxkey->key_len = min_t(u8, 16, len);
0674         memcpy(rxkey->key, key, rxkey->key_len);
0675         break;
0676 
0677     case P54_CRYPTO_TKIPMICHAEL:
0678         rxkey->key_len = 24;
0679         memcpy(rxkey->key, key, 16);
0680         memcpy(&(rxkey->key[16]), &(key
0681             [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
0682         break;
0683 
0684     case P54_CRYPTO_NONE:
0685         rxkey->key_len = 0;
0686         memset(rxkey->key, 0, sizeof(rxkey->key));
0687         break;
0688 
0689     default:
0690         wiphy_err(priv->hw->wiphy,
0691               "invalid cryptographic algorithm: %d\n", algo);
0692         dev_kfree_skb(skb);
0693         return -EINVAL;
0694     }
0695 
0696     p54_tx(priv, skb);
0697     return 0;
0698 }
0699 
0700 int p54_fetch_statistics(struct p54_common *priv)
0701 {
0702     struct ieee80211_tx_info *txinfo;
0703     struct p54_tx_info *p54info;
0704     struct sk_buff *skb;
0705 
0706     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL,
0707                 sizeof(struct p54_statistics),
0708                 P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
0709     if (!skb)
0710         return -ENOMEM;
0711 
0712     /*
0713      * The statistic feedback causes some extra headaches here, if it
0714      * is not to crash/corrupt the firmware data structures.
0715      *
0716      * Unlike all other Control Get OIDs we can not use helpers like
0717      * skb_put to reserve the space for the data we're requesting.
0718      * Instead the extra frame length -which will hold the results later-
0719      * will only be told to the p54_assign_address, so that following
0720      * frames won't be placed into the  allegedly empty area.
0721      */
0722     txinfo = IEEE80211_SKB_CB(skb);
0723     p54info = (void *) txinfo->rate_driver_data;
0724     p54info->extra_len = sizeof(struct p54_statistics);
0725 
0726     p54_tx(priv, skb);
0727     return 0;
0728 }
0729 
0730 int p54_set_groupfilter(struct p54_common *priv)
0731 {
0732     struct p54_group_address_table *grp;
0733     struct sk_buff *skb;
0734     bool on = false;
0735 
0736     skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*grp),
0737                 P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE, GFP_KERNEL);
0738     if (!skb)
0739         return -ENOMEM;
0740 
0741     grp = skb_put(skb, sizeof(*grp));
0742 
0743     on = !(priv->filter_flags & FIF_ALLMULTI) &&
0744          (priv->mc_maclist_num > 0 &&
0745           priv->mc_maclist_num <= MC_FILTER_ADDRESS_NUM);
0746 
0747     if (on) {
0748         grp->filter_enable = cpu_to_le16(1);
0749         grp->num_address = cpu_to_le16(priv->mc_maclist_num);
0750         memcpy(grp->mac_list, priv->mc_maclist, sizeof(grp->mac_list));
0751     } else {
0752         grp->filter_enable = cpu_to_le16(0);
0753         grp->num_address = cpu_to_le16(0);
0754         memset(grp->mac_list, 0, sizeof(grp->mac_list));
0755     }
0756 
0757     p54_tx(priv, skb);
0758     return 0;
0759 }