1/* 2 * Firmware I/O code for mac80211 Prism54 drivers 3 * 4 * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> 5 * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de> 6 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> 7 * 8 * Based on: 9 * - the islsm (softmac prism54) driver, which is: 10 * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. 11 * - stlc45xx driver 12 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License version 2 as 16 * published by the Free Software Foundation. 17 */ 18 19#include <linux/init.h> 20#include <linux/slab.h> 21#include <linux/firmware.h> 22#include <linux/etherdevice.h> 23#include <linux/export.h> 24 25#include <net/mac80211.h> 26 27#include "p54.h" 28#include "eeprom.h" 29#include "lmac.h" 30 31int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) 32{ 33 struct p54_common *priv = dev->priv; 34 struct exp_if *exp_if; 35 struct bootrec *bootrec; 36 u32 *data = (u32 *)fw->data; 37 u32 *end_data = (u32 *)fw->data + (fw->size >> 2); 38 u8 *fw_version = NULL; 39 size_t len; 40 int i; 41 int maxlen; 42 43 if (priv->rx_start) 44 return 0; 45 46 while (data < end_data && *data) 47 data++; 48 49 while (data < end_data && !*data) 50 data++; 51 52 bootrec = (struct bootrec *) data; 53 54 while (bootrec->data <= end_data && (bootrec->data + 55 (len = le32_to_cpu(bootrec->len))) <= end_data) { 56 u32 code = le32_to_cpu(bootrec->code); 57 switch (code) { 58 case BR_CODE_COMPONENT_ID: 59 priv->fw_interface = be32_to_cpup((__be32 *) 60 bootrec->data); 61 switch (priv->fw_interface) { 62 case FW_LM86: 63 case FW_LM20: 64 case FW_LM87: { 65 char *iftype = (char *)bootrec->data; 66 wiphy_info(priv->hw->wiphy, 67 "p54 detected a LM%c%c firmware\n", 68 iftype[2], iftype[3]); 69 break; 70 } 71 case FW_FMAC: 72 default: 73 wiphy_err(priv->hw->wiphy, 74 "unsupported firmware\n"); 75 return -ENODEV; 76 } 77 break; 78 case BR_CODE_COMPONENT_VERSION: 79 /* 24 bytes should be enough for all firmwares */ 80 if (strnlen((unsigned char *) bootrec->data, 24) < 24) 81 fw_version = (unsigned char *) bootrec->data; 82 break; 83 case BR_CODE_DESCR: { 84 struct bootrec_desc *desc = 85 (struct bootrec_desc *)bootrec->data; 86 priv->rx_start = le32_to_cpu(desc->rx_start); 87 /* FIXME add sanity checking */ 88 priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; 89 priv->headroom = desc->headroom; 90 priv->tailroom = desc->tailroom; 91 priv->privacy_caps = desc->privacy_caps; 92 priv->rx_keycache_size = desc->rx_keycache_size; 93 if (le32_to_cpu(bootrec->len) == 11) 94 priv->rx_mtu = le16_to_cpu(desc->rx_mtu); 95 else 96 priv->rx_mtu = (size_t) 97 0x620 - priv->tx_hdr_len; 98 maxlen = priv->tx_hdr_len + /* USB devices */ 99 sizeof(struct p54_rx_data) + 100 4 + /* rx alignment */ 101 IEEE80211_MAX_FRAG_THRESHOLD; 102 if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) { 103 printk(KERN_INFO "p54: rx_mtu reduced from %d " 104 "to %d\n", priv->rx_mtu, maxlen); 105 priv->rx_mtu = maxlen; 106 } 107 break; 108 } 109 case BR_CODE_EXPOSED_IF: 110 exp_if = (struct exp_if *) bootrec->data; 111 for (i = 0; i < (len * sizeof(*exp_if) / 4); i++) 112 if (exp_if[i].if_id == cpu_to_le16(IF_ID_LMAC)) 113 priv->fw_var = le16_to_cpu(exp_if[i].variant); 114 break; 115 case BR_CODE_DEPENDENT_IF: 116 break; 117 case BR_CODE_END_OF_BRA: 118 case LEGACY_BR_CODE_END_OF_BRA: 119 end_data = NULL; 120 break; 121 default: 122 break; 123 } 124 bootrec = (struct bootrec *)&bootrec->data[len]; 125 } 126 127 if (fw_version) { 128 wiphy_info(priv->hw->wiphy, 129 "FW rev %s - Softmac protocol %x.%x\n", 130 fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); 131 snprintf(dev->wiphy->fw_version, sizeof(dev->wiphy->fw_version), 132 "%s - %x.%x", fw_version, 133 priv->fw_var >> 8, priv->fw_var & 0xff); 134 } 135 136 if (priv->fw_var < 0x500) 137 wiphy_info(priv->hw->wiphy, 138 "you are using an obsolete firmware. " 139 "visit http://wireless.kernel.org/en/users/Drivers/p54 " 140 "and grab one for \"kernel >= 2.6.28\"!\n"); 141 142 if (priv->fw_var >= 0x300) { 143 /* Firmware supports QoS, use it! */ 144 145 if (priv->fw_var >= 0x500) { 146 priv->tx_stats[P54_QUEUE_AC_VO].limit = 16; 147 priv->tx_stats[P54_QUEUE_AC_VI].limit = 16; 148 priv->tx_stats[P54_QUEUE_AC_BE].limit = 16; 149 priv->tx_stats[P54_QUEUE_AC_BK].limit = 16; 150 } else { 151 priv->tx_stats[P54_QUEUE_AC_VO].limit = 3; 152 priv->tx_stats[P54_QUEUE_AC_VI].limit = 4; 153 priv->tx_stats[P54_QUEUE_AC_BE].limit = 3; 154 priv->tx_stats[P54_QUEUE_AC_BK].limit = 2; 155 } 156 priv->hw->queues = P54_QUEUE_AC_NUM; 157 } 158 159 wiphy_info(priv->hw->wiphy, 160 "cryptographic accelerator WEP:%s, TKIP:%s, CCMP:%s\n", 161 (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : "no", 162 (priv->privacy_caps & 163 (BR_DESC_PRIV_CAP_TKIP | BR_DESC_PRIV_CAP_MICHAEL)) 164 ? "YES" : "no", 165 (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) 166 ? "YES" : "no"); 167 168 if (priv->rx_keycache_size) { 169 /* 170 * NOTE: 171 * 172 * The firmware provides at most 255 (0 - 254) slots 173 * for keys which are then used to offload decryption. 174 * As a result the 255 entry (aka 0xff) can be used 175 * safely by the driver to mark keys that didn't fit 176 * into the full cache. This trick saves us from 177 * keeping a extra list for uploaded keys. 178 */ 179 180 priv->used_rxkeys = kzalloc(BITS_TO_LONGS( 181 priv->rx_keycache_size), GFP_KERNEL); 182 183 if (!priv->used_rxkeys) 184 return -ENOMEM; 185 } 186 187 return 0; 188} 189EXPORT_SYMBOL_GPL(p54_parse_firmware); 190 191static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags, 192 u16 payload_len, u16 type, gfp_t memflags) 193{ 194 struct p54_hdr *hdr; 195 struct sk_buff *skb; 196 size_t frame_len = sizeof(*hdr) + payload_len; 197 198 if (frame_len > P54_MAX_CTRL_FRAME_LEN) 199 return NULL; 200 201 if (unlikely(skb_queue_len(&priv->tx_pending) > 64)) 202 return NULL; 203 204 skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags); 205 if (!skb) 206 return NULL; 207 skb_reserve(skb, priv->tx_hdr_len); 208 209 hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr)); 210 hdr->flags = cpu_to_le16(hdr_flags); 211 hdr->len = cpu_to_le16(payload_len); 212 hdr->type = cpu_to_le16(type); 213 hdr->tries = hdr->rts_tries = 0; 214 return skb; 215} 216 217int p54_download_eeprom(struct p54_common *priv, void *buf, 218 u16 offset, u16 len) 219{ 220 struct p54_eeprom_lm86 *eeprom_hdr; 221 struct sk_buff *skb; 222 size_t eeprom_hdr_size; 223 int ret = 0; 224 225 if (priv->fw_var >= 0x509) 226 eeprom_hdr_size = sizeof(*eeprom_hdr); 227 else 228 eeprom_hdr_size = 0x4; 229 230 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, eeprom_hdr_size + 231 len, P54_CONTROL_TYPE_EEPROM_READBACK, 232 GFP_KERNEL); 233 if (unlikely(!skb)) 234 return -ENOMEM; 235 236 mutex_lock(&priv->eeprom_mutex); 237 priv->eeprom = buf; 238 eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, 239 eeprom_hdr_size + len); 240 241 if (priv->fw_var < 0x509) { 242 eeprom_hdr->v1.offset = cpu_to_le16(offset); 243 eeprom_hdr->v1.len = cpu_to_le16(len); 244 } else { 245 eeprom_hdr->v2.offset = cpu_to_le32(offset); 246 eeprom_hdr->v2.len = cpu_to_le16(len); 247 eeprom_hdr->v2.magic2 = 0xf; 248 memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4); 249 } 250 251 p54_tx(priv, skb); 252 253 if (!wait_for_completion_interruptible_timeout( 254 &priv->eeprom_comp, HZ)) { 255 wiphy_err(priv->hw->wiphy, "device does not respond!\n"); 256 ret = -EBUSY; 257 } 258 priv->eeprom = NULL; 259 mutex_unlock(&priv->eeprom_mutex); 260 return ret; 261} 262 263int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set) 264{ 265 struct sk_buff *skb; 266 struct p54_tim *tim; 267 268 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim), 269 P54_CONTROL_TYPE_TIM, GFP_ATOMIC); 270 if (unlikely(!skb)) 271 return -ENOMEM; 272 273 tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); 274 tim->count = 1; 275 tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid); 276 p54_tx(priv, skb); 277 return 0; 278} 279 280int p54_sta_unlock(struct p54_common *priv, u8 *addr) 281{ 282 struct sk_buff *skb; 283 struct p54_sta_unlock *sta; 284 285 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta), 286 P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC); 287 if (unlikely(!skb)) 288 return -ENOMEM; 289 290 sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); 291 memcpy(sta->addr, addr, ETH_ALEN); 292 p54_tx(priv, skb); 293 return 0; 294} 295 296int p54_tx_cancel(struct p54_common *priv, __le32 req_id) 297{ 298 struct sk_buff *skb; 299 struct p54_txcancel *cancel; 300 u32 _req_id = le32_to_cpu(req_id); 301 302 if (unlikely(_req_id < priv->rx_start || _req_id > priv->rx_end)) 303 return -EINVAL; 304 305 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel), 306 P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC); 307 if (unlikely(!skb)) 308 return -ENOMEM; 309 310 cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); 311 cancel->req_id = req_id; 312 p54_tx(priv, skb); 313 return 0; 314} 315 316int p54_setup_mac(struct p54_common *priv) 317{ 318 struct sk_buff *skb; 319 struct p54_setup_mac *setup; 320 u16 mode; 321 322 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup), 323 P54_CONTROL_TYPE_SETUP, GFP_ATOMIC); 324 if (!skb) 325 return -ENOMEM; 326 327 setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); 328 if (!(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) { 329 switch (priv->mode) { 330 case NL80211_IFTYPE_STATION: 331 mode = P54_FILTER_TYPE_STATION; 332 break; 333 case NL80211_IFTYPE_AP: 334 mode = P54_FILTER_TYPE_AP; 335 break; 336 case NL80211_IFTYPE_ADHOC: 337 case NL80211_IFTYPE_MESH_POINT: 338 mode = P54_FILTER_TYPE_IBSS; 339 break; 340 case NL80211_IFTYPE_MONITOR: 341 mode = P54_FILTER_TYPE_PROMISCUOUS; 342 break; 343 default: 344 mode = P54_FILTER_TYPE_HIBERNATE; 345 break; 346 } 347 348 /* 349 * "TRANSPARENT and PROMISCUOUS are mutually exclusive" 350 * STSW45X0C LMAC API - page 12 351 */ 352 if (((priv->filter_flags & FIF_PROMISC_IN_BSS) || 353 (priv->filter_flags & FIF_OTHER_BSS)) && 354 (mode != P54_FILTER_TYPE_PROMISCUOUS)) 355 mode |= P54_FILTER_TYPE_TRANSPARENT; 356 } else { 357 mode = P54_FILTER_TYPE_HIBERNATE; 358 } 359 360 setup->mac_mode = cpu_to_le16(mode); 361 memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); 362 memcpy(setup->bssid, priv->bssid, ETH_ALEN); 363 setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */ 364 setup->rx_align = 0; 365 if (priv->fw_var < 0x500) { 366 setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); 367 memset(setup->v1.rts_rates, 0, 8); 368 setup->v1.rx_addr = cpu_to_le32(priv->rx_end); 369 setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); 370 setup->v1.rxhw = cpu_to_le16(priv->rxhw); 371 setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer); 372 setup->v1.unalloc0 = cpu_to_le16(0); 373 } else { 374 setup->v2.rx_addr = cpu_to_le32(priv->rx_end); 375 setup->v2.max_rx = cpu_to_le16(priv->rx_mtu); 376 setup->v2.rxhw = cpu_to_le16(priv->rxhw); 377 setup->v2.timer = cpu_to_le16(priv->wakeup_timer); 378 setup->v2.truncate = cpu_to_le16(48896); 379 setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); 380 setup->v2.sbss_offset = 0; 381 setup->v2.mcast_window = 0; 382 setup->v2.rx_rssi_threshold = 0; 383 setup->v2.rx_ed_threshold = 0; 384 setup->v2.ref_clock = cpu_to_le32(644245094); 385 setup->v2.lpf_bandwidth = cpu_to_le16(65535); 386 setup->v2.osc_start_delay = cpu_to_le16(65535); 387 } 388 p54_tx(priv, skb); 389 priv->phy_idle = mode == P54_FILTER_TYPE_HIBERNATE; 390 return 0; 391} 392 393int p54_scan(struct p54_common *priv, u16 mode, u16 dwell) 394{ 395 struct sk_buff *skb; 396 struct p54_hdr *hdr; 397 struct p54_scan_head *head; 398 struct p54_iq_autocal_entry *iq_autocal; 399 union p54_scan_body_union *body; 400 struct p54_scan_tail_rate *rate; 401 struct pda_rssi_cal_entry *rssi; 402 struct p54_rssi_db_entry *rssi_data; 403 unsigned int i; 404 void *entry; 405 __le16 freq = cpu_to_le16(priv->hw->conf.channel->center_freq); 406 407 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) + 408 2 + sizeof(*iq_autocal) + sizeof(*body) + 409 sizeof(*rate) + 2 * sizeof(*rssi), 410 P54_CONTROL_TYPE_SCAN, GFP_ATOMIC); 411 if (!skb) 412 return -ENOMEM; 413 414 head = (struct p54_scan_head *) skb_put(skb, sizeof(*head)); 415 memset(head->scan_params, 0, sizeof(head->scan_params)); 416 head->mode = cpu_to_le16(mode); 417 head->dwell = cpu_to_le16(dwell); 418 head->freq = freq; 419 420 if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { 421 __le16 *pa_power_points = (__le16 *) skb_put(skb, 2); 422 *pa_power_points = cpu_to_le16(0x0c); 423 } 424 425 iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal)); 426 for (i = 0; i < priv->iq_autocal_len; i++) { 427 if (priv->iq_autocal[i].freq != freq) 428 continue; 429 430 memcpy(iq_autocal, &priv->iq_autocal[i].params, 431 sizeof(struct p54_iq_autocal_entry)); 432 break; 433 } 434 if (i == priv->iq_autocal_len) 435 goto err; 436 437 if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) 438 body = (void *) skb_put(skb, sizeof(body->longbow)); 439 else 440 body = (void *) skb_put(skb, sizeof(body->normal)); 441 442 for (i = 0; i < priv->output_limit->entries; i++) { 443 __le16 *entry_freq = (void *) (priv->output_limit->data + 444 priv->output_limit->entry_size * i); 445 446 if (*entry_freq != freq) 447 continue; 448 449 if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { 450 memcpy(&body->longbow.power_limits, 451 (void *) entry_freq + sizeof(__le16), 452 priv->output_limit->entry_size); 453 } else { 454 struct pda_channel_output_limit *limits = 455 (void *) entry_freq; 456 457 body->normal.val_barker = 0x38; 458 body->normal.val_bpsk = body->normal.dup_bpsk = 459 limits->val_bpsk; 460 body->normal.val_qpsk = body->normal.dup_qpsk = 461 limits->val_qpsk; 462 body->normal.val_16qam = body->normal.dup_16qam = 463 limits->val_16qam; 464 body->normal.val_64qam = body->normal.dup_64qam = 465 limits->val_64qam; 466 } 467 break; 468 } 469 if (i == priv->output_limit->entries) 470 goto err; 471 472 entry = (void *)(priv->curve_data->data + priv->curve_data->offset); 473 for (i = 0; i < priv->curve_data->entries; i++) { 474 if (*((__le16 *)entry) != freq) { 475 entry += priv->curve_data->entry_size; 476 continue; 477 } 478 479 if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { 480 memcpy(&body->longbow.curve_data, 481 (void *) entry + sizeof(__le16), 482 priv->curve_data->entry_size); 483 } else { 484 struct p54_scan_body *chan = &body->normal; 485 struct pda_pa_curve_data *curve_data = 486 (void *) priv->curve_data->data; 487 488 entry += sizeof(__le16); 489 chan->pa_points_per_curve = 8; 490 memset(chan->curve_data, 0, sizeof(*chan->curve_data)); 491 memcpy(chan->curve_data, entry, 492 sizeof(struct p54_pa_curve_data_sample) * 493 min((u8)8, curve_data->points_per_channel)); 494 } 495 break; 496 } 497 if (i == priv->curve_data->entries) 498 goto err; 499 500 if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) { 501 rate = (void *) skb_put(skb, sizeof(*rate)); 502 rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); 503 for (i = 0; i < sizeof(rate->rts_rates); i++) 504 rate->rts_rates[i] = i; 505 } 506 507 rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi)); 508 rssi_data = p54_rssi_find(priv, le16_to_cpu(freq)); 509 rssi->mul = cpu_to_le16(rssi_data->mul); 510 rssi->add = cpu_to_le16(rssi_data->add); 511 if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { 512 /* Longbow frontend needs ever more */ 513 rssi = (void *) skb_put(skb, sizeof(*rssi)); 514 rssi->mul = cpu_to_le16(rssi_data->longbow_unkn); 515 rssi->add = cpu_to_le16(rssi_data->longbow_unk2); 516 } 517 518 if (priv->fw_var >= 0x509) { 519 rate = (void *) skb_put(skb, sizeof(*rate)); 520 rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); 521 for (i = 0; i < sizeof(rate->rts_rates); i++) 522 rate->rts_rates[i] = i; 523 } 524 525 hdr = (struct p54_hdr *) skb->data; 526 hdr->len = cpu_to_le16(skb->len - sizeof(*hdr)); 527 528 p54_tx(priv, skb); 529 priv->cur_rssi = rssi_data; 530 return 0; 531 532err: 533 wiphy_err(priv->hw->wiphy, "frequency change to channel %d failed.\n", 534 ieee80211_frequency_to_channel( 535 priv->hw->conf.channel->center_freq)); 536 537 dev_kfree_skb_any(skb); 538 return -EINVAL; 539} 540 541int p54_set_leds(struct p54_common *priv) 542{ 543 struct sk_buff *skb; 544 struct p54_led *led; 545 546 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led), 547 P54_CONTROL_TYPE_LED, GFP_ATOMIC); 548 if (unlikely(!skb)) 549 return -ENOMEM; 550 551 led = (struct p54_led *) skb_put(skb, sizeof(*led)); 552 led->flags = cpu_to_le16(0x0003); 553 led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state); 554 led->delay[0] = cpu_to_le16(1); 555 led->delay[1] = cpu_to_le16(0); 556 p54_tx(priv, skb); 557 return 0; 558} 559 560int p54_set_edcf(struct p54_common *priv) 561{ 562 struct sk_buff *skb; 563 struct p54_edcf *edcf; 564 u8 rtd; 565 566 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf), 567 P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC); 568 if (unlikely(!skb)) 569 return -ENOMEM; 570 571 edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf)); 572 if (priv->use_short_slot) { 573 edcf->slottime = 9; 574 edcf->sifs = 0x10; 575 edcf->eofpad = 0x00; 576 } else { 577 edcf->slottime = 20; 578 edcf->sifs = 0x0a; 579 edcf->eofpad = 0x06; 580 } 581 /* 582 * calculate the extra round trip delay according to the 583 * formula from 802.11-2007 17.3.8.6. 584 */ 585 rtd = 3 * priv->coverage_class; 586 edcf->slottime += rtd; 587 edcf->round_trip_delay = cpu_to_le16(rtd); 588 /* (see prism54/isl_oid.h for further details) */ 589 edcf->frameburst = cpu_to_le16(0); 590 edcf->flags = 0; 591 memset(edcf->mapping, 0, sizeof(edcf->mapping)); 592 memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); 593 p54_tx(priv, skb); 594 return 0; 595} 596 597int p54_set_ps(struct p54_common *priv) 598{ 599 struct sk_buff *skb; 600 struct p54_psm *psm; 601 unsigned int i; 602 u16 mode; 603 604 if (priv->hw->conf.flags & IEEE80211_CONF_PS && 605 !priv->powersave_override) 606 mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM | 607 P54_PSM_CHECKSUM | P54_PSM_MCBC; 608 else 609 mode = P54_PSM_CAM; 610 611 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm), 612 P54_CONTROL_TYPE_PSM, GFP_ATOMIC); 613 if (!skb) 614 return -ENOMEM; 615 616 psm = (struct p54_psm *)skb_put(skb, sizeof(*psm)); 617 psm->mode = cpu_to_le16(mode); 618 psm->aid = cpu_to_le16(priv->aid); 619 for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) { 620 psm->intervals[i].interval = 621 cpu_to_le16(priv->hw->conf.listen_interval); 622 psm->intervals[i].periods = cpu_to_le16(1); 623 } 624 625 psm->beacon_rssi_skip_max = 200; 626 psm->rssi_delta_threshold = 0; 627 psm->nr = 1; 628 psm->exclude[0] = WLAN_EID_TIM; 629 630 p54_tx(priv, skb); 631 priv->phy_ps = mode != P54_PSM_CAM; 632 return 0; 633} 634 635int p54_init_xbow_synth(struct p54_common *priv) 636{ 637 struct sk_buff *skb; 638 struct p54_xbow_synth *xbow; 639 640 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow), 641 P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL); 642 if (unlikely(!skb)) 643 return -ENOMEM; 644 645 xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow)); 646 xbow->magic1 = cpu_to_le16(0x1); 647 xbow->magic2 = cpu_to_le16(0x2); 648 xbow->freq = cpu_to_le16(5390); 649 memset(xbow->padding, 0, sizeof(xbow->padding)); 650 p54_tx(priv, skb); 651 return 0; 652} 653 654int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len, 655 u8 *addr, u8* key) 656{ 657 struct sk_buff *skb; 658 struct p54_keycache *rxkey; 659 660 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey), 661 P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL); 662 if (unlikely(!skb)) 663 return -ENOMEM; 664 665 rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); 666 rxkey->entry = slot; 667 rxkey->key_id = idx; 668 rxkey->key_type = algo; 669 if (addr) 670 memcpy(rxkey->mac, addr, ETH_ALEN); 671 else 672 memset(rxkey->mac, ~0, ETH_ALEN); 673 674 switch (algo) { 675 case P54_CRYPTO_WEP: 676 case P54_CRYPTO_AESCCMP: 677 rxkey->key_len = min_t(u8, 16, len); 678 memcpy(rxkey->key, key, rxkey->key_len); 679 break; 680 681 case P54_CRYPTO_TKIPMICHAEL: 682 rxkey->key_len = 24; 683 memcpy(rxkey->key, key, 16); 684 memcpy(&(rxkey->key[16]), &(key 685 [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8); 686 break; 687 688 case P54_CRYPTO_NONE: 689 rxkey->key_len = 0; 690 memset(rxkey->key, 0, sizeof(rxkey->key)); 691 break; 692 693 default: 694 wiphy_err(priv->hw->wiphy, 695 "invalid cryptographic algorithm: %d\n", algo); 696 dev_kfree_skb(skb); 697 return -EINVAL; 698 } 699 700 p54_tx(priv, skb); 701 return 0; 702} 703 704int p54_fetch_statistics(struct p54_common *priv) 705{ 706 struct ieee80211_tx_info *txinfo; 707 struct p54_tx_info *p54info; 708 struct sk_buff *skb; 709 710 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, 711 sizeof(struct p54_statistics), 712 P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); 713 if (!skb) 714 return -ENOMEM; 715 716 /* 717 * The statistic feedback causes some extra headaches here, if it 718 * is not to crash/corrupt the firmware data structures. 719 * 720 * Unlike all other Control Get OIDs we can not use helpers like 721 * skb_put to reserve the space for the data we're requesting. 722 * Instead the extra frame length -which will hold the results later- 723 * will only be told to the p54_assign_address, so that following 724 * frames won't be placed into the allegedly empty area. 725 */ 726 txinfo = IEEE80211_SKB_CB(skb); 727 p54info = (void *) txinfo->rate_driver_data; 728 p54info->extra_len = sizeof(struct p54_statistics); 729 730 p54_tx(priv, skb); 731 return 0; 732} 733 734int p54_set_groupfilter(struct p54_common *priv) 735{ 736 struct p54_group_address_table *grp; 737 struct sk_buff *skb; 738 bool on = false; 739 740 skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*grp), 741 P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE, GFP_KERNEL); 742 if (!skb) 743 return -ENOMEM; 744 745 grp = (struct p54_group_address_table *)skb_put(skb, sizeof(*grp)); 746 747 on = !(priv->filter_flags & FIF_ALLMULTI) && 748 (priv->mc_maclist_num > 0 && 749 priv->mc_maclist_num <= MC_FILTER_ADDRESS_NUM); 750 751 if (on) { 752 grp->filter_enable = cpu_to_le16(1); 753 grp->num_address = cpu_to_le16(priv->mc_maclist_num); 754 memcpy(grp->mac_list, priv->mc_maclist, sizeof(grp->mac_list)); 755 } else { 756 grp->filter_enable = cpu_to_le16(0); 757 grp->num_address = cpu_to_le16(0); 758 memset(grp->mac_list, 0, sizeof(grp->mac_list)); 759 } 760 761 p54_tx(priv, skb); 762 return 0; 763} 764