2007-09-25 19:11:01 -06:00
|
|
|
/*
|
|
|
|
* Common code for mac80211 Prism54 drivers
|
|
|
|
*
|
|
|
|
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
|
|
|
|
* Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
|
2008-10-14 08:56:51 -06:00
|
|
|
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
|
2007-09-25 19:11:01 -06:00
|
|
|
*
|
|
|
|
* Based on the islsm (softmac prism54) driver, which is:
|
|
|
|
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/firmware.h>
|
|
|
|
#include <linux/etherdevice.h>
|
|
|
|
|
|
|
|
#include <net/mac80211.h>
|
|
|
|
|
|
|
|
#include "p54.h"
|
|
|
|
#include "p54common.h"
|
|
|
|
|
|
|
|
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
|
|
|
|
MODULE_DESCRIPTION("Softmac Prism54 common code");
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_ALIAS("prism54common");
|
|
|
|
|
2008-09-06 06:25:58 -06:00
|
|
|
static struct ieee80211_rate p54_bgrates[] = {
|
2008-01-24 11:38:38 -07:00
|
|
|
{ .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
|
|
|
{ .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
|
|
|
{ .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
|
|
|
{ .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
|
|
|
{ .bitrate = 60, .hw_value = 4, },
|
|
|
|
{ .bitrate = 90, .hw_value = 5, },
|
|
|
|
{ .bitrate = 120, .hw_value = 6, },
|
|
|
|
{ .bitrate = 180, .hw_value = 7, },
|
|
|
|
{ .bitrate = 240, .hw_value = 8, },
|
|
|
|
{ .bitrate = 360, .hw_value = 9, },
|
|
|
|
{ .bitrate = 480, .hw_value = 10, },
|
|
|
|
{ .bitrate = 540, .hw_value = 11, },
|
|
|
|
};
|
|
|
|
|
2008-09-06 06:25:58 -06:00
|
|
|
static struct ieee80211_channel p54_bgchannels[] = {
|
2008-01-24 11:38:38 -07:00
|
|
|
{ .center_freq = 2412, .hw_value = 1, },
|
|
|
|
{ .center_freq = 2417, .hw_value = 2, },
|
|
|
|
{ .center_freq = 2422, .hw_value = 3, },
|
|
|
|
{ .center_freq = 2427, .hw_value = 4, },
|
|
|
|
{ .center_freq = 2432, .hw_value = 5, },
|
|
|
|
{ .center_freq = 2437, .hw_value = 6, },
|
|
|
|
{ .center_freq = 2442, .hw_value = 7, },
|
|
|
|
{ .center_freq = 2447, .hw_value = 8, },
|
|
|
|
{ .center_freq = 2452, .hw_value = 9, },
|
|
|
|
{ .center_freq = 2457, .hw_value = 10, },
|
|
|
|
{ .center_freq = 2462, .hw_value = 11, },
|
|
|
|
{ .center_freq = 2467, .hw_value = 12, },
|
|
|
|
{ .center_freq = 2472, .hw_value = 13, },
|
|
|
|
{ .center_freq = 2484, .hw_value = 14, },
|
|
|
|
};
|
|
|
|
|
2008-02-20 04:08:12 -07:00
|
|
|
static struct ieee80211_supported_band band_2GHz = {
|
2008-09-06 06:25:58 -06:00
|
|
|
.channels = p54_bgchannels,
|
|
|
|
.n_channels = ARRAY_SIZE(p54_bgchannels),
|
|
|
|
.bitrates = p54_bgrates,
|
|
|
|
.n_bitrates = ARRAY_SIZE(p54_bgrates),
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct ieee80211_rate p54_arates[] = {
|
|
|
|
{ .bitrate = 60, .hw_value = 4, },
|
|
|
|
{ .bitrate = 90, .hw_value = 5, },
|
|
|
|
{ .bitrate = 120, .hw_value = 6, },
|
|
|
|
{ .bitrate = 180, .hw_value = 7, },
|
|
|
|
{ .bitrate = 240, .hw_value = 8, },
|
|
|
|
{ .bitrate = 360, .hw_value = 9, },
|
|
|
|
{ .bitrate = 480, .hw_value = 10, },
|
|
|
|
{ .bitrate = 540, .hw_value = 11, },
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct ieee80211_channel p54_achannels[] = {
|
|
|
|
{ .center_freq = 4920 },
|
|
|
|
{ .center_freq = 4940 },
|
|
|
|
{ .center_freq = 4960 },
|
|
|
|
{ .center_freq = 4980 },
|
|
|
|
{ .center_freq = 5040 },
|
|
|
|
{ .center_freq = 5060 },
|
|
|
|
{ .center_freq = 5080 },
|
|
|
|
{ .center_freq = 5170 },
|
|
|
|
{ .center_freq = 5180 },
|
|
|
|
{ .center_freq = 5190 },
|
|
|
|
{ .center_freq = 5200 },
|
|
|
|
{ .center_freq = 5210 },
|
|
|
|
{ .center_freq = 5220 },
|
|
|
|
{ .center_freq = 5230 },
|
|
|
|
{ .center_freq = 5240 },
|
|
|
|
{ .center_freq = 5260 },
|
|
|
|
{ .center_freq = 5280 },
|
|
|
|
{ .center_freq = 5300 },
|
|
|
|
{ .center_freq = 5320 },
|
|
|
|
{ .center_freq = 5500 },
|
|
|
|
{ .center_freq = 5520 },
|
|
|
|
{ .center_freq = 5540 },
|
|
|
|
{ .center_freq = 5560 },
|
|
|
|
{ .center_freq = 5580 },
|
|
|
|
{ .center_freq = 5600 },
|
|
|
|
{ .center_freq = 5620 },
|
|
|
|
{ .center_freq = 5640 },
|
|
|
|
{ .center_freq = 5660 },
|
|
|
|
{ .center_freq = 5680 },
|
|
|
|
{ .center_freq = 5700 },
|
|
|
|
{ .center_freq = 5745 },
|
|
|
|
{ .center_freq = 5765 },
|
|
|
|
{ .center_freq = 5785 },
|
|
|
|
{ .center_freq = 5805 },
|
|
|
|
{ .center_freq = 5825 },
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct ieee80211_supported_band band_5GHz = {
|
|
|
|
.channels = p54_achannels,
|
|
|
|
.n_channels = ARRAY_SIZE(p54_achannels),
|
|
|
|
.bitrates = p54_arates,
|
|
|
|
.n_bitrates = ARRAY_SIZE(p54_arates),
|
2008-01-24 11:38:38 -07:00
|
|
|
};
|
|
|
|
|
2008-09-01 14:48:41 -06:00
|
|
|
int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
|
2007-09-25 19:11:01 -06:00
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct bootrec_exp_if *exp_if;
|
|
|
|
struct bootrec *bootrec;
|
|
|
|
u32 *data = (u32 *)fw->data;
|
|
|
|
u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
|
|
|
|
u8 *fw_version = NULL;
|
|
|
|
size_t len;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (priv->rx_start)
|
2008-09-01 14:48:41 -06:00
|
|
|
return 0;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
|
|
|
while (data < end_data && *data)
|
|
|
|
data++;
|
|
|
|
|
|
|
|
while (data < end_data && !*data)
|
|
|
|
data++;
|
|
|
|
|
|
|
|
bootrec = (struct bootrec *) data;
|
|
|
|
|
|
|
|
while (bootrec->data <= end_data &&
|
|
|
|
(bootrec->data + (len = le32_to_cpu(bootrec->len))) <= end_data) {
|
|
|
|
u32 code = le32_to_cpu(bootrec->code);
|
|
|
|
switch (code) {
|
|
|
|
case BR_CODE_COMPONENT_ID:
|
2008-09-25 13:54:28 -06:00
|
|
|
priv->fw_interface = be32_to_cpup((__be32 *)
|
|
|
|
bootrec->data);
|
2008-09-04 04:29:38 -06:00
|
|
|
switch (priv->fw_interface) {
|
2007-09-25 19:11:01 -06:00
|
|
|
case FW_FMAC:
|
|
|
|
printk(KERN_INFO "p54: FreeMAC firmware\n");
|
|
|
|
break;
|
|
|
|
case FW_LM20:
|
|
|
|
printk(KERN_INFO "p54: LM20 firmware\n");
|
|
|
|
break;
|
|
|
|
case FW_LM86:
|
|
|
|
printk(KERN_INFO "p54: LM86 firmware\n");
|
|
|
|
break;
|
|
|
|
case FW_LM87:
|
2008-09-04 04:29:38 -06:00
|
|
|
printk(KERN_INFO "p54: LM87 firmware\n");
|
2007-09-25 19:11:01 -06:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printk(KERN_INFO "p54: unknown firmware\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BR_CODE_COMPONENT_VERSION:
|
|
|
|
/* 24 bytes should be enough for all firmwares */
|
|
|
|
if (strnlen((unsigned char*)bootrec->data, 24) < 24)
|
|
|
|
fw_version = (unsigned char*)bootrec->data;
|
|
|
|
break;
|
2008-09-01 14:48:41 -06:00
|
|
|
case BR_CODE_DESCR: {
|
|
|
|
struct bootrec_desc *desc =
|
|
|
|
(struct bootrec_desc *)bootrec->data;
|
|
|
|
priv->rx_start = le32_to_cpu(desc->rx_start);
|
2007-09-25 19:11:01 -06:00
|
|
|
/* FIXME add sanity checking */
|
2008-09-01 14:48:41 -06:00
|
|
|
priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
|
|
|
|
priv->headroom = desc->headroom;
|
|
|
|
priv->tailroom = desc->tailroom;
|
2008-09-25 13:54:28 -06:00
|
|
|
if (le32_to_cpu(bootrec->len) == 11)
|
2008-10-09 18:38:52 -06:00
|
|
|
priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
|
2008-09-01 14:48:41 -06:00
|
|
|
else
|
|
|
|
priv->rx_mtu = (size_t)
|
|
|
|
0x620 - priv->tx_hdr_len;
|
2007-09-25 19:11:01 -06:00
|
|
|
break;
|
2008-09-01 14:48:41 -06:00
|
|
|
}
|
2007-09-25 19:11:01 -06:00
|
|
|
case BR_CODE_EXPOSED_IF:
|
|
|
|
exp_if = (struct bootrec_exp_if *) bootrec->data;
|
|
|
|
for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
|
2007-12-21 21:49:02 -07:00
|
|
|
if (exp_if[i].if_id == cpu_to_le16(0x1a))
|
2007-09-25 19:11:01 -06:00
|
|
|
priv->fw_var = le16_to_cpu(exp_if[i].variant);
|
|
|
|
break;
|
|
|
|
case BR_CODE_DEPENDENT_IF:
|
|
|
|
break;
|
|
|
|
case BR_CODE_END_OF_BRA:
|
|
|
|
case LEGACY_BR_CODE_END_OF_BRA:
|
|
|
|
end_data = NULL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bootrec = (struct bootrec *)&bootrec->data[len];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fw_version)
|
|
|
|
printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n",
|
|
|
|
fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
|
|
|
|
|
|
|
|
if (priv->fw_var >= 0x300) {
|
|
|
|
/* Firmware supports QoS, use it! */
|
2008-08-23 19:15:16 -06:00
|
|
|
priv->tx_stats[4].limit = 3;
|
|
|
|
priv->tx_stats[5].limit = 4;
|
|
|
|
priv->tx_stats[6].limit = 3;
|
|
|
|
priv->tx_stats[7].limit = 1;
|
2007-09-25 19:11:01 -06:00
|
|
|
dev->queues = 4;
|
|
|
|
}
|
2008-09-01 14:48:41 -06:00
|
|
|
|
|
|
|
return 0;
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(p54_parse_firmware);
|
|
|
|
|
2008-08-23 14:15:25 -06:00
|
|
|
static int p54_convert_rev0(struct ieee80211_hw *dev,
|
|
|
|
struct pda_pa_curve_data *curve_data)
|
2007-09-25 19:11:01 -06:00
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
2008-08-23 14:15:25 -06:00
|
|
|
struct p54_pa_curve_data_sample *dst;
|
|
|
|
struct pda_pa_curve_data_sample_rev0 *src;
|
2007-09-25 19:11:01 -06:00
|
|
|
size_t cd_len = sizeof(*curve_data) +
|
2008-08-23 14:15:25 -06:00
|
|
|
(curve_data->points_per_channel*sizeof(*dst) + 2) *
|
2007-09-25 19:11:01 -06:00
|
|
|
curve_data->channels;
|
|
|
|
unsigned int i, j;
|
|
|
|
void *source, *target;
|
|
|
|
|
|
|
|
priv->curve_data = kmalloc(cd_len, GFP_KERNEL);
|
|
|
|
if (!priv->curve_data)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
memcpy(priv->curve_data, curve_data, sizeof(*curve_data));
|
|
|
|
source = curve_data->data;
|
|
|
|
target = priv->curve_data->data;
|
|
|
|
for (i = 0; i < curve_data->channels; i++) {
|
|
|
|
__le16 *freq = source;
|
|
|
|
source += sizeof(__le16);
|
|
|
|
*((__le16 *)target) = *freq;
|
|
|
|
target += sizeof(__le16);
|
|
|
|
for (j = 0; j < curve_data->points_per_channel; j++) {
|
2008-08-23 14:15:25 -06:00
|
|
|
dst = target;
|
|
|
|
src = source;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
2008-08-23 14:15:25 -06:00
|
|
|
dst->rf_power = src->rf_power;
|
|
|
|
dst->pa_detector = src->pa_detector;
|
|
|
|
dst->data_64qam = src->pcv;
|
2007-09-25 19:11:01 -06:00
|
|
|
/* "invent" the points for the other modulations */
|
|
|
|
#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y)
|
2008-08-23 14:15:25 -06:00
|
|
|
dst->data_16qam = SUB(src->pcv, 12);
|
|
|
|
dst->data_qpsk = SUB(dst->data_16qam, 12);
|
|
|
|
dst->data_bpsk = SUB(dst->data_qpsk, 12);
|
|
|
|
dst->data_barker = SUB(dst->data_bpsk, 14);
|
2007-09-25 19:11:01 -06:00
|
|
|
#undef SUB
|
2008-08-23 14:15:25 -06:00
|
|
|
target += sizeof(*dst);
|
|
|
|
source += sizeof(*src);
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-08-23 14:15:25 -06:00
|
|
|
static int p54_convert_rev1(struct ieee80211_hw *dev,
|
|
|
|
struct pda_pa_curve_data *curve_data)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct p54_pa_curve_data_sample *dst;
|
|
|
|
struct pda_pa_curve_data_sample_rev1 *src;
|
|
|
|
size_t cd_len = sizeof(*curve_data) +
|
|
|
|
(curve_data->points_per_channel*sizeof(*dst) + 2) *
|
|
|
|
curve_data->channels;
|
|
|
|
unsigned int i, j;
|
|
|
|
void *source, *target;
|
|
|
|
|
|
|
|
priv->curve_data = kmalloc(cd_len, GFP_KERNEL);
|
|
|
|
if (!priv->curve_data)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
memcpy(priv->curve_data, curve_data, sizeof(*curve_data));
|
|
|
|
source = curve_data->data;
|
|
|
|
target = priv->curve_data->data;
|
|
|
|
for (i = 0; i < curve_data->channels; i++) {
|
|
|
|
__le16 *freq = source;
|
|
|
|
source += sizeof(__le16);
|
|
|
|
*((__le16 *)target) = *freq;
|
|
|
|
target += sizeof(__le16);
|
|
|
|
for (j = 0; j < curve_data->points_per_channel; j++) {
|
|
|
|
memcpy(target, source, sizeof(*src));
|
|
|
|
|
|
|
|
target += sizeof(*dst);
|
|
|
|
source += sizeof(*src);
|
|
|
|
}
|
|
|
|
source++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-10-14 19:30:06 -06:00
|
|
|
static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2",
|
|
|
|
"Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
|
2008-09-06 06:25:58 -06:00
|
|
|
static int p54_init_xbow_synth(struct ieee80211_hw *dev);
|
2008-09-01 14:48:51 -06:00
|
|
|
|
2008-09-25 13:54:28 -06:00
|
|
|
static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
2007-09-25 19:11:01 -06:00
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct eeprom_pda_wrap *wrap = NULL;
|
|
|
|
struct pda_entry *entry;
|
|
|
|
unsigned int data_len, entry_len;
|
|
|
|
void *tmp;
|
|
|
|
int err;
|
2008-02-29 15:28:25 -07:00
|
|
|
u8 *end = (u8 *)eeprom + len;
|
2008-10-25 08:14:14 -06:00
|
|
|
u16 synth = 0;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
|
|
|
wrap = (struct eeprom_pda_wrap *) eeprom;
|
2008-02-29 05:56:33 -07:00
|
|
|
entry = (void *)wrap->data + le16_to_cpu(wrap->len);
|
2008-02-29 15:28:25 -07:00
|
|
|
|
|
|
|
/* verify that at least the entry length/code fits */
|
|
|
|
while ((u8 *)entry <= end - sizeof(*entry)) {
|
2007-09-25 19:11:01 -06:00
|
|
|
entry_len = le16_to_cpu(entry->len);
|
|
|
|
data_len = ((entry_len - 1) << 1);
|
2008-02-29 15:28:25 -07:00
|
|
|
|
|
|
|
/* abort if entry exceeds whole structure */
|
|
|
|
if ((u8 *)entry + sizeof(*entry) + data_len > end)
|
|
|
|
break;
|
|
|
|
|
2007-09-25 19:11:01 -06:00
|
|
|
switch (le16_to_cpu(entry->code)) {
|
|
|
|
case PDR_MAC_ADDRESS:
|
|
|
|
SET_IEEE80211_PERM_ADDR(dev, entry->data);
|
|
|
|
break;
|
|
|
|
case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
|
|
|
|
if (data_len < 2) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (2 + entry->data[1]*sizeof(*priv->output_limit) > data_len) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
priv->output_limit = kmalloc(entry->data[1] *
|
|
|
|
sizeof(*priv->output_limit), GFP_KERNEL);
|
|
|
|
|
|
|
|
if (!priv->output_limit) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(priv->output_limit, &entry->data[2],
|
|
|
|
entry->data[1]*sizeof(*priv->output_limit));
|
|
|
|
priv->output_limit_len = entry->data[1];
|
|
|
|
break;
|
2008-08-23 14:15:25 -06:00
|
|
|
case PDR_PRISM_PA_CAL_CURVE_DATA: {
|
|
|
|
struct pda_pa_curve_data *curve_data =
|
|
|
|
(struct pda_pa_curve_data *)entry->data;
|
|
|
|
if (data_len < sizeof(*curve_data)) {
|
2007-09-25 19:11:01 -06:00
|
|
|
err = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2008-08-23 14:15:25 -06:00
|
|
|
switch (curve_data->cal_method_rev) {
|
|
|
|
case 0:
|
|
|
|
err = p54_convert_rev0(dev, curve_data);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
err = p54_convert_rev1(dev, curve_data);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printk(KERN_ERR "p54: unknown curve data "
|
|
|
|
"revision %d\n",
|
|
|
|
curve_data->cal_method_rev);
|
|
|
|
err = -ENODEV;
|
|
|
|
break;
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
2008-08-23 14:15:25 -06:00
|
|
|
if (err)
|
|
|
|
goto err;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
2008-08-23 14:15:25 -06:00
|
|
|
}
|
2007-09-25 19:11:01 -06:00
|
|
|
case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
|
|
|
|
priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
|
|
|
|
if (!priv->iq_autocal) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(priv->iq_autocal, entry->data, data_len);
|
|
|
|
priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
|
|
|
|
break;
|
|
|
|
case PDR_INTERFACE_LIST:
|
|
|
|
tmp = entry->data;
|
|
|
|
while ((u8 *)tmp < entry->data + data_len) {
|
|
|
|
struct bootrec_exp_if *exp_if = tmp;
|
2008-10-14 19:30:06 -06:00
|
|
|
if (le16_to_cpu(exp_if->if_id) == 0xf)
|
|
|
|
synth = le16_to_cpu(exp_if->variant);
|
2007-09-25 19:11:01 -06:00
|
|
|
tmp += sizeof(struct bootrec_exp_if);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
|
|
|
|
priv->version = *(u8 *)(entry->data + 1);
|
|
|
|
break;
|
|
|
|
case PDR_END:
|
2008-02-29 15:28:25 -07:00
|
|
|
/* make it overrun */
|
|
|
|
entry_len = len;
|
2007-09-25 19:11:01 -06:00
|
|
|
break;
|
2008-02-25 09:51:53 -07:00
|
|
|
default:
|
|
|
|
printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n",
|
|
|
|
le16_to_cpu(entry->code));
|
|
|
|
break;
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
entry = (void *)entry + (entry_len + 1)*2;
|
|
|
|
}
|
|
|
|
|
2008-10-25 08:14:14 -06:00
|
|
|
if (!synth || !priv->iq_autocal || !priv->output_limit ||
|
|
|
|
!priv->curve_data) {
|
2007-09-25 19:11:01 -06:00
|
|
|
printk(KERN_ERR "p54: not all required entries found in eeprom!\n");
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2008-10-14 19:30:06 -06:00
|
|
|
priv->rxhw = synth & 0x07;
|
|
|
|
if (priv->rxhw == 4)
|
2008-09-06 06:25:58 -06:00
|
|
|
p54_init_xbow_synth(dev);
|
2008-10-14 19:30:06 -06:00
|
|
|
if (!(synth & 0x40))
|
2008-09-06 06:25:58 -06:00
|
|
|
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
|
2008-10-14 19:30:06 -06:00
|
|
|
if (!(synth & 0x80))
|
|
|
|
dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
|
2008-09-01 14:48:51 -06:00
|
|
|
|
|
|
|
if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
|
|
|
|
u8 perm_addr[ETH_ALEN];
|
|
|
|
|
|
|
|
printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
|
|
|
|
wiphy_name(dev->wiphy));
|
|
|
|
random_ether_addr(perm_addr);
|
|
|
|
SET_IEEE80211_PERM_ADDR(dev, perm_addr);
|
|
|
|
}
|
|
|
|
|
2008-10-27 16:59:26 -06:00
|
|
|
printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
|
2008-09-01 14:48:51 -06:00
|
|
|
wiphy_name(dev->wiphy),
|
2008-10-27 16:59:26 -06:00
|
|
|
dev->wiphy->perm_addr,
|
2008-09-01 14:48:51 -06:00
|
|
|
priv->version, p54_rf_chips[priv->rxhw]);
|
|
|
|
|
2007-09-25 19:11:01 -06:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (priv->iq_autocal) {
|
|
|
|
kfree(priv->iq_autocal);
|
|
|
|
priv->iq_autocal = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->output_limit) {
|
|
|
|
kfree(priv->output_limit);
|
|
|
|
priv->output_limit = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->curve_data) {
|
|
|
|
kfree(priv->curve_data);
|
|
|
|
priv->curve_data = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
printk(KERN_ERR "p54: eeprom parse failed!\n");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2008-09-05 18:56:23 -06:00
|
|
|
static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
|
|
|
|
{
|
|
|
|
/* TODO: get the rssi_add & rssi_mul data from the eeprom */
|
|
|
|
return ((rssi * 0x83) / 64 - 400) / 4;
|
|
|
|
}
|
|
|
|
|
2008-09-03 14:25:25 -06:00
|
|
|
static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
|
2007-09-25 19:11:01 -06:00
|
|
|
{
|
2008-09-05 18:56:04 -06:00
|
|
|
struct p54_common *priv = dev->priv;
|
2007-09-25 19:11:01 -06:00
|
|
|
struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data;
|
|
|
|
struct ieee80211_rx_status rx_status = {0};
|
|
|
|
u16 freq = le16_to_cpu(hdr->freq);
|
2008-09-03 14:25:25 -06:00
|
|
|
size_t header_len = sizeof(*hdr);
|
2008-09-05 18:56:04 -06:00
|
|
|
u32 tsf32;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
2008-09-05 18:56:12 -06:00
|
|
|
if (!(hdr->magic & cpu_to_le16(0x0001))) {
|
|
|
|
if (priv->filter_flags & FIF_FCSFAIL)
|
|
|
|
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-09-05 18:56:23 -06:00
|
|
|
rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi);
|
|
|
|
rx_status.noise = priv->noise;
|
2008-01-24 11:38:38 -07:00
|
|
|
/* XX correct? */
|
2008-06-30 09:39:49 -06:00
|
|
|
rx_status.qual = (100 * hdr->rssi) / 127;
|
2008-09-30 15:36:00 -06:00
|
|
|
rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ?
|
|
|
|
hdr->rate : (hdr->rate - 4)) & 0xf;
|
2007-09-25 19:11:01 -06:00
|
|
|
rx_status.freq = freq;
|
2008-09-30 15:36:00 -06:00
|
|
|
rx_status.band = dev->conf.channel->band;
|
2007-09-25 19:11:01 -06:00
|
|
|
rx_status.antenna = hdr->antenna;
|
2008-09-05 18:56:04 -06:00
|
|
|
|
|
|
|
tsf32 = le32_to_cpu(hdr->tsf32);
|
|
|
|
if (tsf32 < priv->tsf_low32)
|
|
|
|
priv->tsf_high32++;
|
|
|
|
rx_status.mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
|
|
|
|
priv->tsf_low32 = tsf32;
|
|
|
|
|
2007-12-04 12:33:40 -07:00
|
|
|
rx_status.flag |= RX_FLAG_TSFT;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
2008-09-03 14:25:25 -06:00
|
|
|
if (hdr->magic & cpu_to_le16(0x4000))
|
|
|
|
header_len += hdr->align[0];
|
|
|
|
|
|
|
|
skb_pull(skb, header_len);
|
2007-09-25 19:11:01 -06:00
|
|
|
skb_trim(skb, le16_to_cpu(hdr->len));
|
|
|
|
|
|
|
|
ieee80211_rx_irqsafe(dev, skb, &rx_status);
|
2008-09-03 14:25:25 -06:00
|
|
|
|
|
|
|
return -1;
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < dev->queues; i++)
|
2008-08-23 19:15:16 -06:00
|
|
|
if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit)
|
2007-09-25 19:11:01 -06:00
|
|
|
ieee80211_wake_queue(dev, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
|
|
|
|
struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data;
|
|
|
|
struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next;
|
2008-09-01 14:48:41 -06:00
|
|
|
u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom;
|
2007-09-25 19:11:01 -06:00
|
|
|
struct memrecord *range = NULL;
|
|
|
|
u32 freed = 0;
|
|
|
|
u32 last_addr = priv->rx_start;
|
2008-08-23 19:15:06 -06:00
|
|
|
unsigned long flags;
|
2008-10-14 08:56:51 -06:00
|
|
|
int count, idx;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
2008-08-23 19:15:06 -06:00
|
|
|
spin_lock_irqsave(&priv->tx_queue.lock, flags);
|
2007-09-25 19:11:01 -06:00
|
|
|
while (entry != (struct sk_buff *)&priv->tx_queue) {
|
2008-05-30 13:07:15 -06:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
|
2008-10-21 04:40:02 -06:00
|
|
|
range = (void *)info->rate_driver_data;
|
2007-09-25 19:11:01 -06:00
|
|
|
if (range->start_addr == addr) {
|
|
|
|
struct p54_control_hdr *entry_hdr;
|
|
|
|
struct p54_tx_control_allocdata *entry_data;
|
|
|
|
int pad = 0;
|
|
|
|
|
2008-05-30 13:07:15 -06:00
|
|
|
if (entry->next != (struct sk_buff *)&priv->tx_queue) {
|
|
|
|
struct ieee80211_tx_info *ni;
|
|
|
|
struct memrecord *mr;
|
|
|
|
|
|
|
|
ni = IEEE80211_SKB_CB(entry->next);
|
2008-10-21 04:40:02 -06:00
|
|
|
mr = (struct memrecord *)ni->rate_driver_data;
|
2008-05-30 13:07:15 -06:00
|
|
|
freed = mr->start_addr - last_addr;
|
|
|
|
} else
|
2007-09-25 19:11:01 -06:00
|
|
|
freed = priv->rx_end - last_addr;
|
|
|
|
|
|
|
|
last_addr = range->end_addr;
|
|
|
|
__skb_unlink(entry, &priv->tx_queue);
|
2008-08-23 19:15:06 -06:00
|
|
|
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
|
|
|
|
|
2008-10-14 08:56:51 -06:00
|
|
|
/*
|
|
|
|
* Clear manually, ieee80211_tx_info_clear_status would
|
|
|
|
* clear the counts too and we need them.
|
|
|
|
*/
|
|
|
|
memset(&info->status.ampdu_ack_len, 0,
|
|
|
|
sizeof(struct ieee80211_tx_info) -
|
|
|
|
offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
|
|
|
|
BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
|
|
|
|
status.ampdu_ack_len) != 23);
|
|
|
|
|
2007-09-25 19:11:01 -06:00
|
|
|
entry_hdr = (struct p54_control_hdr *) entry->data;
|
|
|
|
entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
|
|
|
|
if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
|
|
|
|
pad = entry_data->align[0];
|
|
|
|
|
2008-10-14 08:56:51 -06:00
|
|
|
/* walk through the rates array and adjust the counts */
|
|
|
|
count = payload->retries;
|
|
|
|
for (idx = 0; idx < 4; idx++) {
|
|
|
|
if (count >= info->status.rates[idx].count) {
|
|
|
|
count -= info->status.rates[idx].count;
|
|
|
|
} else if (count > 0) {
|
|
|
|
info->status.rates[idx].count = count;
|
|
|
|
count = 0;
|
|
|
|
} else {
|
|
|
|
info->status.rates[idx].idx = -1;
|
|
|
|
info->status.rates[idx].count = 0;
|
|
|
|
}
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
2008-10-14 08:56:51 -06:00
|
|
|
|
|
|
|
priv->tx_stats[entry_data->hw_queue].len--;
|
|
|
|
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
|
|
|
|
!(payload->status & 0x01))
|
|
|
|
info->flags |= IEEE80211_TX_STAT_ACK;
|
2008-09-05 18:56:23 -06:00
|
|
|
info->status.ack_signal = p54_rssi_to_dbm(dev,
|
|
|
|
le16_to_cpu(payload->ack_rssi));
|
2007-09-25 19:11:01 -06:00
|
|
|
skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
|
2008-05-15 04:55:29 -06:00
|
|
|
ieee80211_tx_status_irqsafe(dev, entry);
|
2008-08-23 19:15:06 -06:00
|
|
|
goto out;
|
2007-09-25 19:11:01 -06:00
|
|
|
} else
|
|
|
|
last_addr = range->end_addr;
|
|
|
|
entry = entry->next;
|
|
|
|
}
|
2008-08-23 19:15:06 -06:00
|
|
|
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
|
2007-09-25 19:11:01 -06:00
|
|
|
|
2008-08-23 19:15:06 -06:00
|
|
|
out:
|
2007-09-25 19:11:01 -06:00
|
|
|
if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
|
|
|
|
sizeof(struct p54_control_hdr))
|
|
|
|
p54_wake_free_queues(dev);
|
|
|
|
}
|
|
|
|
|
2008-09-01 14:48:51 -06:00
|
|
|
static void p54_rx_eeprom_readback(struct ieee80211_hw *dev,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
|
|
|
|
struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
|
|
|
|
if (!priv->eeprom)
|
|
|
|
return ;
|
|
|
|
|
2008-09-25 13:54:28 -06:00
|
|
|
memcpy(priv->eeprom, eeprom->data, le16_to_cpu(eeprom->len));
|
2008-09-01 14:48:51 -06:00
|
|
|
|
|
|
|
complete(&priv->eeprom_comp);
|
|
|
|
}
|
|
|
|
|
2008-09-05 18:56:23 -06:00
|
|
|
static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
|
|
|
|
struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
|
|
|
|
u32 tsf32 = le32_to_cpu(stats->tsf32);
|
|
|
|
|
|
|
|
if (tsf32 < priv->tsf_low32)
|
|
|
|
priv->tsf_high32++;
|
|
|
|
priv->tsf_low32 = tsf32;
|
|
|
|
|
|
|
|
priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
|
|
|
|
priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
|
|
|
|
priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
|
|
|
|
|
|
|
|
priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
|
|
|
|
complete(&priv->stats_comp);
|
|
|
|
|
|
|
|
mod_timer(&priv->stats_timer, jiffies + 5 * HZ);
|
|
|
|
}
|
|
|
|
|
2008-09-03 14:25:25 -06:00
|
|
|
static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
|
2007-09-25 19:11:01 -06:00
|
|
|
{
|
|
|
|
struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
|
|
|
|
|
|
|
|
switch (le16_to_cpu(hdr->type)) {
|
|
|
|
case P54_CONTROL_TYPE_TXDONE:
|
|
|
|
p54_rx_frame_sent(dev, skb);
|
|
|
|
break;
|
|
|
|
case P54_CONTROL_TYPE_BBP:
|
|
|
|
break;
|
2008-09-05 18:56:23 -06:00
|
|
|
case P54_CONTROL_TYPE_STAT_READBACK:
|
|
|
|
p54_rx_stats(dev, skb);
|
|
|
|
break;
|
2008-09-01 14:48:51 -06:00
|
|
|
case P54_CONTROL_TYPE_EEPROM_READBACK:
|
|
|
|
p54_rx_eeprom_readback(dev, skb);
|
|
|
|
break;
|
2007-09-25 19:11:01 -06:00
|
|
|
default:
|
|
|
|
printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
|
|
|
|
wiphy_name(dev->wiphy), le16_to_cpu(hdr->type));
|
|
|
|
break;
|
|
|
|
}
|
2008-09-03 14:25:25 -06:00
|
|
|
|
|
|
|
return 0;
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* returns zero if skb can be reused */
|
|
|
|
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8;
|
2008-09-03 14:25:25 -06:00
|
|
|
|
|
|
|
if (type == 0x80)
|
|
|
|
return p54_rx_control(dev, skb);
|
|
|
|
else
|
|
|
|
return p54_rx_data(dev, skb);
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(p54_rx);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* So, the firmware is somewhat stupid and doesn't know what places in its
|
|
|
|
* memory incoming data should go to. By poking around in the firmware, we
|
|
|
|
* can find some unused memory to upload our packets to. However, data that we
|
|
|
|
* want the card to TX needs to stay intact until the card has told us that
|
|
|
|
* it is done with it. This function finds empty places we can upload to and
|
|
|
|
* marks allocated areas as reserved if necessary. p54_rx_frame_sent frees
|
|
|
|
* allocated areas.
|
|
|
|
*/
|
|
|
|
static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
|
2008-05-15 04:55:29 -06:00
|
|
|
struct p54_control_hdr *data, u32 len)
|
2007-09-25 19:11:01 -06:00
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct sk_buff *entry = priv->tx_queue.next;
|
|
|
|
struct sk_buff *target_skb = NULL;
|
|
|
|
u32 last_addr = priv->rx_start;
|
|
|
|
u32 largest_hole = 0;
|
|
|
|
u32 target_addr = priv->rx_start;
|
|
|
|
unsigned long flags;
|
|
|
|
unsigned int left;
|
2008-09-01 14:48:41 -06:00
|
|
|
len = (len + priv->headroom + priv->tailroom + 3) & ~0x3;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
|
|
|
spin_lock_irqsave(&priv->tx_queue.lock, flags);
|
|
|
|
left = skb_queue_len(&priv->tx_queue);
|
|
|
|
while (left--) {
|
|
|
|
u32 hole_size;
|
2008-05-15 04:55:29 -06:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
|
2008-10-21 04:40:02 -06:00
|
|
|
struct memrecord *range = (void *)info->rate_driver_data;
|
2007-09-25 19:11:01 -06:00
|
|
|
hole_size = range->start_addr - last_addr;
|
|
|
|
if (!target_skb && hole_size >= len) {
|
|
|
|
target_skb = entry->prev;
|
|
|
|
hole_size -= len;
|
|
|
|
target_addr = last_addr;
|
|
|
|
}
|
|
|
|
largest_hole = max(largest_hole, hole_size);
|
|
|
|
last_addr = range->end_addr;
|
|
|
|
entry = entry->next;
|
|
|
|
}
|
|
|
|
if (!target_skb && priv->rx_end - last_addr >= len) {
|
|
|
|
target_skb = priv->tx_queue.prev;
|
|
|
|
largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
|
|
|
|
if (!skb_queue_empty(&priv->tx_queue)) {
|
2008-05-15 04:55:29 -06:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb);
|
2008-10-21 04:40:02 -06:00
|
|
|
struct memrecord *range = (void *)info->rate_driver_data;
|
2007-09-25 19:11:01 -06:00
|
|
|
target_addr = range->end_addr;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
largest_hole = max(largest_hole, priv->rx_end - last_addr);
|
|
|
|
|
|
|
|
if (skb) {
|
2008-05-15 04:55:29 -06:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
2008-10-21 04:40:02 -06:00
|
|
|
struct memrecord *range = (void *)info->rate_driver_data;
|
2007-09-25 19:11:01 -06:00
|
|
|
range->start_addr = target_addr;
|
|
|
|
range->end_addr = target_addr + len;
|
|
|
|
__skb_queue_after(&priv->tx_queue, target_skb, skb);
|
2008-09-01 14:48:41 -06:00
|
|
|
if (largest_hole < priv->rx_mtu + priv->headroom +
|
|
|
|
priv->tailroom +
|
2007-09-25 19:11:01 -06:00
|
|
|
sizeof(struct p54_control_hdr))
|
|
|
|
ieee80211_stop_queues(dev);
|
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
|
|
|
|
|
2008-09-01 14:48:41 -06:00
|
|
|
data->req_id = cpu_to_le32(target_addr + priv->headroom);
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
|
|
|
|
2008-09-01 14:48:51 -06:00
|
|
|
int p54_read_eeprom(struct ieee80211_hw *dev)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct p54_control_hdr *hdr = NULL;
|
|
|
|
struct p54_eeprom_lm86 *eeprom_hdr;
|
|
|
|
size_t eeprom_size = 0x2020, offset = 0, blocksize;
|
|
|
|
int ret = -ENOMEM;
|
|
|
|
void *eeprom = NULL;
|
|
|
|
|
|
|
|
hdr = (struct p54_control_hdr *)kzalloc(sizeof(*hdr) +
|
|
|
|
sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN, GFP_KERNEL);
|
|
|
|
if (!hdr)
|
|
|
|
goto free;
|
|
|
|
|
|
|
|
priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL);
|
|
|
|
if (!priv->eeprom)
|
|
|
|
goto free;
|
|
|
|
|
|
|
|
eeprom = kzalloc(eeprom_size, GFP_KERNEL);
|
|
|
|
if (!eeprom)
|
|
|
|
goto free;
|
|
|
|
|
|
|
|
hdr->magic1 = cpu_to_le16(0x8000);
|
|
|
|
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK);
|
|
|
|
hdr->retry1 = hdr->retry2 = 0;
|
|
|
|
eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data;
|
|
|
|
|
|
|
|
while (eeprom_size) {
|
|
|
|
blocksize = min(eeprom_size, (size_t)EEPROM_READBACK_LEN);
|
|
|
|
hdr->len = cpu_to_le16(blocksize + sizeof(*eeprom_hdr));
|
|
|
|
eeprom_hdr->offset = cpu_to_le16(offset);
|
|
|
|
eeprom_hdr->len = cpu_to_le16(blocksize);
|
2008-09-25 13:54:28 -06:00
|
|
|
p54_assign_address(dev, NULL, hdr, le16_to_cpu(hdr->len) +
|
|
|
|
sizeof(*hdr));
|
|
|
|
priv->tx(dev, hdr, le16_to_cpu(hdr->len) + sizeof(*hdr), 0);
|
2008-09-01 14:48:51 -06:00
|
|
|
|
|
|
|
if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
|
|
|
|
printk(KERN_ERR "%s: device does not respond!\n",
|
|
|
|
wiphy_name(dev->wiphy));
|
|
|
|
ret = -EBUSY;
|
|
|
|
goto free;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(eeprom + offset, priv->eeprom, blocksize);
|
|
|
|
offset += blocksize;
|
|
|
|
eeprom_size -= blocksize;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = p54_parse_eeprom(dev, eeprom, offset);
|
|
|
|
free:
|
|
|
|
kfree(priv->eeprom);
|
|
|
|
priv->eeprom = NULL;
|
|
|
|
kfree(hdr);
|
|
|
|
kfree(eeprom);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(p54_read_eeprom);
|
|
|
|
|
2008-05-15 04:55:29 -06:00
|
|
|
static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
2007-09-25 19:11:01 -06:00
|
|
|
{
|
2008-05-15 04:55:29 -06:00
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
2008-04-29 09:18:59 -06:00
|
|
|
struct ieee80211_tx_queue_stats *current_queue;
|
2007-09-25 19:11:01 -06:00
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct p54_control_hdr *hdr;
|
|
|
|
struct p54_tx_control_allocdata *txhdr;
|
|
|
|
size_t padding, len;
|
2008-10-14 08:56:51 -06:00
|
|
|
int i, j, ridx;
|
2007-09-25 19:11:01 -06:00
|
|
|
u8 rate;
|
2008-08-09 18:20:47 -06:00
|
|
|
u8 cts_rate = 0x20;
|
2008-10-21 04:40:02 -06:00
|
|
|
u8 rc_flags;
|
2008-10-14 08:56:51 -06:00
|
|
|
u8 calculated_tries[4];
|
|
|
|
u8 nrates = 0, nremaining = 8;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
2008-08-23 19:15:16 -06:00
|
|
|
current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4];
|
2007-09-25 19:11:01 -06:00
|
|
|
if (unlikely(current_queue->len > current_queue->limit))
|
|
|
|
return NETDEV_TX_BUSY;
|
|
|
|
current_queue->len++;
|
|
|
|
current_queue->count++;
|
|
|
|
if (current_queue->len == current_queue->limit)
|
2008-05-16 16:57:14 -06:00
|
|
|
ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
|
2007-09-25 19:11:01 -06:00
|
|
|
|
|
|
|
padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
|
|
|
|
len = skb->len;
|
|
|
|
|
|
|
|
txhdr = (struct p54_tx_control_allocdata *)
|
|
|
|
skb_push(skb, sizeof(*txhdr) + padding);
|
|
|
|
hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr));
|
|
|
|
|
|
|
|
if (padding)
|
|
|
|
hdr->magic1 = cpu_to_le16(0x4010);
|
|
|
|
else
|
|
|
|
hdr->magic1 = cpu_to_le16(0x0010);
|
|
|
|
hdr->len = cpu_to_le16(len);
|
2008-05-15 04:55:29 -06:00
|
|
|
hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
|
2008-10-14 08:56:51 -06:00
|
|
|
hdr->retry1 = info->control.rates[0].count;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we register the rates in perfect order, and
|
|
|
|
* RTS/CTS won't happen on 5 GHz
|
|
|
|
*/
|
|
|
|
cts_rate = info->control.rts_cts_rate_idx;
|
|
|
|
|
|
|
|
memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
|
|
|
|
|
|
|
|
/* see how many rates got used */
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
if (info->control.rates[i].idx < 0)
|
|
|
|
break;
|
|
|
|
nrates++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* limit tries to 8/nrates per rate */
|
|
|
|
for (i = 0; i < nrates; i++) {
|
|
|
|
/*
|
|
|
|
* The magic expression here is equivalent to 8/nrates for
|
|
|
|
* all values that matter, but avoids division and jumps.
|
|
|
|
* Note that nrates can only take the values 1 through 4.
|
|
|
|
*/
|
|
|
|
calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
|
|
|
|
info->control.rates[i].count);
|
|
|
|
nremaining -= calculated_tries[i];
|
2008-08-09 18:20:47 -06:00
|
|
|
}
|
2008-10-14 08:56:51 -06:00
|
|
|
|
|
|
|
/* if there are tries left, distribute from back to front */
|
|
|
|
for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
|
|
|
|
int tmp = info->control.rates[i].count - calculated_tries[i];
|
|
|
|
|
|
|
|
if (tmp <= 0)
|
|
|
|
continue;
|
|
|
|
/* RC requested more tries at this rate */
|
|
|
|
|
|
|
|
tmp = min_t(int, tmp, nremaining);
|
|
|
|
calculated_tries[i] += tmp;
|
|
|
|
nremaining -= tmp;
|
2008-08-09 18:20:47 -06:00
|
|
|
}
|
2008-10-14 08:56:51 -06:00
|
|
|
|
|
|
|
ridx = 0;
|
|
|
|
for (i = 0; i < nrates && ridx < 8; i++) {
|
|
|
|
/* we register the rates in perfect order */
|
|
|
|
rate = info->control.rates[i].idx;
|
|
|
|
if (info->band == IEEE80211_BAND_5GHZ)
|
|
|
|
rate += 4;
|
|
|
|
|
|
|
|
/* store the count we actually calculated for TX status */
|
|
|
|
info->control.rates[i].count = calculated_tries[i];
|
|
|
|
|
|
|
|
rc_flags = info->control.rates[i].flags;
|
|
|
|
if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
|
|
|
|
rate |= 0x10;
|
|
|
|
cts_rate |= 0x10;
|
|
|
|
}
|
|
|
|
if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
|
|
|
|
rate |= 0x40;
|
|
|
|
else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
|
|
|
|
rate |= 0x20;
|
|
|
|
for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
|
|
|
|
txhdr->rateset[ridx] = rate;
|
|
|
|
ridx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hdr->retry2 = ridx;
|
|
|
|
|
2008-08-09 18:20:47 -06:00
|
|
|
txhdr->key_type = 0;
|
|
|
|
txhdr->key_len = 0;
|
|
|
|
txhdr->hw_queue = skb_get_queue_mapping(skb) + 4;
|
|
|
|
txhdr->tx_antenna = (info->antenna_sel_tx == 0) ?
|
2008-05-15 04:55:29 -06:00
|
|
|
2 : info->antenna_sel_tx - 1;
|
2008-09-06 06:25:53 -06:00
|
|
|
txhdr->output_power = priv->output_power;
|
2008-08-09 18:20:47 -06:00
|
|
|
txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
|
|
|
|
0 : cts_rate;
|
2007-09-25 19:11:01 -06:00
|
|
|
if (padding)
|
|
|
|
txhdr->align[0] = padding;
|
|
|
|
|
2008-05-15 04:55:29 -06:00
|
|
|
/* modifies skb->cb and with it info, so must be last! */
|
|
|
|
p54_assign_address(dev, skb, hdr, skb->len);
|
|
|
|
|
2007-09-25 19:11:01 -06:00
|
|
|
priv->tx(dev, hdr, skb->len, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
|
2008-09-03 14:25:20 -06:00
|
|
|
const u8 *bssid)
|
2007-09-25 19:11:01 -06:00
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct p54_control_hdr *hdr;
|
|
|
|
struct p54_tx_control_filter *filter;
|
2008-09-03 14:25:25 -06:00
|
|
|
size_t data_len;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
|
|
|
hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) +
|
2007-10-13 18:35:05 -06:00
|
|
|
priv->tx_hdr_len, GFP_ATOMIC);
|
2007-09-25 19:11:01 -06:00
|
|
|
if (!hdr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = (void *)hdr + priv->tx_hdr_len;
|
|
|
|
|
|
|
|
filter = (struct p54_tx_control_filter *) hdr->data;
|
|
|
|
hdr->magic1 = cpu_to_le16(0x8001);
|
|
|
|
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
|
|
|
|
|
2008-09-03 14:25:20 -06:00
|
|
|
priv->filter_type = filter->filter_type = cpu_to_le16(filter_type);
|
|
|
|
memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN);
|
|
|
|
if (!bssid)
|
|
|
|
memset(filter->bssid, ~0, ETH_ALEN);
|
2007-09-25 19:11:01 -06:00
|
|
|
else
|
2008-09-03 14:25:20 -06:00
|
|
|
memcpy(filter->bssid, bssid, ETH_ALEN);
|
|
|
|
filter->rx_antenna = priv->rx_antenna;
|
2008-09-03 14:25:25 -06:00
|
|
|
if (priv->fw_var < 0x500) {
|
|
|
|
data_len = P54_TX_CONTROL_FILTER_V1_LEN;
|
2008-10-08 12:52:22 -06:00
|
|
|
filter->v1.basic_rate_mask = cpu_to_le32(0x15f);
|
2008-09-03 14:25:25 -06:00
|
|
|
filter->v1.rx_addr = cpu_to_le32(priv->rx_end);
|
|
|
|
filter->v1.max_rx = cpu_to_le16(priv->rx_mtu);
|
|
|
|
filter->v1.rxhw = cpu_to_le16(priv->rxhw);
|
|
|
|
filter->v1.wakeup_timer = cpu_to_le16(500);
|
|
|
|
} else {
|
|
|
|
data_len = P54_TX_CONTROL_FILTER_V2_LEN;
|
|
|
|
filter->v2.rx_addr = cpu_to_le32(priv->rx_end);
|
|
|
|
filter->v2.max_rx = cpu_to_le16(priv->rx_mtu);
|
|
|
|
filter->v2.rxhw = cpu_to_le16(priv->rxhw);
|
|
|
|
filter->v2.timer = cpu_to_le16(1000);
|
|
|
|
}
|
|
|
|
hdr->len = cpu_to_le16(data_len);
|
|
|
|
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len);
|
|
|
|
priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1);
|
2007-09-25 19:11:01 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct p54_control_hdr *hdr;
|
|
|
|
struct p54_tx_control_channel *chan;
|
|
|
|
unsigned int i;
|
2008-09-03 14:25:25 -06:00
|
|
|
size_t data_len;
|
2007-09-25 19:11:01 -06:00
|
|
|
void *entry;
|
|
|
|
|
2008-08-23 14:15:25 -06:00
|
|
|
hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) +
|
2007-09-25 19:11:01 -06:00
|
|
|
priv->tx_hdr_len, GFP_KERNEL);
|
|
|
|
if (!hdr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = (void *)hdr + priv->tx_hdr_len;
|
|
|
|
|
|
|
|
chan = (struct p54_tx_control_channel *) hdr->data;
|
|
|
|
|
|
|
|
hdr->magic1 = cpu_to_le16(0x8001);
|
2008-09-03 14:25:25 -06:00
|
|
|
|
2007-09-25 19:11:01 -06:00
|
|
|
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
|
|
|
|
|
2008-08-23 14:15:25 -06:00
|
|
|
chan->flags = cpu_to_le16(0x1);
|
|
|
|
chan->dwell = cpu_to_le16(0x0);
|
2007-09-25 19:11:01 -06:00
|
|
|
|
|
|
|
for (i = 0; i < priv->iq_autocal_len; i++) {
|
|
|
|
if (priv->iq_autocal[i].freq != freq)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
memcpy(&chan->iq_autocal, &priv->iq_autocal[i],
|
|
|
|
sizeof(*priv->iq_autocal));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == priv->iq_autocal_len)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
for (i = 0; i < priv->output_limit_len; i++) {
|
|
|
|
if (priv->output_limit[i].freq != freq)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
chan->val_barker = 0x38;
|
2008-08-23 14:15:25 -06:00
|
|
|
chan->val_bpsk = chan->dup_bpsk =
|
|
|
|
priv->output_limit[i].val_bpsk;
|
|
|
|
chan->val_qpsk = chan->dup_qpsk =
|
|
|
|
priv->output_limit[i].val_qpsk;
|
|
|
|
chan->val_16qam = chan->dup_16qam =
|
|
|
|
priv->output_limit[i].val_16qam;
|
|
|
|
chan->val_64qam = chan->dup_64qam =
|
|
|
|
priv->output_limit[i].val_64qam;
|
2007-09-25 19:11:01 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == priv->output_limit_len)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
entry = priv->curve_data->data;
|
|
|
|
for (i = 0; i < priv->curve_data->channels; i++) {
|
|
|
|
if (*((__le16 *)entry) != freq) {
|
|
|
|
entry += sizeof(__le16);
|
2008-08-23 14:15:25 -06:00
|
|
|
entry += sizeof(struct p54_pa_curve_data_sample) *
|
|
|
|
priv->curve_data->points_per_channel;
|
2007-09-25 19:11:01 -06:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry += sizeof(__le16);
|
2008-08-23 14:15:25 -06:00
|
|
|
chan->pa_points_per_curve =
|
|
|
|
min(priv->curve_data->points_per_channel, (u8) 8);
|
|
|
|
|
2007-09-25 19:11:01 -06:00
|
|
|
memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) *
|
|
|
|
chan->pa_points_per_curve);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-09-03 14:25:25 -06:00
|
|
|
if (priv->fw_var < 0x500) {
|
|
|
|
data_len = P54_TX_CONTROL_CHANNEL_V1_LEN;
|
|
|
|
chan->v1.rssical_mul = cpu_to_le16(130);
|
|
|
|
chan->v1.rssical_add = cpu_to_le16(0xfe70);
|
|
|
|
} else {
|
|
|
|
data_len = P54_TX_CONTROL_CHANNEL_V2_LEN;
|
|
|
|
chan->v2.rssical_mul = cpu_to_le16(130);
|
|
|
|
chan->v2.rssical_add = cpu_to_le16(0xfe70);
|
|
|
|
chan->v2.basic_rate_mask = cpu_to_le32(0x15f);
|
|
|
|
}
|
2007-09-25 19:11:01 -06:00
|
|
|
|
2008-09-03 14:25:25 -06:00
|
|
|
hdr->len = cpu_to_le16(data_len);
|
|
|
|
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len);
|
|
|
|
priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1);
|
2007-09-25 19:11:01 -06:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy));
|
|
|
|
kfree(hdr);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct p54_control_hdr *hdr;
|
|
|
|
struct p54_tx_control_led *led;
|
|
|
|
|
|
|
|
hdr = kzalloc(sizeof(*hdr) + sizeof(*led) +
|
|
|
|
priv->tx_hdr_len, GFP_KERNEL);
|
|
|
|
if (!hdr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = (void *)hdr + priv->tx_hdr_len;
|
|
|
|
hdr->magic1 = cpu_to_le16(0x8001);
|
|
|
|
hdr->len = cpu_to_le16(sizeof(*led));
|
|
|
|
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED);
|
2008-05-15 04:55:29 -06:00
|
|
|
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led));
|
2007-09-25 19:11:01 -06:00
|
|
|
|
|
|
|
led = (struct p54_tx_control_led *) hdr->data;
|
|
|
|
led->mode = cpu_to_le16(mode);
|
|
|
|
led->led_permanent = cpu_to_le16(link);
|
|
|
|
led->led_temporary = cpu_to_le16(act);
|
|
|
|
led->duration = cpu_to_le16(1000);
|
|
|
|
|
|
|
|
priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*led), 1);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-10 08:49:38 -07:00
|
|
|
#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \
|
2007-09-25 19:11:01 -06:00
|
|
|
do { \
|
|
|
|
queue.aifs = cpu_to_le16(ai_fs); \
|
|
|
|
queue.cwmin = cpu_to_le16(cw_min); \
|
|
|
|
queue.cwmax = cpu_to_le16(cw_max); \
|
2008-02-10 08:49:38 -07:00
|
|
|
queue.txop = cpu_to_le16(_txop); \
|
2007-09-25 19:11:01 -06:00
|
|
|
} while(0)
|
|
|
|
|
2008-10-14 19:55:37 -06:00
|
|
|
static int p54_set_edcf(struct ieee80211_hw *dev)
|
2007-09-25 19:11:01 -06:00
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct p54_control_hdr *hdr;
|
2008-10-14 19:55:37 -06:00
|
|
|
struct p54_edcf *edcf;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
2008-10-14 19:55:37 -06:00
|
|
|
hdr = kzalloc(priv->tx_hdr_len + sizeof(*hdr) + sizeof(*edcf),
|
|
|
|
GFP_ATOMIC);
|
|
|
|
if (!hdr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = (void *)hdr + priv->tx_hdr_len;
|
2007-09-25 19:11:01 -06:00
|
|
|
hdr->magic1 = cpu_to_le16(0x8001);
|
2008-10-14 19:55:37 -06:00
|
|
|
hdr->len = cpu_to_le16(sizeof(*edcf));
|
2007-09-25 19:11:01 -06:00
|
|
|
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT);
|
2008-10-14 19:55:37 -06:00
|
|
|
hdr->retry1 = hdr->retry2 = 0;
|
|
|
|
edcf = (struct p54_edcf *)hdr->data;
|
2008-10-08 12:52:22 -06:00
|
|
|
if (priv->use_short_slot) {
|
2008-10-14 19:55:37 -06:00
|
|
|
edcf->slottime = 9;
|
|
|
|
edcf->sifs = 0x10;
|
|
|
|
edcf->eofpad = 0x00;
|
2007-09-25 19:11:01 -06:00
|
|
|
} else {
|
2008-10-14 19:55:37 -06:00
|
|
|
edcf->slottime = 20;
|
|
|
|
edcf->sifs = 0x0a;
|
|
|
|
edcf->eofpad = 0x06;
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
|
|
|
/* (see prism54/isl_oid.h for further details) */
|
2008-10-14 19:55:37 -06:00
|
|
|
edcf->frameburst = cpu_to_le16(0);
|
|
|
|
edcf->round_trip_delay = cpu_to_le16(0);
|
|
|
|
memset(edcf->mapping, 0, sizeof(edcf->mapping));
|
|
|
|
memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
|
2007-09-25 19:11:01 -06:00
|
|
|
|
2008-10-14 19:55:37 -06:00
|
|
|
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*edcf));
|
|
|
|
priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*edcf), 1);
|
|
|
|
return 0;
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
|
|
|
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
static int p54_start(struct ieee80211_hw *dev)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
int err;
|
|
|
|
|
2008-09-05 18:56:23 -06:00
|
|
|
if (!priv->cached_stats) {
|
|
|
|
priv->cached_stats = kzalloc(sizeof(struct p54_statistics) +
|
|
|
|
priv->tx_hdr_len + sizeof(struct p54_control_hdr),
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
2008-10-14 19:55:37 -06:00
|
|
|
if (!priv->cached_stats)
|
2008-09-05 18:56:23 -06:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
err = priv->open(dev);
|
|
|
|
if (!err)
|
2008-09-10 16:01:58 -06:00
|
|
|
priv->mode = NL80211_IFTYPE_MONITOR;
|
2008-10-14 19:55:37 -06:00
|
|
|
P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
|
|
|
|
P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
|
|
|
|
P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
|
|
|
|
P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
|
|
|
|
err = p54_set_edcf(dev);
|
|
|
|
if (!err)
|
|
|
|
mod_timer(&priv->stats_timer, jiffies + HZ);
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void p54_stop(struct ieee80211_hw *dev)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct sk_buff *skb;
|
2008-09-05 18:56:23 -06:00
|
|
|
|
|
|
|
del_timer(&priv->stats_timer);
|
2008-05-15 04:55:29 -06:00
|
|
|
while ((skb = skb_dequeue(&priv->tx_queue)))
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
kfree_skb(skb);
|
|
|
|
priv->stop(dev);
|
2008-09-05 18:56:04 -06:00
|
|
|
priv->tsf_high32 = priv->tsf_low32 = 0;
|
2008-09-10 16:01:58 -06:00
|
|
|
priv->mode = NL80211_IFTYPE_UNSPECIFIED;
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
}
|
|
|
|
|
2007-09-25 19:11:01 -06:00
|
|
|
static int p54_add_interface(struct ieee80211_hw *dev,
|
|
|
|
struct ieee80211_if_init_conf *conf)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
|
2008-09-10 16:01:58 -06:00
|
|
|
if (priv->mode != NL80211_IFTYPE_MONITOR)
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
return -EOPNOTSUPP;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
|
|
|
switch (conf->type) {
|
2008-09-10 16:01:58 -06:00
|
|
|
case NL80211_IFTYPE_STATION:
|
2007-09-25 19:11:01 -06:00
|
|
|
priv->mode = conf->type;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
|
2007-09-25 19:11:01 -06:00
|
|
|
|
2008-09-03 14:25:20 -06:00
|
|
|
p54_set_filter(dev, 0, NULL);
|
2007-09-25 19:11:01 -06:00
|
|
|
|
|
|
|
switch (conf->type) {
|
2008-09-10 16:01:58 -06:00
|
|
|
case NL80211_IFTYPE_STATION:
|
2008-09-03 14:25:20 -06:00
|
|
|
p54_set_filter(dev, 1, NULL);
|
2007-09-25 19:11:01 -06:00
|
|
|
break;
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
default:
|
|
|
|
BUG(); /* impossible */
|
|
|
|
break;
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
p54_set_leds(dev, 1, 0, 0);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void p54_remove_interface(struct ieee80211_hw *dev,
|
|
|
|
struct ieee80211_if_init_conf *conf)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
2008-09-10 16:01:58 -06:00
|
|
|
priv->mode = NL80211_IFTYPE_MONITOR;
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
memset(priv->mac_addr, 0, ETH_ALEN);
|
2008-09-03 14:25:20 -06:00
|
|
|
p54_set_filter(dev, 0, NULL);
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
|
|
|
|
2008-10-09 04:18:51 -06:00
|
|
|
static int p54_config(struct ieee80211_hw *dev, u32 changed)
|
2007-09-25 19:11:01 -06:00
|
|
|
{
|
|
|
|
int ret;
|
2008-08-03 16:58:36 -06:00
|
|
|
struct p54_common *priv = dev->priv;
|
2008-10-09 04:18:51 -06:00
|
|
|
struct ieee80211_conf *conf = &dev->conf;
|
2007-09-25 19:11:01 -06:00
|
|
|
|
2008-08-03 16:58:36 -06:00
|
|
|
mutex_lock(&priv->conf_mutex);
|
2008-10-09 04:18:04 -06:00
|
|
|
priv->rx_antenna = 2; /* automatic */
|
2008-09-06 06:25:53 -06:00
|
|
|
priv->output_power = conf->power_level << 2;
|
2008-01-24 11:38:38 -07:00
|
|
|
ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq));
|
2008-10-14 19:55:37 -06:00
|
|
|
if (!ret)
|
|
|
|
ret = p54_set_edcf(dev);
|
2008-08-03 16:58:36 -06:00
|
|
|
mutex_unlock(&priv->conf_mutex);
|
2007-09-25 19:11:01 -06:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-12-18 17:31:26 -07:00
|
|
|
static int p54_config_interface(struct ieee80211_hw *dev,
|
|
|
|
struct ieee80211_vif *vif,
|
2007-09-25 19:11:01 -06:00
|
|
|
struct ieee80211_if_conf *conf)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
|
2008-08-03 16:58:36 -06:00
|
|
|
mutex_lock(&priv->conf_mutex);
|
2008-09-03 14:25:20 -06:00
|
|
|
p54_set_filter(dev, 0, conf->bssid);
|
2007-09-25 19:11:01 -06:00
|
|
|
p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
memcpy(priv->bssid, conf->bssid, ETH_ALEN);
|
2008-08-03 16:58:36 -06:00
|
|
|
mutex_unlock(&priv->conf_mutex);
|
2007-09-25 19:11:01 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
static void p54_configure_filter(struct ieee80211_hw *dev,
|
|
|
|
unsigned int changed_flags,
|
|
|
|
unsigned int *total_flags,
|
|
|
|
int mc_count, struct dev_mc_list *mclist)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
|
2008-09-05 18:56:12 -06:00
|
|
|
*total_flags &= FIF_BCN_PRBRESP_PROMISC |
|
|
|
|
FIF_PROMISC_IN_BSS |
|
|
|
|
FIF_FCSFAIL;
|
|
|
|
|
|
|
|
priv->filter_flags = *total_flags;
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
|
|
|
|
if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
|
|
|
|
if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
|
2008-09-25 13:54:28 -06:00
|
|
|
p54_set_filter(dev, le16_to_cpu(priv->filter_type),
|
|
|
|
NULL);
|
2008-09-05 18:56:12 -06:00
|
|
|
else
|
2008-09-25 13:54:28 -06:00
|
|
|
p54_set_filter(dev, le16_to_cpu(priv->filter_type),
|
|
|
|
priv->bssid);
|
2008-09-05 18:56:12 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (changed_flags & FIF_PROMISC_IN_BSS) {
|
|
|
|
if (*total_flags & FIF_PROMISC_IN_BSS)
|
2008-09-25 13:54:28 -06:00
|
|
|
p54_set_filter(dev, le16_to_cpu(priv->filter_type) |
|
|
|
|
0x8, NULL);
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
else
|
2008-09-25 13:54:28 -06:00
|
|
|
p54_set_filter(dev, le16_to_cpu(priv->filter_type) &
|
|
|
|
~0x8, priv->bssid);
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-30 10:51:21 -06:00
|
|
|
static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
|
2007-09-25 19:11:01 -06:00
|
|
|
const struct ieee80211_tx_queue_params *params)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
|
2008-05-01 15:07:32 -06:00
|
|
|
if ((params) && !(queue > 4)) {
|
2008-10-14 19:55:37 -06:00
|
|
|
P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
|
2008-02-10 08:49:38 -07:00
|
|
|
params->cw_min, params->cw_max, params->txop);
|
2007-09-25 19:11:01 -06:00
|
|
|
} else
|
|
|
|
return -EINVAL;
|
|
|
|
|
2008-10-14 19:55:37 -06:00
|
|
|
return p54_set_edcf(dev);
|
2007-09-25 19:11:01 -06:00
|
|
|
}
|
|
|
|
|
2008-09-06 06:25:58 -06:00
|
|
|
static int p54_init_xbow_synth(struct ieee80211_hw *dev)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct p54_control_hdr *hdr;
|
|
|
|
struct p54_tx_control_xbow_synth *xbow;
|
|
|
|
|
|
|
|
hdr = kzalloc(sizeof(*hdr) + sizeof(*xbow) +
|
|
|
|
priv->tx_hdr_len, GFP_KERNEL);
|
|
|
|
if (!hdr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = (void *)hdr + priv->tx_hdr_len;
|
|
|
|
hdr->magic1 = cpu_to_le16(0x8001);
|
|
|
|
hdr->len = cpu_to_le16(sizeof(*xbow));
|
|
|
|
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_XBOW_SYNTH_CFG);
|
|
|
|
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*xbow));
|
|
|
|
|
|
|
|
xbow = (struct p54_tx_control_xbow_synth *) hdr->data;
|
|
|
|
xbow->magic1 = cpu_to_le16(0x1);
|
|
|
|
xbow->magic2 = cpu_to_le16(0x2);
|
|
|
|
xbow->freq = cpu_to_le16(5390);
|
|
|
|
|
|
|
|
priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*xbow), 1);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-09-05 18:56:23 -06:00
|
|
|
static void p54_statistics_timer(unsigned long data)
|
|
|
|
{
|
|
|
|
struct ieee80211_hw *dev = (struct ieee80211_hw *) data;
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
struct p54_control_hdr *hdr;
|
|
|
|
struct p54_statistics *stats;
|
|
|
|
|
|
|
|
BUG_ON(!priv->cached_stats);
|
|
|
|
|
|
|
|
hdr = (void *)priv->cached_stats + priv->tx_hdr_len;
|
|
|
|
hdr->magic1 = cpu_to_le16(0x8000);
|
|
|
|
hdr->len = cpu_to_le16(sizeof(*stats));
|
|
|
|
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK);
|
|
|
|
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats));
|
|
|
|
|
|
|
|
priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0);
|
|
|
|
}
|
|
|
|
|
2007-09-25 19:11:01 -06:00
|
|
|
static int p54_get_stats(struct ieee80211_hw *dev,
|
|
|
|
struct ieee80211_low_level_stats *stats)
|
|
|
|
{
|
2008-09-05 18:56:23 -06:00
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
|
|
|
|
del_timer(&priv->stats_timer);
|
|
|
|
p54_statistics_timer((unsigned long)dev);
|
|
|
|
|
|
|
|
if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) {
|
|
|
|
printk(KERN_ERR "%s: device does not respond!\n",
|
|
|
|
wiphy_name(dev->wiphy));
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(stats, &priv->stats, sizeof(*stats));
|
|
|
|
|
2007-09-25 19:11:01 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int p54_get_tx_stats(struct ieee80211_hw *dev,
|
|
|
|
struct ieee80211_tx_queue_stats *stats)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
|
2008-08-23 19:15:16 -06:00
|
|
|
memcpy(stats, &priv->tx_stats[4], sizeof(stats[0]) * dev->queues);
|
2007-09-25 19:11:01 -06:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-10-08 12:52:22 -06:00
|
|
|
static void p54_bss_info_changed(struct ieee80211_hw *dev,
|
|
|
|
struct ieee80211_vif *vif,
|
|
|
|
struct ieee80211_bss_conf *info,
|
|
|
|
u32 changed)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
|
|
|
|
|
|
|
if (changed & BSS_CHANGED_ERP_SLOT) {
|
|
|
|
priv->use_short_slot = info->use_short_slot;
|
2008-10-14 19:55:37 -06:00
|
|
|
p54_set_edcf(dev);
|
2008-10-08 12:52:22 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-25 19:11:01 -06:00
|
|
|
static const struct ieee80211_ops p54_ops = {
|
|
|
|
.tx = p54_tx,
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
.start = p54_start,
|
|
|
|
.stop = p54_stop,
|
2007-09-25 19:11:01 -06:00
|
|
|
.add_interface = p54_add_interface,
|
|
|
|
.remove_interface = p54_remove_interface,
|
|
|
|
.config = p54_config,
|
|
|
|
.config_interface = p54_config_interface,
|
2008-10-08 12:52:22 -06:00
|
|
|
.bss_info_changed = p54_bss_info_changed,
|
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2007-09-16 23:29:23 -06:00
|
|
|
.configure_filter = p54_configure_filter,
|
2007-09-25 19:11:01 -06:00
|
|
|
.conf_tx = p54_conf_tx,
|
|
|
|
.get_stats = p54_get_stats,
|
|
|
|
.get_tx_stats = p54_get_tx_stats
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ieee80211_hw *p54_init_common(size_t priv_data_len)
|
|
|
|
{
|
|
|
|
struct ieee80211_hw *dev;
|
|
|
|
struct p54_common *priv;
|
|
|
|
|
|
|
|
dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
|
|
|
|
if (!dev)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
priv = dev->priv;
|
2008-09-10 16:01:58 -06:00
|
|
|
priv->mode = NL80211_IFTYPE_UNSPECIFIED;
|
2007-09-25 19:11:01 -06:00
|
|
|
skb_queue_head_init(&priv->tx_queue);
|
|
|
|
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
|
2008-05-08 11:15:40 -06:00
|
|
|
IEEE80211_HW_RX_INCLUDES_FCS |
|
2008-09-05 18:56:23 -06:00
|
|
|
IEEE80211_HW_SIGNAL_DBM |
|
|
|
|
IEEE80211_HW_NOISE_DBM;
|
2008-08-29 17:26:43 -06:00
|
|
|
|
2008-10-10 05:21:59 -06:00
|
|
|
/*
|
|
|
|
* XXX: when this driver gets support for any mode that
|
|
|
|
* requires beacons (AP, MESH, IBSS) then it must
|
|
|
|
* implement IEEE80211_TX_CTL_ASSIGN_SEQ.
|
|
|
|
*/
|
2008-08-29 17:26:43 -06:00
|
|
|
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
|
|
|
|
2007-09-25 19:11:01 -06:00
|
|
|
dev->channel_change_time = 1000; /* TODO: find actual value */
|
2008-08-23 19:15:16 -06:00
|
|
|
priv->tx_stats[0].limit = 1;
|
|
|
|
priv->tx_stats[1].limit = 1;
|
|
|
|
priv->tx_stats[2].limit = 1;
|
|
|
|
priv->tx_stats[3].limit = 1;
|
|
|
|
priv->tx_stats[4].limit = 5;
|
2007-09-25 19:11:01 -06:00
|
|
|
dev->queues = 1;
|
2008-09-05 18:56:23 -06:00
|
|
|
priv->noise = -94;
|
2008-10-14 08:56:51 -06:00
|
|
|
/*
|
|
|
|
* We support at most 8 tries no matter which rate they're at,
|
|
|
|
* we cannot support max_rates * max_rate_tries as we set it
|
|
|
|
* here, but setting it correctly to 4/2 or so would limit us
|
|
|
|
* artificially if the RC algorithm wants just two rates, so
|
|
|
|
* let's say 4/7, we'll redistribute it at TX time, see the
|
|
|
|
* comments there.
|
|
|
|
*/
|
|
|
|
dev->max_rates = 4;
|
|
|
|
dev->max_rate_tries = 7;
|
2007-09-25 19:11:01 -06:00
|
|
|
dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
|
|
|
|
sizeof(struct p54_tx_control_allocdata);
|
|
|
|
|
2008-08-03 16:58:36 -06:00
|
|
|
mutex_init(&priv->conf_mutex);
|
2008-09-01 14:48:51 -06:00
|
|
|
init_completion(&priv->eeprom_comp);
|
2008-09-05 18:56:23 -06:00
|
|
|
init_completion(&priv->stats_comp);
|
|
|
|
setup_timer(&priv->stats_timer, p54_statistics_timer,
|
|
|
|
(unsigned long)dev);
|
2007-09-25 19:11:01 -06:00
|
|
|
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(p54_init_common);
|
|
|
|
|
|
|
|
void p54_free_common(struct ieee80211_hw *dev)
|
|
|
|
{
|
|
|
|
struct p54_common *priv = dev->priv;
|
2008-09-05 18:56:23 -06:00
|
|
|
kfree(priv->cached_stats);
|
2007-09-25 19:11:01 -06:00
|
|
|
kfree(priv->iq_autocal);
|
|
|
|
kfree(priv->output_limit);
|
|
|
|
kfree(priv->curve_data);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(p54_free_common);
|
|
|
|
|
|
|
|
static int __init p54_init(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit p54_exit(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(p54_init);
|
|
|
|
module_exit(p54_exit);
|