* [PATCH 09/16] wl1251: disable power saving in monitor mode
From: Pali Rohár @ 2013-10-26 20:34 UTC (permalink / raw)
To: Luciano Coelho, John W. Linville, Johannes Berg, David S. Miller
Cc: linux-wireless, netdev, linux-kernel, freemangordon,
aaro.koskinen, pavel, sre, joni.lapilainen, pali.rohar,
David Gnedt
In-Reply-To: <1382819655-30430-1-git-send-email-pali.rohar@gmail.com>
From: David Gnedt <david.gnedt@davizone.at>
Force power saving off while monitor interface is present.
Signed-off-by: David Gnedt <david.gnedt@davizone.at>
---
drivers/net/wireless/ti/wl1251/main.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 727f2ee..62cb374 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -617,7 +617,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
goto out_sleep;
}
- if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
+ if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested &&
+ !wl->monitor_present) {
wl1251_debug(DEBUG_PSM, "psm enabled");
wl->psm_requested = true;
@@ -633,8 +634,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
if (ret < 0)
goto out_sleep;
- } else if (!(conf->flags & IEEE80211_CONF_PS) &&
- wl->psm_requested) {
+ } else if ((!(conf->flags & IEEE80211_CONF_PS) || wl->monitor_present)
+ && wl->psm_requested) {
wl1251_debug(DEBUG_PSM, "psm disabled");
wl->psm_requested = false;
--
1.7.10.4
^ permalink raw reply related
* [PATCH 10/16] wl1251: fix channel switching in monitor mode
From: Pali Rohár @ 2013-10-26 20:34 UTC (permalink / raw)
To: Luciano Coelho, John W. Linville, Johannes Berg, David S. Miller
Cc: linux-wireless, netdev, linux-kernel, freemangordon,
aaro.koskinen, pavel, sre, joni.lapilainen, pali.rohar,
David Gnedt
In-Reply-To: <1382819655-30430-1-git-send-email-pali.rohar@gmail.com>
From: David Gnedt <david.gnedt@davizone.at>
Use the ENABLE_RX command for channel switching when no interface is present
(monitor mode only).
The advantage of ENABLE_RX is that it leaves the tx data path disabled in
firmware, whereas the usual JOIN command seems to transmit some frames at
firmware level.
Signed-off-by: David Gnedt <david.gnedt@davizone.at>
---
drivers/net/wireless/ti/wl1251/main.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 62cb374..7e6b6d1 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -611,8 +611,19 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
if (channel != wl->channel) {
wl->channel = channel;
- ret = wl1251_join(wl, wl->bss_type, wl->channel,
- wl->beacon_int, wl->dtim_period);
+ /*
+ * Use ENABLE_RX command for channel switching when no
+ * interface is present (monitor mode only).
+ * This leaves the tx path disabled in firmware, whereas
+ * the usual JOIN command seems to transmit some frames
+ * at firmware level.
+ */
+ if (wl->vif == NULL) {
+ ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1);
+ } else {
+ ret = wl1251_join(wl, wl->bss_type, wl->channel,
+ wl->beacon_int, wl->dtim_period);
+ }
if (ret < 0)
goto out_sleep;
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 11/16] wl1251: enable tx path in monitor mode if necessary for packet injection
From: Pali Rohár @ 2013-10-26 20:34 UTC (permalink / raw)
To: Luciano Coelho, John W. Linville, Johannes Berg, David S. Miller
Cc: linux-wireless, netdev, linux-kernel, freemangordon,
aaro.koskinen, pavel, sre, joni.lapilainen, pali.rohar,
David Gnedt
In-Reply-To: <1382819655-30430-1-git-send-email-pali.rohar@gmail.com>
From: David Gnedt <david.gnedt@davizone.at>
If necessary enable the tx path in monitor mode for packet injection using
the JOIN command with BSS_TYPE_STA_BSS and zero BSSID.
Signed-off-by: David Gnedt <david.gnedt@davizone.at>
---
drivers/net/wireless/ti/wl1251/main.c | 5 +++++
drivers/net/wireless/ti/wl1251/tx.c | 17 +++++++++++++++++
drivers/net/wireless/ti/wl1251/wl1251.h | 1 +
3 files changed, 23 insertions(+)
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 7e6b6d1..174f403 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -487,6 +487,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
wl->rssi_thold = 0;
wl->channel = WL1251_DEFAULT_CHANNEL;
wl->monitor_present = false;
+ wl->joined = false;
wl1251_debugfs_reset(wl);
@@ -546,6 +547,7 @@ static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&wl->mutex);
wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
wl->vif = NULL;
+ memset(wl->bssid, 0, ETH_ALEN);
mutex_unlock(&wl->mutex);
}
@@ -619,6 +621,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
* at firmware level.
*/
if (wl->vif == NULL) {
+ wl->joined = false;
ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1);
} else {
ret = wl1251_join(wl, wl->bss_type, wl->channel,
@@ -1610,7 +1613,9 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work);
wl->channel = WL1251_DEFAULT_CHANNEL;
wl->monitor_present = false;
+ wl->joined = false;
wl->scanning = false;
+ wl->bss_type = MAX_BSS_TYPE;
wl->default_key = 0;
wl->listen_int = 1;
wl->rx_counter = 0;
diff --git a/drivers/net/wireless/ti/wl1251/tx.c b/drivers/net/wireless/ti/wl1251/tx.c
index 3cc82fd..1de4ccb 100644
--- a/drivers/net/wireless/ti/wl1251/tx.c
+++ b/drivers/net/wireless/ti/wl1251/tx.c
@@ -28,6 +28,7 @@
#include "tx.h"
#include "ps.h"
#include "io.h"
+#include "event.h"
static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count)
{
@@ -298,6 +299,22 @@ static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
}
}
+ /* Enable tx path in monitor mode for packet injection */
+ if ((wl->vif == NULL) && !wl->joined) {
+ ret = wl1251_cmd_join(wl, BSS_TYPE_STA_BSS, wl->channel,
+ wl->beacon_int, wl->dtim_period);
+ if (ret < 0)
+ wl1251_warning("join failed");
+ else {
+ ret = wl1251_event_wait(wl, JOIN_EVENT_COMPLETE_ID,
+ 100);
+ if (ret < 0)
+ wl1251_warning("join timeout");
+ else
+ wl->joined = true;
+ }
+ }
+
ret = wl1251_tx_path_status(wl);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h
index e478e61..1bdf779 100644
--- a/drivers/net/wireless/ti/wl1251/wl1251.h
+++ b/drivers/net/wireless/ti/wl1251/wl1251.h
@@ -311,6 +311,7 @@ struct wl1251 {
u8 listen_int;
int channel;
bool monitor_present;
+ bool joined;
void *target_mem_map;
struct acx_data_path_params_resp *data_path;
--
1.7.10.4
^ permalink raw reply related
* [PATCH 12/16] wl1251: disable retry and ACK policy for injected packets
From: Pali Rohár @ 2013-10-26 20:34 UTC (permalink / raw)
To: Luciano Coelho, John W. Linville, Johannes Berg, David S. Miller
Cc: linux-wireless, netdev, linux-kernel, freemangordon,
aaro.koskinen, pavel, sre, joni.lapilainen, pali.rohar,
David Gnedt
In-Reply-To: <1382819655-30430-1-git-send-email-pali.rohar@gmail.com>
From: David Gnedt <david.gnedt@davizone.at>
Set the retry limit to 0 and disable the ACK policy for injected packets.
Signed-off-by: David Gnedt <david.gnedt@davizone.at>
---
drivers/net/wireless/ti/wl1251/acx.c | 8 +++++++-
drivers/net/wireless/ti/wl1251/tx.c | 7 ++++++-
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c
index 14da6de..f98d46f 100644
--- a/drivers/net/wireless/ti/wl1251/acx.c
+++ b/drivers/net/wireless/ti/wl1251/acx.c
@@ -943,12 +943,18 @@ int wl1251_acx_rate_policies(struct wl1251 *wl)
}
/* configure one default (one-size-fits-all) rate class */
- acx->rate_class_cnt = 1;
+ acx->rate_class_cnt = 2;
acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED;
acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT;
acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT;
acx->rate_class[0].aflags = 0;
+ /* no-retry rate class */
+ acx->rate_class[1].enabled_rates = ACX_RATE_MASK_UNSPECIFIED;
+ acx->rate_class[1].short_retry_limit = 0;
+ acx->rate_class[1].long_retry_limit = 0;
+ acx->rate_class[1].aflags = 0;
+
ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
if (ret < 0) {
wl1251_warning("Setting of rate policies failed: %d", ret);
diff --git a/drivers/net/wireless/ti/wl1251/tx.c b/drivers/net/wireless/ti/wl1251/tx.c
index 1de4ccb..e559bc4 100644
--- a/drivers/net/wireless/ti/wl1251/tx.c
+++ b/drivers/net/wireless/ti/wl1251/tx.c
@@ -90,8 +90,12 @@ static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr,
/* 802.11 packets */
tx_hdr->control.packet_type = 0;
- if (control->flags & IEEE80211_TX_CTL_NO_ACK)
+ /* Also disable retry and ACK policy for injected packets */
+ if ((control->flags & IEEE80211_TX_CTL_NO_ACK) ||
+ (control->flags & IEEE80211_TX_CTL_INJECTED)) {
+ tx_hdr->control.rate_policy = 1;
tx_hdr->control.ack_policy = 1;
+ }
tx_hdr->control.tx_complete = 1;
@@ -414,6 +418,7 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl,
info = IEEE80211_SKB_CB(skb);
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+ !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
(result->status == TX_SUCCESS))
info->flags |= IEEE80211_TX_STAT_ACK;
--
1.7.10.4
^ permalink raw reply related
* [PATCH 13/16] wl1251: enforce changed hw encryption support on monitor state change
From: Pali Rohár @ 2013-10-26 20:34 UTC (permalink / raw)
To: Luciano Coelho, John W. Linville, Johannes Berg, David S. Miller
Cc: linux-wireless, netdev, linux-kernel, freemangordon,
aaro.koskinen, pavel, sre, joni.lapilainen, pali.rohar,
David Gnedt
In-Reply-To: <1382819655-30430-1-git-send-email-pali.rohar@gmail.com>
From: David Gnedt <david.gnedt@davizone.at>
The firmware doesn't support per packet encryption selection, so disable hw
encryption support completly while a monitor interface is present to support
injection of packets (which shouldn't get encrypted by hw).
To enforce the changed hw encryption support force a disassociation on
non-monitor interfaces.
For disassociation a workaround using hw connection monitor is employed,
which temporary enables hw connection manager flag.
Signed-off-by: David Gnedt <david.gnedt@davizone.at>
---
drivers/net/wireless/ti/wl1251/main.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 174f403..f054741 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -685,6 +685,16 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
wl->power_level = conf->power_level;
}
+ /*
+ * Tell stack that connection is lost because hw encryption isn't
+ * supported in monitor mode.
+ * XXX This requires temporary enabling the hw connection monitor flag
+ */
+ if ((changed & IEEE80211_CONF_CHANGE_MONITOR) && wl->vif) {
+ wl->hw->flags |= IEEE80211_HW_CONNECTION_MONITOR;
+ ieee80211_connection_loss(wl->vif);
+ }
+
out_sleep:
wl1251_ps_elp_sleep(wl);
@@ -1116,6 +1126,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ASSOC) {
+ /* XXX Disable temporary enabled hw connection monitor flag */
+ wl->hw->flags &= ~IEEE80211_HW_CONNECTION_MONITOR;
+
if (bss_conf->assoc) {
wl->beacon_int = bss_conf->beacon_int;
--
1.7.10.4
^ permalink raw reply related
* [PATCH 14/16] wl1251: add nvs file name to module firmware list
From: Pali Rohár @ 2013-10-26 20:34 UTC (permalink / raw)
To: Luciano Coelho, John W. Linville, Johannes Berg, David S. Miller
Cc: linux-wireless, netdev, linux-kernel, freemangordon,
aaro.koskinen, pavel, sre, joni.lapilainen, pali.rohar
In-Reply-To: <1382819655-30430-1-git-send-email-pali.rohar@gmail.com>
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
---
drivers/net/wireless/ti/wl1251/main.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index f054741..7b9efc8 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -1709,3 +1709,4 @@ MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
MODULE_FIRMWARE(WL1251_FW_NAME);
+MODULE_FIRMWARE(WL1251_NVS_NAME);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 15/16] wl1251: Add sysfs file tx_mgmt_frm_rate for setting rate
From: Pali Rohár @ 2013-10-26 20:34 UTC (permalink / raw)
To: Luciano Coelho, John W. Linville, Johannes Berg, David S. Miller
Cc: linux-wireless, netdev, linux-kernel, freemangordon,
aaro.koskinen, pavel, sre, joni.lapilainen, pali.rohar
In-Reply-To: <1382819655-30430-1-git-send-email-pali.rohar@gmail.com>
This patch was extracted from Maemo 2.6.28 kernel
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
---
drivers/net/wireless/ti/wl1251/main.c | 152 +++++++++++++++++++++++++++++++++
1 file changed, 152 insertions(+)
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 7b9efc8..29625c2 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -1375,6 +1375,147 @@ static const struct ieee80211_ops wl1251_ops = {
.get_survey = wl1251_op_get_survey,
};
+static ssize_t wl1251_sysfs_show_tx_mgmt_frm_rate(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct wl1251 *wl = dev_get_drvdata(dev);
+ ssize_t len;
+ int val;
+
+ /* FIXME: what's the maximum length of buf? page size?*/
+ len = 500;
+
+ switch (wl->tx_mgmt_frm_rate) {
+ /* skip 1 and 12 Mbps because they have same value 0x0a */
+ case RATE_2MBPS:
+ val = 20;
+ break;
+ case RATE_5_5MBPS:
+ val = 55;
+ break;
+ case RATE_11MBPS:
+ val = 110;
+ break;
+ case RATE_6MBPS:
+ val = 60;
+ break;
+ case RATE_9MBPS:
+ val = 90;
+ break;
+ case RATE_12MBPS:
+ val = 120;
+ break;
+ case RATE_18MBPS:
+ val = 180;
+ break;
+ case RATE_24MBPS:
+ val = 240;
+ break;
+ case RATE_36MBPS:
+ val = 360;
+ break;
+ case RATE_48MBPS:
+ val = 480;
+ break;
+ case RATE_54MBPS:
+ val = 540;
+ break;
+ default:
+ val = 10;
+ }
+
+ /* for 1 and 12 Mbps we have to check the modulation */
+ if (wl->tx_mgmt_frm_rate == RATE_1MBPS) {
+ switch (wl->tx_mgmt_frm_rate) {
+ case CCK_LONG:
+ val = 10;
+ break;
+ case OFDM:
+ val = 120;
+ break;
+ default:
+ val = 10;
+ break;
+ }
+ }
+ len = snprintf(buf, len, "%d", val);
+
+ return len;
+}
+
+static ssize_t wl1251_sysfs_store_tx_mgmt_frm_rate(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct wl1251 *wl = dev_get_drvdata(dev);
+ unsigned long res;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &res);
+
+ if (ret < 0) {
+ wl1251_warning("incorrect value written to tx_mgmt_frm_rate");
+ return 0;
+ }
+
+ switch (res) {
+ case 10:
+ wl->tx_mgmt_frm_rate = RATE_1MBPS;
+ wl->tx_mgmt_frm_mod = CCK_LONG;
+ break;
+ case 20:
+ wl->tx_mgmt_frm_rate = RATE_2MBPS;
+ wl->tx_mgmt_frm_mod = CCK_LONG;
+ break;
+ case 55:
+ wl->tx_mgmt_frm_rate = RATE_5_5MBPS;
+ wl->tx_mgmt_frm_mod = CCK_LONG;
+ break;
+ case 110:
+ wl->tx_mgmt_frm_rate = RATE_11MBPS;
+ wl->tx_mgmt_frm_mod = CCK_LONG;
+ break;
+ case 60:
+ wl->tx_mgmt_frm_rate = RATE_6MBPS;
+ wl->tx_mgmt_frm_mod = OFDM;
+ break;
+ case 90:
+ wl->tx_mgmt_frm_rate = RATE_9MBPS;
+ wl->tx_mgmt_frm_mod = OFDM;
+ break;
+ case 120:
+ wl->tx_mgmt_frm_rate = RATE_12MBPS;
+ wl->tx_mgmt_frm_mod = OFDM;
+ break;
+ case 180:
+ wl->tx_mgmt_frm_rate = RATE_18MBPS;
+ wl->tx_mgmt_frm_mod = OFDM;
+ break;
+ case 240:
+ wl->tx_mgmt_frm_rate = RATE_24MBPS;
+ wl->tx_mgmt_frm_mod = OFDM;
+ break;
+ case 360:
+ wl->tx_mgmt_frm_rate = RATE_36MBPS;
+ wl->tx_mgmt_frm_mod = OFDM;
+ break;
+ case 480:
+ wl->tx_mgmt_frm_rate = RATE_48MBPS;
+ wl->tx_mgmt_frm_mod = OFDM;
+ break;
+ case 540:
+ wl->tx_mgmt_frm_rate = RATE_54MBPS;
+ wl->tx_mgmt_frm_mod = OFDM;
+ break;
+ default:
+ wl1251_warning("incorrect value written to tx_mgmt_frm_rate");
+ return 0;
+ }
+
+ return count;
+}
+
static ssize_t wl1251_sysfs_show_bt_coex_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1443,6 +1584,10 @@ out:
return count;
}
+static DEVICE_ATTR(tx_mgmt_frm_rate, S_IRUGO | S_IWUSR,
+ wl1251_sysfs_show_tx_mgmt_frm_rate,
+ wl1251_sysfs_store_tx_mgmt_frm_rate);
+
static DEVICE_ATTR(bt_coex_mode, S_IRUGO | S_IWUSR,
wl1251_sysfs_show_bt_coex_mode,
wl1251_sysfs_store_bt_coex_mode);
@@ -1583,6 +1728,13 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
}
dev_set_drvdata(&wl1251_device.dev, wl);
+ /* Create sysfs file tx_mgmt_frm_rate */
+ ret = device_create_file(&wl1251_device.dev,
+ &dev_attr_tx_mgmt_frm_rate);
+ if (ret < 0) {
+ wl1251_error("failed to create sysfs file tx_mgmt_frm_rate");
+ goto out;
+ }
/* Create sysfs file to control bt coex state */
ret = device_create_file(&wl1251_device.dev, &dev_attr_bt_coex_mode);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 16/16] wl1251: Add sysfs file address for setting permanent mac address
From: Pali Rohár @ 2013-10-26 20:34 UTC (permalink / raw)
To: Luciano Coelho, John W. Linville, Johannes Berg, David S. Miller
Cc: linux-wireless, netdev, linux-kernel, freemangordon,
aaro.koskinen, pavel, sre, joni.lapilainen, pali.rohar
In-Reply-To: <1382819655-30430-1-git-send-email-pali.rohar@gmail.com>
Driver wl1251 generating mac address randomly at startup and there is no way to
set permanent mac address via SET_IEEE80211_PERM_ADDR. This patch export sysfs
file which can set permanent mac address by userspace helper program. Patch is
needed for devices which do not store mac address in internal wl1251 eeprom.
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
---
drivers/net/wireless/ti/wl1251/main.c | 52 +++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 29625c2..91a009c 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -1375,6 +1375,46 @@ static const struct ieee80211_ops wl1251_ops = {
.get_survey = wl1251_op_get_survey,
};
+static ssize_t wl1251_sysfs_show_address(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct wl1251 *wl = dev_get_drvdata(dev);
+ ssize_t len;
+
+ /* FIXME: what's the maximum length of buf? page size?*/
+ len = 500;
+
+ len = snprintf(buf, len, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+ wl->mac_addr[0], wl->mac_addr[1], wl->mac_addr[2],
+ wl->mac_addr[3], wl->mac_addr[4], wl->mac_addr[5]);
+
+ return len;
+}
+
+static ssize_t wl1251_sysfs_store_address(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct wl1251 *wl = dev_get_drvdata(dev);
+ unsigned int addr[6];
+ int ret, i;
+
+ ret = sscanf(buf, "%2x:%2x:%2x:%2x:%2x:%2x\n",
+ &addr[0], &addr[1], &addr[2],
+ &addr[3], &addr[4], &addr[5]);
+
+ if (ret != 6)
+ return -EINVAL;
+
+ for (i = 0; i < 6; i++)
+ wl->mac_addr[i] = addr[i] & 0xff;
+
+ SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
+
+ return count;
+}
+
static ssize_t wl1251_sysfs_show_tx_mgmt_frm_rate(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1584,6 +1624,10 @@ out:
return count;
}
+static DEVICE_ATTR(address, S_IRUGO | S_IWUSR,
+ wl1251_sysfs_show_address,
+ wl1251_sysfs_store_address);
+
static DEVICE_ATTR(tx_mgmt_frm_rate, S_IRUGO | S_IWUSR,
wl1251_sysfs_show_tx_mgmt_frm_rate,
wl1251_sysfs_store_tx_mgmt_frm_rate);
@@ -1728,6 +1772,14 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
}
dev_set_drvdata(&wl1251_device.dev, wl);
+ /* Create sysfs file address */
+ ret = device_create_file(&wl1251_device.dev,
+ &dev_attr_address);
+ if (ret < 0) {
+ wl1251_error("failed to create sysfs file address");
+ goto out;
+ }
+
/* Create sysfs file tx_mgmt_frm_rate */
ret = device_create_file(&wl1251_device.dev,
&dev_attr_tx_mgmt_frm_rate);
--
1.7.10.4
^ permalink raw reply related
* BRCM 4324 Help
From: Hiemanshu Sharma @ 2013-10-26 20:54 UTC (permalink / raw)
To: linux-wireless
Hey,
Trying to follow the instructions at
http://wireless.kernel.org/en/users/Drivers/brcm80211 I need a
brcmfmac-sdio.txt with the nvram values but I am not able to find out
where to get the file from. I've tried google a lot but there doesn't
seem to be a lot of help out there.
dmesg says :
brcmfam: brcmf_sdbrcm_download_nvram : Fail to request nvram -2
brcmfmac: _brcmf_sdbrcm_download_firmware: dongle nvram file download failed
I've used firmware from the git, and the message for missing firmware
is not shown anymore.
Regards,
Hiemanshu Sharma.
^ permalink raw reply
* iwlegacy (4965) - what would 0x8000 as the completed TX rate indicate?
From: Adrian Chadd @ 2013-10-26 23:56 UTC (permalink / raw)
To: linux-wireless@vger.kernel.org
Hi all,
I'm debugging some issues that i see with the 4965 driver on FreeBSD. I
figure maybe someone here with experience with the iwlegacy driver may know.
I've set it up to do non-aggregate 11abg only traffic in my tests and I do
occasionally see the TX rate control completion status show the rate is
0x8000. I don't know to interpret it. It typically happens with the retry
count being non-zero, but there are also completed frames with non-zero
retry and normal rate results. The returned status is OK.
Here's an example:
Oct 26 16:06:11 lucy kernel: iwn4965_tx_done: qid 0 idx 210 retries 0 nkill
0 rate 4003 duration 294 status 201
Oct 26 16:06:11 lucy kernel: iwn4965_tx_done: qid 0 idx 211 retries 0 nkill
0 rate 4003 duration 182 status 201
Oct 26 16:06:11 lucy kernel: iwn4965_tx_done: qid 0 idx 212 retries 1 nkill
0 rate 8000 duration 616 status 201
Oct 26 16:06:12 lucy kernel: iwn4965_tx_done: qid 0 idx 213 retries 0 nkill
0 rate 4003 duration 294 status 201
Oct 26 16:06:12 lucy kernel: iwn4965_tx_done: qid 0 idx 214 retries 1 nkill
0 rate 8000 duration 292 status 201
Oct 26 16:06:12 lucy kernel: iwn4965_tx_done: qid 0 idx 215 retries 0 nkill
0 rate 4003 duration 86 status 201
Oct 26 16:06:12 lucy kernel: iwn4965_tx_done: qid 0 idx 216 retries 0 nkill
0 rate 4003 duration 86 status 201
I definitely am programming the initial rate control fine and the flags
field doesn't have the linkq stuff set, so it should be transmitting only
at that rate.
The status indicates things are transmitting and completing fine.
So, any ideas what that 0x8000 rate in the rate completion means?
Thanks!
-adrian
^ permalink raw reply
* Re: [PATCH] staging: vt6656: device.h Remove typedef enum __device_init_type.
From: Greg KH @ 2013-10-27 13:49 UTC (permalink / raw)
To: Malcolm Priestley; +Cc: linux-wireless
In-Reply-To: <1382469974.6738.8.camel@canaries64-MCP7A>
On Tue, Oct 22, 2013 at 08:26:14PM +0100, Malcolm Priestley wrote:
> Since typedef enum __device_init_type is only ever called
> in one state.
Then why not remove it entirely?
> Remove the typedef from main_usb.c:device_init_registers
> and if braces and just apply the enum value to sInitCmd.byInitClass.
You kind of did this, but things are still a bit messed up:
> }
> - if (InitType == DEVICE_INIT_COLD) {
>
> ntStatus = CONTROLnsRequestIn(pDevice,MESSAGE_TYPE_INIT_RSP,0,0,sizeof(RSP_CARD_INIT), (u8 *) &(sInitRsp));
>
> @@ -574,7 +572,6 @@ static int device_init_registers(struct vnt_private *pDevice,
> /* if exist SW network address, use it */
> DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Network address = %pM\n",
> pDevice->abyCurrentNetAddr);
> - }
You remove this if, but the indentation is not fixed up.
Just remove the enum entirely if it's not used.
thanks,
greg k-h
^ permalink raw reply
* [PATCH] nl80211: introduce NL80211_SCAN_FLAG_DISCOVERY_MODE
From: Vladimir Kondratiev @ 2013-10-27 15:54 UTC (permalink / raw)
To: Johannes Berg
Cc: Vladimir Kondratiev, linux-wireless, Luis R . Rodriguez,
John W . Linville, Jouni Malinen
for the DMG (60GHz) networks, there is new scan parameter added in the 802.11 spec -
DiscoveryMode. This parameter defines whether station performing active scan shall
generate special form of DMG beacons. In particular, this flag used in the P2P
discovery.
Introduce flag to support this feature.
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
---
include/uapi/linux/nl80211.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index fde2c02..469ed2b 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3808,11 +3808,18 @@ enum nl80211_connect_failed_reason {
* dangerous because will destroy stations performance as a lot of frames
* will be lost while scanning off-channel, therefore it must be used only
* when really needed
+ * @NL80211_SCAN_FLAG_DISCOVERY_MODE: scan to use discovery mode, as in
+ * 802.11 spec for DMG (60GHz) networks in clause:
+ * 10.1.3.4 DMG Beacon generation before network initialization
+ * If set, station should transmit special form of DMG beacons when
+ * performing active scan. In 60GHz networks, this feature used
+ * in the P2P discovery procedure.
*/
enum nl80211_scan_flags {
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
NL80211_SCAN_FLAG_FLUSH = 1<<1,
NL80211_SCAN_FLAG_AP = 1<<2,
+ NL80211_SCAN_FLAG_DISCOVERY_MODE = 1<<3,
};
/**
--
1.8.3.2
^ permalink raw reply related
* [PATCH 4/4] wl1251: spi: add device tree support
From: Sebastian Reichel @ 2013-10-27 16:14 UTC (permalink / raw)
To: Sebastian Reichel, Luciano Coelho
Cc: Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren,
Ian Campbell, Rob Landley, Tony Lindgren, Russell King,
John W. Linville, Felipe Balbi, Sachin Kamat, Greg Kroah-Hartman,
Bill Pemberton, devicetree, linux-doc, linux-kernel, linux-omap,
linux-arm-kernel, linux-wireless, netdev, Sebastian Reichel
In-Reply-To: <1382890469-25286-1-git-send-email-sre@debian.org>
Add device tree support for the spi variant of wl1251
and document the binding.
Signed-off-by: Sebastian Reichel <sre@debian.org>
---
.../devicetree/bindings/net/wireless/ti,wl1251.txt | 36 ++++++++++++++++++++++
drivers/net/wireless/ti/wl1251/spi.c | 23 ++++++++++----
2 files changed, 53 insertions(+), 6 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt
diff --git a/Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt b/Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt
new file mode 100644
index 0000000..5f8a154
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt
@@ -0,0 +1,36 @@
+* Texas Instruments wl1251 controller
+
+The wl1251 chip can be connected via SPI or via SDIO. The linux
+kernel currently only supports device tree for the SPI variant.
+
+Required properties:
+- compatible : Should be "ti,wl1251"
+- interrupts : Should contain interrupt line
+- interrupt-parent : Should be the phandle for the interrupt
+ controller that services interrupts for this device
+- vio-supply : phandle to regulator providing VIO
+- power-gpio : GPIO connected to chip's PMEN pin
+- For additional required properties on SPI, please consult
+ Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Optional properties:
+- ti,use-eeprom : If found, configuration will be loaded from eeprom.
+
+Examples:
+
+&spi1 {
+ wl1251_spi@0 {
+ compatible = "ti,wl1251";
+
+ reg = <0>;
+ spi-max-frequency = <48000000>;
+ spi-cpol;
+ spi-cpha;
+
+ interrupt-parent = <&gpio2>;
+ interrupts = <10 IRQ_TYPE_NONE>; /* gpio line 42 */
+
+ vio-supply = <&vio>;
+ power-gpio = <&gpio3 23 GPIO_ACTIVE_HIGH>; /* 87 */
+ };
+};
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c
index efea57a..ee6ce4c 100644
--- a/drivers/net/wireless/ti/wl1251/spi.c
+++ b/drivers/net/wireless/ti/wl1251/spi.c
@@ -27,6 +27,8 @@
#include <linux/spi/spi.h>
#include <linux/wl12xx.h>
#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include "wl1251.h"
@@ -240,13 +242,13 @@ static const struct wl1251_if_operations wl1251_spi_ops = {
static int wl1251_spi_probe(struct spi_device *spi)
{
- struct wl1251_platform_data *pdata;
+ struct wl1251_platform_data *pdata = spi->dev.platform_data;
+ struct device_node *np = spi->dev.of_node;
struct ieee80211_hw *hw;
struct wl1251 *wl;
int ret;
- pdata = spi->dev.platform_data;
- if (!pdata) {
+ if (!np && !pdata) {
wl1251_error("no platform data");
return -ENODEV;
}
@@ -273,7 +275,18 @@ static int wl1251_spi_probe(struct spi_device *spi)
goto out_free;
}
- wl->power_gpio = pdata->power_gpio;
+ if (np) {
+ wl->use_eeprom = of_property_read_bool(np, "ti,use-eeprom");
+ wl->power_gpio = of_get_named_gpio(np, "power-gpio", 0);
+ } else if (pdata) {
+ wl->power_gpio = pdata->power_gpio;
+ wl->use_eeprom = pdata->use_eeprom;
+ }
+
+ if (wl->power_gpio == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto out_free;
+ }
if (gpio_is_valid(wl->power_gpio)) {
ret = devm_gpio_request_one(&spi->dev, wl->power_gpio,
@@ -295,8 +308,6 @@ static int wl1251_spi_probe(struct spi_device *spi)
goto out_free;
}
- wl->use_eeprom = pdata->use_eeprom;
-
irq_set_status_flags(wl->irq, IRQ_NOAUTOEN);
ret = devm_request_irq(&spi->dev, wl->irq, wl1251_irq, 0,
DRIVER_NAME, wl);
--
1.8.4.rc3
^ permalink raw reply related
* [PATCH 3/4] wl1251: spi: add vio regulator support
From: Sebastian Reichel @ 2013-10-27 16:14 UTC (permalink / raw)
To: Sebastian Reichel, Luciano Coelho
Cc: Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren,
Ian Campbell, Rob Landley, Tony Lindgren, Russell King,
John W. Linville, Felipe Balbi, Sachin Kamat, Greg Kroah-Hartman,
Bill Pemberton, devicetree, linux-doc, linux-kernel, linux-omap,
linux-arm-kernel, linux-wireless, netdev, Sebastian Reichel
In-Reply-To: <1382890469-25286-1-git-send-email-sre@debian.org>
This patch adds support for requesting the regulator powering
the vio pin.
The patch also adds the regulator for the all boards using the
wl1251 in spi mode (only the Nokia N900).
Signed-off-by: Sebastian Reichel <sre@debian.org>
---
arch/arm/mach-omap2/board-rx51-peripherals.c | 2 ++
drivers/net/wireless/ti/wl1251/spi.c | 19 +++++++++++++++++--
drivers/net/wireless/ti/wl1251/wl1251.h | 2 ++
3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index b9d95dd..a791fef 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -552,6 +552,8 @@ static struct regulator_consumer_supply rx51_vio_supplies[] = {
REGULATOR_SUPPLY("vio", "2-0063"),
/* lis3lv02d */
REGULATOR_SUPPLY("Vdd_IO", "3-001d"),
+ /* wl1251 */
+ REGULATOR_SUPPLY("vio", "spi4.0"),
};
static struct regulator_consumer_supply rx51_vaux1_consumers[] = {
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c
index 9a2df9d..efea57a 100644
--- a/drivers/net/wireless/ti/wl1251/spi.c
+++ b/drivers/net/wireless/ti/wl1251/spi.c
@@ -27,6 +27,7 @@
#include <linux/spi/spi.h>
#include <linux/wl12xx.h>
#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
#include "wl1251.h"
#include "reg.h"
@@ -306,13 +307,26 @@ static int wl1251_spi_probe(struct spi_device *spi)
irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
- ret = wl1251_init_ieee80211(wl);
+ wl->vio = devm_regulator_get(&spi->dev, "vio");
+ if (IS_ERR(wl->vio)) {
+ ret = PTR_ERR(wl->vio);
+ wl1251_error("vio regulator missing: %d", ret);
+ goto out_free;
+ }
+
+ ret = regulator_enable(wl->vio);
if (ret)
goto out_free;
+ ret = wl1251_init_ieee80211(wl);
+ if (ret)
+ goto disable_regulator;
+
return 0;
- out_free:
+disable_regulator:
+ regulator_disable(wl->vio);
+out_free:
ieee80211_free_hw(hw);
return ret;
@@ -324,6 +338,7 @@ static int wl1251_spi_remove(struct spi_device *spi)
free_irq(wl->irq, wl);
wl1251_free_hw(wl);
+ regulator_disable(wl->vio);
return 0;
}
diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h
index 5e9808c..010718b 100644
--- a/drivers/net/wireless/ti/wl1251/wl1251.h
+++ b/drivers/net/wireless/ti/wl1251/wl1251.h
@@ -279,6 +279,8 @@ struct wl1251 {
int irq;
bool use_eeprom;
+ struct regulator *vio;
+
spinlock_t wl_lock;
enum wl1251_state state;
--
1.8.4.rc3
^ permalink raw reply related
* [PATCH 2/4] wl1251: move power GPIO handling into the driver
From: Sebastian Reichel @ 2013-10-27 16:14 UTC (permalink / raw)
To: Sebastian Reichel, Luciano Coelho
Cc: Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren,
Ian Campbell, Rob Landley, Tony Lindgren, Russell King,
John W. Linville, Felipe Balbi, Sachin Kamat, Greg Kroah-Hartman,
Bill Pemberton, devicetree, linux-doc, linux-kernel, linux-omap,
linux-arm-kernel, linux-wireless, netdev, Sebastian Reichel
In-Reply-To: <1382890469-25286-1-git-send-email-sre@debian.org>
Move the power GPIO handling from the board code into
the driver. This is a dependency for device tree support.
Signed-off-by: Sebastian Reichel <sre@debian.org>
---
arch/arm/mach-omap2/board-omap3pandora.c | 2 ++
arch/arm/mach-omap2/board-rx51-peripherals.c | 11 ++--------
drivers/net/wireless/ti/wl1251/sdio.c | 21 +++++++++++++-----
drivers/net/wireless/ti/wl1251/spi.c | 33 ++++++++++++++++++----------
drivers/net/wireless/ti/wl1251/wl1251.h | 2 +-
include/linux/wl12xx.h | 2 +-
6 files changed, 43 insertions(+), 28 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index 24f3c1b..cf18340 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -541,6 +541,8 @@ static void __init pandora_wl1251_init(void)
memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata));
+ pandora_wl1251_pdata.power_gpio = -1;
+
ret = gpio_request_one(PANDORA_WIFI_IRQ_GPIO, GPIOF_IN, "wl1251 irq");
if (ret < 0)
goto fail;
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 0d8e7d2..b9d95dd 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -1164,13 +1164,7 @@ static inline void board_smc91x_init(void)
#endif
-static void rx51_wl1251_set_power(bool enable)
-{
- gpio_set_value(RX51_WL1251_POWER_GPIO, enable);
-}
-
static struct gpio rx51_wl1251_gpios[] __initdata = {
- { RX51_WL1251_POWER_GPIO, GPIOF_OUT_INIT_LOW, "wl1251 power" },
{ RX51_WL1251_IRQ_GPIO, GPIOF_IN, "wl1251 irq" },
};
@@ -1187,17 +1181,16 @@ static void __init rx51_init_wl1251(void)
if (irq < 0)
goto err_irq;
- wl1251_pdata.set_power = rx51_wl1251_set_power;
+ wl1251_pdata.power_gpio = RX51_WL1251_POWER_GPIO;
rx51_peripherals_spi_board_info[RX51_SPI_WL1251].irq = irq;
return;
err_irq:
gpio_free(RX51_WL1251_IRQ_GPIO);
- gpio_free(RX51_WL1251_POWER_GPIO);
error:
printk(KERN_ERR "wl1251 board initialisation failed\n");
- wl1251_pdata.set_power = NULL;
+ wl1251_pdata.power_gpio = -1;
/*
* Now rx51_peripherals_spi_board_info[1].irq is zero and
diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c
index b75a37a..b661f89 100644
--- a/drivers/net/wireless/ti/wl1251/sdio.c
+++ b/drivers/net/wireless/ti/wl1251/sdio.c
@@ -28,6 +28,7 @@
#include <linux/wl12xx.h>
#include <linux/irq.h>
#include <linux/pm_runtime.h>
+#include <linux/gpio.h>
#include "wl1251.h"
@@ -182,8 +183,9 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
* callback in case it wants to do any additional setup,
* for example enabling clock buffer for the module.
*/
- if (wl->set_power)
- wl->set_power(true);
+ if (gpio_is_valid(wl->power_gpio))
+ gpio_set_value(wl->power_gpio, true);
+
ret = pm_runtime_get_sync(&func->dev);
if (ret < 0) {
@@ -203,8 +205,8 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
if (ret < 0)
goto out;
- if (wl->set_power)
- wl->set_power(false);
+ if (gpio_is_valid(wl->power_gpio))
+ gpio_set_value(wl->power_gpio, false);
}
out:
@@ -256,11 +258,20 @@ static int wl1251_sdio_probe(struct sdio_func *func,
wl1251_board_data = wl1251_get_platform_data();
if (!IS_ERR(wl1251_board_data)) {
- wl->set_power = wl1251_board_data->set_power;
+ wl->power_gpio = wl1251_board_data->power_gpio;
wl->irq = wl1251_board_data->irq;
wl->use_eeprom = wl1251_board_data->use_eeprom;
}
+ if (gpio_is_valid(wl->power_gpio)) {
+ ret = devm_gpio_request(&func->dev, wl->power_gpio,
+ "wl1251 power");
+ if (ret) {
+ wl1251_error("Failed to request gpio: %d\n", ret);
+ goto disable;
+ }
+ }
+
if (wl->irq) {
irq_set_status_flags(wl->irq, IRQ_NOAUTOEN);
ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl);
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c
index 6bbbfe6..9a2df9d 100644
--- a/drivers/net/wireless/ti/wl1251/spi.c
+++ b/drivers/net/wireless/ti/wl1251/spi.c
@@ -26,6 +26,7 @@
#include <linux/crc7.h>
#include <linux/spi/spi.h>
#include <linux/wl12xx.h>
+#include <linux/gpio.h>
#include "wl1251.h"
#include "reg.h"
@@ -221,8 +222,8 @@ static void wl1251_spi_disable_irq(struct wl1251 *wl)
static int wl1251_spi_set_power(struct wl1251 *wl, bool enable)
{
- if (wl->set_power)
- wl->set_power(enable);
+ if (gpio_is_valid(wl->power_gpio))
+ gpio_set_value(wl->power_gpio, enable);
return 0;
}
@@ -271,22 +272,33 @@ static int wl1251_spi_probe(struct spi_device *spi)
goto out_free;
}
- wl->set_power = pdata->set_power;
- if (!wl->set_power) {
- wl1251_error("set power function missing in platform data");
- return -ENODEV;
+ wl->power_gpio = pdata->power_gpio;
+
+ if (gpio_is_valid(wl->power_gpio)) {
+ ret = devm_gpio_request_one(&spi->dev, wl->power_gpio,
+ GPIOF_OUT_INIT_LOW, "wl1251 power");
+ if (ret) {
+ wl1251_error("Failed to request gpio: %d\n", ret);
+ goto out_free;
+ }
+ } else {
+ wl1251_error("set power gpio missing in platform data");
+ ret = -ENODEV;
+ goto out_free;
}
wl->irq = spi->irq;
if (wl->irq < 0) {
wl1251_error("irq missing in platform data");
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free;
}
wl->use_eeprom = pdata->use_eeprom;
irq_set_status_flags(wl->irq, IRQ_NOAUTOEN);
- ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
+ ret = devm_request_irq(&spi->dev, wl->irq, wl1251_irq, 0,
+ DRIVER_NAME, wl);
if (ret < 0) {
wl1251_error("request_irq() failed: %d", ret);
goto out_free;
@@ -296,13 +308,10 @@ static int wl1251_spi_probe(struct spi_device *spi)
ret = wl1251_init_ieee80211(wl);
if (ret)
- goto out_irq;
+ goto out_free;
return 0;
- out_irq:
- free_irq(wl->irq, wl);
-
out_free:
ieee80211_free_hw(hw);
diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h
index fd02060..5e9808c 100644
--- a/drivers/net/wireless/ti/wl1251/wl1251.h
+++ b/drivers/net/wireless/ti/wl1251/wl1251.h
@@ -275,7 +275,7 @@ struct wl1251 {
void *if_priv;
const struct wl1251_if_operations *if_ops;
- void (*set_power)(bool enable);
+ int power_gpio;
int irq;
bool use_eeprom;
diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h
index b516b4f..a9c723b 100644
--- a/include/linux/wl12xx.h
+++ b/include/linux/wl12xx.h
@@ -49,7 +49,7 @@ enum {
};
struct wl1251_platform_data {
- void (*set_power)(bool enable);
+ int power_gpio;
/* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */
int irq;
bool use_eeprom;
--
1.8.4.rc3
^ permalink raw reply related
* [PATCH 1/4] wl1251: split wl251 platform data to a separate structure
From: Sebastian Reichel @ 2013-10-27 16:14 UTC (permalink / raw)
To: Sebastian Reichel, Luciano Coelho
Cc: Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren,
Ian Campbell, Rob Landley, Tony Lindgren, Russell King,
John W. Linville, Felipe Balbi, Sachin Kamat, Greg Kroah-Hartman,
Bill Pemberton, devicetree, linux-doc, linux-kernel, linux-omap,
linux-arm-kernel, linux-wireless, netdev, Luciano Coelho
In-Reply-To: <1382890469-25286-1-git-send-email-sre@debian.org>
From: Luciano Coelho <coelho@ti.com>
Move the wl1251 part of the wl12xx platform data structure into a new
structure specifically for wl1251. Change the platform data built-in
block and board files accordingly.
Cc: Tony Lindgren <tony@atomide.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Reviewed-by: Felipe Balbi <balbi@ti.com>
---
arch/arm/mach-omap2/board-omap3pandora.c | 4 +--
arch/arm/mach-omap2/board-rx51-peripherals.c | 2 +-
drivers/net/wireless/ti/wilink_platform_data.c | 37 +++++++++++++++++++++-----
drivers/net/wireless/ti/wl1251/sdio.c | 12 ++++-----
drivers/net/wireless/ti/wl1251/spi.c | 2 +-
include/linux/wl12xx.h | 22 ++++++++++++++-
6 files changed, 62 insertions(+), 17 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index de1bc6b..24f3c1b 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -536,7 +536,7 @@ static struct spi_board_info omap3pandora_spi_board_info[] __initdata = {
static void __init pandora_wl1251_init(void)
{
- struct wl12xx_platform_data pandora_wl1251_pdata;
+ struct wl1251_platform_data pandora_wl1251_pdata;
int ret;
memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata));
@@ -550,7 +550,7 @@ static void __init pandora_wl1251_init(void)
goto fail_irq;
pandora_wl1251_pdata.use_eeprom = true;
- ret = wl12xx_set_platform_data(&pandora_wl1251_pdata);
+ ret = wl1251_set_platform_data(&pandora_wl1251_pdata);
if (ret < 0)
goto fail_irq;
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 65e3627..0d8e7d2 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -82,7 +82,7 @@ enum {
RX51_SPI_MIPID, /* LCD panel */
};
-static struct wl12xx_platform_data wl1251_pdata;
+static struct wl1251_platform_data wl1251_pdata;
static struct tsc2005_platform_data tsc2005_pdata;
#if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
diff --git a/drivers/net/wireless/ti/wilink_platform_data.c b/drivers/net/wireless/ti/wilink_platform_data.c
index 998e958..a92bd3e 100644
--- a/drivers/net/wireless/ti/wilink_platform_data.c
+++ b/drivers/net/wireless/ti/wilink_platform_data.c
@@ -23,17 +23,17 @@
#include <linux/err.h>
#include <linux/wl12xx.h>
-static struct wl12xx_platform_data *platform_data;
+static struct wl12xx_platform_data *wl12xx_platform_data;
int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
{
- if (platform_data)
+ if (wl12xx_platform_data)
return -EBUSY;
if (!data)
return -EINVAL;
- platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
- if (!platform_data)
+ wl12xx_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
+ if (!wl12xx_platform_data)
return -ENOMEM;
return 0;
@@ -41,9 +41,34 @@ int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
struct wl12xx_platform_data *wl12xx_get_platform_data(void)
{
- if (!platform_data)
+ if (!wl12xx_platform_data)
return ERR_PTR(-ENODEV);
- return platform_data;
+ return wl12xx_platform_data;
}
EXPORT_SYMBOL(wl12xx_get_platform_data);
+
+static struct wl1251_platform_data *wl1251_platform_data;
+
+int __init wl1251_set_platform_data(const struct wl1251_platform_data *data)
+{
+ if (wl1251_platform_data)
+ return -EBUSY;
+ if (!data)
+ return -EINVAL;
+
+ wl1251_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
+ if (!wl1251_platform_data)
+ return -ENOMEM;
+
+ return 0;
+}
+
+struct wl1251_platform_data *wl1251_get_platform_data(void)
+{
+ if (!wl1251_platform_data)
+ return ERR_PTR(-ENODEV);
+
+ return wl1251_platform_data;
+}
+EXPORT_SYMBOL(wl1251_get_platform_data);
diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c
index e2b3d9c..b75a37a 100644
--- a/drivers/net/wireless/ti/wl1251/sdio.c
+++ b/drivers/net/wireless/ti/wl1251/sdio.c
@@ -227,7 +227,7 @@ static int wl1251_sdio_probe(struct sdio_func *func,
struct wl1251 *wl;
struct ieee80211_hw *hw;
struct wl1251_sdio *wl_sdio;
- const struct wl12xx_platform_data *wl12xx_board_data;
+ const struct wl1251_platform_data *wl1251_board_data;
hw = wl1251_alloc_hw();
if (IS_ERR(hw))
@@ -254,11 +254,11 @@ static int wl1251_sdio_probe(struct sdio_func *func,
wl->if_priv = wl_sdio;
wl->if_ops = &wl1251_sdio_ops;
- wl12xx_board_data = wl12xx_get_platform_data();
- if (!IS_ERR(wl12xx_board_data)) {
- wl->set_power = wl12xx_board_data->set_power;
- wl->irq = wl12xx_board_data->irq;
- wl->use_eeprom = wl12xx_board_data->use_eeprom;
+ wl1251_board_data = wl1251_get_platform_data();
+ if (!IS_ERR(wl1251_board_data)) {
+ wl->set_power = wl1251_board_data->set_power;
+ wl->irq = wl1251_board_data->irq;
+ wl->use_eeprom = wl1251_board_data->use_eeprom;
}
if (wl->irq) {
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c
index c7dc6fe..6bbbfe6 100644
--- a/drivers/net/wireless/ti/wl1251/spi.c
+++ b/drivers/net/wireless/ti/wl1251/spi.c
@@ -238,7 +238,7 @@ static const struct wl1251_if_operations wl1251_spi_ops = {
static int wl1251_spi_probe(struct spi_device *spi)
{
- struct wl12xx_platform_data *pdata;
+ struct wl1251_platform_data *pdata;
struct ieee80211_hw *hw;
struct wl1251 *wl;
int ret;
diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h
index a54fe82..b516b4f 100644
--- a/include/linux/wl12xx.h
+++ b/include/linux/wl12xx.h
@@ -48,11 +48,15 @@ enum {
WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */
};
-struct wl12xx_platform_data {
+struct wl1251_platform_data {
void (*set_power)(bool enable);
/* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */
int irq;
bool use_eeprom;
+};
+
+struct wl12xx_platform_data {
+ int irq;
int board_ref_clock;
int board_tcxo_clock;
unsigned long platform_quirks;
@@ -68,6 +72,10 @@ int wl12xx_set_platform_data(const struct wl12xx_platform_data *data);
struct wl12xx_platform_data *wl12xx_get_platform_data(void);
+int wl1251_set_platform_data(const struct wl1251_platform_data *data);
+
+struct wl1251_platform_data *wl1251_get_platform_data(void);
+
#else
static inline
@@ -82,6 +90,18 @@ struct wl12xx_platform_data *wl12xx_get_platform_data(void)
return ERR_PTR(-ENODATA);
}
+static inline
+int wl1251_set_platform_data(const struct wl1251_platform_data *data)
+{
+ return -ENOSYS;
+}
+
+static inline
+struct wl1251_platform_data *wl1251_get_platform_data(void)
+{
+ return ERR_PTR(-ENODATA);
+}
+
#endif
#endif
--
1.8.4.rc3
^ permalink raw reply related
* [PATCH 0/4] wl1251 device tree support
From: Sebastian Reichel @ 2013-10-27 16:14 UTC (permalink / raw)
To: Sebastian Reichel, Luciano Coelho
Cc: Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren,
Ian Campbell, Rob Landley, Tony Lindgren, Russell King,
John W. Linville, Felipe Balbi, Sachin Kamat, Greg Kroah-Hartman,
Bill Pemberton, devicetree, linux-doc, linux-kernel, linux-omap,
linux-arm-kernel, linux-wireless, netdev, Sebastian Reichel
Hi,
The following patchset adds device tree support to
the spi variant of the wl1251 driver.
Some notes:
The first patch is from Luciano's wilink DT support
patchset [0].
The third patch (vio regulator support) is optional. N900's
wifi also worked without this patch, but its probably cleaner
to have it.
The patchset has been tested using DT boot with the Nokia N900
and connecting to my wlan access point.
[0] https://lkml.org/lkml/2013/7/3/333
-- Sebastian
Luciano Coelho (1):
wl1251: split wl251 platform data to a separate structure
Sebastian Reichel (3):
wl1251: move power GPIO handling into the driver
wl1251: spi: add vio regulator support
wl1251: spi: add device tree support
.../devicetree/bindings/net/wireless/ti,wl1251.txt | 36 +++++++++++
arch/arm/mach-omap2/board-omap3pandora.c | 6 +-
arch/arm/mach-omap2/board-rx51-peripherals.c | 15 ++---
drivers/net/wireless/ti/wilink_platform_data.c | 37 +++++++++--
drivers/net/wireless/ti/wl1251/sdio.c | 31 +++++++---
drivers/net/wireless/ti/wl1251/spi.c | 71 ++++++++++++++++------
drivers/net/wireless/ti/wl1251/wl1251.h | 4 +-
include/linux/wl12xx.h | 24 +++++++-
8 files changed, 175 insertions(+), 49 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt
--
1.8.4.rc3
^ permalink raw reply
* Re: [rt2x00-users] [PATCH] rt2x00: rt2800lib: update RF registers for RT5390
From: Andreas Hartmann @ 2013-10-27 16:29 UTC (permalink / raw)
To: Kevin Lo, John Linville; +Cc: linux-wireless, users
In-Reply-To: <5269D154.5000606@kevlo.org>
Hello Kevin!
Kevin Lo wrote:
> Andreas Hartmann wrote:
[...]
>> In a nutshell: Use a few, but big USB packets instead of a lot of small
>> ones, which needs a lot of interrupts / s and therefore needs a lot of
>> CPU resources - which aren't available on the PI at all.
>
> I have a lot of embedded devices (Freescale imx5/imx6, Marvell armanda xp
> ... etc) here and I've also noticed usb performance issues.
>
> Firstly, I want to sync register settings, which is obtained from the
> vendor driver. When it's done, I will take a look at how usb is handled by
> the vendor driver and fix performance issues. Since I don't have
> datasheets,
> I'm not sure updating register values won't help much...
The problem is: as long as the USB interface "filters" as bottleneck
each small change, it's hard to tell if the change was successful or not.
But I'm happy to hear that you see the same problems and I would be
happy if you could fix them. I can test the fixes you hopefully provide
with big (SMP hardware) and small (ARM) hardware and with rt3572 and rt3573.
Thanks,
kind regards,
Andreas
^ permalink raw reply
* [ANN] backports-20131025 released
From: Hauke Mehrtens @ 2013-10-27 19:32 UTC (permalink / raw)
To: backports@vger.kernel.org, linux-wireless@vger.kernel.org,
linux-kernel
Finally backports is in sync with linux-next again, we just did the
backports-20131025 release which is based on linux-next next-20131025.
The release can be found here:
https://www.kernel.org/pub/linux/kernel/projects/backports/2013/10/25/backports-20131025.tar.bz2
There are also older releases based on older linux-next releases.
The source code can temporary be found here:
https://github.com/hauke/backports
Currently Stephen Rothwell, the original author of the linux-next tree,
is on vacation, but Thierry Reding took over [1] and backports is based
on his releases [2] now.
Now getting new stable releases based on kernel 3.10, 3.11 and 3.12 is
the next goal.
This release and further releases will not contain any GPU drivers any
more, it was too much work to backport them to older kernel versions and
it looked like that code did not had any users.
More information can be found in our wiki:
https://backports.wiki.kernel.org/index.php/Main_Page
Hauke
[1]: https://lkml.org/lkml/2013/9/30/179
[2]: git://gitorious.org/thierryreding/linux-next.git
^ permalink raw reply
* Re: [PATCH 2/4] wl1251: move power GPIO handling into the driver
From: Sebastian Reichel @ 2013-10-27 20:12 UTC (permalink / raw)
To: Alexander Shiyan
Cc: Luciano Coelho, Mark Rutland, devicetree, Russell King,
Pawel Moll, Ian Campbell, Tony Lindgren, Greg Kroah-Hartman,
Stephen Warren, linux-doc, John W. Linville, Rob Herring,
linux-kernel, Sachin Kamat, Bill Pemberton, Felipe Balbi,
Rob Landley, netdev, linux-wireless, linux-omap, linux-arm-kernel
In-Reply-To: <1382891056.102746625@f315.i.mail.ru>
[-- Attachment #1: Type: text/plain, Size: 1537 bytes --]
On Sun, Oct 27, 2013 at 08:24:16PM +0400, Alexander Shiyan wrote:
> > Move the power GPIO handling from the board code into
> > the driver. This is a dependency for device tree support.
> >
> > Signed-off-by: Sebastian Reichel <sre@debian.org>
> > ---
> > arch/arm/mach-omap2/board-omap3pandora.c | 2 ++
> > arch/arm/mach-omap2/board-rx51-peripherals.c | 11 ++--------
> > drivers/net/wireless/ti/wl1251/sdio.c | 21 +++++++++++++-----
> > drivers/net/wireless/ti/wl1251/spi.c | 33 ++++++++++++++++++----------
> > drivers/net/wireless/ti/wl1251/wl1251.h | 2 +-
> > include/linux/wl12xx.h | 2 +-
> > 6 files changed, 43 insertions(+), 28 deletions(-)
> ...
> > diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h
> > index b516b4f..a9c723b 100644
> > --- a/include/linux/wl12xx.h
> > +++ b/include/linux/wl12xx.h
> > @@ -49,7 +49,7 @@ enum {
> > };
> >
> > struct wl1251_platform_data {
> > - void (*set_power)(bool enable);
> > + int power_gpio;
> > /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */
> > int irq;
> > bool use_eeprom;
> > --
>
> What a reason for not using regulator API here with GPIO-based
> regulator?
I think this pin is not used as power supply, but like an enable pin
for low power states. Of course the regulator API could still be
(mis?)used for this, but I think it would be the first linux device
driver doing this.
Note: I don't have wl1251 documentation.
-- Sebastian
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH 0/6] crda: few updates and license changes
From: Luis R. Rodriguez @ 2013-10-28 1:52 UTC (permalink / raw)
To: linux-wireless; +Cc: wireless-regdb, Luis R. Rodriguez
Here's a few updates to CRDA. This depends on the removal of
antenna gain patches I posted last week. The tools developed
in this series are designed to help folks who want to contribute
to wireless-regdb but have a regulatory database format in some
other form that is non-optimized. The stream parser helps users
get their data out into non optimized form, and provide also
optimizers.
The optimizer work by doing a union and intersections on the
set of rules of a regulatory domain. Lastly as I mentioned the
last wireless summit I'd be making a library here, making CRDA
and its other tools share code. Other tools may use the library
later but these require a bit more work and as it is right now
the db2rd and optimizer require a bit more work to be shipped
by default.
This work has all been valgrinized.
Luis R. Rodriguez (6):
crda: relicense under copyleft-next-0.3.0
crda: fix -pedantic gcc compilation
crda: add regulatory domain stream parser
crda: add regulatory domain optimizer
crda: make ssl keys include stdint.h
crda: make reglib a shared library
LICENSE | 14 +-
Makefile | 54 +++-
copyleft-next-0.3.0 | 219 +++++++++++++++
crda.c | 4 +-
db2rd.c | 30 ++
optimize.c | 38 +++
reglib.c | 790 ++++++++++++++++++++++++++++++++++++++++++++++++++++
reglib.h | 60 ++++
utils/key2pub.py | 2 +
9 files changed, 1199 insertions(+), 12 deletions(-)
create mode 100644 copyleft-next-0.3.0
create mode 100644 db2rd.c
create mode 100644 optimize.c
--
1.8.4.rc3
^ permalink raw reply
* [PATCH 1/6] crda: relicense under copyleft-next-0.3.0
From: Luis R. Rodriguez @ 2013-10-28 1:52 UTC (permalink / raw)
To: linux-wireless; +Cc: wireless-regdb, Luis R. Rodriguez
In-Reply-To: <1382925182-7393-1-git-send-email-mcgrof@do-not-panic.com>
I'm relicensing CRDA to copyleft-next-0.3.0. The original
motivation was to help with the BSD family but they are not
using any of this software and as this software grows I'd
like to ensure we use the best free software license
possible.
Fontana's work on copyleft-next is great and has good
community traction. At this point development for
copyleft-next has slowed down as copyleft-next-0.3.0
is already a good, usable alternative to GPLv2 and GPLv3.
A few notes:
* With copyleft we don't have to specify 'at your option
any later version' since the license allows that by
default.
* Some folks might wonder if copyleft-next-0.3.0 is
OSI OSD-conformant or FSF-free since neither of
those bodies have examined the license officially,
but note, although IANAL, that copyleft-next is
outbound-compatible with GPLv2 and GPLv3
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
---
LICENSE | 14 +++-
copyleft-next-0.3.0 | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 232 insertions(+), 1 deletion(-)
create mode 100644 copyleft-next-0.3.0
diff --git a/LICENSE b/LICENSE
index 652a6dd..cc26ff2 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,16 @@
-Copyright (c) 2008, Luis R. Rodriguez <mcgrof@gmail.com>
+Copyright (c) 2013, Luis R. Rodriguez <mcgrof@do-not-panic.com>
+
+CRDA is licensed under copyleft-next 0.3.0
+
+Refer to copyleft-next-0.3.0 for license details, you can
+also always get the latest updates of copyleft-next from:
+
+https://gitorious.org/copyleft-next/
+
+This file incorporates work covered by the following copyright and
+permission notice:
+
+Copyright (c) 2008, Luis R. Rodriguez <mcgrof@do-not-panic.com>
Copyright (c) 2008, Johannes Berg <johannes@sipsolutions.net>
Copyright (c) 2008, Michael Green <Michael.Green@Atheros.com>
diff --git a/copyleft-next-0.3.0 b/copyleft-next-0.3.0
new file mode 100644
index 0000000..a66d5bf
--- /dev/null
+++ b/copyleft-next-0.3.0
@@ -0,0 +1,219 @@
+ copyleft-next 0.3.0 ("this License")
+ Release date: 2013-05-16
+
+1. License Grants; No Trademark License
+
+ Subject to the terms of this License, I grant You:
+
+ a) A non-exclusive, worldwide, perpetual, royalty-free, irrevocable
+ copyright license, to reproduce, Distribute, prepare derivative works
+ of, publicly perform and publicly display My Work.
+
+ b) A non-exclusive, worldwide, perpetual, royalty-free, irrevocable
+ patent license under Licensed Patents to make, have made, use, sell,
+ offer for sale, and import Covered Works.
+
+ This License does not grant any rights in My name, trademarks, service
+ marks, or logos.
+
+2. Distribution: General Conditions
+
+ You may Distribute Covered Works, provided that You (i) inform
+ recipients how they can obtain a copy of this License; (ii) satisfy the
+ applicable conditions of sections 3 through 6; and (iii) preserve all
+ Legal Notices contained in My Work (to the extent they remain
+ pertinent). "Legal Notices" means copyright notices, license notices,
+ license texts, and author attributions, but does not include logos,
+ other graphical images, trademarks or trademark legends.
+
+3. Conditions for Distributing Derived Works; Outbound GPL Compatibility
+
+ If You Distribute a Derived Work, You must license the entire Derived
+ Work as a whole under this License, with prominent notice of such
+ licensing. This condition may not be avoided through such means as
+ separate Distribution of portions of the Derived Work. You may
+ additionally license the Derived Work under the GPL, so that the
+ recipient may further Distribute the Derived Work under either this
+ License or the GPL.
+
+4. Condition Against Further Restrictions; Inbound License Compatibility
+
+ When Distributing a Covered Work, You may not impose further
+ restrictions on the exercise of rights in the Covered Work granted under
+ this License. This condition is not excused merely because such
+ restrictions result from Your compliance with conditions or obligations
+ extrinsic to this License (such as a court order or an agreement with a
+ third party).
+
+ However, You may Distribute a Covered Work incorporating material
+ governed by a license that is both OSI-Approved and FSF-Free as of the
+ release date of this License, provided that Your Distribution complies
+ with such other license.
+
+5. Conditions for Distributing Object Code
+
+ You may Distribute an Object Code form of a Covered Work, provided that
+ you accompany the Object Code with a URL through which the Corresponding
+ Source is made available, at no charge, by some standard or customary
+ means of providing network access to source code.
+
+ If you Distribute the Object Code in a physical product or tangible
+ storage medium ("Product"), the Corresponding Source must be available
+ through such URL for two years from the date of Your most recent
+ Distribution of the Object Code in the Product. However, if the Product
+ itself contains or is accompanied by the Corresponding Source (made
+ available in a customarily accessible manner), You need not also comply
+ with the first paragraph of this section.
+
+ Each recipient of the Covered Work from You is an intended third-party
+ beneficiary of this License solely as to this section 5, with the right
+ to enforce its terms.
+
+6. Symmetrical Licensing Condition for Upstream Contributions
+
+ If You Distribute a work to Me specifically for inclusion in or
+ modification of a Covered Work (a "Patch"), and no explicit licensing
+ terms apply to the Patch, You license the Patch under this License, to
+ the extent of Your copyright in the Patch. This condition does not
+ negate the other conditions of this License, if applicable to the Patch.
+
+7. Nullification of Copyleft/Proprietary Dual Licensing
+
+ If I offer to license, for a fee, a Covered Work under terms other than
+ a license that is OSI-Approved or FSF-Free as of the release date of this
+ License or a numbered version of copyleft-next released by the
+ Copyleft-Next Project, then the license I grant You under section 1 is no
+ longer subject to the conditions in sections 2 through 5.
+
+8. Copyleft Sunset
+
+ The conditions in sections 2 through 5 no longer apply once fifteen
+ years have elapsed from the date of My first Distribution of My Work
+ under this License.
+
+9. Pass-Through
+
+ When You Distribute a Covered Work, the recipient automatically receives
+ a license to My Work from Me, subject to the terms of this License.
+
+10. Termination
+
+ Your license grants under section 1 are automatically terminated if You
+
+ a) fail to comply with the conditions of this License, unless You cure
+ such noncompliance within thirty days after becoming aware of it, or
+
+ b) initiate a patent infringement litigation claim (excluding
+ declaratory judgment actions, counterclaims, and cross-claims)
+ alleging that any part of My Work directly or indirectly infringes
+ any patent.
+
+ Termination of Your license grants extends to all copies of Covered
+ Works You subsequently obtain. Termination does not terminate the
+ rights of those who have received copies or rights from You subject to
+ this License.
+
+ To the extent permission to make copies of a Covered Work is necessary
+ merely for running it, such permission is not terminable.
+
+11. Later License Versions
+
+ The Copyleft-Next Project may release new versions of copyleft-next,
+ designated by a distinguishing version number ("Later Versions").
+ Unless I explicitly remove the option of Distributing Covered Works
+ under Later Versions, You may Distribute Covered Works under any Later
+ Version.
+
+** 12. No Warranty **
+** **
+** My Work is provided "as-is", without warranty. You bear the risk **
+** of using it. To the extent permitted by applicable law, each **
+** Distributor of My Work excludes the implied warranties of title, **
+** merchantability, fitness for a particular purpose and **
+** non-infringement. **
+
+** 13. Limitation of Liability **
+** **
+** To the extent permitted by applicable law, in no event will any **
+** Distributor of My Work be liable to You for any damages **
+** whatsoever, whether direct, indirect, special, incidental, or **
+** consequential damages, whether arising under contract, tort **
+** (including negligence), or otherwise, even where the Distributor **
+** knew or should have known about the possibility of such damages. **
+
+14. Severability
+
+ The invalidity or unenforceability of any provision of this License
+ does not affect the validity or enforceability of the remainder of
+ this License. Such provision is to be reformed to the minimum extent
+ necessary to make it valid and enforceable.
+
+15. Definitions
+
+ "Copyleft-Next Project" means the project that maintains the source
+ code repository at <https://gitorious.org/copyleft-next/> as of the
+ release date of this License.
+
+ "Corresponding Source" of a Covered Work in Object Code form means (i)
+ the Source Code form of the Covered Work; (ii) all scripts,
+ instructions and similar information that are reasonably necessary for
+ a skilled developer to generate such Object Code from the Source Code
+ provided under (i); and (iii) a list clearly identifying all Separate
+ Works (other than those provided in compliance with (ii)) that were
+ specifically used in building and (if applicable) installing the
+ Covered Work (for example, a specified proprietary compiler including
+ its version number). Corresponding Source must be machine-readable.
+
+ "Covered Work" means My Work or a Derived Work.
+
+ "Derived Work" means a work of authorship that copies from, modifies,
+ adapts, is based on, is a derivative work of, transforms, translates or
+ contains all or part of My Work, such that copyright permission is
+ required. The following are not Derived Works: (i) Mere Aggregation;
+ (ii) a mere reproduction of My Work; and (iii) if My Work fails to
+ explicitly state an expectation otherwise, a work that merely makes
+ reference to My Work.
+
+ "Distribute" means to distribute, transfer or make a copy available to
+ someone else, such that copyright permission is required.
+
+ "Distributor" means Me and anyone else who Distributes a Covered Work.
+
+ "FSF-Free" means classified as 'free' by the Free Software Foundation.
+
+ "GPL" means a version of the GNU General Public License or the GNU
+ Affero General Public License.
+
+ "I"/"Me"/"My" refers to the individual or legal entity that places My
+ Work under this License. "You"/"Your" refers to the individual or legal
+ entity exercising rights in My Work under this License. A legal entity
+ includes each entity that controls, is controlled by, or is under
+ common control with such legal entity. "Control" means (a) the power to
+ direct the actions of such legal entity, whether by contract or
+ otherwise, or (b) ownership of more than fifty percent of the
+ outstanding shares or beneficial ownership of such legal entity.
+
+ "Licensed Patents" means all patent claims licensable royalty-free by
+ Me, now or in the future, that are necessarily infringed by making,
+ using, or selling My Work, and excludes claims that would be infringed
+ only as a consequence of further modification of My Work.
+
+ "Mere Aggregation" means an aggregation of a Covered Work with a
+ Separate Work.
+
+ "My Work" means the particular work of authorship I license to You
+ under this License.
+
+ "Object Code" means any form of a work that is not Source Code.
+
+ "OSI-Approved" means approved as 'Open Source' by the Open Source
+ Initiative.
+
+ "Separate Work" means a work that is separate from and independent of a
+ particular Covered Work and is not by its nature an extension or
+ enhancement of the Covered Work, and/or a runtime library, standard
+ library or similar component that is used to generate an Object Code
+ form of a Covered Work.
+
+ "Source Code" means the preferred form of a work for making
+ modifications to it.
--
1.8.4.rc3
^ permalink raw reply related
* [PATCH 2/6] crda: fix -pedantic gcc compilation
From: Luis R. Rodriguez @ 2013-10-28 1:52 UTC (permalink / raw)
To: linux-wireless; +Cc: wireless-regdb, Luis R. Rodriguez
In-Reply-To: <1382925182-7393-1-git-send-email-mcgrof@do-not-panic.com>
gcc likes to complain about this, fix that as we're
going to get a bit more anal with code here soon as
we're moving towards making a library out of reglib.
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
---
crda.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/crda.c b/crda.c
index 2a601eb..4751a39 100644
--- a/crda.c
+++ b/crda.c
@@ -141,13 +141,15 @@ int main(int argc, char **argv)
{
int fd = -1;
int i = 0, j, r;
- char alpha2[3] = {}; /* NUL-terminate */
+ char alpha2[3];
char *env_country;
struct nl80211_state nlstate;
struct nl_cb *cb = NULL;
struct nl_msg *msg;
int finished = 0;
+ memset(alpha2, 0, 3);
+
struct nlattr *nl_reg_rules;
const struct ieee80211_regdomain *rd = NULL;
--
1.8.4.rc3
^ permalink raw reply related
* [PATCH 3/6] crda: add regulatory domain stream parser
From: Luis R. Rodriguez @ 2013-10-28 1:52 UTC (permalink / raw)
To: linux-wireless; +Cc: wireless-regdb, Luis R. Rodriguez
In-Reply-To: <1382925182-7393-1-git-send-email-mcgrof@do-not-panic.com>
This adds a stream parser for regulatory domains. This
allows developers to build regulatory domains now using
the db.txt from a stream, either stdin, or a from an
opened file.
This also adds a simple db2rd which for now only uses the
library but with a bit of effort can also be used as a
suitable replacement for the kernel's genregdb.awk.
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
---
Makefile | 10 +-
db2rd.c | 30 ++++
reglib.c | 539 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
reglib.h | 44 ++++++
4 files changed, 621 insertions(+), 2 deletions(-)
create mode 100644 db2rd.c
diff --git a/Makefile b/Makefile
index 7d2e33f..bd9c220 100644
--- a/Makefile
+++ b/Makefile
@@ -24,10 +24,11 @@ PUBKEY_DIR?=pubkeys
RUNTIME_PUBKEY_DIR?=/etc/wireless-regdb/pubkeys
CFLAGS += -Wall -g
+LDLIBS += -lm
all: all_noverify verify
-all_noverify: crda intersect regdbdump
+all_noverify: crda intersect regdbdump db2rd
ifeq ($(USE_OPENSSL),1)
CFLAGS += -DUSE_OPENSSL -DPUBKEY_DIR=\"$(RUNTIME_PUBKEY_DIR)\" `pkg-config --cflags openssl`
@@ -121,6 +122,10 @@ intersect: reglib.o intersect.o
$(NQ) ' LD ' $@
$(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+db2rd: reglib.o db2rd.o
+ $(NQ) ' LD ' $@
+ $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+
verify: $(REG_BIN) regdbdump
$(NQ) ' CHK $(REG_BIN)'
$(Q)./regdbdump $(REG_BIN) >/dev/null
@@ -152,5 +157,6 @@ install: crda crda.8.gz regdbdump.8.gz
$(Q)$(INSTALL) -m 644 -t $(DESTDIR)/$(MANDIR)/man8/ regdbdump.8.gz
clean:
- $(Q)rm -f crda regdbdump intersect *.o *~ *.pyc keys-*.c *.gz \
+ $(Q)rm -f crda regdbdump intersect db2rd \
+ *.o *~ *.pyc keys-*.c *.gz \
udev/$(UDEV_LEVEL)regulatory.rules udev/regulatory.rules.parsed
diff --git a/db2rd.c b/db2rd.c
new file mode 100644
index 0000000..fe6f55b
--- /dev/null
+++ b/db2rd.c
@@ -0,0 +1,30 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <arpa/inet.h> /* ntohl */
+#include <string.h>
+
+#include "nl80211.h"
+#include "reglib.h"
+
+int main(int argc, char **argv)
+{
+ struct ieee80211_regdomain *rd = NULL;
+ FILE *fp;
+
+ if (argc != 1) {
+ fprintf(stderr, "Usage: cat db.txt | %s\n", argv[0]);
+ return -EINVAL;
+ }
+
+ fp = reglib_create_parse_stream(stdin);
+
+ reglib_for_each_country_stream(fp, rd) {
+ reglib_print_regdom(rd);
+ free(rd);
+ }
+
+ fclose(fp);
+
+ return 0;
+}
diff --git a/reglib.c b/reglib.c
index b0c61e5..0793fab 100644
--- a/reglib.c
+++ b/reglib.c
@@ -38,6 +38,19 @@
#include "keys-gcrypt.c"
#endif
+int debug = 0;
+
+struct reglib_rule_parse_list {
+ int n_parsers;
+ int (*rule_parsers[])(char *line, struct ieee80211_reg_rule *reg_rule);
+};
+
+struct reglib_country_parse_list {
+ int n_parsers;
+ int (*country_parsers[])(char *line, struct ieee80211_regdomain *rd);
+};
+
+
void *
reglib_get_file_ptr(uint8_t *db, size_t dblen, size_t structlen, uint32_t ptr)
{
@@ -707,3 +720,529 @@ void reglib_print_regdom(const struct ieee80211_regdomain *rd)
print_reg_rule(&rd->reg_rules[i]);
printf("\n");
}
+
+static unsigned int reglib_parse_dfs_region(char *dfs_region)
+{
+ if (strncmp(dfs_region, "DFS-FCC", 7) == 0)
+ return REGDB_DFS_FCC;
+ if (strncmp(dfs_region, "DFS-ETSI", 8) == 0)
+ return REGDB_DFS_ETSI;
+ if (strncmp(dfs_region, "DFS-JP", 6) == 0)
+ return REGDB_DFS_JP;
+ return REGDB_DFS_UNSET;
+}
+
+static uint32_t reglib_parse_rule_flag(char *flag_s)
+{
+ if (strncmp(flag_s, "NO-OFDM", 7) == 0)
+ return RRF_NO_OFDM;
+ if (strncmp(flag_s, "NO-CCK", 6) == 0)
+ return RRF_NO_CCK;
+ if (strncmp(flag_s, "NO-INDOOR", 9) == 0)
+ return RRF_NO_INDOOR;
+ if (strncmp(flag_s, "NO-OUTDOOR", 10) == 0)
+ return RRF_NO_OUTDOOR;
+ if (strncmp(flag_s, "DFS", 3) == 0)
+ return RRF_DFS;
+ if (strncmp(flag_s, "PTP-ONLY", 8) == 0)
+ return RRF_PTP_ONLY;
+ if (strncmp(flag_s, "PTMP-ONLY", 9) == 0)
+ return RRF_PTMP_ONLY;
+ if (strncmp(flag_s, "NO-IR", 5) == 0)
+ return RRF_NO_IR;
+
+ return 0;
+}
+
+static int
+reglib_parse_rule_simple(char *line, struct ieee80211_reg_rule *reg_rule)
+{
+ int hits;
+ float start_freq_khz, end_freq_khz, max_bandwidth_khz, max_eirp;
+
+ hits = sscanf(line, "\t(%f - %f @ %f), (%f)\n",
+ &start_freq_khz,
+ &end_freq_khz,
+ &max_bandwidth_khz,
+ &max_eirp);
+
+ if (hits != 4)
+ return -EINVAL;
+
+ reg_rule->freq_range.start_freq_khz =
+ REGLIB_MHZ_TO_KHZ(start_freq_khz);
+ reg_rule->freq_range.end_freq_khz =
+ REGLIB_MHZ_TO_KHZ(end_freq_khz);
+ reg_rule->freq_range.max_bandwidth_khz =
+ REGLIB_MHZ_TO_KHZ(max_bandwidth_khz);
+ reg_rule->power_rule.max_eirp =
+ REGLIB_DBM_TO_MBM(max_eirp);
+
+ reg_rule->flags = 0;
+
+ if (debug)
+ printf("reglib_parse_rule_simple(): %d line: %s", hits, line);
+
+
+ return 0;
+}
+
+static int
+reglib_parse_rule_simple_mw(char *line, struct ieee80211_reg_rule *reg_rule)
+{
+ int hits;
+ float start_freq_khz, end_freq_khz, max_bandwidth_khz, max_eirp;
+ char mw[3];
+
+ hits = sscanf(line, "\t(%f - %f @ %f), (%f %2[mW])\n",
+ &start_freq_khz,
+ &end_freq_khz,
+ &max_bandwidth_khz,
+ &max_eirp, mw);
+
+ if (hits != 4)
+ return -EINVAL;
+
+
+ reg_rule->freq_range.start_freq_khz =
+ REGLIB_MHZ_TO_KHZ(start_freq_khz);
+ reg_rule->freq_range.end_freq_khz =
+ REGLIB_MHZ_TO_KHZ(end_freq_khz);
+ reg_rule->freq_range.max_bandwidth_khz =
+ REGLIB_MHZ_TO_KHZ(max_bandwidth_khz);
+ reg_rule->power_rule.max_eirp =
+ REGLIB_MW_TO_MBM(max_eirp);
+
+ reg_rule->flags = 0;
+
+ if (debug)
+ printf("reglib_parse_rule_simple_mw(): %d line: %s",
+ hits, line);
+
+ return 0;
+}
+
+static int
+reglib_parse_rule_args(char *line, struct ieee80211_reg_rule *reg_rule)
+{
+#define IGNORE_COMMA_OR_SPACE "%*[ ,]"
+ int hits;
+ char flag_list[9][100];
+ unsigned int i = 0;
+ float start_freq_khz, end_freq_khz, max_bandwidth_khz, max_eirp;
+
+ for (i = 0; i < 9; i++)
+ memset(flag_list[i], 0, sizeof(flag_list[i]));
+
+ hits = sscanf(line, "\t(%f - %f @ %f), (%f)"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s",
+ &start_freq_khz,
+ &end_freq_khz,
+ &max_bandwidth_khz,
+ &max_eirp,
+ flag_list[0],
+ flag_list[1],
+ flag_list[2],
+ flag_list[3],
+ flag_list[4],
+ flag_list[5],
+ flag_list[6],
+ flag_list[7],
+ flag_list[8]);
+
+ if (hits < 5)
+ return -EINVAL;
+
+ reg_rule->freq_range.start_freq_khz =
+ REGLIB_MHZ_TO_KHZ(start_freq_khz);
+ reg_rule->freq_range.end_freq_khz =
+ REGLIB_MHZ_TO_KHZ(end_freq_khz);
+ reg_rule->freq_range.max_bandwidth_khz =
+ REGLIB_MHZ_TO_KHZ(max_bandwidth_khz);
+ reg_rule->power_rule.max_eirp =
+ REGLIB_DBM_TO_MBM(max_eirp);
+
+ for (i = 0; i < 8; i++)
+ reg_rule->flags |= reglib_parse_rule_flag(flag_list[i]);
+
+ if (debug)
+ printf("reglib_parse_rule_args(): %d flags: %d, line: %s",
+ hits, reg_rule->flags, line);
+
+ return 0;
+#undef IGNORE_COMMA_OR_SPACE
+}
+
+
+static int
+reglib_parse_rule_args_mw(char *line, struct ieee80211_reg_rule *reg_rule)
+{
+#define IGNORE_COMMA_OR_SPACE "%*[ ,]"
+ int hits;
+ char flag_list[9][100];
+ unsigned int i = 0;
+ char mw[3];
+ float start_freq_khz, end_freq_khz, max_bandwidth_khz, max_eirp;
+
+ for (i = 0; i < 9; i++)
+ memset(flag_list[i], 0, sizeof(flag_list[i]));
+
+ hits = sscanf(line, "\t(%f - %f @ %f), (%f %2[mW])"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s"
+ IGNORE_COMMA_OR_SPACE "%s",
+ &start_freq_khz,
+ &end_freq_khz,
+ &max_bandwidth_khz,
+ &max_eirp,
+ mw,
+ flag_list[0],
+ flag_list[1],
+ flag_list[2],
+ flag_list[3],
+ flag_list[4],
+ flag_list[5],
+ flag_list[6],
+ flag_list[7],
+ flag_list[8]);
+
+ if (hits < 5)
+ return -EINVAL;
+
+ reg_rule->freq_range.start_freq_khz =
+ REGLIB_MHZ_TO_KHZ(start_freq_khz);
+ reg_rule->freq_range.end_freq_khz =
+ REGLIB_MHZ_TO_KHZ(end_freq_khz);
+ reg_rule->freq_range.max_bandwidth_khz =
+ REGLIB_MHZ_TO_KHZ(max_bandwidth_khz);
+ reg_rule->power_rule.max_eirp =
+ REGLIB_MW_TO_MBM(max_eirp);
+
+ for (i = 0; i < 8; i++)
+ reg_rule->flags |= reglib_parse_rule_flag(flag_list[i]);
+
+ if (debug)
+ printf("reglib_parse_rule_args_mw(): %d flags: %d, line: %s",
+ hits, reg_rule->flags, line);
+ return 0;
+#undef IGNORE_COMMA_OR_SPACE
+}
+
+static int reglib_parse_rule(FILE *fp, struct ieee80211_reg_rule *reg_rule)
+{
+ char line[1024];
+ char *line_p;
+ unsigned int i;
+ int r = 0;
+ struct reglib_rule_parse_list *reglib_rule_parsers;
+
+ reglib_rule_parsers = malloc(sizeof(struct reglib_rule_parse_list) +
+ 4 * sizeof(int (*)(char *, struct ieee80211_reg_rule *)));
+ if (!reglib_rule_parsers)
+ return -EINVAL;
+
+ reglib_rule_parsers->n_parsers = 4;
+
+ /*
+ * XXX: sscanf() is a bit odd with picking up mW
+ * case over the simple one, this order however works,
+ * gotta figure out how to be more precise.
+ */
+ reglib_rule_parsers->rule_parsers[0] = reglib_parse_rule_args_mw;
+ reglib_rule_parsers->rule_parsers[1] = reglib_parse_rule_args;
+ reglib_rule_parsers->rule_parsers[2] = reglib_parse_rule_simple;
+ reglib_rule_parsers->rule_parsers[3] = reglib_parse_rule_simple_mw;
+
+ memset(line, 0, sizeof(line));
+ line_p = fgets(line, sizeof(line), fp);
+ if (line_p != line)
+ return -EINVAL;
+
+ for (i = 0; i < reglib_rule_parsers->n_parsers; i++) {
+ r = reglib_rule_parsers->rule_parsers[i](line, reg_rule);
+ if (r == 0)
+ break;
+ }
+
+ return r;
+}
+
+static uint32_t
+reglib_get_n_rules(FILE *fp, struct ieee80211_reg_rule *reg_rule)
+{
+ uint32_t n_rules = 0;
+ int r;
+ bool save_debug = false;
+
+ save_debug = debug;
+ debug = false;
+
+ while (1) {
+ r = reglib_parse_rule(fp, reg_rule);
+ if (r != 0)
+ break;
+ n_rules++;
+ }
+
+ debug = save_debug;
+
+ return n_rules;
+}
+
+static int reglib_parse_reg_rule(FILE *fp, struct ieee80211_reg_rule *reg_rule)
+{
+ int r;
+
+ while (1) {
+ r = reglib_parse_rule(fp, reg_rule);
+ if (r != 0)
+ continue;
+ return 0;
+ }
+}
+
+static struct ieee80211_regdomain *
+reglib_parse_rules(FILE *fp, struct ieee80211_regdomain *trd)
+{
+ struct ieee80211_regdomain *rd;
+ struct ieee80211_reg_rule rule;
+ struct ieee80211_reg_rule *reg_rule;
+ fpos_t pos;
+ unsigned int i;
+ uint32_t size_of_regd = 0, num_rules = 0;
+ int r;
+
+ memset(&rule, 0, sizeof(rule));
+ reg_rule = &rule;
+
+ r = fgetpos(fp, &pos);
+ if (r != 0) {
+ fprintf(stderr, "fgetpos() failed: %s\n",
+ strerror(errno));
+ return NULL;
+ }
+
+ num_rules = reglib_get_n_rules(fp, reg_rule);
+ if (!num_rules)
+ return NULL;
+
+ size_of_regd = reglib_array_len(sizeof(struct ieee80211_regdomain),
+ num_rules + 1,
+ sizeof(struct ieee80211_reg_rule));
+ rd = malloc(size_of_regd);
+ if (!rd)
+ return NULL;
+
+ memset(rd, 0, size_of_regd);
+ memcpy(rd, trd, sizeof(*trd));
+
+ rd->n_reg_rules = num_rules;
+
+ r = fsetpos(fp, &pos);
+ if (r != 0) {
+ fprintf(stderr, "fsetpos() failed: %s\n",
+ strerror(errno));
+ free(rd);
+ return NULL;
+ }
+ for (i = 0; i < num_rules; i++) {
+ struct ieee80211_reg_rule *rrule = &rd->reg_rules[i];
+
+ if (reglib_parse_reg_rule(fp, rrule) != 0) {
+ fprintf(stderr, "rule parse failed\n");
+ free(rd);
+ return NULL;
+ }
+ }
+ return rd;
+}
+
+static int
+reglib_parse_country_simple(char *line, struct ieee80211_regdomain *rd)
+{
+ char dfs_region_alpha[9];
+ char alpha2[2];
+ int hits;
+
+ memset(rd, 0, sizeof(rd));
+ memset(alpha2, 0, sizeof(alpha2));
+ memset(dfs_region_alpha, 0, sizeof(dfs_region_alpha));
+
+ hits = sscanf(line, "country %2[a-zA-Z0-9]:",
+ alpha2);
+
+ if (hits != 1)
+ return -EINVAL;
+
+ rd->alpha2[0] = alpha2[0];
+ rd->alpha2[1] = alpha2[1];
+
+ return 0;
+}
+
+static int reglib_parse_country_dfs(char *line, struct ieee80211_regdomain *rd)
+{
+ char dfs_region_alpha[9];
+ char alpha2[2];
+ int hits;
+
+ memset(rd, 0, sizeof(rd));
+ memset(alpha2, 0, sizeof(alpha2));
+ memset(dfs_region_alpha, 0, sizeof(dfs_region_alpha));
+
+ hits = sscanf(line, "country %2[a-zA-Z0-9]:%*[ ]%s\n",
+ alpha2,
+ dfs_region_alpha);
+ if (hits <= 0)
+ return -EINVAL;
+
+ if (hits != 2)
+ return -EINVAL;
+
+
+ rd->alpha2[0] = alpha2[0];
+ rd->alpha2[1] = alpha2[1];
+ rd->dfs_region = reglib_parse_dfs_region(dfs_region_alpha);
+
+ return 0;
+}
+
+struct ieee80211_regdomain *__reglib_parse_country(FILE *fp)
+{
+ struct ieee80211_regdomain *rd;
+ struct ieee80211_regdomain tmp_rd;
+ char line[1024];
+ char *line_p;
+ unsigned int i;
+ int r = 0;
+ struct reglib_country_parse_list *reglib_country_parsers;
+
+ reglib_country_parsers = malloc(sizeof(struct reglib_country_parse_list) +
+ 2 * sizeof(int (*)(char *, struct ieee80211_regdomain *)));
+ if (!reglib_country_parsers)
+ return NULL;
+
+ reglib_country_parsers->n_parsers = 2;
+ reglib_country_parsers->country_parsers[0] =
+ reglib_parse_country_simple;
+ reglib_country_parsers->country_parsers[1] =
+ reglib_parse_country_dfs;
+
+ memset(&tmp_rd, 0, sizeof(tmp_rd));
+ memset(line, 0, sizeof(line));
+
+ line_p = fgets(line, sizeof(line), fp);
+
+ if (line_p != line)
+ return NULL;
+
+ for (i = 0; i < reglib_country_parsers->n_parsers; i++) {
+ r = reglib_country_parsers->country_parsers[i](line, &tmp_rd);
+ if (r == 0)
+ break;
+ }
+
+ if (r != 0) {
+ fprintf(stderr, "Invalid country line: %s", line);
+ return NULL;
+ }
+
+ rd = reglib_parse_rules(fp, &tmp_rd);
+
+ return rd;
+}
+
+static int reglib_find_next_country_stream(FILE *fp)
+{
+ fpos_t prev_pos;
+ int r;
+ unsigned int i = 0;
+
+ while(1) {
+ char line[1024];
+ char *line_p;
+
+ r = fgetpos(fp, &prev_pos);
+ if (r != 0) {
+ fprintf(stderr, "fgetpos() failed: %s\n",
+ strerror(errno));
+ return r;
+ }
+
+ memset(line, 0, sizeof(line));
+
+ line_p = fgets(line, sizeof(line), fp);
+ if (line_p == line) {
+ if (strspn(line, "\n") == strlen(line)) {
+ i++;
+ continue;
+ }
+ if (strncmp(line, "country", 7) != 0)
+ continue;
+ r = fsetpos(fp, &prev_pos);
+ if (r != 0) {
+ fprintf(stderr, "fsetpos() failed: %s\n",
+ strerror(errno));
+ return r;
+ }
+ return 0;
+ } else
+ return EOF;
+ }
+}
+
+struct ieee80211_regdomain *reglib_parse_country(FILE *fp)
+{
+ int r;
+
+ r = reglib_find_next_country_stream(fp);
+ if (r != 0)
+ return NULL;
+ return __reglib_parse_country(fp);
+}
+
+FILE *reglib_create_parse_stream(FILE *f)
+{
+ unsigned int lines = 0;
+ FILE *fp;
+
+ fp = tmpfile();
+ if (errno) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ return NULL;
+ }
+
+ while(1) {
+ char line[1024];
+ char *line_p;
+
+ line_p = fgets(line, sizeof(line), f);
+ if (line_p == line) {
+ if (strchr(line, '#') == NULL) {
+ fputs(line, fp);
+ lines++;
+ }
+ continue;
+ } else
+ break;
+ }
+
+ rewind(fp);
+ fflush(fp);
+
+ return fp;
+}
diff --git a/reglib.h b/reglib.h
index 7a586a3..885792e 100644
--- a/reglib.h
+++ b/reglib.h
@@ -1,10 +1,12 @@
#ifndef REG_LIB_H
#define REG_LIB_H
+#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/stat.h>
+#include <math.h>
#include "regdb.h"
@@ -35,6 +37,19 @@ struct ieee80211_regdomain {
struct ieee80211_reg_rule reg_rules[];
};
+/* Remove this once upstream nl80211.h gets this */
+#define NL80211_RRF_NO_IR (1<<7)
+
+#define REGLIB_MHZ_TO_KHZ(freq) ((freq) * 1000)
+#define REGLIB_KHZ_TO_MHZ(freq) ((freq) / 1000)
+#define REGLIB_DBI_TO_MBI(gain) ((gain) * 100)
+#define REGLIB_MBI_TO_DBI(gain) ((gain) / 100)
+#define REGLIB_DBM_TO_MBM(gain) ((gain) * 100)
+#define REGLIB_MBM_TO_DBM(gain) ((gain) / 100)
+
+#define REGLIB_MW_TO_DBM(gain) (10 * log10(gain))
+#define REGLIB_MW_TO_MBM(gain) (REGLIB_DBM_TO_MBM(REGLIB_MW_TO_DBM(gain)))
+
/**
* struct reglib_regdb_ctx - reglib regdb context
*
@@ -180,4 +195,33 @@ reglib_intersect_rds(const struct ieee80211_regdomain *rd1,
const struct ieee80211_regdomain *
reglib_intersect_regdb(const struct reglib_regdb_ctx *ctx);
+/**
+ * @reglib_create_parse_stream - provide a clean new stream for processing
+ *
+ * @fp: FILE stream, could be stdin, or a stream from an open file.
+ *
+ * In order to parse a stream we recommend to create a new stream
+ * using this helper. A new stream is preferred in order to work
+ * with stdin, as otherwise we cannot rewind() and move around
+ * the stream. This helper will create new stream using tmpfile()
+ * and also remove all comments. It will be closed and the file
+ * deleted when the process terminates.
+ */
+FILE *reglib_create_parse_stream(FILE *fp);
+
+/**
+ * @reglib_parse_country - parse stream to build a regulatory domain
+ *
+ * @fp: FILE stream, could be stdin, or a stream from an open file.
+ *
+ * Parse stream and return back a built regulatory domain. Returns
+ * NULL if one could not be built.
+ */
+struct ieee80211_regdomain *reglib_parse_country(FILE *fp);
+
+#define reglib_for_each_country_stream(__fp, __rd) \
+ for (__rd = reglib_parse_country(__fp); \
+ __rd != NULL; \
+ __rd = reglib_parse_country(__fp)) \
+
#endif
--
1.8.4.rc3
^ permalink raw reply related
* [PATCH 4/6] crda: add regulatory domain optimizer
From: Luis R. Rodriguez @ 2013-10-28 1:53 UTC (permalink / raw)
To: linux-wireless; +Cc: wireless-regdb, Luis R. Rodriguez
In-Reply-To: <1382925182-7393-1-git-send-email-mcgrof@do-not-panic.com>
This adds a regulatory domain optimizer which can be
used with information of a regulatory domain in db.txt
format in stdin. It makes use of the new shiny regulatory
domain stream parser.
The way this works is it iterates over the regulatory domain
computing unions between each frequency, starting from each
frequency as a pivot. If a union leads to a valid regulatory
rule we verify that the pivot and othre frequency rules that
provided that valid union can fit into that union regulatory
rule by computing an intersection. If an intersection is
possible it means two rules can be optimized out. We do
this repetitively.
Screenshot:
mcgrof@frijol ~/devel/crda (git::master)$ cat us
country US: DFS-FCC
(5170 - 5190 @ 20), (17)
(5190 - 5210 @ 20), (17)
(5210 - 5230 @ 20), (17)
(5230 - 5250 @ 20), (17)
(5250 - 5270 @ 20), (23), DFS
(5270 - 5290 @ 20), (23), DFS
(5290 - 5310 @ 20), (23), DFS
(5310 - 5330 @ 20), (23), DFS
(5735 - 5755 @ 20), (30)
(5755 - 5775 @ 20), (30)
(5775 - 5795 @ 20), (30)
(5795 - 5815 @ 20), (30)
(5815 - 5835 @ 20), (30)
(5170 - 5210 @ 40), (17)
(5210 - 5250 @ 40), (17)
(5250 - 5290 @ 40), (23), DFS
(5290 - 5330 @ 40), (23), DFS
(5735 - 5775 @ 40), (30)
(5775 - 5815 @ 40), (30)
(5170 - 5250 @ 80), (17)
(5250 - 5330 @ 80), (23), DFS
(5735 - 5815 @ 80), (30)
mcgrof@frijol ~/devel/crda (git::master)$ cat us | ./optimize
country US: DFS-UNSET
(5170.000 - 5250.000 @ 80.000), (17.00)
(5250.000 - 5330.000 @ 80.000), (23.00), DFS
(5735.000 - 5835.000 @ 80.000), (30.00)
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
---
Makefile | 8 +-
optimize.c | 38 ++++++++++
reglib.c | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
reglib.h | 16 ++++
4 files changed, 311 insertions(+), 2 deletions(-)
create mode 100644 optimize.c
diff --git a/Makefile b/Makefile
index bd9c220..9e37ccd 100644
--- a/Makefile
+++ b/Makefile
@@ -28,7 +28,7 @@ LDLIBS += -lm
all: all_noverify verify
-all_noverify: crda intersect regdbdump db2rd
+all_noverify: crda intersect regdbdump db2rd optimize
ifeq ($(USE_OPENSSL),1)
CFLAGS += -DUSE_OPENSSL -DPUBKEY_DIR=\"$(RUNTIME_PUBKEY_DIR)\" `pkg-config --cflags openssl`
@@ -126,6 +126,10 @@ db2rd: reglib.o db2rd.o
$(NQ) ' LD ' $@
$(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+optimize: reglib.o optimize.o
+ $(NQ) ' LD ' $@
+ $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+
verify: $(REG_BIN) regdbdump
$(NQ) ' CHK $(REG_BIN)'
$(Q)./regdbdump $(REG_BIN) >/dev/null
@@ -157,6 +161,6 @@ install: crda crda.8.gz regdbdump.8.gz
$(Q)$(INSTALL) -m 644 -t $(DESTDIR)/$(MANDIR)/man8/ regdbdump.8.gz
clean:
- $(Q)rm -f crda regdbdump intersect db2rd \
+ $(Q)rm -f crda regdbdump intersect db2rd optimize \
*.o *~ *.pyc keys-*.c *.gz \
udev/$(UDEV_LEVEL)regulatory.rules udev/regulatory.rules.parsed
diff --git a/optimize.c b/optimize.c
new file mode 100644
index 0000000..c87371d
--- /dev/null
+++ b/optimize.c
@@ -0,0 +1,38 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <arpa/inet.h> /* ntohl */
+#include <string.h>
+
+#include "nl80211.h"
+#include "reglib.h"
+
+int main(int argc, char **argv)
+{
+ struct ieee80211_regdomain *rd = NULL, *rd_opt = NULL;
+ FILE *fp;
+
+ if (argc != 1) {
+ fprintf(stderr, "Usage: cat db.txt | %s\n", argv[0]);
+ return -EINVAL;
+ }
+
+ fp = reglib_create_parse_stream(stdin);
+
+ reglib_for_each_country_stream(fp, rd) {
+ rd_opt = reglib_optimize_regdom(rd);
+ if (!rd_opt){
+ fprintf(stderr, "Unable to optimize %c%c\n",
+ rd->alpha2[0],
+ rd->alpha2[1]);
+ free(rd);
+ continue;
+ }
+ reglib_print_regdom(rd_opt);
+ free(rd);
+ free(rd_opt);
+ }
+
+ fclose(fp);
+ return 0;
+}
diff --git a/reglib.c b/reglib.c
index 0793fab..ae4b017 100644
--- a/reglib.c
+++ b/reglib.c
@@ -459,6 +459,43 @@ int reglib_is_valid_rd(const struct ieee80211_regdomain *rd)
return 1;
}
+static int reg_rules_union(const struct ieee80211_reg_rule *rule1,
+ const struct ieee80211_reg_rule *rule2,
+ struct ieee80211_reg_rule *union_rule)
+{
+ const struct ieee80211_freq_range *freq_range1, *freq_range2;
+ struct ieee80211_freq_range *freq_range;
+ const struct ieee80211_power_rule *power_rule1, *power_rule2;
+ struct ieee80211_power_rule *power_rule;
+
+ freq_range1 = &rule1->freq_range;
+ freq_range2 = &rule2->freq_range;
+ freq_range = &union_rule->freq_range;
+
+ power_rule1 = &rule1->power_rule;
+ power_rule2 = &rule2->power_rule;
+ power_rule = &union_rule->power_rule;
+
+ freq_range->start_freq_khz = reglib_min(freq_range1->start_freq_khz,
+ freq_range2->start_freq_khz);
+ freq_range->end_freq_khz = reglib_max(freq_range1->end_freq_khz,
+ freq_range2->end_freq_khz);
+ freq_range->max_bandwidth_khz = reglib_max(freq_range1->max_bandwidth_khz,
+ freq_range2->max_bandwidth_khz);
+
+ power_rule->max_eirp = reglib_max(power_rule1->max_eirp,
+ power_rule2->max_eirp);
+ power_rule->max_antenna_gain = reglib_max(power_rule1->max_antenna_gain,
+ power_rule2->max_antenna_gain);
+
+ union_rule->flags = rule1->flags | rule2->flags;
+
+ if (!is_valid_reg_rule(union_rule))
+ return -EINVAL;
+
+ return 0;
+}
+
/*
* Helper for reglib_intersect_rds(), this does the real
* mathematical intersection fun
@@ -1246,3 +1283,217 @@ FILE *reglib_create_parse_stream(FILE *f)
return fp;
}
+
+/*
+ * The idea behind a rule key is that if two rule keys share the
+ * same key they can be merged together if their frequencies overlap.
+ */
+static uint64_t reglib_rule_key(struct ieee80211_reg_rule *reg_rule)
+{
+ struct ieee80211_power_rule *power_rule;
+ uint32_t key;
+
+ power_rule = ®_rule->power_rule;
+
+ key = ((power_rule->max_eirp ^ 0) << 0) ^
+ ((reg_rule->flags ^ 8) << 8);
+
+ return key;
+}
+
+/* XXX: cannot support > 32 rules */
+struct reglib_optimize_map {
+ bool optimized[32];
+ uint32_t keys[32];
+};
+
+/* Does the provided rule suffice both of the other two */
+static int reglib_opt_rule_fit(struct ieee80211_reg_rule *rule1,
+ struct ieee80211_reg_rule *rule2,
+ struct ieee80211_reg_rule *opt_rule)
+{
+ struct ieee80211_reg_rule interesected_rule;
+ struct ieee80211_reg_rule *int_rule;
+ int r;
+
+ memset(&interesected_rule, 0, sizeof(struct ieee80211_reg_rule));
+ int_rule = &interesected_rule;
+
+ r = reg_rules_intersect(rule1, opt_rule, int_rule);
+ if (r != 0)
+ return r;
+ r = reg_rules_intersect(rule2, opt_rule, int_rule);
+ if (r != 0)
+ return r;
+
+ return 0;
+}
+
+static int reg_rule_optimize(struct ieee80211_reg_rule *rule1,
+ struct ieee80211_reg_rule *rule2,
+ struct ieee80211_reg_rule *opt_rule)
+{
+ int r;
+
+ r = reg_rules_union(rule1, rule2, opt_rule);
+ if (r != 0)
+ return r;
+ r = reglib_opt_rule_fit(rule1, rule2, opt_rule);
+ if (r != 0)
+ return r;
+
+ return 0;
+}
+
+/*
+ * Here's the math explanation:
+ *
+ * This takes each pivot frequency on the regulatory domain, computes
+ * the union between it each regulatory rule on the regulatory domain
+ * sequentially, and after that it tries to verify that the pivot frequency
+ * fits on it by computing an intersection between it and the union, if
+ * a rule exist as a possible intersection then we know the rule can be
+ * subset of the combination of the two frequency ranges (union) computed.
+ */
+static unsigned int reg_rule_optimize_rd(struct ieee80211_regdomain *rd,
+ unsigned int rule_idx,
+ struct ieee80211_reg_rule *opt_rule,
+ struct reglib_optimize_map *opt_map)
+{
+ unsigned int i;
+ struct ieee80211_reg_rule *rule1;
+ struct ieee80211_reg_rule *rule2;
+
+ struct ieee80211_reg_rule tmp_optimized_rule;
+ struct ieee80211_reg_rule *tmp_opt_rule;
+
+ struct ieee80211_reg_rule *target_rule;
+
+ unsigned int optimized = 0;
+ int r;
+
+ if (rule_idx > rd->n_reg_rules)
+ return 0;
+
+ rule1 = &rd->reg_rules[rule_idx];
+
+ memset(&tmp_optimized_rule, 0, sizeof(struct ieee80211_reg_rule));
+ tmp_opt_rule = &tmp_optimized_rule;
+
+ memset(opt_rule, 0, sizeof(*opt_rule));
+
+ for (i = 0; i < rd->n_reg_rules; i++) {
+ if (rule_idx == i)
+ continue;
+ rule2 = &rd->reg_rules[i];
+ if (opt_map->keys[rule_idx] != opt_map->keys[i])
+ continue;
+
+ target_rule = optimized ? opt_rule : rule1;
+ r = reg_rule_optimize(target_rule, rule2, tmp_opt_rule);
+ if (r != 0)
+ continue;
+ memcpy(opt_rule, tmp_opt_rule, sizeof(*tmp_opt_rule));
+
+ if (!opt_map->optimized[i]) {
+ opt_map->optimized[i] = true;
+ optimized++;
+ }
+ if (!opt_map->optimized[rule_idx]) {
+ opt_map->optimized[rule_idx] = true;
+ optimized++;
+ }
+ }
+ return optimized;
+}
+
+struct ieee80211_regdomain *
+reglib_optimize_regdom(struct ieee80211_regdomain *rd)
+{
+ struct ieee80211_regdomain *opt_rd = NULL;
+ struct ieee80211_reg_rule *reg_rule;
+ struct ieee80211_reg_rule *reg_rule_dst;
+ struct ieee80211_reg_rule optimized_reg_rule;
+ struct ieee80211_reg_rule *opt_reg_rule;
+ struct reglib_optimize_map opt_map;
+ unsigned int i, idx = 0, non_opt = 0, opt = 0;
+ size_t num_rules, size_of_regd;
+ unsigned int num_opts = 0;
+
+ memset(&opt_map, 0, sizeof(struct reglib_optimize_map));
+ memset(&optimized_reg_rule, 0, sizeof(struct ieee80211_reg_rule));
+
+ opt_reg_rule = &optimized_reg_rule;
+
+ for (i = 0; i < rd->n_reg_rules; i++) {
+ reg_rule = &rd->reg_rules[i];
+ opt_map.keys[i] = reglib_rule_key(reg_rule);
+ }
+ for (i = 0; i < rd->n_reg_rules; i++) {
+ reg_rule = &rd->reg_rules[i];
+ if (opt_map.optimized[i])
+ continue;
+ num_opts = reg_rule_optimize_rd(rd, i, opt_reg_rule, &opt_map);
+ if (!num_opts)
+ non_opt++;
+ else
+ opt += (num_opts ? 1 : 0);
+ }
+
+ num_rules = non_opt + opt;
+
+ if (num_rules > rd->n_reg_rules)
+ return NULL;
+
+ size_of_regd = reglib_array_len(sizeof(struct ieee80211_regdomain),
+ num_rules + 1,
+ sizeof(struct ieee80211_reg_rule));
+
+ opt_rd = malloc(size_of_regd);
+ if (!opt_rd)
+ return NULL;
+ memset(opt_rd, 0, size_of_regd);
+
+ opt_rd->n_reg_rules = num_rules;
+ opt_rd->alpha2[0] = rd->alpha2[0];
+ opt_rd->alpha2[1] = rd->alpha2[1];
+ opt_rd->dfs_region = rd->dfs_region;
+
+ memset(&opt_map, 0, sizeof(struct reglib_optimize_map));
+ memset(&optimized_reg_rule, 0, sizeof(struct ieee80211_reg_rule));
+
+ opt_reg_rule = &optimized_reg_rule;
+
+ for (i = 0; i < rd->n_reg_rules; i++) {
+ reg_rule = &rd->reg_rules[i];
+ opt_map.keys[i] = reglib_rule_key(reg_rule);
+ }
+
+ for (i = 0; i < rd->n_reg_rules; i++) {
+ reg_rule = &rd->reg_rules[i];
+ reg_rule_dst = &opt_rd->reg_rules[idx];
+ if (opt_map.optimized[i])
+ continue;
+ num_opts = reg_rule_optimize_rd(rd, i, opt_reg_rule, &opt_map);
+ if (!num_opts)
+ memcpy(reg_rule_dst, reg_rule, sizeof(struct ieee80211_reg_rule));
+ else
+ memcpy(reg_rule_dst, opt_reg_rule, sizeof(struct ieee80211_reg_rule));
+ idx++;
+ }
+
+ if (idx != num_rules) {
+ free(opt_rd);
+ return NULL;
+ }
+
+ for (i = 0; i < opt_rd->n_reg_rules; i++) {
+ reg_rule = &opt_rd->reg_rules[i];
+ if (!is_valid_reg_rule(reg_rule)) {
+ free(opt_rd);
+ return NULL;
+ }
+ }
+
+ return opt_rd;
+}
diff --git a/reglib.h b/reglib.h
index 885792e..d570c36 100644
--- a/reglib.h
+++ b/reglib.h
@@ -219,6 +219,22 @@ FILE *reglib_create_parse_stream(FILE *fp);
*/
struct ieee80211_regdomain *reglib_parse_country(FILE *fp);
+/**
+ * @reglib_optimize_regdom - optimize a regulatory domain
+ *
+ * @rd: a regulatory domain to be optimized
+ *
+ * A regulatory domain may exist without optimal expressions
+ * over its rules. This will look for regulatory rules that can
+ * be combined together to reduce the size of the regulatory
+ * domain and its expression.
+ *
+ * Regulatory rules will be combined if their max allowed
+ * bandwidth, max EIRP, and flags all match.
+ */
+struct ieee80211_regdomain *
+reglib_optimize_regdom(struct ieee80211_regdomain *rd);
+
#define reglib_for_each_country_stream(__fp, __rd) \
for (__rd = reglib_parse_country(__fp); \
__rd != NULL; \
--
1.8.4.rc3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox