Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH 8/8] iwlwifi: greenfield support only true for 11n devices
From: Reinette Chatre @ 2010-04-30 23:00 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Wey-Yi Guy, Reinette Chatre
In-Reply-To: <1272668425-3753-1-git-send-email-reinette.chatre@intel.com>

From: Wey-Yi Guy <wey-yi.w.guy@intel.com>

Greenfield is a 11n feature, remove it from non-11n devices
configuration parameters list

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/iwl-1000.c |    1 -
 drivers/net/wireless/iwlwifi/iwl-6000.c |    3 ---
 2 files changed, 0 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 8431ffc..fb59af2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -282,7 +282,6 @@ struct iwl_cfg iwl1000_bg_cfg = {
 	.use_bsm = false,
 	.max_ll_items = OTP_MAX_LL_ITEMS_1000,
 	.shadow_ram_support = false,
-	.ht_greenfield_support = true,
 	.led_compensation = 51,
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.support_ct_kill_exit = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index c492650..7acef70 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -500,7 +500,6 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
 	.pa_type = IWL_PA_INTERNAL,
 	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
 	.shadow_ram_support = true,
-	.ht_greenfield_support = true,
 	.led_compensation = 51,
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.supports_idle = true,
@@ -533,7 +532,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
 	.pa_type = IWL_PA_INTERNAL,
 	.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
 	.shadow_ram_support = true,
-	.ht_greenfield_support = true,
 	.led_compensation = 51,
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.supports_idle = true,
@@ -600,7 +598,6 @@ struct iwl_cfg iwl6050_2abg_cfg = {
 	.pa_type = IWL_PA_SYSTEM,
 	.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
 	.shadow_ram_support = true,
-	.ht_greenfield_support = true,
 	.led_compensation = 51,
 	.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
 	.supports_idle = true,
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 5/8] iwl3945: add ucode statistics
From: Reinette Chatre @ 2010-04-30 23:00 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, ipw3945-devel, Abhijeet Kolekar, Reinette Chatre
In-Reply-To: <1272668425-3753-1-git-send-email-reinette.chatre@intel.com>

From: Abhijeet Kolekar <abhijeet.kolekar@intel.com>

Add general, rx and tx uCode statistics to 3945. This will help
in debugging

Signed-off-by: Abhijeet Kolekar <abhijeet.kolekar@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
 drivers/net/wireless/iwlwifi/Makefile           |    1 +
 drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c |  500 +++++++++++++++++++++++
 drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h |   60 +++
 drivers/net/wireless/iwlwifi/iwl-3945.c         |   72 ++++-
 drivers/net/wireless/iwlwifi/iwl-3945.h         |    2 +
 drivers/net/wireless/iwlwifi/iwl-debugfs.c      |   18 +-
 drivers/net/wireless/iwlwifi/iwl-dev.h          |    5 +
 drivers/net/wireless/iwlwifi/iwl3945-base.c     |    2 +-
 8 files changed, 646 insertions(+), 14 deletions(-)
 create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
 create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h

diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 5ed2dcb..7c72353 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -22,5 +22,6 @@ iwlagn-$(CONFIG_IWL5000) += iwl-1000.o
 # 3945
 obj-$(CONFIG_IWL3945)	+= iwl3945.o
 iwl3945-objs		:= iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o
+iwl3945-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-3945-debugfs.o
 
 ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
new file mode 100644
index 0000000..6a9c64a
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
@@ -0,0 +1,500 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+#include "iwl-3945-debugfs.h"
+
+ssize_t iwl3945_ucode_rx_stats_read(struct file *file,
+				    char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0;
+	char *buf;
+	int bufsz = sizeof(struct iwl39_statistics_rx_phy) * 40 +
+		    sizeof(struct iwl39_statistics_rx_non_phy) * 40 + 400;
+	ssize_t ret;
+	struct iwl39_statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
+	struct iwl39_statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
+	struct iwl39_statistics_rx_non_phy *general, *accum_general;
+	struct iwl39_statistics_rx_non_phy *delta_general, *max_general;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf) {
+		IWL_ERR(priv, "Can not allocate Buffer\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * The statistic information display here is based on
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+	ofdm = &priv->_3945.statistics.rx.ofdm;
+	cck = &priv->_3945.statistics.rx.cck;
+	general = &priv->_3945.statistics.rx.general;
+	accum_ofdm = &priv->_3945.accum_statistics.rx.ofdm;
+	accum_cck = &priv->_3945.accum_statistics.rx.cck;
+	accum_general = &priv->_3945.accum_statistics.rx.general;
+	delta_ofdm = &priv->_3945.delta_statistics.rx.ofdm;
+	delta_cck = &priv->_3945.delta_statistics.rx.cck;
+	delta_general = &priv->_3945.delta_statistics.rx.general;
+	max_ofdm = &priv->_3945.max_delta.rx.ofdm;
+	max_cck = &priv->_3945.max_delta.rx.cck;
+	max_general = &priv->_3945.max_delta.rx.general;
+
+	pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+	pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+			 "acumulative       delta         max\n",
+			 "Statistics_Rx - OFDM:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "ina_cnt:", le32_to_cpu(ofdm->ina_cnt),
+			 accum_ofdm->ina_cnt,
+			 delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "fina_cnt:",
+			 le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
+			 delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n", "plcp_err:",
+			 le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
+			 delta_ofdm->plcp_err, max_ofdm->plcp_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",  "crc32_err:",
+			 le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
+			 delta_ofdm->crc32_err, max_ofdm->crc32_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n", "overrun_err:",
+			 le32_to_cpu(ofdm->overrun_err),
+			 accum_ofdm->overrun_err, delta_ofdm->overrun_err,
+			 max_ofdm->overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "early_overrun_err:",
+			 le32_to_cpu(ofdm->early_overrun_err),
+			 accum_ofdm->early_overrun_err,
+			 delta_ofdm->early_overrun_err,
+			 max_ofdm->early_overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "crc32_good:", le32_to_cpu(ofdm->crc32_good),
+			 accum_ofdm->crc32_good, delta_ofdm->crc32_good,
+			 max_ofdm->crc32_good);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n", "false_alarm_cnt:",
+			 le32_to_cpu(ofdm->false_alarm_cnt),
+			 accum_ofdm->false_alarm_cnt,
+			 delta_ofdm->false_alarm_cnt,
+			 max_ofdm->false_alarm_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "fina_sync_err_cnt:",
+			 le32_to_cpu(ofdm->fina_sync_err_cnt),
+			 accum_ofdm->fina_sync_err_cnt,
+			 delta_ofdm->fina_sync_err_cnt,
+			 max_ofdm->fina_sync_err_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "sfd_timeout:",
+			 le32_to_cpu(ofdm->sfd_timeout),
+			 accum_ofdm->sfd_timeout,
+			 delta_ofdm->sfd_timeout,
+			 max_ofdm->sfd_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "fina_timeout:",
+			 le32_to_cpu(ofdm->fina_timeout),
+			 accum_ofdm->fina_timeout,
+			 delta_ofdm->fina_timeout,
+			 max_ofdm->fina_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "unresponded_rts:",
+			 le32_to_cpu(ofdm->unresponded_rts),
+			 accum_ofdm->unresponded_rts,
+			 delta_ofdm->unresponded_rts,
+			 max_ofdm->unresponded_rts);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "rxe_frame_lmt_ovrun:",
+			 le32_to_cpu(ofdm->rxe_frame_limit_overrun),
+			 accum_ofdm->rxe_frame_limit_overrun,
+			 delta_ofdm->rxe_frame_limit_overrun,
+			 max_ofdm->rxe_frame_limit_overrun);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "sent_ack_cnt:",
+			 le32_to_cpu(ofdm->sent_ack_cnt),
+			 accum_ofdm->sent_ack_cnt,
+			 delta_ofdm->sent_ack_cnt,
+			 max_ofdm->sent_ack_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "sent_cts_cnt:",
+			 le32_to_cpu(ofdm->sent_cts_cnt),
+			 accum_ofdm->sent_cts_cnt,
+			 delta_ofdm->sent_cts_cnt, max_ofdm->sent_cts_cnt);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+			 "acumulative       delta         max\n",
+			 "Statistics_Rx - CCK:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "ina_cnt:",
+			 le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
+			 delta_cck->ina_cnt, max_cck->ina_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "fina_cnt:",
+			 le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
+			 delta_cck->fina_cnt, max_cck->fina_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "plcp_err:",
+			 le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
+			 delta_cck->plcp_err, max_cck->plcp_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "crc32_err:",
+			 le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
+			 delta_cck->crc32_err, max_cck->crc32_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "overrun_err:",
+			 le32_to_cpu(cck->overrun_err),
+			 accum_cck->overrun_err,
+			 delta_cck->overrun_err, max_cck->overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "early_overrun_err:",
+			 le32_to_cpu(cck->early_overrun_err),
+			 accum_cck->early_overrun_err,
+			 delta_cck->early_overrun_err,
+			 max_cck->early_overrun_err);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "crc32_good:",
+			 le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
+			 delta_cck->crc32_good,
+			 max_cck->crc32_good);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "false_alarm_cnt:",
+			 le32_to_cpu(cck->false_alarm_cnt),
+			 accum_cck->false_alarm_cnt,
+			 delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "fina_sync_err_cnt:",
+			 le32_to_cpu(cck->fina_sync_err_cnt),
+			 accum_cck->fina_sync_err_cnt,
+			 delta_cck->fina_sync_err_cnt,
+			 max_cck->fina_sync_err_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "sfd_timeout:",
+			 le32_to_cpu(cck->sfd_timeout),
+			 accum_cck->sfd_timeout,
+			 delta_cck->sfd_timeout, max_cck->sfd_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "fina_timeout:",
+			 le32_to_cpu(cck->fina_timeout),
+			 accum_cck->fina_timeout,
+			 delta_cck->fina_timeout, max_cck->fina_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "unresponded_rts:",
+			 le32_to_cpu(cck->unresponded_rts),
+			 accum_cck->unresponded_rts,
+			 delta_cck->unresponded_rts,
+			 max_cck->unresponded_rts);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "rxe_frame_lmt_ovrun:",
+			 le32_to_cpu(cck->rxe_frame_limit_overrun),
+			 accum_cck->rxe_frame_limit_overrun,
+			 delta_cck->rxe_frame_limit_overrun,
+			 max_cck->rxe_frame_limit_overrun);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "sent_ack_cnt:",
+			 le32_to_cpu(cck->sent_ack_cnt),
+			 accum_cck->sent_ack_cnt,
+			 delta_cck->sent_ack_cnt,
+			 max_cck->sent_ack_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "sent_cts_cnt:",
+			 le32_to_cpu(cck->sent_cts_cnt),
+			 accum_cck->sent_cts_cnt,
+			 delta_cck->sent_cts_cnt,
+			 max_cck->sent_cts_cnt);
+
+	pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+			 "acumulative       delta         max\n",
+			 "Statistics_Rx - GENERAL:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "bogus_cts:",
+			 le32_to_cpu(general->bogus_cts),
+			 accum_general->bogus_cts,
+			 delta_general->bogus_cts, max_general->bogus_cts);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "bogus_ack:",
+			 le32_to_cpu(general->bogus_ack),
+			 accum_general->bogus_ack,
+			 delta_general->bogus_ack, max_general->bogus_ack);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "non_bssid_frames:",
+			 le32_to_cpu(general->non_bssid_frames),
+			 accum_general->non_bssid_frames,
+			 delta_general->non_bssid_frames,
+			 max_general->non_bssid_frames);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "filtered_frames:",
+			 le32_to_cpu(general->filtered_frames),
+			 accum_general->filtered_frames,
+			 delta_general->filtered_frames,
+			 max_general->filtered_frames);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "non_channel_beacons:",
+			 le32_to_cpu(general->non_channel_beacons),
+			 accum_general->non_channel_beacons,
+			 delta_general->non_channel_beacons,
+			 max_general->non_channel_beacons);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+ssize_t iwl3945_ucode_tx_stats_read(struct file *file,
+				    char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0;
+	char *buf;
+	int bufsz = (sizeof(struct iwl39_statistics_tx) * 48) + 250;
+	ssize_t ret;
+	struct iwl39_statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf) {
+		IWL_ERR(priv, "Can not allocate Buffer\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * The statistic information display here is based on
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+	tx = &priv->_3945.statistics.tx;
+	accum_tx = &priv->_3945.accum_statistics.tx;
+	delta_tx = &priv->_3945.delta_statistics.tx;
+	max_tx = &priv->_3945.max_delta.tx;
+	pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+	pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+			 "acumulative       delta         max\n",
+			 "Statistics_Tx:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "preamble:",
+			 le32_to_cpu(tx->preamble_cnt),
+			 accum_tx->preamble_cnt,
+			 delta_tx->preamble_cnt, max_tx->preamble_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "rx_detected_cnt:",
+			 le32_to_cpu(tx->rx_detected_cnt),
+			 accum_tx->rx_detected_cnt,
+			 delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "bt_prio_defer_cnt:",
+			 le32_to_cpu(tx->bt_prio_defer_cnt),
+			 accum_tx->bt_prio_defer_cnt,
+			 delta_tx->bt_prio_defer_cnt,
+			 max_tx->bt_prio_defer_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "bt_prio_kill_cnt:",
+			 le32_to_cpu(tx->bt_prio_kill_cnt),
+			 accum_tx->bt_prio_kill_cnt,
+			 delta_tx->bt_prio_kill_cnt,
+			 max_tx->bt_prio_kill_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "few_bytes_cnt:",
+			 le32_to_cpu(tx->few_bytes_cnt),
+			 accum_tx->few_bytes_cnt,
+			 delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "cts_timeout:",
+			 le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
+			 delta_tx->cts_timeout, max_tx->cts_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "ack_timeout:",
+			 le32_to_cpu(tx->ack_timeout),
+			 accum_tx->ack_timeout,
+			 delta_tx->ack_timeout, max_tx->ack_timeout);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "expected_ack_cnt:",
+			 le32_to_cpu(tx->expected_ack_cnt),
+			 accum_tx->expected_ack_cnt,
+			 delta_tx->expected_ack_cnt,
+			 max_tx->expected_ack_cnt);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "actual_ack_cnt:",
+			 le32_to_cpu(tx->actual_ack_cnt),
+			 accum_tx->actual_ack_cnt,
+			 delta_tx->actual_ack_cnt,
+			 max_tx->actual_ack_cnt);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+ssize_t iwl3945_ucode_general_stats_read(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = file->private_data;
+	int pos = 0;
+	char *buf;
+	int bufsz = sizeof(struct iwl39_statistics_general) * 10 + 300;
+	ssize_t ret;
+	struct iwl39_statistics_general *general, *accum_general;
+	struct iwl39_statistics_general *delta_general, *max_general;
+	struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
+	struct iwl39_statistics_div *div, *accum_div, *delta_div, *max_div;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf) {
+		IWL_ERR(priv, "Can not allocate Buffer\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * The statistic information display here is based on
+	 * the last statistics notification from uCode
+	 * might not reflect the current uCode activity
+	 */
+	general = &priv->_3945.statistics.general;
+	dbg = &priv->_3945.statistics.general.dbg;
+	div = &priv->_3945.statistics.general.div;
+	accum_general = &priv->_3945.accum_statistics.general;
+	delta_general = &priv->_3945.delta_statistics.general;
+	max_general = &priv->_3945.max_delta.general;
+	accum_dbg = &priv->_3945.accum_statistics.general.dbg;
+	delta_dbg = &priv->_3945.delta_statistics.general.dbg;
+	max_dbg = &priv->_3945.max_delta.general.dbg;
+	accum_div = &priv->_3945.accum_statistics.general.div;
+	delta_div = &priv->_3945.delta_statistics.general.div;
+	max_div = &priv->_3945.max_delta.general.div;
+	pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+	pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+			 "acumulative       delta         max\n",
+			 "Statistics_General:");
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "burst_check:",
+			 le32_to_cpu(dbg->burst_check),
+			 accum_dbg->burst_check,
+			 delta_dbg->burst_check, max_dbg->burst_check);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "burst_count:",
+			 le32_to_cpu(dbg->burst_count),
+			 accum_dbg->burst_count,
+			 delta_dbg->burst_count, max_dbg->burst_count);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "sleep_time:",
+			 le32_to_cpu(general->sleep_time),
+			 accum_general->sleep_time,
+			 delta_general->sleep_time, max_general->sleep_time);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "slots_out:",
+			 le32_to_cpu(general->slots_out),
+			 accum_general->slots_out,
+			 delta_general->slots_out, max_general->slots_out);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "slots_idle:",
+			 le32_to_cpu(general->slots_idle),
+			 accum_general->slots_idle,
+			 delta_general->slots_idle, max_general->slots_idle);
+	pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n",
+			 le32_to_cpu(general->ttl_timestamp));
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "tx_on_a:",
+			 le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
+			 delta_div->tx_on_a, max_div->tx_on_a);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "tx_on_b:",
+			 le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
+			 delta_div->tx_on_b, max_div->tx_on_b);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "exec_time:",
+			 le32_to_cpu(div->exec_time), accum_div->exec_time,
+			 delta_div->exec_time, max_div->exec_time);
+	pos += scnprintf(buf + pos, bufsz - pos,
+			 "  %-30s %10u  %10u  %10u  %10u\n",
+			 "probe_time:",
+			 le32_to_cpu(div->probe_time), accum_div->probe_time,
+			 delta_div->probe_time, max_div->probe_time);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h
new file mode 100644
index 0000000..70809c5
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-debug.h"
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ssize_t iwl3945_ucode_rx_stats_read(struct file *file, char __user *user_buf,
+				    size_t count, loff_t *ppos);
+ssize_t iwl3945_ucode_tx_stats_read(struct file *file, char __user *user_buf,
+				    size_t count, loff_t *ppos);
+ssize_t iwl3945_ucode_general_stats_read(struct file *file,
+					 char __user *user_buf, size_t count,
+					 loff_t *ppos);
+#else
+static ssize_t iwl3945_ucode_rx_stats_read(struct file *file,
+					   char __user *user_buf, size_t count,
+					   loff_t *ppos)
+{
+	return 0;
+}
+static ssize_t iwl3945_ucode_tx_stats_read(struct file *file,
+					   char __user *user_buf, size_t count,
+					   loff_t *ppos)
+{
+	return 0;
+}
+static ssize_t iwl3945_ucode_general_stats_read(struct file *file,
+						char __user *user_buf,
+						size_t count, loff_t *ppos)
+{
+	return 0;
+}
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index d10e59d..9dad867 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -49,6 +49,7 @@
 #include "iwl-helpers.h"
 #include "iwl-led.h"
 #include "iwl-3945-led.h"
+#include "iwl-3945-debugfs.h"
 
 #define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \
 	[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,   \
@@ -292,7 +293,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
  * iwl3945_rx_reply_tx - Handle Tx response
  */
 static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
-			    struct iwl_rx_mem_buffer *rxb)
+				struct iwl_rx_mem_buffer *rxb)
 {
 	struct iwl_rx_packet *pkt = rxb_addr(rxb);
 	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
@@ -350,18 +351,81 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
  *  RX handler implementations
  *
  *****************************************************************************/
+#ifdef CONFIG_IWLWIFI_DEBUG
+/*
+ *  based on the assumption of all statistics counter are in DWORD
+ *  FIXME: This function is for debugging, do not deal with
+ *  the case of counters roll-over.
+ */
+static void iwl3945_accumulative_statistics(struct iwl_priv *priv,
+					    __le32 *stats)
+{
+	int i;
+	__le32 *prev_stats;
+	u32 *accum_stats;
+	u32 *delta, *max_delta;
+
+	prev_stats = (__le32 *)&priv->_3945.statistics;
+	accum_stats = (u32 *)&priv->_3945.accum_statistics;
+	delta = (u32 *)&priv->_3945.delta_statistics;
+	max_delta = (u32 *)&priv->_3945.max_delta;
+
+	for (i = sizeof(__le32); i < sizeof(struct iwl3945_notif_statistics);
+	     i += sizeof(__le32), stats++, prev_stats++, delta++,
+	     max_delta++, accum_stats++) {
+		if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
+			*delta = (le32_to_cpu(*stats) -
+				le32_to_cpu(*prev_stats));
+			*accum_stats += *delta;
+			if (*delta > *max_delta)
+				*max_delta = *delta;
+		}
+	}
+
+	/* reset accumulative statistics for "no-counter" type statistics */
+	priv->_3945.accum_statistics.general.temperature =
+		priv->_3945.statistics.general.temperature;
+	priv->_3945.accum_statistics.general.ttl_timestamp =
+		priv->_3945.statistics.general.ttl_timestamp;
+}
+#endif
 
 void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
 		struct iwl_rx_mem_buffer *rxb)
 {
 	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
 	IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
 		     (int)sizeof(struct iwl3945_notif_statistics),
 		     le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
+#ifdef CONFIG_IWLWIFI_DEBUG
+	iwl3945_accumulative_statistics(priv, (__le32 *)&pkt->u.raw);
+#endif
 
 	memcpy(&priv->_3945.statistics, pkt->u.raw, sizeof(priv->_3945.statistics));
 }
 
+void iwl3945_reply_statistics(struct iwl_priv *priv,
+			      struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	__le32 *flag = (__le32 *)&pkt->u.raw;
+
+	if (le32_to_cpu(*flag) & UCODE_STATISTICS_CLEAR_MSK) {
+#ifdef CONFIG_IWLWIFI_DEBUG
+		memset(&priv->_3945.accum_statistics, 0,
+			sizeof(struct iwl3945_notif_statistics));
+		memset(&priv->_3945.delta_statistics, 0,
+			sizeof(struct iwl3945_notif_statistics));
+		memset(&priv->_3945.max_delta, 0,
+			sizeof(struct iwl3945_notif_statistics));
+#endif
+		IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
+	}
+	iwl3945_hw_rx_statistics(priv, rxb);
+}
+
+
 /******************************************************************************
  *
  * Misc. internal state and helper functions
@@ -2735,6 +2799,12 @@ static struct iwl_lib_ops iwl3945_lib = {
 	.isr = iwl_isr_legacy,
 	.config_ap = iwl3945_config_ap,
 	.add_bcast_station = iwl3945_add_bcast_station,
+
+	.debugfs_ops = {
+		.rx_stats_read = iwl3945_ucode_rx_stats_read,
+		.tx_stats_read = iwl3945_ucode_tx_stats_read,
+		.general_stats_read = iwl3945_ucode_general_stats_read,
+	},
 };
 
 static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index e9674f0..643adb6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -264,6 +264,8 @@ extern int iwl3945_hw_reg_send_txpower(struct iwl_priv *priv);
 extern int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
 extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
 				 struct iwl_rx_mem_buffer *rxb);
+void iwl3945_reply_statistics(struct iwl_priv *priv,
+			      struct iwl_rx_mem_buffer *rxb);
 extern void iwl3945_disable_events(struct iwl_priv *priv);
 extern int iwl4965_get_temperature(const struct iwl_priv *priv);
 extern void iwl3945_post_associate(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index d789f8d..0aedbec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -1053,10 +1053,8 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
 					size_t count, loff_t *ppos)
 {
 	struct iwl_priv *priv = file->private_data;
-	if (priv->cfg->ops->lib->debugfs_ops.rx_stats_read)
-		return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
-						user_buf, count, ppos);
-	return 0;
+	return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
+			user_buf, count, ppos);
 }
 
 static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
@@ -1064,10 +1062,8 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
 					size_t count, loff_t *ppos)
 {
 	struct iwl_priv *priv = file->private_data;
-	if (priv->cfg->ops->lib->debugfs_ops.tx_stats_read)
-		return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
-						user_buf, count, ppos);
-	return 0;
+	return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
+			user_buf, count, ppos);
 }
 
 static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
@@ -1075,10 +1071,8 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
 					size_t count, loff_t *ppos)
 {
 	struct iwl_priv *priv = file->private_data;
-	if (priv->cfg->ops->lib->debugfs_ops.general_stats_read)
-		return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
-						user_buf, count, ppos);
-	return 0;
+	return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
+			user_buf, count, ppos);
 }
 
 static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index bdc60aa..58c69a5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1202,6 +1202,11 @@ struct iwl_priv {
 			struct delayed_work rfkill_poll;
 
 			struct iwl3945_notif_statistics statistics;
+#ifdef CONFIG_IWLWIFI_DEBUG
+			struct iwl3945_notif_statistics accum_statistics;
+			struct iwl3945_notif_statistics delta_statistics;
+			struct iwl3945_notif_statistics max_delta;
+#endif
 
 			u32 sta_supp_rates;
 			int last_rx_rssi;	/* From Rx packet statistics */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 789480b..98055fb 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -956,7 +956,7 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv)
 	 * statistics request from the host as well as for the periodic
 	 * statistics notifications (after received beacons) from the uCode.
 	 */
-	priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics;
+	priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_reply_statistics;
 	priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics;
 
 	iwl_setup_rx_scan_handlers(priv);
-- 
1.6.3.3


^ permalink raw reply related

* Re: [PATCH V2] mac80211: fix paged defragmentation
From: Ben Gamari @ 2010-04-30 23:49 UTC (permalink / raw)
  To: Abhijeet Kolekar, linux-wireless; +Cc: yi.zhu, Abhijeet Kolekar
In-Reply-To: <1272668279-6065-1-git-send-email-abhijeet.kolekar@intel.com>

On Fri, 30 Apr 2010 15:57:59 -0700, Abhijeet Kolekar <abhijeet.kolekar@intel.com> wrote:
> 
> diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
> index 72efbd8..e7217e2 100644
> --- a/net/mac80211/rx.c
> +++ b/net/mac80211/rx.c
> @@ -1255,6 +1255,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
>  	if (skb_linearize(rx->skb))
>  		return RX_DROP_UNUSABLE;
>  
> +	hdr = (struct ieee80211_hdr *)rx->skb->data;
>  	seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
>  
It seems to me that this might deserve a comment describing exactly why
hdr needs to be set twice in one function. To the uninformed outsider
the code simply seems redundant. It's unclear semantics like this that
could cause nasty issues when someone goes back for housecleaning. Just
a thought.

- Ben

^ permalink raw reply

* ar9170-fw
From: David H. Lynch Jr. @ 2010-05-01  0:15 UTC (permalink / raw)
  To: linux-wireless

     I tried to build the toolchain from an uptodate pull of the git 
repository,

     I am getting a sequence of errors when the build reach libssp.

     My guess would be that libssp is not needed for the ar9170 firmware.

     Is this correct and I would appreciate an easy suguestion to 
disable it if so.

make[3]: Entering directory `/usr/src/ar9170-fw/toolchain/build/gcc/sh-elf/libssp'
if/bin/bash ./libtool --tag=CC --mode=compile
/usr/src/ar9170-fw/toolchain/build/gcc/./gcc/xgcc
-B/usr/src/ar9170-fw/toolchain/build/gcc/./gcc/
-B/usr/src/ar9170-fw/toolchain/inst/sh-elf/bin/
-B/usr/src/ar9170-fw/toolchain/inst/sh-elf/lib/  -isystem
/usr/src/ar9170-fw/toolchain/inst/sh-elf/include -isystem
/usr/src/ar9170-fw/toolchain/inst/sh-elf/sys-include -DHAVE_CONFIG_H -I.
-I/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp -I. -Wall -O2 -g -g -O2 -MT
ssp.lo -MD -MP -MF ".deps/ssp.Tpo" -c -o ssp.lo
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c; \
then mv -f ".deps/ssp.Tpo" ".deps/ssp.Plo"; else rm -f ".deps/ssp.Tpo"; exit 1; fi
libtool: compile:/usr/src/ar9170-fw/toolchain/build/gcc/./gcc/xgcc
-B/usr/src/ar9170-fw/toolchain/build/gcc/./gcc/
-B/usr/src/ar9170-fw/toolchain/inst/sh-elf/bin/
-B/usr/src/ar9170-fw/toolchain/inst/sh-elf/lib/  -isystem
/usr/src/ar9170-fw/toolchain/inst/sh-elf/include -isystem
/usr/src/ar9170-fw/toolchain/inst/sh-elf/sys-include -DHAVE_CONFIG_H -I.
-I/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp -I. -Wall -O2 -g -g -O2 -MT
ssp.lo -MD -MP -MF .deps/ssp.Tpo -c
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c -o ssp.o
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c: In function
'__guard_setup':
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:70: warning: implicit
declaration of function 'open'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:70: error: 'O_RDONLY'
undeclared (first use in this function)
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:70: error: (Each
undeclared identifier is reported only once
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:70: error: for each
function it appears in.)
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:73: error: 'ssize_t'
undeclared (first use in this function)
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:73: error: expected ';'
before 'size'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:75: warning: implicit
declaration of function 'close'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:76: error: 'size'
undeclared (first use in this function)
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c: At top level:
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:89: error: expected
declaration specifiers or '...' before 'size_t'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c: In function 'fail':
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:100: error: 'O_WRONLY'
undeclared (first use in this function)
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:104: error: 'size_t'
undeclared (first use in this function)
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:104: error: expected ';'
before 'progname_len'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:107: error:
'progname_len' undeclared (first use in this function)
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:107: warning: implicit
declaration of function 'strlen'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:107: warning:
incompatible implicit declaration of built-in function 'strlen'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:108: error: 'len'
undeclared (first use in this function)
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:108: error: 'msg1len'
undeclared (first use in this function)
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:109: warning: implicit
declaration of function 'alloca'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:109: warning:
incompatible implicit declaration of built-in function 'alloca'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:111: warning: implicit
declaration of function 'memcpy'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:111: warning:
incompatible implicit declaration of built-in function 'memcpy'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:119: error: 'ssize_t'
undeclared (first use in this function)
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:119: error: expected ';'
before 'wrote'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:120: error: 'wrote'
undeclared (first use in this function)
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:151: warning: implicit
declaration of function '_exit'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:151: warning:
incompatible implicit declaration of built-in function '_exit'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c: In function
'__stack_chk_fail':
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:161: warning:
incompatible implicit declaration of built-in function 'strlen'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:161: warning: passing
argument 2 of 'fail' makes pointer from integer without a cast
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:161: error: too many
arguments to function 'fail'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c: In function '__chk_fail':
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:168: warning:
incompatible implicit declaration of built-in function 'strlen'
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:168: warning: passing
argument 2 of 'fail' makes pointer from integer without a cast
/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:168: error: too many
arguments to function 'fail'
make[3]: *** [ssp.lo] Error 1
make[3]: Leaving directory `/usr/src/ar9170-fw/toolchain/build/gcc/sh-elf/libssp'
make[2]: *** [install-target-libssp] Error 2
make[2]: Leaving directory `/usr/src/ar9170-fw/toolchain/build/gcc'
make[1]: *** [install] Error 2
make[1]: Leaving directory `/usr/src/ar9170-fw/toolchain/build/gcc'
make: *** [gcc] Error 2





-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.587.7774 	       dhlii@dlasys.net 	  http://www.dlasys.net
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein


^ permalink raw reply

* Re: ar9170-fw
From: Stefan Lippers-Hollmann @ 2010-05-01  1:23 UTC (permalink / raw)
  To: David H. Lynch Jr.; +Cc: linux-wireless
In-Reply-To: <4BDB72AA.7000203@dlasys.net>

Hi

On Saturday 01 May 2010, David H. Lynch Jr. wrote:
>      I tried to build the toolchain from an uptodate pull of the git 
> repository,
> 
>      I am getting a sequence of errors when the build reach libssp.
> 
>      My guess would be that libssp is not needed for the ar9170 firmware.
> 
>      Is this correct and I would appreciate an easy suguestion to 
> disable it if so.
> 
> make[3]: Entering directory `/usr/src/ar9170-fw/toolchain/build/gcc/sh-elf/libssp'
[...]
> -I/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp -I. -Wall -O2 -g -g -O2 -MT
> ssp.lo -MD -MP -MF .deps/ssp.Tpo -c
> /usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c -o ssp.o
> /usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c: In function
> '__guard_setup':
> /usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:70: warning: implicit
> declaration of function 'open'
> /usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:70: error: 'O_RDONLY'
> undeclared (first use in this function)
[...]

I assume your host's /bin/sh is not bash.

---------------------------------------------------------------------------

ar9170.fw: fix bashisms while building the cross toolchain.

Signed-off-by: Stefan Lippers-Hollmann <s.l-h@gmx.de>

--- a/toolchain/Makefile
+++ b/toolchain/Makefile
@@ -31,7 +31,8 @@ src/newlib-$(NEWLIB_VER): src/$(NEWLIB_T
 
 src/gcc-$(GCC_VER): src/$(GCC_TAR) src/newlib-$(NEWLIB_VER)
 	tar -C src -xjf $<
-	ln -s $(BASEDIR)/src/newlib-$(NEWLIB_VER)/{newlib,libgloss} $@
+	ln -s $(BASEDIR)/src/newlib-$(NEWLIB_VER)/newlib $@
+	ln -s $(BASEDIR)/src/newlib-$(NEWLIB_VER)/libgloss $@
 
 binutils: src/binutils-$(BINUTILS_VER)
 	mkdir -p build/binutils

---------------------------------------------------------------------------

While you're at it, I'd suggest to bump the versions for the required 
cross-build environment as well, as it noticably improves stability of the 
firmware images built by it (still not perfectly, but better).

---------------------------------------------------------------------------

ar9170.fw: update cross-toolchain.

Updating the toolchain improves stability of the built firmware images 
significantly.

* gcc-4.4.4
* binutils-2.20.1
* newlib 1.18.0

Signed-off-by: Stefan Lippers-Hollmann <s.l-h@gmx.de>

--- a/toolchain/Makefile
+++ b/toolchain/Makefile
@@ -1,12 +1,12 @@
-BINUTILS_VER=2.19.1
+BINUTILS_VER=2.20.1
 BINUTILS_URL=http://mirrors.kernel.org/gnu/binutils/binutils-$(BINUTILS_VER).tar.bz2
 BINUTILS_TAR=binutils-$(BINUTILS_VER).tar.bz2
 
-NEWLIB_VER=1.17.0
+NEWLIB_VER=1.18.0
 NEWLIB_URL=ftp://sources.redhat.com/pub/newlib/newlib-$(NEWLIB_VER).tar.gz
 NEWLIB_TAR=newlib-$(NEWLIB_VER).tar.gz
 
-GCC_VER=4.3.3
+GCC_VER=4.4.4
 GCC_URL=http://mirrors.kernel.org/gnu/gcc/gcc-$(GCC_VER)/gcc-core-$(GCC_VER).tar.bz2
 GCC_TAR=gcc-core-$(GCC_VER).tar.bz2
 
---------------------------------------------------------------------------

Regards
	Stefan Lippers-Hollmann

^ permalink raw reply

* Re: wl1251_sdio PSM
From: Kalle Valo @ 2010-05-01  5:19 UTC (permalink / raw)
  To: GNUtoo; +Cc: linux-wireless
In-Reply-To: <1272230300.2349.23.camel@gnutoo-desktop>

GNUtoo <GNUtoo@no-log.org> writes:

> Hi,

Hi Mr. GNUtoo,

> We are trying to make the htc dream(also known as G1) android phone
> usable with a standard GNU(non android) userland.

I'm interested about this. Are there any references about this? For
example, instructions how to install etc.

-- 
Kalle Valo

^ permalink raw reply

* Re: ar9170-fw
From: Johannes Berg @ 2010-05-01  5:43 UTC (permalink / raw)
  To: Stefan Lippers-Hollmann; +Cc: David H. Lynch Jr., linux-wireless
In-Reply-To: <201005010323.53295.s.L-H@gmx.de>

Hi,

> >      I tried to build the toolchain from an uptodate pull of the git 
> > repository,

Not sure if that's still my repository, but


> ar9170.fw: fix bashisms while building the cross toolchain.

> ar9170.fw: update cross-toolchain.

I applied both your patches to it.

johannes


^ permalink raw reply

* Re: ar9170-fw
From: David H. Lynch Jr. @ 2010-05-01  8:38 UTC (permalink / raw)
  To: Stefan Lippers-Hollmann; +Cc: linux-wireless
In-Reply-To: <201005010323.53295.s.L-H@gmx.de>

On 04/30/2010 09:23 PM, Stefan Lippers-Hollmann wrote:
> Hi
>
> I assume your host's /bin/sh is not bash.
>    
ubuntu default

ls -al /bin/sh
lrwxrwxrwx 1 root root 4 2010-04-02 01:25 sh -> dash

I have bumped into similar problems with buildroot.

Is there a serious downside to linking /bin/sh to bash ?

> ---------------------------------------------------------------------------
>
> ar9170.fw: fix bashisms while building the cross toolchain.
>
> Signed-off-by: Stefan Lippers-Hollmann<s.l-h@gmx.de>
>
> --- a/toolchain/Makefile
> +++ b/toolchain/Makefile
> @@ -31,7 +31,8 @@ src/newlib-$(NEWLIB_VER): src/$(NEWLIB_T
>
>   src/gcc-$(GCC_VER): src/$(GCC_TAR) src/newlib-$(NEWLIB_VER)
>   	tar -C src -xjf $<
> -	ln -s $(BASEDIR)/src/newlib-$(NEWLIB_VER)/{newlib,libgloss} $@
> +	ln -s $(BASEDIR)/src/newlib-$(NEWLIB_VER)/newlib $@
> +	ln -s $(BASEDIR)/src/newlib-$(NEWLIB_VER)/libgloss $@
>
>   binutils: src/binutils-$(BINUTILS_VER)
>   	mkdir -p build/binutils
>
> ---------------------------------------------------------------------------
>
> While you're at it, I'd suggest to bump the versions for the required
> cross-build environment as well, as it noticably improves stability of the
> firmware images built by it (still not perfectly, but better).
>
> ---------------------------------------------------------------------------
>
> ar9170.fw: update cross-toolchain.
>
> Updating the toolchain improves stability of the built firmware images
> significantly.
>
> * gcc-4.4.4
> * binutils-2.20.1
> * newlib 1.18.0
>
> Signed-off-by: Stefan Lippers-Hollmann<s.l-h@gmx.de>
>
> --- a/toolchain/Makefile
> +++ b/toolchain/Makefile
> @@ -1,12 +1,12 @@
> -BINUTILS_VER=2.19.1
> +BINUTILS_VER=2.20.1
>   BINUTILS_URL=http://mirrors.kernel.org/gnu/binutils/binutils-$(BINUTILS_VER).tar.bz2
>   BINUTILS_TAR=binutils-$(BINUTILS_VER).tar.bz2
>
> -NEWLIB_VER=1.17.0
> +NEWLIB_VER=1.18.0
>   NEWLIB_URL=ftp://sources.redhat.com/pub/newlib/newlib-$(NEWLIB_VER).tar.gz
>   NEWLIB_TAR=newlib-$(NEWLIB_VER).tar.gz
>
> -GCC_VER=4.3.3
> +GCC_VER=4.4.4
>   GCC_URL=http://mirrors.kernel.org/gnu/gcc/gcc-$(GCC_VER)/gcc-core-$(GCC_VER).tar.bz2
>   GCC_TAR=gcc-core-$(GCC_VER).tar.bz2
>
> ---------------------------------------------------------------------------
>
> Regards
> 	Stefan Lippers-Hollmann
>    


-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.587.7774 	       dhlii@dlasys.net 	  http://www.dlasys.net
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein


^ permalink raw reply

* RE: [RFC PATCH 1/1] mac80211: Disable cfg80211 assoc timeout warning
From: Johannes Berg @ 2010-05-01  8:47 UTC (permalink / raw)
  To: ext-saravanan.dhanabal; +Cc: linux-wireless
In-Reply-To: <04BB8F4F2843A24294353CA037CA5B585DAF132911@NOK-EUMSG-01.mgdnok.nokia.com>

On Wed, 2010-04-28 at 15:12 +0200, ext-saravanan.dhanabal@nokia.com
wrote:
> OK. Please let me know about that fix after testing, so that I could follow it up.

This is tracked here: https://bugzilla.kernel.org/show_bug.cgi?id=15794

johannes


^ permalink raw reply

* HT rate warning with openwrt AP using wireless-compat and ath9k
From: Kalle Valo @ 2010-05-01  9:27 UTC (permalink / raw)
  To: linux-wireless

Hi,

I'm running OpenWrt 10.03 on Netgear WNDR3700 and I'm having stability
issues. The AP reboots few times a week, maybe even daily. I get the
feeling that my wife's windows laptop is related to the reboots
somehow, but I haven't investigated this in detail yet. Also I do not
have access to serial console, so I don't have proper logs.

But today the AP didn't reboot, wireless was just dead. I managed to
find this with ssh:

------------[ cut here ]------------
WARNING: at
/home/openwrt/backfire/build/ar71xx/build_dir/linux-ar71xx/compat-wireless-2010-03-24/net/mac80211/rx.c:2528
0x83115884()
Rate marked as an HT rate but passed status->rate_idx is not an MCS
index [0-76]: 123 (0x7b)
Modules linked in: ip6t_REJECT ip6t_LOG ip6t_rt ip6t_hbh ip6t_mh
ip6t_ipv6header ip6t_frag ip6t_eui64 ip6t_ah ip6table_raw ip6_queue
ip6table_mangle ip6table_filter ip6_tables nf_conntrack_ipv6
nf_nat_tftp nf_conntrack_tftp nf_nat_irc nf_conntrack_irc nf_nat_ftp
nf_conntrack_ftp ipt_MASQUERADE iptable_nat nf_nat xt_NOTRACK
iptable_raw xt_state nf_conntrack_ipv4 nf_defrag_ipv4 nf_conntrack
pppoe pppox ipt_REJECT xt_TCPMSS ipt_LOG xt_comment xt_multiport
xt_mac xt_limit iptable_mangle iptable_filter ip_tables xt_tcpudp
x_tables sit tunnel4 ppp_async ppp_generic slhc ath9k ath9k_common
ath9k_hw ath mac80211 crc_ccitt cfg80211 compat_firmware_class compat
arc4 aes_generic deflate ecb cbc ipv6 leds_gpio button_hotplug
gpio_buttons input_polldev input_core
Call Trace:[<8007d338>] 0x8007d338
[<800683c4>] 0x800683c4
[<800683c4>] 0x800683c4
[<8007cb6c>] 0x8007cb6c
[<83115884>] 0x83115884
[<8007cbec>] 0x8007cbec
[<800d5ab0>] 0x800d5ab0
[<83115884>] 0x83115884
[<801e1ed8>] 0x801e1ed8
[<83b96c38>] 0x83b96c38
[<830858b0>] 0x830858b0
[<830847d0>] 0x830847d0
[<80081b98>] 0x80081b98
[<800a7968>] 0x800a7968
[<8008238c>] 0x8008238c
[<8008246c>] 0x8008246c
[<8006082c>] 0x8006082c
[<80060a00>] 0x80060a00
[<8006b330>] 0x8006b330
[<8006c7d0>] 0x8006c7d0
[<80060a20>] 0x80060a20
[<802d1a48>] 0x802d1a48
[<802d13a8>] 0x802d13a8

---[ end trace 85c3d4dc1fef0e68 ]---

Some info about the setup:

Linux harkko.valot.fi 2.6.32.10 #20 Tue Apr 6 15:01:26 CEST 2010 mips
GNU/Linux

kmod-ath9k - 2.6.32.10+2010-03-24-5
kmod-mac80211 - 2.6.32.10+2010-03-24-5

DISTRIB_ID="OpenWrt"
DISTRIB_RELEASE="10.03"
DISTRIB_CODENAME="backfire"
DISTRIB_DESCRIPTION="OpenWrt Backfire 10.03"

phy0: Atheros AR9280 Rev:2 mem=0xb0000000, irq=48
phy1: Atheros AR9280 Rev:2 mem=0xb0010000, irq=49

-- 
Kalle Valo

^ permalink raw reply

* Re: ar9170-fw
From: David H. Lynch Jr. @ 2010-05-01 10:11 UTC (permalink / raw)
  To: Stefan Lippers-Hollmann; +Cc: linux-wireless
In-Reply-To: <201005010323.53295.s.L-H@gmx.de>

  Did a git pull and picked up the bashisms and versions update.
At HEAD I get build failures in bfd

----------------------------------
make[5]: Entering directory 
`/usr/src/ar9170-fw/toolchain/build/binutils/bfd'
1011 /bin/sh ./libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. 
-I/usr/src/ar9170-fw/toolchain/src/binutils-2.20.1/bfd
1012 libtool: compile: gcc -DHAVE_CONFIG_H -I. 
-I/usr/src/ar9170-fw/toolchain/src/binutils-2.20.1/bfd -I. 
-I/usr/src/ar9170-fw/
1013 cc1: warnings being treated as errors
1014 In file included from 
/usr/src/ar9170-fw/toolchain/src/binutils-2.20.1/bfd/elf32-sh.c:6055:
1015 ./elf32-target.h:718: error: initialization makes pointer from 
integer without a cast
1016 ./elf32-target.h:731: error: large integer implicitly truncated to 
unsigned type
1017 ./elf32-target.h:738: error: missing initializer
1018 ./elf32-target.h:738: error: (near initialization for 
‘elf32_bed.want_p_paddr_set_to_zero’)
1019 ./elf32-target.h:826: error: ‘bfd_elf32_bfd_define_common_symbol’ 
undeclared here (not in a function)
1020 In file included from 
/usr/src/ar9170-fw/toolchain/src/binutils-2.20.1/bfd/elf32-sh.c:6074:
------------------------------------

If I back off to
dc858db5b191d70362d30f90906d68c1c3c2c972
the bashism fixes I get the same build errors in libssp in my first email.

In an unrelated toolchain build project (buildroot for a ppc405) I get 
libssp errors if I enable SSP.

I am reading the errors is a failure to properly include standard headers.

I am working under ubuntu lucid
gcc --ver as follows:

Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 
4.4.3-4ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs 
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr 
--enable-shared --enable-multiarch --enable-linker-build-id 
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext 
--enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 
--program-suffix=-4.4 --enable-nls --enable-clocale=gnu 
--enable-libstdcxx-debug --enable-plugin --enable-objc-gc 
--enable-targets=all --disable-werror --with-arch-32=i486 
--with-tune=generic --enable-checking=release --build=i486-linux-gnu 
--host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)

Alternately maybe I am missing some development dependency that 
configure is not warning about





On 04/30/2010 09:23 PM, Stefan Lippers-Hollmann wrote:
> Hi
>
> On Saturday 01 May 2010, David H. Lynch Jr. wrote:
>    
>>       I tried to build the toolchain from an uptodate pull of the git
>> repository,
>>
>>       I am getting a sequence of errors when the build reach libssp.
>>
>>       My guess would be that libssp is not needed for the ar9170 firmware.
>>
>>       Is this correct and I would appreciate an easy suguestion to
>> disable it if so.
>>
>> make[3]: Entering directory `/usr/src/ar9170-fw/toolchain/build/gcc/sh-elf/libssp'
>>      
> [...]
>    
>> -I/usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp -I. -Wall -O2 -g -g -O2 -MT
>> ssp.lo -MD -MP -MF .deps/ssp.Tpo -c
>> /usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c -o ssp.o
>> /usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c: In function
>> '__guard_setup':
>> /usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:70: warning: implicit
>> declaration of function 'open'
>> /usr/src/ar9170-fw/toolchain/src/gcc-4.3.3/libssp/ssp.c:70: error: 'O_RDONLY'
>> undeclared (first use in this function)
>>      
> [...]
>
> I assume your host's /bin/sh is not bash.
>
> ---------------------------------------------------------------------------
>
> ar9170.fw: fix bashisms while building the cross toolchain.
>
> Signed-off-by: Stefan Lippers-Hollmann<s.l-h@gmx.de>
>
> --- a/toolchain/Makefile
> +++ b/toolchain/Makefile
> @@ -31,7 +31,8 @@ src/newlib-$(NEWLIB_VER): src/$(NEWLIB_T
>
>   src/gcc-$(GCC_VER): src/$(GCC_TAR) src/newlib-$(NEWLIB_VER)
>   	tar -C src -xjf $<
> -	ln -s $(BASEDIR)/src/newlib-$(NEWLIB_VER)/{newlib,libgloss} $@
> +	ln -s $(BASEDIR)/src/newlib-$(NEWLIB_VER)/newlib $@
> +	ln -s $(BASEDIR)/src/newlib-$(NEWLIB_VER)/libgloss $@
>
>   binutils: src/binutils-$(BINUTILS_VER)
>   	mkdir -p build/binutils
>
> ---------------------------------------------------------------------------
>
> While you're at it, I'd suggest to bump the versions for the required
> cross-build environment as well, as it noticably improves stability of the
> firmware images built by it (still not perfectly, but better).
>
> ---------------------------------------------------------------------------
>
> ar9170.fw: update cross-toolchain.
>
> Updating the toolchain improves stability of the built firmware images
> significantly.
>
> * gcc-4.4.4
> * binutils-2.20.1
> * newlib 1.18.0
>
> Signed-off-by: Stefan Lippers-Hollmann<s.l-h@gmx.de>
>
> --- a/toolchain/Makefile
> +++ b/toolchain/Makefile
> @@ -1,12 +1,12 @@
> -BINUTILS_VER=2.19.1
> +BINUTILS_VER=2.20.1
>   BINUTILS_URL=http://mirrors.kernel.org/gnu/binutils/binutils-$(BINUTILS_VER).tar.bz2
>   BINUTILS_TAR=binutils-$(BINUTILS_VER).tar.bz2
>
> -NEWLIB_VER=1.17.0
> +NEWLIB_VER=1.18.0
>   NEWLIB_URL=ftp://sources.redhat.com/pub/newlib/newlib-$(NEWLIB_VER).tar.gz
>   NEWLIB_TAR=newlib-$(NEWLIB_VER).tar.gz
>
> -GCC_VER=4.3.3
> +GCC_VER=4.4.4
>   GCC_URL=http://mirrors.kernel.org/gnu/gcc/gcc-$(GCC_VER)/gcc-core-$(GCC_VER).tar.bz2
>   GCC_TAR=gcc-core-$(GCC_VER).tar.bz2
>
> ---------------------------------------------------------------------------
>
> Regards
> 	Stefan Lippers-Hollmann
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>    


-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.587.7774 	       dhlii@dlasys.net 	  http://www.dlasys.net
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein


^ permalink raw reply

* ar9170-fw II
From: David H. Lynch Jr. @ 2010-05-01 10:19 UTC (permalink / raw)
  To: linux-wireless

     I have ethernet driver experience but not wifi. I have a project to 
add some features to the ar9170 that will require additions to the 
firmware. I would appreciate pointers for docs etc. to get me started.

What is available for the ar9170 itself ?
How does the firmware and the linux driver communicate?
  Is there an overview of the firmware - what is where ?

-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.587.7774 	       dhlii@dlasys.net 	  http://www.dlasys.net
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein


^ permalink raw reply

* Re: ar9170-fw
From: Stefan Lippers-Hollmann @ 2010-05-01 11:42 UTC (permalink / raw)
  To: David H. Lynch Jr.; +Cc: linux-wireless
In-Reply-To: <4BDBFE51.2010305@dlasys.net>

Hi

On Saturday 01 May 2010, David H. Lynch Jr. wrote:
>   Did a git pull and picked up the bashisms and versions update.
> At HEAD I get build failures in bfd
> 
> ----------------------------------
> make[5]: Entering directory 
> `/usr/src/ar9170-fw/toolchain/build/binutils/bfd'
> 1011 /bin/sh ./libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. 
> -I/usr/src/ar9170-fw/toolchain/src/binutils-2.20.1/bfd
> 1012 libtool: compile: gcc -DHAVE_CONFIG_H -I. 
> -I/usr/src/ar9170-fw/toolchain/src/binutils-2.20.1/bfd -I. 
> -I/usr/src/ar9170-fw/
> 1013 cc1: warnings being treated as errors
> 1014 In file included from 
> /usr/src/ar9170-fw/toolchain/src/binutils-2.20.1/bfd/elf32-sh.c:6055:
> 1015 ./elf32-target.h:718: error: initialization makes pointer from 
> integer without a cast
> 1016 ./elf32-target.h:731: error: large integer implicitly truncated to 
> unsigned type
> 1017 ./elf32-target.h:738: error: missing initializer
> 1018 ./elf32-target.h:738: error: (near initialization for 
> ‘elf32_bed.want_p_paddr_set_to_zero’)
> 1019 ./elf32-target.h:826: error: ‘bfd_elf32_bfd_define_common_symbol’ 
> undeclared here (not in a function)
> 1020 In file included from 
> /usr/src/ar9170-fw/toolchain/src/binutils-2.20.1/bfd/elf32-sh.c:6074:
> ------------------------------------
> 
> If I back off to
> dc858db5b191d70362d30f90906d68c1c3c2c972
> the bashism fixes I get the same build errors in libssp in my first email.
> 
> In an unrelated toolchain build project (buildroot for a ppc405) I get 
> libssp errors if I enable SSP.
> 
> I am reading the errors is a failure to properly include standard headers.
> 
> I am working under ubuntu lucid
[...]
> Alternately maybe I am missing some development dependency that 
> configure is not warning about

I have verified before sending the mail yesterday that ar9170.fw still 
builds fine on current Debian unstable (gcc-4.4, but it also worked on 
4.4.2, 4.4.3 before; confirmed in a minimal build chroot (pbuilder) 
environment), so you're likely just missing build dependencies.

# apt-get install build-essential
# apt-get build-dep gcc-4.4 binutils newlib

While this pulls a little more than you'd absolutely need, it still makes
sure that all eventual build dependencies are covered.

Regards
	Stefan Lippers-Hollmann

^ permalink raw reply

* Re: wl1251_sdio PSM
From: GNUtoo @ 2010-05-01 11:53 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless
In-Reply-To: <87sk6cjj20.fsf@purkki.valot.fi>

On Sat, 2010-05-01 at 08:19 +0300, Kalle Valo wrote:
> GNUtoo <GNUtoo@no-log.org> writes:
> 
> > Hi,
> 
> Hi Mr. GNUtoo,
> 
> > We are trying to make the htc dream(also known as G1) android phone
> > usable with a standard GNU(non android) userland.
> 
> I'm interested about this. Are there any references about this? For
> example, instructions how to install etc.
There is a status at
http://www.htc-linux.org/wiki/index.php?title=Dream#Status

Here are preview images with FSO:
http://downloads.freesmartphone.org/releases/fso2-preview-1/htcdream/

Zhone is only a test program,it's not our goal.
Our goal is targetting the SHR distribution instead
( http://trac.shr-project.org/trac )

For now In order to have a SHR image,for now you have to build one
yourself using openembedded
Select htcdream as the machine and shr as the distribution
also include that in the local.conf:
require conf/distro/include/fso-autorev.inc
require conf/distro/include/shr-autorev.inc

http://docs.openembedded.org/usermanual/usermanual.html#chapter_getting_oe
Contains some information on how to get the build system setup.

Denis.



^ permalink raw reply

* BCM4312 802.11b/g LP-PHY (rev 01) dma & led problems
From: Philippe De Muyter @ 2010-05-01 12:17 UTC (permalink / raw)
  To: Larry Finger; +Cc: Matthew Garrett, Dan Williams, linux-wireless
In-Reply-To: <4BD4A1D8.8000203@lwfinger.net>

This is a followup on my attempt to use b43 (now from 2.6.34-rc6) on
a HP Pavilion dv6-1300sb.

With 2.6.34-rc6, I have not had any boot problem (blocking around ssb/b43)
so far.

But, dma mode gives an error (like before) and driver now switches
automatically to PIO mode (new).  

	[   89.830222] device mon0 entered promiscuous mode
	[  101.965896] NOHZ: local_softirq_pending 08
	[  101.969431] NOHZ: local_softirq_pending 08
	[  101.972230] NOHZ: local_softirq_pending 08
	[  101.975041] NOHZ: local_softirq_pending 08
	[  101.977771] NOHZ: local_softirq_pending 08
	[  101.984651] NOHZ: local_softirq_pending 08
	[  101.988808] NOHZ: local_softirq_pending 08
	[  101.991562] NOHZ: local_softirq_pending 08
	[  101.994363] NOHZ: local_softirq_pending 08
	[  101.997116] NOHZ: local_softirq_pending 08
	[  111.816257] hpet1: lost 1 rtc interrupts
	[  112.131040] hpet1: lost 1 rtc interrupts
	[  112.133343] hpet1: lost 1 rtc interrupts
	[  112.135528] hpet1: lost 1 rtc interrupts
	[  112.137722] hpet1: lost 1 rtc interrupts
	[  112.139911] hpet1: lost 1 rtc interrupts
	[  112.142089] hpet1: lost 1 rtc interrupts
	[  112.146370] hpet1: lost 1 rtc interrupts
	[  112.150637] hpet1: lost 1 rtc interrupts
	[  112.152849] hpet1: lost 1 rtc interrupts
	[  113.100932] b43-phy0 ERROR: Fatal DMA error: 0x00000000, 0x00000800, 0x00000000, 0x00000000, 0x00000000, 0x00000000
	[  113.100949] b43-phy0 ERROR: This device does not support DMA on your system. Please use PIO instead.
	[  113.100957] b43-phy0: Controller RESET (DMA error) ...
	[  113.336119] b43-phy0: Loading firmware version 478.104 (2008-07-01 00:50:23)
	[  118.853353] b43-phy0: Controller restarted

During the switch, the led switches from blue to red and returns to blue
after some seconds.  Touching the led switches the hardware blocking on
and off, but the led color does not change.

I then tried with the broadcom supplied hybrid driver, and there the
touch/led functionality works as expected : led is red whenever
I touch the button (enabling hardware blocking) or when I issue
a rfkill block 0 (enabling software blocking).  Led is blue only when
both blocking are disabled.  But, hybrid driver does not give monitor
functionality :( (and of course, also no injection).
	[10703.172776] wl: module license 'unspecified' taints kernel.
	[10703.172791] Disabling lock debugging due to kernel taint
	[10703.174286] wl: Unknown symbol lib80211_get_crypto_ops
	[10778.692746] lib80211: common routines for IEEE802.11 drivers
	[10778.692759] lib80211_crypt: registered algorithm 'NULL'
	[10783.823152] wl 0000:02:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
	[10783.823188] wl 0000:02:00.0: setting latency timer to 64
	[10783.921236] lib80211_crypt: registered algorithm 'TKIP'
	[10783.921623] eth1: Broadcom BCM4315 802.11 Hybrid Wireless Controller 5.60.48.36

Any idea on what I could do to debug more / fix the dma and led problems ?

Philippe

Here the output of lspci -nvv for that chip :

linux-m1ew:~ # lspci -nvv -s 02:00.0                                            
02:00.0 0280: 14e4:4315 (rev 01)                                                
        Subsystem: 103c:1508                                                    
        Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0, Cache Line Size: 64 bytes
        Interrupt: pin A routed to IRQ 16
        Region 0: Memory at d9000000 (64-bit, non-prefetchable) [size=16K]
        Capabilities: [40] Power Management version 3
                Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
                Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=2 PME-
        Capabilities: [58] Vendor Specific Information: Len=78 <?>
        Capabilities: [e8] MSI: Enable- Count=1/1 Maskable- 64bit+
                Address: 0000000000000000  Data: 0000
        Capabilities: [d0] Express (v1) Endpoint, MSI 00
                DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <4us, L1 unlimited
                        ExtTag+ AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
                DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
                        RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
                        MaxPayload 128 bytes, MaxReadReq 128 bytes
                DevSta: CorrErr+ UncorrErr- FatalErr- UnsuppReq+ AuxPwr- TransPend-
                LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1, Latency L0 <4us, L1 <64us
                        ClockPM+ Surprise- LLActRep- BwNot-
                LnkCtl: ASPM L0s L1 Enabled; RCB 64 bytes Disabled- Retrain- CommClk+
                        ExtSynch- ClockPM+ AutWidDis- BWInt- AutBWInt-
                LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
        Capabilities: [100 v1] Advanced Error Reporting
                UESta:  DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
                UEMsk:  DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
                UESvrt: DLP+ SDES- TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
                CESta:  RxErr+ BadTLP- BadDLLP- Rollover- Timeout+ NonFatalErr+
                CEMsk:  RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
                AERCap: First Error Pointer: 14, GenCap+ CGenEn- ChkCap+ ChkEn-
        Capabilities: [13c v1] Virtual Channel
                Caps:   LPEVC=0 RefClk=100ns PATEntryBits=1
                Arb:    Fixed- WRR32- WRR64- WRR128-
                Ctrl:   ArbSelect=Fixed
                Status: InProgress-
                VC0:    Caps:   PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
                        Arb:    Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
                        Ctrl:   Enable+ ID=0 ArbSelect=Fixed TC/VC=01
                        Status: NegoPending- InProgress-
        Capabilities: [160 v1] Device Serial Number 00-00-00-ff-ff-00-ff-ff
        Capabilities: [16c v1] Power Budgeting <?>
        Kernel driver in use: b43-pci-bridge

^ permalink raw reply

* [PATCH 0/6] orinoco: Add support for Agere based USB cards
From: David Kilroy @ 2010-05-01 13:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, linville, David Kilroy

This patch series adds the orinoco_usb driver, originally written by
Manuel Estrada Sainz.

I believe the main stumbling block the last time this driver was
submitted for inclusion was the way it handled the orinoco driver
locking. I've reworked this into something reasonably sane (patch 3).

The resulting driver has been basically tested with a Compaq WL215
(thanks to Mark Davis for supplying one). Managed mode with WEP works
on this card while a WPA-enabled PCMCIA orinoco card is running.

I'm not familiar with the USB subsystem, so there may be issues that
need to be resolved in that area. Also the original driver used
in_atomic in one location. I left this as-is in the main driver
commit (patch 4), and the subsequent patch (5) is my attempt to fix
this up. It works, but there may be a better way to do this.

Changes since RFC:
 * added firmware download capability to orinoco_usb
 * changed reference to IW_MODE_MONITOR to NL80211_IFTYPE_MONITOR
 * propogated the op->locks to a number of other places that take
   priv->lock
 * added static annotations to a number of functions
 * added sparse annotations to lock wrappers

Regards,

Dave.
---
David Kilroy (6):
  orinoco: add hermes_ops
  orinoco: allow driver to specify netdev_ops
  orinoco: encapsulate driver locking
  orinoco: add orinoco_usb driver
  orinoco_usb: avoid in_atomic
  orinoco_usb: implement fw download

 drivers/net/wireless/orinoco/Kconfig          |    7 +
 drivers/net/wireless/orinoco/Makefile         |    1 +
 drivers/net/wireless/orinoco/airport.c        |    8 +-
 drivers/net/wireless/orinoco/cfg.c            |    2 +-
 drivers/net/wireless/orinoco/fw.c             |   10 +-
 drivers/net/wireless/orinoco/hermes.c         |  286 ++++-
 drivers/net/wireless/orinoco/hermes.h         |   62 +-
 drivers/net/wireless/orinoco/hermes_dld.c     |  243 +----
 drivers/net/wireless/orinoco/hw.c             |   63 +-
 drivers/net/wireless/orinoco/main.c           |  137 ++-
 drivers/net/wireless/orinoco/orinoco.h        |   30 +-
 drivers/net/wireless/orinoco/orinoco_cs.c     |    6 +-
 drivers/net/wireless/orinoco/orinoco_nortel.c |    2 +-
 drivers/net/wireless/orinoco/orinoco_pci.c    |    2 +-
 drivers/net/wireless/orinoco/orinoco_plx.c    |    2 +-
 drivers/net/wireless/orinoco/orinoco_tmd.c    |    2 +-
 drivers/net/wireless/orinoco/orinoco_usb.c    | 1800 +++++++++++++++++++++++++
 drivers/net/wireless/orinoco/spectrum_cs.c    |    7 +-
 drivers/net/wireless/orinoco/wext.c           |    6 +-
 19 files changed, 2278 insertions(+), 398 deletions(-)
 create mode 100644 drivers/net/wireless/orinoco/orinoco_usb.c


^ permalink raw reply

* [PATCH 2/6] orinoco: allow driver to specify netdev_ops
From: David Kilroy @ 2010-05-01 13:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, linville, David Kilroy
In-Reply-To: <1272719143-26171-1-git-send-email-kilroyd@googlemail.com>

Allow the main drivers to specify a custom version of the net_device_ops
structure. This is required by orinoco_usb to supply a separate transmit
function.

Export existing net_device_ops callbacks so that the drivers can reuse
some of the existing code.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/airport.c        |    2 +-
 drivers/net/wireless/orinoco/main.c           |   28 +++++++++++++++++-------
 drivers/net/wireless/orinoco/orinoco.h        |   11 +++++++++-
 drivers/net/wireless/orinoco/orinoco_cs.c     |    2 +-
 drivers/net/wireless/orinoco/orinoco_nortel.c |    2 +-
 drivers/net/wireless/orinoco/orinoco_pci.c    |    2 +-
 drivers/net/wireless/orinoco/orinoco_plx.c    |    2 +-
 drivers/net/wireless/orinoco/orinoco_tmd.c    |    2 +-
 drivers/net/wireless/orinoco/spectrum_cs.c    |    2 +-
 9 files changed, 37 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c
index ea23c4f..7dac5ad 100644
--- a/drivers/net/wireless/orinoco/airport.c
+++ b/drivers/net/wireless/orinoco/airport.c
@@ -210,7 +210,7 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
 	}
 
 	/* Register an interface with the stack */
-	if (orinoco_if_add(priv, phys_addr, card->irq) != 0) {
+	if (orinoco_if_add(priv, phys_addr, card->irq, NULL) != 0) {
 		printk(KERN_ERR PFX "orinoco_if_add() failed\n");
 		goto failed;
 	}
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 8c8009c..9dc458d 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -254,7 +254,7 @@ void set_port_type(struct orinoco_private *priv)
 /* Device methods                                                   */
 /********************************************************************/
 
-static int orinoco_open(struct net_device *dev)
+int orinoco_open(struct net_device *dev)
 {
 	struct orinoco_private *priv = ndev_priv(dev);
 	unsigned long flags;
@@ -272,8 +272,9 @@ static int orinoco_open(struct net_device *dev)
 
 	return err;
 }
+EXPORT_SYMBOL(orinoco_open);
 
-static int orinoco_stop(struct net_device *dev)
+int orinoco_stop(struct net_device *dev)
 {
 	struct orinoco_private *priv = ndev_priv(dev);
 	int err = 0;
@@ -291,15 +292,17 @@ static int orinoco_stop(struct net_device *dev)
 
 	return err;
 }
+EXPORT_SYMBOL(orinoco_stop);
 
-static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
+struct net_device_stats *orinoco_get_stats(struct net_device *dev)
 {
 	struct orinoco_private *priv = ndev_priv(dev);
 
 	return &priv->stats;
 }
+EXPORT_SYMBOL(orinoco_get_stats);
 
-static void orinoco_set_multicast_list(struct net_device *dev)
+void orinoco_set_multicast_list(struct net_device *dev)
 {
 	struct orinoco_private *priv = ndev_priv(dev);
 	unsigned long flags;
@@ -313,8 +316,9 @@ static void orinoco_set_multicast_list(struct net_device *dev)
 	__orinoco_set_multicast_list(dev);
 	orinoco_unlock(priv, &flags);
 }
+EXPORT_SYMBOL(orinoco_set_multicast_list);
 
-static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
+int orinoco_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct orinoco_private *priv = ndev_priv(dev);
 
@@ -330,6 +334,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
 
 	return 0;
 }
+EXPORT_SYMBOL(orinoco_change_mtu);
 
 /********************************************************************/
 /* Tx path                                                          */
@@ -615,7 +620,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
 	netif_wake_queue(dev);
 }
 
-static void orinoco_tx_timeout(struct net_device *dev)
+void orinoco_tx_timeout(struct net_device *dev)
 {
 	struct orinoco_private *priv = ndev_priv(dev);
 	struct net_device_stats *stats = &priv->stats;
@@ -630,6 +635,7 @@ static void orinoco_tx_timeout(struct net_device *dev)
 
 	schedule_work(&priv->reset_work);
 }
+EXPORT_SYMBOL(orinoco_tx_timeout);
 
 /********************************************************************/
 /* Rx path (data frames)                                            */
@@ -2193,7 +2199,8 @@ EXPORT_SYMBOL(alloc_orinocodev);
  */
 int orinoco_if_add(struct orinoco_private *priv,
 		   unsigned long base_addr,
-		   unsigned int irq)
+		   unsigned int irq,
+		   const struct net_device_ops *ops)
 {
 	struct wiphy *wiphy = priv_to_wiphy(priv);
 	struct wireless_dev *wdev;
@@ -2212,12 +2219,17 @@ int orinoco_if_add(struct orinoco_private *priv,
 
 	/* Setup / override net_device fields */
 	dev->ieee80211_ptr = wdev;
-	dev->netdev_ops = &orinoco_netdev_ops;
 	dev->watchdog_timeo = HZ; /* 1 second timeout */
 	dev->wireless_handlers = &orinoco_handler_def;
 #ifdef WIRELESS_SPY
 	dev->wireless_data = &priv->wireless_data;
 #endif
+	/* Default to standard ops if not set */
+	if (ops)
+		dev->netdev_ops = ops;
+	else
+		dev->netdev_ops = &orinoco_netdev_ops;
+
 	/* we use the default eth_mac_addr for setting the MAC addr */
 
 	/* Reserve space in skb for the SNAP header */
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index ff6b7b1..f1901d6 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -190,12 +190,21 @@ extern void free_orinocodev(struct orinoco_private *priv);
 extern int orinoco_init(struct orinoco_private *priv);
 extern int orinoco_if_add(struct orinoco_private *priv,
 			  unsigned long base_addr,
-			  unsigned int irq);
+			  unsigned int irq,
+			  const struct net_device_ops *ops);
 extern void orinoco_if_del(struct orinoco_private *priv);
 extern int orinoco_up(struct orinoco_private *priv);
 extern void orinoco_down(struct orinoco_private *priv);
 extern irqreturn_t orinoco_interrupt(int irq, void *dev_id);
 
+/* Common ndo functions exported for reuse by orinoco_usb */
+int orinoco_open(struct net_device *dev);
+int orinoco_stop(struct net_device *dev);
+struct net_device_stats *orinoco_get_stats(struct net_device *dev);
+void orinoco_set_multicast_list(struct net_device *dev);
+int orinoco_change_mtu(struct net_device *dev, int new_mtu);
+void orinoco_tx_timeout(struct net_device *dev);
+
 /********************************************************************/
 /* Locking and synchronization functions                            */
 /********************************************************************/
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index fdc9613..525f74e 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -296,7 +296,7 @@ orinoco_cs_config(struct pcmcia_device *link)
 
 	/* Register an interface with the stack */
 	if (orinoco_if_add(priv, link->io.BasePort1,
-			   link->irq.AssignedIRQ) != 0) {
+			   link->irq.AssignedIRQ, NULL) != 0) {
 		printk(KERN_ERR PFX "orinoco_if_add() failed\n");
 		goto failed;
 	}
diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c
index 075f446..bc3ea0b 100644
--- a/drivers/net/wireless/orinoco/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco/orinoco_nortel.c
@@ -220,7 +220,7 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
 		goto fail;
 	}
 
-	err = orinoco_if_add(priv, 0, 0);
+	err = orinoco_if_add(priv, 0, 0, NULL);
 	if (err) {
 		printk(KERN_ERR PFX "orinoco_if_add() failed\n");
 		goto fail;
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c
index bda5317..468197f 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco/orinoco_pci.c
@@ -170,7 +170,7 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
 		goto fail;
 	}
 
-	err = orinoco_if_add(priv, 0, 0);
+	err = orinoco_if_add(priv, 0, 0, NULL);
 	if (err) {
 		printk(KERN_ERR PFX "orinoco_if_add() failed\n");
 		goto fail;
diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c
index e0d5874..9358f4d 100644
--- a/drivers/net/wireless/orinoco/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco/orinoco_plx.c
@@ -259,7 +259,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
 		goto fail;
 	}
 
-	err = orinoco_if_add(priv, 0, 0);
+	err = orinoco_if_add(priv, 0, 0, NULL);
 	if (err) {
 		printk(KERN_ERR PFX "orinoco_if_add() failed\n");
 		goto fail;
diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c
index 88cbc79..784605f 100644
--- a/drivers/net/wireless/orinoco/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco/orinoco_tmd.c
@@ -156,7 +156,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
 		goto fail;
 	}
 
-	err = orinoco_if_add(priv, 0, 0);
+	err = orinoco_if_add(priv, 0, 0, NULL);
 	if (err) {
 		printk(KERN_ERR PFX "orinoco_if_add() failed\n");
 		goto fail;
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index 59bda24..77b5871 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -374,7 +374,7 @@ spectrum_cs_config(struct pcmcia_device *link)
 
 	/* Register an interface with the stack */
 	if (orinoco_if_add(priv, link->io.BasePort1,
-			   link->irq.AssignedIRQ) != 0) {
+			   link->irq.AssignedIRQ, NULL) != 0) {
 		printk(KERN_ERR PFX "orinoco_if_add() failed\n");
 		goto failed;
 	}
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH 1/6] orinoco: add hermes_ops
From: David Kilroy @ 2010-05-01 13:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, linville, David Kilroy
In-Reply-To: <1272719143-26171-1-git-send-email-kilroyd@googlemail.com>

Pave the way for introducing USB alternative functions.

Force callers to dereference ops instead of providing wrappers.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/airport.c    |    2 +-
 drivers/net/wireless/orinoco/cfg.c        |    2 +-
 drivers/net/wireless/orinoco/fw.c         |    2 +-
 drivers/net/wireless/orinoco/hermes.c     |   52 ++++++++++--------
 drivers/net/wireless/orinoco/hermes.h     |   50 ++++++++++--------
 drivers/net/wireless/orinoco/hermes_dld.c |   34 ++++++------
 drivers/net/wireless/orinoco/hw.c         |   63 +++++++++++-----------
 drivers/net/wireless/orinoco/main.c       |   83 +++++++++++++++--------------
 drivers/net/wireless/orinoco/wext.c       |    6 +-
 9 files changed, 154 insertions(+), 140 deletions(-)

diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c
index c60df2c..ea23c4f 100644
--- a/drivers/net/wireless/orinoco/airport.c
+++ b/drivers/net/wireless/orinoco/airport.c
@@ -195,7 +195,7 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
 	ssleep(1);
 
 	/* Reset it before we get the interrupt */
-	hermes_init(hw);
+	hw->ops->init(hw);
 
 	if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) {
 		printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq);
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index 90dd4d0..81d228d 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -189,7 +189,7 @@ static int orinoco_set_channel(struct wiphy *wiphy,
 	if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
 		/* Fast channel change - no commit if successful */
 		hermes_t *hw = &priv->hw;
-		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+		err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
 					    HERMES_TEST_SET_CHANNEL,
 					channel, NULL);
 	}
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c
index 5ea0f7c..4c99240 100644
--- a/drivers/net/wireless/orinoco/fw.c
+++ b/drivers/net/wireless/orinoco/fw.c
@@ -260,7 +260,7 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
 	}
 
 	/* Reset hermes chip and make sure it responds */
-	ret = hermes_init(hw);
+	ret = hw->ops->init(hw);
 
 	/* hermes_reset() should return 0 with the secondary firmware */
 	if (secondary && ret != 0)
diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c
index 1a2fca7..a7df524 100644
--- a/drivers/net/wireless/orinoco/hermes.c
+++ b/drivers/net/wireless/orinoco/hermes.c
@@ -70,6 +70,7 @@
 
 #endif /* ! HERMES_DEBUG */
 
+static const struct hermes_ops hermes_ops_local;
 
 /*
  * Internal functions
@@ -111,9 +112,9 @@ static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0,
  */
 
 /* For doing cmds that wipe the magic constant in SWSUPPORT0 */
-int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
-		       u16 parm0, u16 parm1, u16 parm2,
-		       struct hermes_response *resp)
+static int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
+			      u16 parm0, u16 parm1, u16 parm2,
+			      struct hermes_response *resp)
 {
 	int err = 0;
 	int k;
@@ -163,17 +164,17 @@ int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
 out:
 	return err;
 }
-EXPORT_SYMBOL(hermes_doicmd_wait);
 
 void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
 {
 	hw->iobase = address;
 	hw->reg_spacing = reg_spacing;
 	hw->inten = 0x0;
+	hw->ops = &hermes_ops_local;
 }
 EXPORT_SYMBOL(hermes_struct_init);
 
-int hermes_init(hermes_t *hw)
+static int hermes_init(hermes_t *hw)
 {
 	u16 reg;
 	int err = 0;
@@ -217,7 +218,6 @@ int hermes_init(hermes_t *hw)
 
 	return err;
 }
-EXPORT_SYMBOL(hermes_init);
 
 /* Issue a command to the chip, and (busy!) wait for it to
  * complete.
@@ -228,8 +228,8 @@ EXPORT_SYMBOL(hermes_init);
  *     > 0 on error returned by the firmware
  *
  * Callable from any context, but locking is your problem. */
-int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
-		      struct hermes_response *resp)
+static int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
+			     struct hermes_response *resp)
 {
 	int err;
 	int k;
@@ -291,9 +291,8 @@ int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
  out:
 	return err;
 }
-EXPORT_SYMBOL(hermes_docmd_wait);
 
-int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
+static int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
 {
 	int err = 0;
 	int k;
@@ -333,7 +332,6 @@ int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
 
 	return 0;
 }
-EXPORT_SYMBOL(hermes_allocate);
 
 /* Set up a BAP to read a particular chunk of data from card's internal buffer.
  *
@@ -403,8 +401,8 @@ static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
  *       0 on success
  *     > 0 on error from firmware
  */
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
-		     u16 id, u16 offset)
+static int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
+			    u16 id, u16 offset)
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	int err = 0;
@@ -422,7 +420,6 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
  out:
 	return err;
 }
-EXPORT_SYMBOL(hermes_bap_pread);
 
 /* Write a block of data to the chip's buffer, via the
  * BAP. Synchronization/serialization is the caller's problem.
@@ -432,8 +429,8 @@ EXPORT_SYMBOL(hermes_bap_pread);
  *       0 on success
  *     > 0 on error from firmware
  */
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
-		      u16 id, u16 offset)
+static int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
+			     u16 id, u16 offset)
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	int err = 0;
@@ -451,7 +448,6 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
  out:
 	return err;
 }
-EXPORT_SYMBOL(hermes_bap_pwrite);
 
 /* Read a Length-Type-Value record from the card.
  *
@@ -461,8 +457,8 @@ EXPORT_SYMBOL(hermes_bap_pwrite);
  * practice.
  *
  * Callable from user or bh context.  */
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
-		    u16 *length, void *buf)
+static int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
+			   u16 *length, void *buf)
 {
 	int err = 0;
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
@@ -505,10 +501,9 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
 
 	return 0;
 }
-EXPORT_SYMBOL(hermes_read_ltv);
 
-int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
-		     u16 length, const void *value)
+static int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
+			    u16 length, const void *value)
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	int err = 0;
@@ -533,4 +528,15 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
 
 	return err;
 }
-EXPORT_SYMBOL(hermes_write_ltv);
+
+/* Hermes operations for local buses */
+static const struct hermes_ops hermes_ops_local = {
+	.init = hermes_init,
+	.cmd_wait = hermes_docmd_wait,
+	.init_cmd_wait = hermes_doicmd_wait,
+	.allocate = hermes_allocate,
+	.read_ltv = hermes_read_ltv,
+	.write_ltv = hermes_write_ltv,
+	.bap_pread = hermes_bap_pread,
+	.bap_pwrite = hermes_bap_pwrite
+};
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index 2dddbb5..18b268c 100644
--- a/drivers/net/wireless/orinoco/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
@@ -374,6 +374,27 @@ struct hermes_multicast {
 /* Timeouts */
 #define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
 
+struct hermes;
+
+/* Functions to access hardware */
+struct hermes_ops {
+	int (*init)(struct hermes *hw);
+	int (*cmd_wait)(struct hermes *hw, u16 cmd, u16 parm0,
+			struct hermes_response *resp);
+	int (*init_cmd_wait)(struct hermes *hw, u16 cmd,
+			     u16 parm0, u16 parm1, u16 parm2,
+			     struct hermes_response *resp);
+	int (*allocate)(struct hermes *hw, u16 size, u16 *fid);
+	int (*read_ltv)(struct hermes *hw, int bap, u16 rid, unsigned buflen,
+			u16 *length, void *buf);
+	int (*write_ltv)(struct hermes *hw, int bap, u16 rid,
+			 u16 length, const void *value);
+	int (*bap_pread)(struct hermes *hw, int bap, void *buf, int len,
+			 u16 id, u16 offset);
+	int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf,
+			  int len, u16 id, u16 offset);
+};
+
 /* Basic control structure */
 typedef struct hermes {
 	void __iomem *iobase;
@@ -381,6 +402,7 @@ typedef struct hermes {
 #define HERMES_16BIT_REGSPACING	0
 #define HERMES_32BIT_REGSPACING	1
 	u16 inten; /* Which interrupts should be enabled? */
+	const struct hermes_ops *ops;
 } hermes_t;
 
 /* Register access convenience macros */
@@ -394,22 +416,6 @@ typedef struct hermes {
 
 /* Function prototypes */
 void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing);
-int hermes_init(hermes_t *hw);
-int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
-		      struct hermes_response *resp);
-int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
-		       u16 parm0, u16 parm1, u16 parm2,
-		       struct hermes_response *resp);
-int hermes_allocate(hermes_t *hw, u16 size, u16 *fid);
-
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
-		       u16 id, u16 offset);
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
-			u16 id, u16 offset);
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen,
-		    u16 *length, void *buf);
-int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
-		      u16 length, const void *value);
 
 /* Inline functions */
 
@@ -426,13 +432,13 @@ static inline void hermes_set_irqmask(hermes_t *hw, u16 events)
 
 static inline int hermes_enable_port(hermes_t *hw, int port)
 {
-	return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
+	return hw->ops->cmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
 				 0, NULL);
 }
 
 static inline int hermes_disable_port(hermes_t *hw, int port)
 {
-	return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8),
+	return hw->ops->cmd_wait(hw, HERMES_CMD_DISABLE | (port << 8),
 				 0, NULL);
 }
 
@@ -440,7 +446,7 @@ static inline int hermes_disable_port(hermes_t *hw, int port)
  * information frame in __orinoco_ev_info() */
 static inline int hermes_inquire(hermes_t *hw, u16 rid)
 {
-	return hermes_docmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
+	return hw->ops->cmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
 }
 
 #define HERMES_BYTES_TO_RECLEN(n) ((((n)+1)/2) + 1)
@@ -475,10 +481,10 @@ static inline void hermes_clear_words(struct hermes *hw, int off,
 }
 
 #define HERMES_READ_RECORD(hw, bap, rid, buf) \
-	(hermes_read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
+	(hw->ops->read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
 #define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
-	(hermes_write_ltv((hw), (bap), (rid), \
-			  HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf)))
+	(hw->ops->write_ltv((hw), (bap), (rid), \
+			    HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf)))
 
 static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word)
 {
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index fb157eb..8f22e20 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -293,7 +293,7 @@ int hermes_read_pda(hermes_t *hw,
 		/* PDA of spectrum symbol is in eeprom */
 
 		/* Issue command to read EEPROM */
-		ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
+		ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
 		if (ret)
 			return ret;
 	} else {
@@ -408,16 +408,16 @@ int hermesi_program_init(hermes_t *hw, u32 offset)
 	/* Acknowledge any outstanding command */
 	hermes_write_regn(hw, EVACK, 0xFFFF);
 
-	/* Using doicmd_wait rather than docmd_wait */
-	err = hermes_doicmd_wait(hw,
-				 0x0100 | HERMES_CMD_INIT,
-				 0, 0, 0, NULL);
+	/* Using init_cmd_wait rather than cmd_wait */
+	err = hw->ops->init_cmd_wait(hw,
+				     0x0100 | HERMES_CMD_INIT,
+				     0, 0, 0, NULL);
 	if (err)
 		return err;
 
-	err = hermes_doicmd_wait(hw,
-				 0x0000 | HERMES_CMD_INIT,
-				 0, 0, 0, NULL);
+	err = hw->ops->init_cmd_wait(hw,
+				     0x0000 | HERMES_CMD_INIT,
+				     0, 0, 0, NULL);
 	if (err)
 		return err;
 
@@ -428,12 +428,12 @@ int hermesi_program_init(hermes_t *hw, u32 offset)
 		return err;
 
 	pr_debug(PFX "Enabling volatile, EP 0x%08x\n", offset);
-	err = hermes_doicmd_wait(hw,
-				 HERMES_PROGRAM_ENABLE_VOLATILE,
-				 offset & 0xFFFFu,
-				 offset >> 16,
-				 0,
-				 NULL);
+	err = hw->ops->init_cmd_wait(hw,
+				     HERMES_PROGRAM_ENABLE_VOLATILE,
+				     offset & 0xFFFFu,
+				     offset >> 16,
+				     0,
+				     NULL);
 	pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err);
 
 	return err;
@@ -451,7 +451,7 @@ int hermesi_program_end(hermes_t *hw)
 	int rc = 0;
 	int err;
 
-	rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
+	rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
 
 	pr_debug(PFX "PROGRAM_DISABLE returned %d, "
 		 "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
@@ -468,8 +468,8 @@ int hermesi_program_end(hermes_t *hw)
 	hermes_write_regn(hw, EVACK, 0xFFFF);
 
 	/* Reinitialise, ignoring return */
-	(void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
-				  0, 0, 0, NULL);
+	(void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
+				      0, 0, 0, NULL);
 
 	return rc ? rc : err;
 }
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index 24ea4b4..9c86acc 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -177,9 +177,9 @@ int determine_fw_capabilities(struct orinoco_private *priv,
 		/* 3Com MAC : 00:50:DA:* */
 		memset(tmp, 0, sizeof(tmp));
 		/* Get the Symbol firmware version */
-		err = hermes_read_ltv(hw, USER_BAP,
-				      HERMES_RID_SECONDARYVERSION_SYMBOL,
-				      SYMBOL_MAX_VER_LEN, NULL, &tmp);
+		err = hw->ops->read_ltv(hw, USER_BAP,
+					HERMES_RID_SECONDARYVERSION_SYMBOL,
+					SYMBOL_MAX_VER_LEN, NULL, &tmp);
 		if (err) {
 			dev_warn(dev, "Error %d reading Symbol firmware info. "
 				 "Wildly guessing capabilities...\n", err);
@@ -286,8 +286,8 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
 	u16 reclen;
 
 	/* Get the MAC address */
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
-			      ETH_ALEN, NULL, dev_addr);
+	err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+				ETH_ALEN, NULL, dev_addr);
 	if (err) {
 		dev_warn(dev, "Failed to read MAC address!\n");
 		goto out;
@@ -296,8 +296,8 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
 	dev_dbg(dev, "MAC address %pM\n", dev_addr);
 
 	/* Get the station name */
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
-			      sizeof(nickbuf), &reclen, &nickbuf);
+	err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+				sizeof(nickbuf), &reclen, &nickbuf);
 	if (err) {
 		dev_err(dev, "failed to read station name\n");
 		goto out;
@@ -413,11 +413,11 @@ int orinoco_hw_allocate_fid(struct orinoco_private *priv)
 	struct hermes *hw = &priv->hw;
 	int err;
 
-	err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+	err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
 	if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
 		/* Try workaround for old Symbol firmware bug */
 		priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
-		err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+		err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
 
 		dev_warn(dev, "Firmware ALLOC bug detected "
 			 "(old Symbol firmware?). Work around %s\n",
@@ -463,8 +463,9 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
 	struct hermes_idstring idbuf;
 
 	/* Set the MAC address */
-	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
-			       HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
+	err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+				 HERMES_BYTES_TO_RECLEN(ETH_ALEN),
+				 dev->dev_addr);
 	if (err) {
 		printk(KERN_ERR "%s: Error %d setting MAC address\n",
 		       dev->name, err);
@@ -527,7 +528,7 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
 	idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
 	memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
 	/* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
-	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
+	err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
 			HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
 			&idbuf);
 	if (err) {
@@ -535,7 +536,7 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
 		       dev->name, err);
 		return err;
 	}
-	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
+	err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
 			HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
 			&idbuf);
 	if (err) {
@@ -547,9 +548,9 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
 	/* Set the station name */
 	idbuf.len = cpu_to_le16(strlen(priv->nick));
 	memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
-	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
-			       HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
-			       &idbuf);
+	err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+				 HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
+				 &idbuf);
 	if (err) {
 		printk(KERN_ERR "%s: Error %d setting nickname\n",
 		       dev->name, err);
@@ -664,12 +665,12 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
 	if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
 		/* Enable monitor mode */
 		dev->type = ARPHRD_IEEE80211;
-		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+		err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
 					    HERMES_TEST_MONITOR, 0, NULL);
 	} else {
 		/* Disable monitor mode */
 		dev->type = ARPHRD_ETHER;
-		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+		err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
 					    HERMES_TEST_STOP, 0, NULL);
 	}
 	if (err)
@@ -695,8 +696,8 @@ int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
 	if ((key < 0) || (key >= 4))
 		return -EINVAL;
 
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
-			      sizeof(tsc_arr), NULL, &tsc_arr);
+	err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
+				sizeof(tsc_arr), NULL, &tsc_arr);
 	if (!err)
 		memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
 
@@ -875,7 +876,7 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
 				memcpy(key, priv->keys[i].key,
 				       priv->keys[i].key_len);
 
-				err = hermes_write_ltv(hw, USER_BAP,
+				err = hw->ops->write_ltv(hw, USER_BAP,
 						HERMES_RID_CNFDEFAULTKEY0 + i,
 						HERMES_BYTES_TO_RECLEN(keylen),
 						key);
@@ -1092,7 +1093,7 @@ int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
 			memcpy(mclist.addr[i++], p->dmi_addr, ETH_ALEN);
 		}
 
-		err = hermes_write_ltv(hw, USER_BAP,
+		err = hw->ops->write_ltv(hw, USER_BAP,
 				   HERMES_RID_CNFGROUPADDRESSES,
 				   HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
 				   &mclist);
@@ -1134,15 +1135,15 @@ int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
 		rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
 			HERMES_RID_CNFDESIREDSSID;
 
-		err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
-				      NULL, &essidbuf);
+		err = hw->ops->read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
+					NULL, &essidbuf);
 		if (err)
 			goto fail_unlock;
 	} else {
 		*active = 0;
 
-		err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
-				      sizeof(essidbuf), NULL, &essidbuf);
+		err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
+					sizeof(essidbuf), NULL, &essidbuf);
 		if (err)
 			goto fail_unlock;
 	}
@@ -1213,8 +1214,8 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
 
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
-			      sizeof(list), NULL, &list);
+	err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
+				sizeof(list), NULL, &list);
 	orinoco_unlock(priv, &flags);
 
 	if (err)
@@ -1281,7 +1282,7 @@ int orinoco_hw_trigger_scan(struct orinoco_private *priv,
 				idbuf.len = cpu_to_le16(len);
 				memcpy(idbuf.val, ssid->ssid, len);
 
-				err = hermes_write_ltv(hw, USER_BAP,
+				err = hw->ops->write_ltv(hw, USER_BAP,
 					       HERMES_RID_CNFSCANSSID_AGERE,
 					       HERMES_BYTES_TO_RECLEN(len + 2),
 					       &idbuf);
@@ -1345,8 +1346,8 @@ int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
 	hermes_t *hw = &priv->hw;
 	int err;
 
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-			      ETH_ALEN, NULL, addr);
+	err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+				ETH_ALEN, NULL, addr);
 
 	return err;
 }
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 413e9ab..8c8009c 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -400,8 +400,8 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 		memset(&desc, 0, sizeof(desc));
 
 		*txcntl = cpu_to_le16(tx_control);
-		err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
-					txfid, 0);
+		err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+					  txfid, 0);
 		if (err) {
 			if (net_ratelimit())
 				printk(KERN_ERR "%s: Error %d writing Tx "
@@ -414,8 +414,8 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 		memset(&desc, 0, sizeof(desc));
 
 		desc.tx_control = cpu_to_le16(tx_control);
-		err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
-					txfid, 0);
+		err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+					  txfid, 0);
 		if (err) {
 			if (net_ratelimit())
 				printk(KERN_ERR "%s: Error %d writing Tx "
@@ -458,8 +458,8 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 		memcpy(eh, &hdr, sizeof(hdr));
 	}
 
-	err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len,
-				txfid, HERMES_802_3_OFFSET);
+	err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len,
+				  txfid, HERMES_802_3_OFFSET);
 	if (err) {
 		printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
 		       dev->name, err);
@@ -490,8 +490,8 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 			    skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
 
 		/* Write the MIC */
-		err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
-					txfid, HERMES_802_3_OFFSET + offset);
+		err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
+					  txfid, HERMES_802_3_OFFSET + offset);
 		if (err) {
 			printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
 			       dev->name, err);
@@ -502,7 +502,7 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* Finally, we actually initiate the send */
 	netif_stop_queue(dev);
 
-	err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
+	err = hw->ops->cmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
 				txfid, NULL);
 	if (err) {
 		netif_start_queue(dev);
@@ -572,9 +572,9 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
 		return; /* Nothing's really happened */
 
 	/* Read part of the frame header - we need status and addr1 */
-	err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
-			       sizeof(struct hermes_txexc_data),
-			       fid, 0);
+	err = hw->ops->bap_pread(hw, IRQ_BAP, &hdr,
+				 sizeof(struct hermes_txexc_data),
+				 fid, 0);
 
 	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
 	stats->tx_errors++;
@@ -764,9 +764,9 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
 
 	/* If any, copy the data from the card to the skb */
 	if (datalen > 0) {
-		err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
-				       ALIGN(datalen, 2), rxfid,
-				       HERMES_802_2_OFFSET);
+		err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+					 ALIGN(datalen, 2), rxfid,
+					 HERMES_802_2_OFFSET);
 		if (err) {
 			printk(KERN_ERR "%s: error %d reading monitor frame\n",
 			       dev->name, err);
@@ -814,8 +814,8 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 
 	rxfid = hermes_read_regn(hw, RXFID);
 
-	err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
-			       rxfid, 0);
+	err = hw->ops->bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
+				 rxfid, 0);
 	if (err) {
 		printk(KERN_ERR "%s: error %d reading Rx descriptor. "
 		       "Frame dropped.\n", dev->name, err);
@@ -882,9 +882,9 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 	   nothing is removed.  2 is for aligning the IP header.  */
 	skb_reserve(skb, ETH_HLEN + 2);
 
-	err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
-			       ALIGN(length, 2), rxfid,
-			       HERMES_802_2_OFFSET);
+	err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, length),
+				 ALIGN(length, 2), rxfid,
+				 HERMES_802_2_OFFSET);
 	if (err) {
 		printk(KERN_ERR "%s: error %d reading frame. "
 		       "Frame dropped.\n", dev->name, err);
@@ -1145,9 +1145,9 @@ static void orinoco_join_ap(struct work_struct *work)
 		goto out;
 
 	/* Read scan results from the firmware */
-	err = hermes_read_ltv(hw, USER_BAP,
-			      HERMES_RID_SCANRESULTSTABLE,
-			      MAX_SCAN_LEN, &len, buf);
+	err = hw->ops->read_ltv(hw, USER_BAP,
+				HERMES_RID_SCANRESULTSTABLE,
+				MAX_SCAN_LEN, &len, buf);
 	if (err) {
 		printk(KERN_ERR "%s: Cannot read scan results\n",
 		       dev->name);
@@ -1194,8 +1194,8 @@ static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
 	union iwreq_data wrqu;
 	int err;
 
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-			      ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
+	err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+				ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
 	if (err != 0)
 		return;
 
@@ -1217,8 +1217,8 @@ static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
 	if (!priv->has_wpa)
 		return;
 
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
-			      sizeof(buf), NULL, &buf);
+	err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
+				sizeof(buf), NULL, &buf);
 	if (err != 0)
 		return;
 
@@ -1247,8 +1247,9 @@ static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
 	if (!priv->has_wpa)
 		return;
 
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
-			      sizeof(buf), NULL, &buf);
+	err = hw->ops->read_ltv(hw, USER_BAP,
+				HERMES_RID_CURRENT_ASSOC_RESP_INFO,
+				sizeof(buf), NULL, &buf);
 	if (err != 0)
 		return;
 
@@ -1371,8 +1372,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 	infofid = hermes_read_regn(hw, INFOFID);
 
 	/* Read the info frame header - don't try too hard */
-	err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),
-			       infofid, 0);
+	err = hw->ops->bap_pread(hw, IRQ_BAP, &info, sizeof(info),
+				 infofid, 0);
 	if (err) {
 		printk(KERN_ERR "%s: error %d reading info frame. "
 		       "Frame dropped.\n", dev->name, err);
@@ -1393,8 +1394,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 			len = sizeof(tallies);
 		}
 
-		err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len,
-				       infofid, sizeof(info));
+		err = hw->ops->bap_pread(hw, IRQ_BAP, &tallies, len,
+					 infofid, sizeof(info));
 		if (err)
 			break;
 
@@ -1429,8 +1430,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 			break;
 		}
 
-		err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len,
-				       infofid, sizeof(info));
+		err = hw->ops->bap_pread(hw, IRQ_BAP, &linkstatus, len,
+					 infofid, sizeof(info));
 		if (err)
 			break;
 		newstatus = le16_to_cpu(linkstatus.linkstatus);
@@ -1494,8 +1495,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 		}
 
 		/* Read scan data */
-		err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
-				       infofid, sizeof(info));
+		err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) buf, len,
+					 infofid, sizeof(info));
 		if (err) {
 			kfree(buf);
 			qabort_scan(priv);
@@ -1547,8 +1548,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 			break;
 
 		/* Read scan data */
-		err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
-				       infofid, sizeof(info));
+		err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) bss, len,
+					 infofid, sizeof(info));
 		if (err)
 			kfree(bss);
 		else
@@ -1647,7 +1648,7 @@ static int orinoco_reinit_firmware(struct orinoco_private *priv)
 	struct hermes *hw = &priv->hw;
 	int err;
 
-	err = hermes_init(hw);
+	err = hw->ops->init(hw);
 	if (priv->do_fw_download && !err) {
 		err = orinoco_download(priv);
 		if (err)
@@ -1984,7 +1985,7 @@ int orinoco_init(struct orinoco_private *priv)
 	priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
 
 	/* Initialize the firmware */
-	err = hermes_init(hw);
+	err = hw->ops->init(hw);
 	if (err != 0) {
 		dev_err(dev, "Failed to initialize firmware (err = %d)\n",
 			err);
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index a1006bf..5775124 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -458,7 +458,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
 	if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
 		/* Fast channel change - no commit if successful */
 		hermes_t *hw = &priv->hw;
-		err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+		err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
 					    HERMES_TEST_SET_CHANNEL,
 					chan, NULL);
 	}
@@ -1273,8 +1273,8 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
 
-	err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
-			      extra);
+	err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
+				extra);
 	if (err)
 		goto out;
 
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH 3/6] orinoco: encapsulate driver locking
From: David Kilroy @ 2010-05-01 13:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, linville, David Kilroy
In-Reply-To: <1272719143-26171-1-git-send-email-kilroyd@googlemail.com>

Local bus and USB drivers will need to do locking differently.

The original orinoco_usb patches had a boolean variable controlling
whether spin_lock_bh was used, or irq based locking. This version
provides wrappers for the lock functions and the drivers specify the
functions pointers needed.

This will introduce a performance penalty, but I'm not expecting it to
be noticable.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/airport.c     |    4 ++--
 drivers/net/wireless/orinoco/hermes.c      |   28 +++++++++++++++++++++++++++-
 drivers/net/wireless/orinoco/hermes.h      |    4 ++++
 drivers/net/wireless/orinoco/main.c        |   20 ++++++++++----------
 drivers/net/wireless/orinoco/orinoco.h     |   16 +++++++++++++---
 drivers/net/wireless/orinoco/orinoco_cs.c  |    4 ++--
 drivers/net/wireless/orinoco/spectrum_cs.c |    4 ++--
 7 files changed, 60 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c
index 7dac5ad..9bcee10 100644
--- a/drivers/net/wireless/orinoco/airport.c
+++ b/drivers/net/wireless/orinoco/airport.c
@@ -77,9 +77,9 @@ airport_resume(struct macio_dev *mdev)
 
 	enable_irq(card->irq);
 
-	spin_lock_irqsave(&priv->lock, flags);
+	priv->hw.ops->lock_irqsave(&priv->lock, &flags);
 	err = orinoco_up(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
 	return err;
 }
diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c
index a7df524..845693f 100644
--- a/drivers/net/wireless/orinoco/hermes.c
+++ b/drivers/net/wireless/orinoco/hermes.c
@@ -529,6 +529,28 @@ static int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
 	return err;
 }
 
+static void hermes_lock_irqsave(spinlock_t *lock,
+				unsigned long *flags) __acquires(lock)
+{
+	spin_lock_irqsave(lock, *flags);
+}
+
+static void hermes_unlock_irqrestore(spinlock_t *lock,
+				     unsigned long *flags) __releases(lock)
+{
+	spin_unlock_irqrestore(lock, *flags);
+}
+
+static void hermes_lock_irq(spinlock_t *lock) __acquires(lock)
+{
+	spin_lock_irq(lock);
+}
+
+static void hermes_unlock_irq(spinlock_t *lock) __releases(lock)
+{
+	spin_unlock_irq(lock);
+}
+
 /* Hermes operations for local buses */
 static const struct hermes_ops hermes_ops_local = {
 	.init = hermes_init,
@@ -538,5 +560,9 @@ static const struct hermes_ops hermes_ops_local = {
 	.read_ltv = hermes_read_ltv,
 	.write_ltv = hermes_write_ltv,
 	.bap_pread = hermes_bap_pread,
-	.bap_pwrite = hermes_bap_pwrite
+	.bap_pwrite = hermes_bap_pwrite,
+	.lock_irqsave = hermes_lock_irqsave,
+	.unlock_irqrestore = hermes_unlock_irqrestore,
+	.lock_irq = hermes_lock_irq,
+	.unlock_irq = hermes_unlock_irq,
 };
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index 18b268c..9e21ecd 100644
--- a/drivers/net/wireless/orinoco/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
@@ -393,6 +393,10 @@ struct hermes_ops {
 			 u16 id, u16 offset);
 	int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf,
 			  int len, u16 id, u16 offset);
+	void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags);
+	void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags);
+	void (*lock_irq)(spinlock_t *lock);
+	void (*unlock_irq)(spinlock_t *lock);
 };
 
 /* Basic control structure */
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 9dc458d..78a210d 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -282,13 +282,13 @@ int orinoco_stop(struct net_device *dev)
 	/* We mustn't use orinoco_lock() here, because we need to be
 	   able to close the interface even if hw_unavailable is set
 	   (e.g. as we're released after a PC Card removal) */
-	spin_lock_irq(&priv->lock);
+	orinoco_lock_irq(priv);
 
 	priv->open = 0;
 
 	err = __orinoco_down(priv);
 
-	spin_unlock_irq(&priv->lock);
+	orinoco_unlock_irq(priv);
 
 	return err;
 }
@@ -1742,7 +1742,7 @@ void orinoco_reset(struct work_struct *work)
 	}
 
 	/* This has to be called from user context */
-	spin_lock_irq(&priv->lock);
+	orinoco_lock_irq(priv);
 
 	priv->hw_unavailable--;
 
@@ -1757,7 +1757,7 @@ void orinoco_reset(struct work_struct *work)
 			dev->trans_start = jiffies;
 	}
 
-	spin_unlock_irq(&priv->lock);
+	orinoco_unlock_irq(priv);
 
 	return;
  disable:
@@ -2074,9 +2074,9 @@ int orinoco_init(struct orinoco_private *priv)
 
 	/* Make the hardware available, as long as it hasn't been
 	 * removed elsewhere (e.g. by PCMCIA hot unplug) */
-	spin_lock_irq(&priv->lock);
+	orinoco_lock_irq(priv);
 	priv->hw_unavailable--;
-	spin_unlock_irq(&priv->lock);
+	orinoco_unlock_irq(priv);
 
 	dev_dbg(dev, "Ready\n");
 
@@ -2318,7 +2318,7 @@ int orinoco_up(struct orinoco_private *priv)
 	unsigned long flags;
 	int err;
 
-	spin_lock_irqsave(&priv->lock, flags);
+	priv->hw.ops->lock_irqsave(&priv->lock, &flags);
 
 	err = orinoco_reinit_firmware(priv);
 	if (err) {
@@ -2338,7 +2338,7 @@ int orinoco_up(struct orinoco_private *priv)
 	}
 
 exit:
-	spin_unlock_irqrestore(&priv->lock, flags);
+	priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
 	return 0;
 }
@@ -2350,7 +2350,7 @@ void orinoco_down(struct orinoco_private *priv)
 	unsigned long flags;
 	int err;
 
-	spin_lock_irqsave(&priv->lock, flags);
+	priv->hw.ops->lock_irqsave(&priv->lock, &flags);
 	err = __orinoco_down(priv);
 	if (err)
 		printk(KERN_WARNING "%s: Error %d downing interface\n",
@@ -2358,7 +2358,7 @@ void orinoco_down(struct orinoco_private *priv)
 
 	netif_device_detach(dev);
 	priv->hw_unavailable++;
-	spin_unlock_irqrestore(&priv->lock, flags);
+	priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 }
 EXPORT_SYMBOL(orinoco_down);
 
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index f1901d6..80a1386 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -212,11 +212,11 @@ void orinoco_tx_timeout(struct net_device *dev);
 static inline int orinoco_lock(struct orinoco_private *priv,
 			       unsigned long *flags)
 {
-	spin_lock_irqsave(&priv->lock, *flags);
+	priv->hw.ops->lock_irqsave(&priv->lock, flags);
 	if (priv->hw_unavailable) {
 		DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n",
 		       priv->ndev);
-		spin_unlock_irqrestore(&priv->lock, *flags);
+		priv->hw.ops->unlock_irqrestore(&priv->lock, flags);
 		return -EBUSY;
 	}
 	return 0;
@@ -225,7 +225,17 @@ static inline int orinoco_lock(struct orinoco_private *priv,
 static inline void orinoco_unlock(struct orinoco_private *priv,
 				  unsigned long *flags)
 {
-	spin_unlock_irqrestore(&priv->lock, *flags);
+	priv->hw.ops->unlock_irqrestore(&priv->lock, flags);
+}
+
+static inline void orinoco_lock_irq(struct orinoco_private *priv)
+{
+	priv->hw.ops->lock_irq(&priv->lock);
+}
+
+static inline void orinoco_unlock_irq(struct orinoco_private *priv)
+{
+	priv->hw.ops->unlock_irq(&priv->lock);
 }
 
 /*** Navigate from net_device to orinoco_private ***/
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index 525f74e..f99b13b 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -327,9 +327,9 @@ orinoco_cs_release(struct pcmcia_device *link)
 
 	/* We're committed to taking the device away now, so mark the
 	 * hardware as unavailable */
-	spin_lock_irqsave(&priv->lock, flags);
+	priv->hw.ops->lock_irqsave(&priv->lock, &flags);
 	priv->hw_unavailable++;
-	spin_unlock_irqrestore(&priv->lock, flags);
+	priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
 	pcmcia_disable_device(link);
 	if (priv->hw.iobase)
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index 77b5871..b4f68ef 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -405,9 +405,9 @@ spectrum_cs_release(struct pcmcia_device *link)
 
 	/* We're committed to taking the device away now, so mark the
 	 * hardware as unavailable */
-	spin_lock_irqsave(&priv->lock, flags);
+	priv->hw.ops->lock_irqsave(&priv->lock, &flags);
 	priv->hw_unavailable++;
-	spin_unlock_irqrestore(&priv->lock, flags);
+	priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
 	pcmcia_disable_device(link);
 	if (priv->hw.iobase)
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH 4/6] orinoco: add orinoco_usb driver
From: David Kilroy @ 2010-05-01 13:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, linville, David Kilroy
In-Reply-To: <1272719143-26171-1-git-send-email-kilroyd@googlemail.com>

This driver uses the core orinoco modules for the bulk of
the functionality. The low level hermes routines (for local bus
cards) are replaced, the driver supplies its own ndo_xmit_start
function, and locking is done with the _bh variant.

Some recent functionality is not available to the USB cards yet
(firmware loading and WPA).

Out-of-tree driver originally written by Manuel Estrada Sainz.

Thanks to Mark Davis for supplying hardware to test the updates.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/Kconfig       |    7 +
 drivers/net/wireless/orinoco/Makefile      |    1 +
 drivers/net/wireless/orinoco/hermes.h      |    1 +
 drivers/net/wireless/orinoco/main.c        |    6 +-
 drivers/net/wireless/orinoco/orinoco.h     |    3 +
 drivers/net/wireless/orinoco/orinoco_usb.c | 1680 ++++++++++++++++++++++++++++
 6 files changed, 1696 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/wireless/orinoco/orinoco_usb.c

diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig
index 6116b54..60819bc 100644
--- a/drivers/net/wireless/orinoco/Kconfig
+++ b/drivers/net/wireless/orinoco/Kconfig
@@ -132,3 +132,10 @@ config PCMCIA_SPECTRUM
 	  This driver requires firmware download on startup.  Utilities
 	  for downloading Symbol firmware are available at
 	  <http://sourceforge.net/projects/orinoco/>
+
+config ORINOCO_USB
+	tristate "Agere Orinoco USB support"
+	depends on USB && HERMES
+	select FW_LOADER
+	---help---
+	  This driver is for USB versions of the Agere Orinoco card.
diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile
index e645269..bfdefb8 100644
--- a/drivers/net/wireless/orinoco/Makefile
+++ b/drivers/net/wireless/orinoco/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_PCI_HERMES)	+= orinoco_pci.o
 obj-$(CONFIG_TMD_HERMES)	+= orinoco_tmd.o
 obj-$(CONFIG_NORTEL_HERMES)	+= orinoco_nortel.o
 obj-$(CONFIG_PCMCIA_SPECTRUM)	+= spectrum_cs.o
+obj-$(CONFIG_ORINOCO_USB)	+= orinoco_usb.o
 
 # Orinoco should be endian clean.
 ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index 9e21ecd..aed14ff 100644
--- a/drivers/net/wireless/orinoco/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
@@ -407,6 +407,7 @@ typedef struct hermes {
 #define HERMES_32BIT_REGSPACING	1
 	u16 inten; /* Which interrupts should be enabled? */
 	const struct hermes_ops *ops;
+	void *priv;
 } hermes_t;
 
 /* Register access convenience macros */
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 78a210d..1d60c7e 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -798,7 +798,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
 	stats->rx_dropped++;
 }
 
-static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
+void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 {
 	struct orinoco_private *priv = ndev_priv(dev);
 	struct net_device_stats *stats = &priv->stats;
@@ -919,6 +919,7 @@ update_stats:
 out:
 	kfree(desc);
 }
+EXPORT_SYMBOL(__orinoco_ev_rx);
 
 static void orinoco_rx(struct net_device *dev,
 		       struct hermes_rx_descriptor *desc,
@@ -1360,7 +1361,7 @@ static void orinoco_process_scan_results(struct work_struct *work)
 	spin_unlock_irqrestore(&priv->scan_lock, flags);
 }
 
-static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
+void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
 	struct orinoco_private *priv = ndev_priv(dev);
 	u16 infofid;
@@ -1578,6 +1579,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 
 	return;
 }
+EXPORT_SYMBOL(__orinoco_ev_info);
 
 static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
 {
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index 80a1386..e9f415a 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -197,6 +197,9 @@ extern int orinoco_up(struct orinoco_private *priv);
 extern void orinoco_down(struct orinoco_private *priv);
 extern irqreturn_t orinoco_interrupt(int irq, void *dev_id);
 
+extern void __orinoco_ev_info(struct net_device *dev, hermes_t *hw);
+extern void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw);
+
 /* Common ndo functions exported for reuse by orinoco_usb */
 int orinoco_open(struct net_device *dev);
 int orinoco_stop(struct net_device *dev);
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
new file mode 100644
index 0000000..ce0069d
--- /dev/null
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -0,0 +1,1680 @@
+/*
+ * USB Orinoco driver
+ *
+ * Copyright (c) 2003 Manuel Estrada Sainz
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ *
+ * Queueing code based on linux-wlan-ng 0.2.1-pre5
+ *
+ * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+ *
+ *	The license is the same as above.
+ *
+ * Initialy based on USB Skeleton driver - 0.7
+ *
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation; either version 2 of
+ *	the License, or (at your option) any later version.
+ *
+ * NOTE: The original USB Skeleton driver is GPL, but all that code is
+ * gone so MPL/GPL applies.
+ */
+
+#define DRIVER_NAME "orinoco_usb"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/timer.h>
+
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+
+#include "orinoco.h"
+
+#ifndef URB_ASYNC_UNLINK
+#define URB_ASYNC_UNLINK 0
+#endif
+
+/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
+static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+#define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)
+
+struct header_struct {
+	/* 802.3 */
+	u8 dest[ETH_ALEN];
+	u8 src[ETH_ALEN];
+	__be16 len;
+	/* 802.2 */
+	u8 dsap;
+	u8 ssap;
+	u8 ctrl;
+	/* SNAP */
+	u8 oui[3];
+	__be16 ethertype;
+} __attribute__ ((packed));
+
+struct ez_usb_fw {
+	u16 size;
+	const u8 *code;
+};
+
+static struct ez_usb_fw firmware = {
+	.size = 0,
+	.code = NULL,
+};
+
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+/* Debugging macros */
+#undef dbg
+#define dbg(format, arg...) \
+	do { if (debug) printk(KERN_DEBUG PFX "%s: " format "\n", \
+			       __func__ , ## arg); } while (0)
+#undef err
+#define err(format, arg...) \
+	do { printk(KERN_ERR PFX format "\n", ## arg); } while (0)
+
+/* Module paramaters */
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+MODULE_FIRMWARE("orinoco_ezusb_fw");
+
+/*
+ * Under some conditions, the card gets stuck and stops paying attention
+ * to the world (i.e. data communication stalls) until we do something to
+ * it.  Sending an INQ_TALLIES command seems to be enough and should be
+ * harmless otherwise.  This behaviour has been observed when using the
+ * driver on a systemimager client during installation.  In the past a
+ * timer was used to send INQ_TALLIES commands when there was no other
+ * activity, but it was troublesome and was removed.
+ */
+
+#define USB_COMPAQ_VENDOR_ID     0x049f /* Compaq Computer Corp. */
+#define USB_COMPAQ_WL215_ID      0x001f /* Compaq WL215 USB Adapter */
+#define USB_COMPAQ_W200_ID       0x0076 /* Compaq W200 USB Adapter */
+#define USB_HP_WL215_ID          0x0082 /* Compaq WL215 USB Adapter */
+
+#define USB_MELCO_VENDOR_ID      0x0411
+#define USB_BUFFALO_L11_ID       0x0006 /* BUFFALO WLI-USB-L11 */
+#define USB_BUFFALO_L11G_WR_ID   0x000B /* BUFFALO WLI-USB-L11G-WR */
+#define USB_BUFFALO_L11G_ID      0x000D /* BUFFALO WLI-USB-L11G */
+
+#define USB_LUCENT_VENDOR_ID     0x047E /* Lucent Technologies */
+#define USB_LUCENT_ORINOCO_ID    0x0300 /* Lucent/Agere Orinoco USB Client */
+
+#define USB_AVAYA8_VENDOR_ID     0x0D98
+#define USB_AVAYAE_VENDOR_ID     0x0D9E
+#define USB_AVAYA_WIRELESS_ID    0x0300 /* Avaya Wireless USB Card */
+
+#define USB_AGERE_VENDOR_ID      0x0D4E /* Agere Systems */
+#define USB_AGERE_MODEL0801_ID   0x1000 /* Wireless USB Card Model 0801 */
+#define USB_AGERE_MODEL0802_ID   0x1001 /* Wireless USB Card Model 0802 */
+#define USB_AGERE_REBRANDED_ID   0x047A /* WLAN USB Card */
+
+#define USB_ELSA_VENDOR_ID       0x05CC
+#define USB_ELSA_AIRLANCER_ID    0x3100 /* ELSA AirLancer USB-11 */
+
+#define USB_LEGEND_VENDOR_ID     0x0E7C
+#define USB_LEGEND_JOYNET_ID     0x0300 /* Joynet WLAN USB Card */
+
+#define USB_SAMSUNG_VENDOR_ID    0x04E8
+#define USB_SAMSUNG_SEW2001U1_ID 0x5002 /* Samsung SEW-2001u Card */
+#define USB_SAMSUNG_SEW2001U2_ID 0x5B11 /* Samsung SEW-2001u Card */
+#define USB_SAMSUNG_SEW2003U_ID  0x7011 /* Samsung SEW-2003U Card */
+
+#define USB_IGATE_VENDOR_ID      0x0681
+#define USB_IGATE_IGATE_11M_ID   0x0012 /* I-GATE 11M USB Card */
+
+#define USB_FUJITSU_VENDOR_ID    0x0BF8
+#define USB_FUJITSU_E1100_ID     0x1002 /* connect2AIR WLAN E-1100 USB */
+
+#define USB_2WIRE_VENDOR_ID      0x1630
+#define USB_2WIRE_WIRELESS_ID    0xff81 /* 2Wire Wireless USB adapter */
+
+
+#define EZUSB_REQUEST_FW_TRANS		0xA0
+#define EZUSB_REQUEST_TRIGER		0xAA
+#define EZUSB_REQUEST_TRIG_AC		0xAC
+#define EZUSB_CPUCS_REG			0x7F92
+
+#define EZUSB_RID_TX			0x0700
+#define EZUSB_RID_RX			0x0701
+#define EZUSB_RID_INIT1			0x0702
+#define EZUSB_RID_ACK			0x0710
+#define EZUSB_RID_DOCMD			0x0860
+
+/* Recognize info frames */
+#define EZUSB_IS_INFO(id)		((id >= 0xF000) && (id <= 0xF2FF))
+
+#define EZUSB_MAGIC			0x0210
+
+#define EZUSB_FRAME_DATA		1
+#define EZUSB_FRAME_CONTROL		2
+
+#define DEF_TIMEOUT			(3*HZ)
+
+#define BULK_BUF_SIZE			2048
+
+#define FW_BUF_SIZE			64
+#define FW_VAR_OFFSET_PTR		0x359
+#define FW_VAR_VALUE			0
+#define FW_HOLE_START			0x100
+#define FW_HOLE_END			0x300
+
+struct ezusb_packet {
+	__le16 magic;		/* 0x0210 */
+	u8 req_reply_count;
+	u8 ans_reply_count;
+	__le16 frame_type;	/* 0x01 for data frames, 0x02 otherwise */
+	__le16 size;		/* transport size */
+	__le16 crc;		/* CRC up to here */
+	__le16 hermes_len;
+	__le16 hermes_rid;
+	u8 data[0];
+} __attribute__ ((packed));
+
+/* Table of devices that work or may work with this driver */
+static struct usb_device_id ezusb_table[] = {
+	{USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_WL215_ID)},
+	{USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_HP_WL215_ID)},
+	{USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_W200_ID)},
+	{USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11_ID)},
+	{USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_WR_ID)},
+	{USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_ID)},
+	{USB_DEVICE(USB_LUCENT_VENDOR_ID, USB_LUCENT_ORINOCO_ID)},
+	{USB_DEVICE(USB_AVAYA8_VENDOR_ID, USB_AVAYA_WIRELESS_ID)},
+	{USB_DEVICE(USB_AVAYAE_VENDOR_ID, USB_AVAYA_WIRELESS_ID)},
+	{USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0801_ID)},
+	{USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0802_ID)},
+	{USB_DEVICE(USB_ELSA_VENDOR_ID, USB_ELSA_AIRLANCER_ID)},
+	{USB_DEVICE(USB_LEGEND_VENDOR_ID, USB_LEGEND_JOYNET_ID)},
+	{USB_DEVICE_VER(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U1_ID,
+			0, 0)},
+	{USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U2_ID)},
+	{USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2003U_ID)},
+	{USB_DEVICE(USB_IGATE_VENDOR_ID, USB_IGATE_IGATE_11M_ID)},
+	{USB_DEVICE(USB_FUJITSU_VENDOR_ID, USB_FUJITSU_E1100_ID)},
+	{USB_DEVICE(USB_2WIRE_VENDOR_ID, USB_2WIRE_WIRELESS_ID)},
+	{USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_REBRANDED_ID)},
+	{}			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, ezusb_table);
+
+/* Structure to hold all of our device specific stuff */
+struct ezusb_priv {
+	struct usb_device *udev;
+	struct net_device *dev;
+	struct mutex mtx;
+	spinlock_t req_lock;
+	struct list_head req_pending;
+	struct list_head req_active;
+	spinlock_t reply_count_lock;
+	u16 hermes_reg_fake[0x40];
+	u8 *bap_buf;
+	struct urb *read_urb;
+	int read_pipe;
+	int write_pipe;
+	u8 reply_count;
+};
+
+enum ezusb_state {
+	EZUSB_CTX_START,
+	EZUSB_CTX_QUEUED,
+	EZUSB_CTX_REQ_SUBMITTED,
+	EZUSB_CTX_REQ_COMPLETE,
+	EZUSB_CTX_RESP_RECEIVED,
+	EZUSB_CTX_REQ_TIMEOUT,
+	EZUSB_CTX_REQ_FAILED,
+	EZUSB_CTX_RESP_TIMEOUT,
+	EZUSB_CTX_REQSUBMIT_FAIL,
+	EZUSB_CTX_COMPLETE,
+};
+
+struct request_context {
+	struct list_head list;
+	atomic_t refcount;
+	struct completion done;	/* Signals that CTX is dead */
+	int killed;
+	struct urb *outurb;	/* OUT for req pkt */
+	struct ezusb_priv *upriv;
+	struct ezusb_packet *buf;
+	int buf_length;
+	struct timer_list timer;	/* Timeout handling */
+	enum ezusb_state state;	/* Current state */
+	/* the RID that we will wait for */
+	u16 out_rid;
+	u16 in_rid;
+};
+
+
+/* Forward declarations */
+static void ezusb_ctx_complete(struct request_context *ctx);
+static void ezusb_req_queue_run(struct ezusb_priv *upriv);
+static void ezusb_bulk_in_callback(struct urb *urb);
+
+static inline u8 ezusb_reply_inc(u8 count)
+{
+	if (count < 0x7F)
+		return count + 1;
+	else
+		return 1;
+}
+
+static void ezusb_request_context_put(struct request_context *ctx)
+{
+	if (!atomic_dec_and_test(&ctx->refcount))
+		return;
+
+	WARN_ON(!ctx->done.done);
+	BUG_ON(ctx->outurb->status == -EINPROGRESS);
+	BUG_ON(timer_pending(&ctx->timer));
+	usb_free_urb(ctx->outurb);
+	kfree(ctx->buf);
+	kfree(ctx);
+}
+
+static inline void ezusb_mod_timer(struct ezusb_priv *upriv,
+				   struct timer_list *timer,
+				   unsigned long expire)
+{
+	if (!upriv->udev)
+		return;
+	mod_timer(timer, expire);
+}
+
+static void ezusb_request_timerfn(u_long _ctx)
+{
+	struct request_context *ctx = (void *) _ctx;
+
+	ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
+	if (usb_unlink_urb(ctx->outurb) == -EINPROGRESS) {
+		ctx->state = EZUSB_CTX_REQ_TIMEOUT;
+	} else {
+		ctx->state = EZUSB_CTX_RESP_TIMEOUT;
+		dbg("couldn't unlink");
+		atomic_inc(&ctx->refcount);
+		ctx->killed = 1;
+		ezusb_ctx_complete(ctx);
+		ezusb_request_context_put(ctx);
+	}
+};
+
+static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv,
+					       u16 out_rid, u16 in_rid)
+{
+	struct request_context *ctx;
+
+	ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
+	if (!ctx)
+		return NULL;
+
+	memset(ctx, 0, sizeof(*ctx));
+
+	ctx->buf = kmalloc(BULK_BUF_SIZE, GFP_ATOMIC);
+	if (!ctx->buf) {
+		kfree(ctx);
+		return NULL;
+	}
+	ctx->outurb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!ctx->outurb) {
+		kfree(ctx->buf);
+		kfree(ctx);
+		return NULL;
+	}
+
+	ctx->upriv = upriv;
+	ctx->state = EZUSB_CTX_START;
+	ctx->out_rid = out_rid;
+	ctx->in_rid = in_rid;
+
+	atomic_set(&ctx->refcount, 1);
+	init_completion(&ctx->done);
+
+	init_timer(&ctx->timer);
+	ctx->timer.function = ezusb_request_timerfn;
+	ctx->timer.data = (u_long) ctx;
+	return ctx;
+}
+
+
+/* Hopefully the real complete_all will soon be exported, in the mean
+ * while this should work. */
+static inline void ezusb_complete_all(struct completion *comp)
+{
+	complete(comp);
+	complete(comp);
+	complete(comp);
+	complete(comp);
+}
+
+static void ezusb_ctx_complete(struct request_context *ctx)
+{
+	struct ezusb_priv *upriv = ctx->upriv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&upriv->req_lock, flags);
+
+	list_del_init(&ctx->list);
+	if (upriv->udev) {
+		spin_unlock_irqrestore(&upriv->req_lock, flags);
+		ezusb_req_queue_run(upriv);
+		spin_lock_irqsave(&upriv->req_lock, flags);
+	}
+
+	switch (ctx->state) {
+	case EZUSB_CTX_COMPLETE:
+	case EZUSB_CTX_REQSUBMIT_FAIL:
+	case EZUSB_CTX_REQ_FAILED:
+	case EZUSB_CTX_REQ_TIMEOUT:
+	case EZUSB_CTX_RESP_TIMEOUT:
+		spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+		if ((ctx->out_rid == EZUSB_RID_TX) && upriv->dev) {
+			struct net_device *dev = upriv->dev;
+			struct orinoco_private *priv = ndev_priv(dev);
+			struct net_device_stats *stats = &priv->stats;
+
+			if (ctx->state != EZUSB_CTX_COMPLETE)
+				stats->tx_errors++;
+			else
+				stats->tx_packets++;
+
+			netif_wake_queue(dev);
+		}
+		ezusb_complete_all(&ctx->done);
+		ezusb_request_context_put(ctx);
+		break;
+
+	default:
+		spin_unlock_irqrestore(&upriv->req_lock, flags);
+		if (!upriv->udev) {
+			/* This is normal, as all request contexts get flushed
+			 * when the device is disconnected */
+			err("Called, CTX not terminating, but device gone");
+			ezusb_complete_all(&ctx->done);
+			ezusb_request_context_put(ctx);
+			break;
+		}
+
+		err("Called, CTX not in terminating state.");
+		/* Things are really bad if this happens. Just leak
+		 * the CTX because it may still be linked to the
+		 * queue or the OUT urb may still be active.
+		 * Just leaking at least prevents an Oops or Panic.
+		 */
+		break;
+	}
+}
+
+/**
+ * ezusb_req_queue_run:
+ * Description:
+ *	Note: Only one active CTX at any one time, because there's no
+ *	other (reliable) way to match the response URB to the correct
+ *	CTX.
+ **/
+static void ezusb_req_queue_run(struct ezusb_priv *upriv)
+{
+	unsigned long flags;
+	struct request_context *ctx;
+	int result;
+
+	spin_lock_irqsave(&upriv->req_lock, flags);
+
+	if (!list_empty(&upriv->req_active))
+		goto unlock;
+
+	if (list_empty(&upriv->req_pending))
+		goto unlock;
+
+	ctx =
+	    list_entry(upriv->req_pending.next, struct request_context,
+		       list);
+
+	if (!ctx->upriv->udev)
+		goto unlock;
+
+	/* We need to split this off to avoid a race condition */
+	list_move_tail(&ctx->list, &upriv->req_active);
+
+	if (ctx->state == EZUSB_CTX_QUEUED) {
+		atomic_inc(&ctx->refcount);
+		result = usb_submit_urb(ctx->outurb, GFP_ATOMIC);
+		if (result) {
+			ctx->state = EZUSB_CTX_REQSUBMIT_FAIL;
+
+			spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+			err("Fatal, failed to submit command urb."
+			    " error=%d\n", result);
+
+			ezusb_ctx_complete(ctx);
+			ezusb_request_context_put(ctx);
+			goto done;
+		}
+
+		ctx->state = EZUSB_CTX_REQ_SUBMITTED;
+		ezusb_mod_timer(ctx->upriv, &ctx->timer,
+				jiffies + DEF_TIMEOUT);
+	}
+
+ unlock:
+	spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+ done:
+	return;
+}
+
+static void ezusb_req_enqueue_run(struct ezusb_priv *upriv,
+				  struct request_context *ctx)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&upriv->req_lock, flags);
+
+	if (!ctx->upriv->udev) {
+		spin_unlock_irqrestore(&upriv->req_lock, flags);
+		goto done;
+	}
+	atomic_inc(&ctx->refcount);
+	list_add_tail(&ctx->list, &upriv->req_pending);
+	spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+	ctx->state = EZUSB_CTX_QUEUED;
+	ezusb_req_queue_run(upriv);
+
+ done:
+	return;
+}
+
+static void ezusb_request_out_callback(struct urb *urb)
+{
+	unsigned long flags;
+	enum ezusb_state state;
+	struct request_context *ctx = urb->context;
+	struct ezusb_priv *upriv = ctx->upriv;
+
+	spin_lock_irqsave(&upriv->req_lock, flags);
+
+	del_timer(&ctx->timer);
+
+	if (ctx->killed) {
+		spin_unlock_irqrestore(&upriv->req_lock, flags);
+		pr_warning("interrupt called with dead ctx");
+		goto out;
+	}
+
+	state = ctx->state;
+
+	if (urb->status == 0) {
+		switch (state) {
+		case EZUSB_CTX_REQ_SUBMITTED:
+			if (ctx->in_rid) {
+				ctx->state = EZUSB_CTX_REQ_COMPLETE;
+				/* reply URB still pending */
+				ezusb_mod_timer(upriv, &ctx->timer,
+						jiffies + DEF_TIMEOUT);
+				spin_unlock_irqrestore(&upriv->req_lock,
+						       flags);
+				break;
+			}
+			/* fall through */
+		case EZUSB_CTX_RESP_RECEIVED:
+			/* IN already received before this OUT-ACK */
+			ctx->state = EZUSB_CTX_COMPLETE;
+			spin_unlock_irqrestore(&upriv->req_lock, flags);
+			ezusb_ctx_complete(ctx);
+			break;
+
+		default:
+			spin_unlock_irqrestore(&upriv->req_lock, flags);
+			err("Unexpected state(0x%x, %d) in OUT URB",
+			    state, urb->status);
+			break;
+		}
+	} else {
+		/* If someone cancels the OUT URB then its status
+		 * should be either -ECONNRESET or -ENOENT.
+		 */
+		switch (state) {
+		case EZUSB_CTX_REQ_SUBMITTED:
+		case EZUSB_CTX_RESP_RECEIVED:
+			ctx->state = EZUSB_CTX_REQ_FAILED;
+			/* fall through */
+
+		case EZUSB_CTX_REQ_FAILED:
+		case EZUSB_CTX_REQ_TIMEOUT:
+			spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+			ezusb_ctx_complete(ctx);
+			break;
+
+		default:
+			spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+			err("Unexpected state(0x%x, %d) in OUT URB",
+			    state, urb->status);
+			break;
+		}
+	}
+ out:
+	ezusb_request_context_put(ctx);
+}
+
+static void ezusb_request_in_callback(struct ezusb_priv *upriv,
+				      struct urb *urb)
+{
+	struct ezusb_packet *ans = urb->transfer_buffer;
+	struct request_context *ctx = NULL;
+	enum ezusb_state state;
+	unsigned long flags;
+
+	/* Find the CTX on the active queue that requested this URB */
+	spin_lock_irqsave(&upriv->req_lock, flags);
+	if (upriv->udev) {
+		struct list_head *item;
+
+		list_for_each(item, &upriv->req_active) {
+			struct request_context *c;
+			int reply_count;
+
+			c = list_entry(item, struct request_context, list);
+			reply_count =
+			    ezusb_reply_inc(c->buf->req_reply_count);
+			if ((ans->ans_reply_count == reply_count)
+			    && (le16_to_cpu(ans->hermes_rid) == c->in_rid)) {
+				ctx = c;
+				break;
+			}
+			dbg("Skipped (0x%x/0x%x) (%d/%d)",
+			    le16_to_cpu(ans->hermes_rid),
+			    c->in_rid, ans->ans_reply_count, reply_count);
+		}
+	}
+
+	if (ctx == NULL) {
+		spin_unlock_irqrestore(&upriv->req_lock, flags);
+		err("%s: got unexpected RID: 0x%04X", __func__,
+		    le16_to_cpu(ans->hermes_rid));
+		ezusb_req_queue_run(upriv);
+		return;
+	}
+
+	/* The data we want is in the in buffer, exchange */
+	urb->transfer_buffer = ctx->buf;
+	ctx->buf = (void *) ans;
+	ctx->buf_length = urb->actual_length;
+
+	state = ctx->state;
+	switch (state) {
+	case EZUSB_CTX_REQ_SUBMITTED:
+		/* We have received our response URB before
+		 * our request has been acknowledged. Do NOT
+		 * destroy our CTX yet, because our OUT URB
+		 * is still alive ...
+		 */
+		ctx->state = EZUSB_CTX_RESP_RECEIVED;
+		spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+		/* Let the machine continue running. */
+		break;
+
+	case EZUSB_CTX_REQ_COMPLETE:
+		/* This is the usual path: our request
+		 * has already been acknowledged, and
+		 * we have now received the reply.
+		 */
+		ctx->state = EZUSB_CTX_COMPLETE;
+
+		/* Stop the intimer */
+		del_timer(&ctx->timer);
+		spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+		/* Call the completion handler */
+		ezusb_ctx_complete(ctx);
+		break;
+
+	default:
+		spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+		pr_warning("Matched IN URB, unexpected context state(0x%x)",
+		     state);
+		/* Throw this CTX away and try submitting another */
+		del_timer(&ctx->timer);
+		ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
+		usb_unlink_urb(ctx->outurb);
+		ezusb_req_queue_run(upriv);
+		break;
+	}			/* switch */
+}
+
+
+static void ezusb_req_ctx_wait(struct ezusb_priv *upriv,
+			       struct request_context *ctx)
+{
+	switch (ctx->state) {
+	case EZUSB_CTX_QUEUED:
+	case EZUSB_CTX_REQ_SUBMITTED:
+	case EZUSB_CTX_REQ_COMPLETE:
+	case EZUSB_CTX_RESP_RECEIVED:
+		if (in_atomic()) {
+			/* If we get called from a timer, timeout timers don't
+			 * get the chance to run themselves. So we make sure
+			 * that we don't sleep for ever */
+			int msecs = DEF_TIMEOUT * (1000 / HZ);
+			while (!ctx->done.done && msecs--)
+				udelay(1000);
+		} else {
+			wait_event_interruptible(ctx->done.wait,
+						 ctx->done.done);
+		}
+		break;
+	default:
+		/* Done or failed - nothing to wait for */
+		break;
+	}
+}
+
+static inline u16 build_crc(struct ezusb_packet *data)
+{
+	u16 crc = 0;
+	u8 *bytes = (u8 *)data;
+	int i;
+
+	for (i = 0; i < 8; i++)
+		crc = (crc << 1) + bytes[i];
+
+	return crc;
+}
+
+/**
+ * ezusb_fill_req:
+ *
+ * if data == NULL and length > 0 the data is assumed to be already in
+ * the target buffer and only the header is filled.
+ *
+ */
+static int ezusb_fill_req(struct ezusb_packet *req, u16 length, u16 rid,
+			  const void *data, u16 frame_type, u8 reply_count)
+{
+	int total_size = sizeof(*req) + length;
+
+	BUG_ON(total_size > BULK_BUF_SIZE);
+
+	req->magic = cpu_to_le16(EZUSB_MAGIC);
+	req->req_reply_count = reply_count;
+	req->ans_reply_count = 0;
+	req->frame_type = cpu_to_le16(frame_type);
+	req->size = cpu_to_le16(length + 4);
+	req->crc = cpu_to_le16(build_crc(req));
+	req->hermes_len = cpu_to_le16(HERMES_BYTES_TO_RECLEN(length));
+	req->hermes_rid = cpu_to_le16(rid);
+	if (data)
+		memcpy(req->data, data, length);
+	return total_size;
+}
+
+static int ezusb_submit_in_urb(struct ezusb_priv *upriv)
+{
+	int retval = 0;
+	void *cur_buf = upriv->read_urb->transfer_buffer;
+
+	if (upriv->read_urb->status == -EINPROGRESS) {
+		dbg("urb busy, not resubmiting");
+		retval = -EBUSY;
+		goto exit;
+	}
+	usb_fill_bulk_urb(upriv->read_urb, upriv->udev, upriv->read_pipe,
+			  cur_buf, BULK_BUF_SIZE,
+			  ezusb_bulk_in_callback, upriv);
+	upriv->read_urb->transfer_flags = 0;
+	retval = usb_submit_urb(upriv->read_urb, GFP_ATOMIC);
+	if (retval)
+		err("%s submit failed %d", __func__, retval);
+
+ exit:
+	return retval;
+}
+
+static inline int ezusb_8051_cpucs(struct ezusb_priv *upriv, int reset)
+{
+	u8 res_val = reset;	/* avoid argument promotion */
+
+	if (!upriv->udev) {
+		err("%s: !upriv->udev", __func__);
+		return -EFAULT;
+	}
+	return usb_control_msg(upriv->udev,
+			       usb_sndctrlpipe(upriv->udev, 0),
+			       EZUSB_REQUEST_FW_TRANS,
+			       USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+			       USB_DIR_OUT, EZUSB_CPUCS_REG, 0, &res_val,
+			       sizeof(res_val), DEF_TIMEOUT);
+}
+
+static int ezusb_firmware_download(struct ezusb_priv *upriv,
+				   struct ez_usb_fw *fw)
+{
+	u8 fw_buffer[FW_BUF_SIZE];
+	int retval, addr;
+	int variant_offset;
+
+	/*
+	 * This byte is 1 and should be replaced with 0.  The offset is
+	 * 0x10AD in version 0.0.6.  The byte in question should follow
+	 * the end of the code pointed to by the jump in the beginning
+	 * of the firmware.  Also, it is read by code located at 0x358.
+	 */
+	variant_offset = be16_to_cpup((__be16 *) &fw->code[FW_VAR_OFFSET_PTR]);
+	if (variant_offset >= fw->size) {
+		printk(KERN_ERR PFX "Invalid firmware variant offset: "
+		       "0x%04x\n", variant_offset);
+		retval = -EINVAL;
+		goto fail;
+	}
+
+	retval = ezusb_8051_cpucs(upriv, 1);
+	if (retval < 0)
+		goto fail;
+	for (addr = 0; addr < fw->size; addr += FW_BUF_SIZE) {
+		/* 0x100-0x300 should be left alone, it contains card
+		 * specific data, like USB enumeration information */
+		if ((addr >= FW_HOLE_START) && (addr < FW_HOLE_END))
+			continue;
+
+		memcpy(fw_buffer, &fw->code[addr], FW_BUF_SIZE);
+		if (variant_offset >= addr &&
+		    variant_offset < addr + FW_BUF_SIZE) {
+			dbg("Patching card_variant byte at 0x%04X",
+			    variant_offset);
+			fw_buffer[variant_offset - addr] = FW_VAR_VALUE;
+		}
+		retval = usb_control_msg(upriv->udev,
+					 usb_sndctrlpipe(upriv->udev, 0),
+					 EZUSB_REQUEST_FW_TRANS,
+					 USB_TYPE_VENDOR | USB_RECIP_DEVICE
+					 | USB_DIR_OUT,
+					 addr, 0x0,
+					 fw_buffer, FW_BUF_SIZE,
+					 DEF_TIMEOUT);
+
+		if (retval < 0)
+			goto fail;
+	}
+	retval = ezusb_8051_cpucs(upriv, 0);
+	if (retval < 0)
+		goto fail;
+
+	goto exit;
+ fail:
+	printk(KERN_ERR PFX "Firmware download failed, error %d\n",
+	       retval);
+ exit:
+	return retval;
+}
+
+static int ezusb_access_ltv(struct ezusb_priv *upriv,
+			    struct request_context *ctx,
+			    u16 length, const void *data, u16 frame_type,
+			    void *ans_buff, int ans_size, u16 *ans_length)
+{
+	int req_size;
+	int retval = 0;
+	enum ezusb_state state;
+
+	BUG_ON(in_irq());
+
+	if (!upriv->udev) {
+		dbg("Device disconnected");
+		return -ENODEV;
+	}
+
+	if (upriv->read_urb->status != -EINPROGRESS)
+		err("%s: in urb not pending", __func__);
+
+	/* protect upriv->reply_count, guarantee sequential numbers */
+	spin_lock_bh(&upriv->reply_count_lock);
+	req_size = ezusb_fill_req(ctx->buf, length, ctx->out_rid, data,
+				  frame_type, upriv->reply_count);
+	usb_fill_bulk_urb(ctx->outurb, upriv->udev, upriv->write_pipe,
+			  ctx->buf, req_size,
+			  ezusb_request_out_callback, ctx);
+
+	if (ctx->in_rid)
+		upriv->reply_count = ezusb_reply_inc(upriv->reply_count);
+
+	ezusb_req_enqueue_run(upriv, ctx);
+
+	spin_unlock_bh(&upriv->reply_count_lock);
+
+	if (ctx->in_rid)
+		ezusb_req_ctx_wait(upriv, ctx);
+
+	state = ctx->state;
+	switch (state) {
+	case EZUSB_CTX_COMPLETE:
+		retval = ctx->outurb->status;
+		break;
+
+	case EZUSB_CTX_QUEUED:
+	case EZUSB_CTX_REQ_SUBMITTED:
+		if (!ctx->in_rid)
+			break;
+	default:
+		err("%s: Unexpected context state %d", __func__,
+		    state);
+		/* fall though */
+	case EZUSB_CTX_REQ_TIMEOUT:
+	case EZUSB_CTX_REQ_FAILED:
+	case EZUSB_CTX_RESP_TIMEOUT:
+	case EZUSB_CTX_REQSUBMIT_FAIL:
+		printk(KERN_ERR PFX "Access failed, resetting (state %d,"
+		       " reply_count %d)\n", state, upriv->reply_count);
+		upriv->reply_count = 0;
+		if (state == EZUSB_CTX_REQ_TIMEOUT
+		    || state == EZUSB_CTX_RESP_TIMEOUT) {
+			printk(KERN_ERR PFX "ctx timed out\n");
+			retval = -ETIMEDOUT;
+		} else {
+			printk(KERN_ERR PFX "ctx failed\n");
+			retval = -EFAULT;
+		}
+		goto exit;
+		break;
+	}
+	if (ctx->in_rid) {
+		struct ezusb_packet *ans = ctx->buf;
+		int exp_len;
+
+		if (ans->hermes_len != 0)
+			exp_len = le16_to_cpu(ans->hermes_len) * 2 + 12;
+		else
+			exp_len = 14;
+
+		if (exp_len != ctx->buf_length) {
+			err("%s: length mismatch for RID 0x%04x: "
+			    "expected %d, got %d", __func__,
+			    ctx->in_rid, exp_len, ctx->buf_length);
+			retval = -EIO;
+			goto exit;
+		}
+
+		if (ans_buff)
+			memcpy(ans_buff, ans->data,
+			       min_t(int, exp_len, ans_size));
+		if (ans_length)
+			*ans_length = le16_to_cpu(ans->hermes_len);
+	}
+ exit:
+	ezusb_request_context_put(ctx);
+	return retval;
+}
+
+static int ezusb_write_ltv(hermes_t *hw, int bap, u16 rid,
+			   u16 length, const void *data)
+{
+	struct ezusb_priv *upriv = hw->priv;
+	u16 frame_type;
+	struct request_context *ctx;
+
+	if (length == 0)
+		return -EINVAL;
+
+	length = HERMES_RECLEN_TO_BYTES(length);
+
+	/* On memory mapped devices HERMES_RID_CNFGROUPADDRESSES can be
+	 * set to be empty, but the USB bridge doesn't like it */
+	if (length == 0)
+		return 0;
+
+	ctx = ezusb_alloc_ctx(upriv, rid, EZUSB_RID_ACK);
+	if (!ctx)
+		return -ENOMEM;
+
+	if (rid == EZUSB_RID_TX)
+		frame_type = EZUSB_FRAME_DATA;
+	else
+		frame_type = EZUSB_FRAME_CONTROL;
+
+	return ezusb_access_ltv(upriv, ctx, length, data, frame_type,
+				NULL, 0, NULL);
+}
+
+static int ezusb_read_ltv(hermes_t *hw, int bap, u16 rid,
+			  unsigned bufsize, u16 *length, void *buf)
+{
+	struct ezusb_priv *upriv = hw->priv;
+	struct request_context *ctx;
+
+	if ((bufsize < 0) || (bufsize % 2))
+		return -EINVAL;
+
+	ctx = ezusb_alloc_ctx(upriv, rid, rid);
+	if (!ctx)
+		return -ENOMEM;
+
+	return ezusb_access_ltv(upriv, ctx, 0, NULL, EZUSB_FRAME_CONTROL,
+				buf, bufsize, length);
+}
+
+static int ezusb_doicmd_wait(hermes_t *hw, u16 cmd, u16 parm0, u16 parm1,
+			     u16 parm2, struct hermes_response *resp)
+{
+	struct ezusb_priv *upriv = hw->priv;
+	struct request_context *ctx;
+
+	__le16 data[4] = {
+		cpu_to_le16(cmd),
+		cpu_to_le16(parm0),
+		cpu_to_le16(parm1),
+		cpu_to_le16(parm2),
+	};
+	dbg("0x%04X, parm0 0x%04X, parm1 0x%04X, parm2 0x%04X",
+	    cmd, parm0, parm1, parm2);
+	ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK);
+	if (!ctx)
+		return -ENOMEM;
+
+	return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+				EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
+			    struct hermes_response *resp)
+{
+	struct ezusb_priv *upriv = hw->priv;
+	struct request_context *ctx;
+
+	__le16 data[4] = {
+		cpu_to_le16(cmd),
+		cpu_to_le16(parm0),
+		0,
+		0,
+	};
+	dbg("0x%04X, parm0 0x%04X", cmd, parm0);
+	ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK);
+	if (!ctx)
+		return -ENOMEM;
+
+	return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+				EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_bap_pread(struct hermes *hw, int bap,
+			   void *buf, int len, u16 id, u16 offset)
+{
+	struct ezusb_priv *upriv = hw->priv;
+	struct ezusb_packet *ans = (void *) upriv->read_urb->transfer_buffer;
+	int actual_length = upriv->read_urb->actual_length;
+
+	if (id == EZUSB_RID_RX) {
+		if ((sizeof(*ans) + offset + len) > actual_length) {
+			printk(KERN_ERR PFX "BAP read beyond buffer end "
+			       "in rx frame\n");
+			return -EINVAL;
+		}
+		memcpy(buf, ans->data + offset, len);
+		return 0;
+	}
+
+	if (EZUSB_IS_INFO(id)) {
+		/* Include 4 bytes for length/type */
+		if ((sizeof(*ans) + offset + len - 4) > actual_length) {
+			printk(KERN_ERR PFX "BAP read beyond buffer end "
+			       "in info frame\n");
+			return -EFAULT;
+		}
+		memcpy(buf, ans->data + offset - 4, len);
+	} else {
+		printk(KERN_ERR PFX "Unexpected fid 0x%04x\n", id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct orinoco_private *priv = ndev_priv(dev);
+	struct net_device_stats *stats = &priv->stats;
+	struct ezusb_priv *upriv = priv->card;
+	int err = 0;
+	char *p;
+	struct ethhdr *eh;
+	int len, data_len, data_off;
+	__le16 tx_control;
+	unsigned long flags;
+	struct request_context *ctx;
+	u8 *buf;
+	int tx_size;
+
+	if (!netif_running(dev)) {
+		printk(KERN_ERR "%s: Tx on stopped device!\n",
+		       dev->name);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (netif_queue_stopped(dev)) {
+		printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
+		       dev->name);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (orinoco_lock(priv, &flags) != 0) {
+		printk(KERN_ERR
+		       "%s: orinoco_xmit() called while hw_unavailable\n",
+		       dev->name);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (!netif_carrier_ok(dev) ||
+	    (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
+		/* Oops, the firmware hasn't established a connection,
+		   silently drop the packet (this seems to be the
+		   safest approach). */
+		stats->tx_errors++;
+		orinoco_unlock(priv, &flags);
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0);
+	if (!ctx)
+		goto fail;
+
+	memset(ctx->buf, 0, BULK_BUF_SIZE);
+	buf = ctx->buf->data;
+
+	/* Length of the packet body */
+	/* FIXME: what if the skb is smaller than this? */
+	len = max_t(int, skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN);
+
+	eh = (struct ethhdr *) skb->data;
+
+	tx_control = cpu_to_le16(0);
+	memcpy(buf, &tx_control, sizeof(tx_control));
+	buf += sizeof(tx_control);
+	/* Encapsulate Ethernet-II frames */
+	if (ntohs(eh->h_proto) > ETH_DATA_LEN) {	/* Ethernet-II frame */
+		struct header_struct *hdr = (void *) buf;
+		buf += sizeof(*hdr);
+		data_len = len;
+		data_off = sizeof(tx_control) + sizeof(*hdr);
+		p = skb->data + ETH_HLEN;
+
+		/* 802.3 header */
+		memcpy(hdr->dest, eh->h_dest, ETH_ALEN);
+		memcpy(hdr->src, eh->h_source, ETH_ALEN);
+		hdr->len = htons(data_len + ENCAPS_OVERHEAD);
+
+		/* 802.2 header */
+		memcpy(&hdr->dsap, &encaps_hdr, sizeof(encaps_hdr));
+
+		hdr->ethertype = eh->h_proto;
+	} else {		/* IEEE 802.3 frame */
+		data_len = len + ETH_HLEN;
+		data_off = sizeof(tx_control);
+		p = skb->data;
+	}
+
+	memcpy(buf, p, data_len);
+	buf += data_len;
+
+	/* Finally, we actually initiate the send */
+	netif_stop_queue(dev);
+
+	/* The card may behave better if we send evenly sized usb transfers */
+	tx_size = ALIGN(buf - ctx->buf->data, 2);
+
+	err = ezusb_access_ltv(upriv, ctx, tx_size, NULL,
+			       EZUSB_FRAME_DATA, NULL, 0, NULL);
+
+	if (err) {
+		netif_start_queue(dev);
+		if (net_ratelimit())
+			printk(KERN_ERR "%s: Error %d transmitting packet\n",
+				dev->name, err);
+		stats->tx_errors++;
+		goto fail;
+	}
+
+	dev->trans_start = jiffies;
+	stats->tx_bytes += data_off + data_len;
+
+	orinoco_unlock(priv, &flags);
+
+	dev_kfree_skb(skb);
+
+	return NETDEV_TX_OK;
+
+ fail:
+	orinoco_unlock(priv, &flags);
+	return NETDEV_TX_BUSY;
+}
+
+static int ezusb_allocate(struct hermes *hw, u16 size, u16 *fid)
+{
+	*fid = EZUSB_RID_TX;
+	return 0;
+}
+
+
+static int ezusb_hard_reset(struct orinoco_private *priv)
+{
+	struct ezusb_priv *upriv = priv->card;
+	int retval = ezusb_8051_cpucs(upriv, 1);
+
+	if (retval < 0) {
+		err("Failed to reset");
+		return retval;
+	}
+
+	retval = ezusb_8051_cpucs(upriv, 0);
+	if (retval < 0) {
+		err("Failed to unreset");
+		return retval;
+	}
+
+	dbg("sending control message");
+	retval = usb_control_msg(upriv->udev,
+				 usb_sndctrlpipe(upriv->udev, 0),
+				 EZUSB_REQUEST_TRIGER,
+				 USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+				 USB_DIR_OUT, 0x0, 0x0, NULL, 0,
+				 DEF_TIMEOUT);
+	if (retval < 0) {
+		err("EZUSB_REQUEST_TRIGER failed retval %d", retval);
+		return retval;
+	}
+#if 0
+	dbg("Sending EZUSB_REQUEST_TRIG_AC");
+	retval = usb_control_msg(upriv->udev,
+				 usb_sndctrlpipe(upriv->udev, 0),
+				 EZUSB_REQUEST_TRIG_AC,
+				 USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+				 USB_DIR_OUT, 0x00FA, 0x0, NULL, 0,
+				 DEF_TIMEOUT);
+	if (retval < 0) {
+		err("EZUSB_REQUEST_TRIG_AC failed retval %d", retval);
+		return retval;
+	}
+#endif
+
+	return 0;
+}
+
+
+static int ezusb_init(hermes_t *hw)
+{
+	struct ezusb_priv *upriv = hw->priv;
+	int retval;
+
+	BUG_ON(in_interrupt());
+	BUG_ON(!upriv);
+
+	upriv->reply_count = 0;
+	/* Write the MAGIC number on the simulated registers to keep
+	 * orinoco.c happy */
+	hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
+	hermes_write_regn(hw, RXFID, EZUSB_RID_RX);
+
+	usb_kill_urb(upriv->read_urb);
+	ezusb_submit_in_urb(upriv);
+
+	retval = ezusb_write_ltv(hw, 0, EZUSB_RID_INIT1,
+				 HERMES_BYTES_TO_RECLEN(2), "\x10\x00");
+	if (retval < 0) {
+		printk(KERN_ERR PFX "EZUSB_RID_INIT1 error %d\n", retval);
+		return retval;
+	}
+
+	retval = ezusb_docmd_wait(hw, HERMES_CMD_INIT, 0, NULL);
+	if (retval < 0) {
+		printk(KERN_ERR PFX "HERMES_CMD_INIT error %d\n", retval);
+		return retval;
+	}
+
+	return 0;
+}
+
+static void ezusb_bulk_in_callback(struct urb *urb)
+{
+	struct ezusb_priv *upriv = (struct ezusb_priv *) urb->context;
+	struct ezusb_packet *ans = urb->transfer_buffer;
+	u16 crc;
+	u16 hermes_rid;
+
+	if (upriv->udev == NULL) {
+		dbg("disconnected");
+		return;
+	}
+
+	if (urb->status == -ETIMEDOUT) {
+		/* When a device gets unplugged we get this every time
+		 * we resubmit, flooding the logs.  Since we don't use
+		 * USB timeouts, it shouldn't happen any other time*/
+		pr_warning("%s: urb timed out, not resubmiting", __func__);
+		return;
+	}
+	if (urb->status == -ECONNABORTED) {
+		pr_warning("%s: connection abort, resubmiting urb",
+		     __func__);
+		goto resubmit;
+	}
+	if ((urb->status == -EILSEQ)
+	    || (urb->status == -ENOENT)
+	    || (urb->status == -ECONNRESET)) {
+		dbg("status %d, not resubmiting", urb->status);
+		return;
+	}
+	if (urb->status)
+		dbg("status: %d length: %d",
+		    urb->status, urb->actual_length);
+	if (urb->actual_length < sizeof(*ans)) {
+		err("%s: short read, ignoring", __func__);
+		goto resubmit;
+	}
+	crc = build_crc(ans);
+	if (le16_to_cpu(ans->crc) != crc) {
+		err("CRC error, ignoring packet");
+		goto resubmit;
+	}
+
+	hermes_rid = le16_to_cpu(ans->hermes_rid);
+	if ((hermes_rid != EZUSB_RID_RX) && !EZUSB_IS_INFO(hermes_rid)) {
+		ezusb_request_in_callback(upriv, urb);
+	} else if (upriv->dev) {
+		struct net_device *dev = upriv->dev;
+		struct orinoco_private *priv = ndev_priv(dev);
+		hermes_t *hw = &priv->hw;
+
+		if (hermes_rid == EZUSB_RID_RX) {
+			__orinoco_ev_rx(dev, hw);
+		} else {
+			hermes_write_regn(hw, INFOFID,
+					  le16_to_cpu(ans->hermes_rid));
+			__orinoco_ev_info(dev, hw);
+		}
+	}
+
+ resubmit:
+	if (upriv->udev)
+		ezusb_submit_in_urb(upriv);
+}
+
+static inline void ezusb_delete(struct ezusb_priv *upriv)
+{
+	struct net_device *dev;
+	struct list_head *item;
+	struct list_head *tmp_item;
+	unsigned long flags;
+
+	BUG_ON(in_interrupt());
+	BUG_ON(!upriv);
+
+	dev = upriv->dev;
+	mutex_lock(&upriv->mtx);
+
+	upriv->udev = NULL;	/* No timer will be rearmed from here */
+
+	usb_kill_urb(upriv->read_urb);
+
+	spin_lock_irqsave(&upriv->req_lock, flags);
+	list_for_each_safe(item, tmp_item, &upriv->req_active) {
+		struct request_context *ctx;
+		int err;
+
+		ctx = list_entry(item, struct request_context, list);
+		atomic_inc(&ctx->refcount);
+
+		ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
+		err = usb_unlink_urb(ctx->outurb);
+
+		spin_unlock_irqrestore(&upriv->req_lock, flags);
+		if (err == -EINPROGRESS)
+			wait_for_completion(&ctx->done);
+
+		del_timer_sync(&ctx->timer);
+		/* FIXME: there is an slight chance for the irq handler to
+		 * be running */
+		if (!list_empty(&ctx->list))
+			ezusb_ctx_complete(ctx);
+
+		ezusb_request_context_put(ctx);
+		spin_lock_irqsave(&upriv->req_lock, flags);
+	}
+	spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+	list_for_each_safe(item, tmp_item, &upriv->req_pending)
+	    ezusb_ctx_complete(list_entry(item,
+					  struct request_context, list));
+
+	if (upriv->read_urb->status == -EINPROGRESS)
+		printk(KERN_ERR PFX "Some URB in progress\n");
+
+	mutex_unlock(&upriv->mtx);
+
+	kfree(upriv->read_urb->transfer_buffer);
+	if (upriv->bap_buf != NULL)
+		kfree(upriv->bap_buf);
+	if (upriv->read_urb != NULL)
+		usb_free_urb(upriv->read_urb);
+	if (upriv->dev) {
+		struct orinoco_private *priv = ndev_priv(upriv->dev);
+		orinoco_if_del(priv);
+		free_orinocodev(priv);
+	}
+}
+
+static void ezusb_lock_irqsave(spinlock_t *lock,
+			       unsigned long *flags) __acquires(lock)
+{
+	spin_lock_bh(lock);
+}
+
+static void ezusb_unlock_irqrestore(spinlock_t *lock,
+				    unsigned long *flags) __releases(lock)
+{
+	spin_unlock_bh(lock);
+}
+
+static void ezusb_lock_irq(spinlock_t *lock) __acquires(lock)
+{
+	spin_lock_bh(lock);
+}
+
+static void ezusb_unlock_irq(spinlock_t *lock) __releases(lock)
+{
+	spin_unlock_bh(lock);
+}
+
+static const struct hermes_ops ezusb_ops = {
+	.init = ezusb_init,
+	.cmd_wait = ezusb_docmd_wait,
+	.init_cmd_wait = ezusb_doicmd_wait,
+	.allocate = ezusb_allocate,
+	.read_ltv = ezusb_read_ltv,
+	.write_ltv = ezusb_write_ltv,
+	.bap_pread = ezusb_bap_pread,
+	.lock_irqsave = ezusb_lock_irqsave,
+	.unlock_irqrestore = ezusb_unlock_irqrestore,
+	.lock_irq = ezusb_lock_irq,
+	.unlock_irq = ezusb_unlock_irq,
+};
+
+static const struct net_device_ops ezusb_netdev_ops = {
+	.ndo_open		= orinoco_open,
+	.ndo_stop		= orinoco_stop,
+	.ndo_start_xmit		= ezusb_xmit,
+	.ndo_set_multicast_list	= orinoco_set_multicast_list,
+	.ndo_change_mtu		= orinoco_change_mtu,
+	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_tx_timeout		= orinoco_tx_timeout,
+	.ndo_get_stats		= orinoco_get_stats,
+};
+
+static int ezusb_probe(struct usb_interface *interface,
+		       const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct orinoco_private *priv;
+	hermes_t *hw;
+	struct ezusb_priv *upriv = NULL;
+	struct usb_interface_descriptor *iface_desc;
+	struct usb_endpoint_descriptor *ep;
+	const struct firmware *fw_entry;
+	int retval = 0;
+	int i;
+
+	priv = alloc_orinocodev(sizeof(*upriv), &udev->dev,
+				ezusb_hard_reset, NULL);
+	if (!priv) {
+		err("Couldn't allocate orinocodev");
+		goto exit;
+	}
+
+	hw = &priv->hw;
+
+	upriv = priv->card;
+
+	mutex_init(&upriv->mtx);
+	spin_lock_init(&upriv->reply_count_lock);
+
+	spin_lock_init(&upriv->req_lock);
+	INIT_LIST_HEAD(&upriv->req_pending);
+	INIT_LIST_HEAD(&upriv->req_active);
+
+	upriv->udev = udev;
+
+	hw->iobase = (void __force __iomem *) &upriv->hermes_reg_fake;
+	hw->reg_spacing = HERMES_16BIT_REGSPACING;
+	hw->priv = upriv;
+	hw->ops = &ezusb_ops;
+
+	/* set up the endpoint information */
+	/* check out the endpoints */
+
+	iface_desc = &interface->altsetting[0].desc;
+	for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
+		ep = &interface->altsetting[0].endpoint[i].desc;
+
+		if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+		     == USB_DIR_IN) &&
+		    ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+		     == USB_ENDPOINT_XFER_BULK)) {
+			/* we found a bulk in endpoint */
+			if (upriv->read_urb != NULL) {
+				pr_warning("Found a second bulk in ep, ignored");
+				continue;
+			}
+
+			upriv->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+			if (!upriv->read_urb) {
+				err("No free urbs available");
+				goto error;
+			}
+			if (le16_to_cpu(ep->wMaxPacketSize) != 64)
+				pr_warning("bulk in: wMaxPacketSize!= 64");
+			if (ep->bEndpointAddress != (2 | USB_DIR_IN))
+				pr_warning("bulk in: bEndpointAddress: %d",
+				     ep->bEndpointAddress);
+			upriv->read_pipe = usb_rcvbulkpipe(udev,
+							 ep->
+							 bEndpointAddress);
+			upriv->read_urb->transfer_buffer =
+			    kmalloc(BULK_BUF_SIZE, GFP_KERNEL);
+			if (!upriv->read_urb->transfer_buffer) {
+				err("Couldn't allocate IN buffer");
+				goto error;
+			}
+		}
+
+		if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+		     == USB_DIR_OUT) &&
+		    ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+		     == USB_ENDPOINT_XFER_BULK)) {
+			/* we found a bulk out endpoint */
+			if (upriv->bap_buf != NULL) {
+				pr_warning("Found a second bulk out ep, ignored");
+				continue;
+			}
+
+			if (le16_to_cpu(ep->wMaxPacketSize) != 64)
+				pr_warning("bulk out: wMaxPacketSize != 64");
+			if (ep->bEndpointAddress != 2)
+				pr_warning("bulk out: bEndpointAddress: %d",
+				     ep->bEndpointAddress);
+			upriv->write_pipe = usb_sndbulkpipe(udev,
+							  ep->
+							  bEndpointAddress);
+			upriv->bap_buf = kmalloc(BULK_BUF_SIZE, GFP_KERNEL);
+			if (!upriv->bap_buf) {
+				err("Couldn't allocate bulk_out_buffer");
+				goto error;
+			}
+		}
+	}
+	if (!upriv->bap_buf || !upriv->read_urb) {
+		err("Didn't find the required bulk endpoints");
+		goto error;
+	}
+
+	if (request_firmware(&fw_entry, "orinoco_ezusb_fw",
+			     &interface->dev) == 0) {
+		firmware.size = fw_entry->size;
+		firmware.code = fw_entry->data;
+	}
+	if (firmware.size && firmware.code) {
+		ezusb_firmware_download(upriv, &firmware);
+	} else {
+		err("No firmware to download");
+		goto error;
+	}
+
+	if (ezusb_hard_reset(priv) < 0) {
+		err("Cannot reset the device");
+		goto error;
+	}
+
+	/* If the firmware is already downloaded orinoco.c will call
+	 * ezusb_init but if the firmware is not already there, that will make
+	 * the kernel very unstable, so we try initializing here and quit in
+	 * case of error */
+	if (ezusb_init(hw) < 0) {
+		err("Couldn't initialize the device");
+		err("Firmware may not be downloaded or may be wrong.");
+		goto error;
+	}
+
+	/* Initialise the main driver */
+	if (orinoco_init(priv) != 0) {
+		err("orinoco_init() failed\n");
+		goto error;
+	}
+
+	if (orinoco_if_add(priv, 0, 0, &ezusb_netdev_ops) != 0) {
+		upriv->dev = NULL;
+		err("%s: orinoco_if_add() failed", __func__);
+		goto error;
+	}
+	upriv->dev = priv->ndev;
+
+	goto exit;
+
+ error:
+	ezusb_delete(upriv);
+	if (upriv->dev) {
+		/* upriv->dev was 0, so ezusb_delete() didn't free it */
+		free_orinocodev(priv);
+	}
+	upriv = NULL;
+	retval = -EFAULT;
+ exit:
+	if (fw_entry) {
+		firmware.code = NULL;
+		firmware.size = 0;
+		release_firmware(fw_entry);
+	}
+	usb_set_intfdata(interface, upriv);
+	return retval;
+}
+
+
+static void ezusb_disconnect(struct usb_interface *intf)
+{
+	struct ezusb_priv *upriv = usb_get_intfdata(intf);
+	usb_set_intfdata(intf, NULL);
+	ezusb_delete(upriv);
+	printk(KERN_INFO PFX "Disconnected\n");
+}
+
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver orinoco_driver = {
+	.name = DRIVER_NAME,
+	.probe = ezusb_probe,
+	.disconnect = ezusb_disconnect,
+	.id_table = ezusb_table,
+};
+
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+    " (Manuel Estrada Sainz)";
+
+static int __init ezusb_module_init(void)
+{
+	int err;
+
+	printk(KERN_DEBUG "%s\n", version);
+
+	/* register this driver with the USB subsystem */
+	err = usb_register(&orinoco_driver);
+	if (err < 0) {
+		printk(KERN_ERR PFX "usb_register failed, error %d\n",
+		       err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __exit ezusb_module_exit(void)
+{
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&orinoco_driver);
+}
+
+
+module_init(ezusb_module_init);
+module_exit(ezusb_module_exit);
+
+MODULE_AUTHOR("Manuel Estrada Sainz");
+MODULE_DESCRIPTION
+    ("Driver for Orinoco wireless LAN cards using EZUSB bridge");
+MODULE_LICENSE("Dual MPL/GPL");
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH 5/6] orinoco_usb: avoid in_atomic
From: David Kilroy @ 2010-05-01 13:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, linville, David Kilroy
In-Reply-To: <1272719143-26171-1-git-send-email-kilroyd@googlemail.com>

We expect to be either in process contect or soft interrupt context. So
use in_softirq instead.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/orinoco_usb.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index ce0069d..8e1b31c 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -701,7 +701,7 @@ static void ezusb_req_ctx_wait(struct ezusb_priv *upriv,
 	case EZUSB_CTX_REQ_SUBMITTED:
 	case EZUSB_CTX_REQ_COMPLETE:
 	case EZUSB_CTX_RESP_RECEIVED:
-		if (in_atomic()) {
+		if (in_softirq()) {
 			/* If we get called from a timer, timeout timers don't
 			 * get the chance to run themselves. So we make sure
 			 * that we don't sleep for ever */
-- 
1.6.4.4


^ permalink raw reply related

* [PATCH 6/6] orinoco_usb: implement fw download
From: David Kilroy @ 2010-05-01 13:05 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, linville, David Kilroy
In-Reply-To: <1272719143-26171-1-git-send-email-kilroyd@googlemail.com>

This involves some refactorring of the common fw download code to
substitute ezusb versions of various functions.

Note that WPA-enabled firmwares (9.xx series) will not work fully with
orinoco_usb yet.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/fw.c          |    8 +-
 drivers/net/wireless/orinoco/hermes.c      |  208 ++++++++++++++++++++++++
 drivers/net/wireless/orinoco/hermes.h      |    7 +
 drivers/net/wireless/orinoco/hermes_dld.c  |  243 +--------------------------
 drivers/net/wireless/orinoco/orinoco_usb.c |  120 ++++++++++++++
 drivers/net/wireless/orinoco/spectrum_cs.c |    1 +
 6 files changed, 349 insertions(+), 238 deletions(-)

diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c
index 4c99240..3e1947d 100644
--- a/drivers/net/wireless/orinoco/fw.c
+++ b/drivers/net/wireless/orinoco/fw.c
@@ -122,7 +122,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
 	dev_dbg(dev, "Attempting to download firmware %s\n", firmware);
 
 	/* Read current plug data */
-	err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
+	err = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
 	dev_dbg(dev, "Read PDA returned %d\n", err);
 	if (err)
 		goto free;
@@ -149,7 +149,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
 	}
 
 	/* Enable aux port to allow programming */
-	err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
+	err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point));
 	dev_dbg(dev, "Program init returned %d\n", err);
 	if (err != 0)
 		goto abort;
@@ -177,7 +177,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
 		goto abort;
 
 	/* Tell card we've finished */
-	err = hermesi_program_end(hw);
+	err = hw->ops->program_end(hw);
 	dev_dbg(dev, "Program end returned %d\n", err);
 	if (err != 0)
 		goto abort;
@@ -224,7 +224,7 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
 		if (!pda)
 			return -ENOMEM;
 
-		ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1);
+		ret = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
 		if (ret)
 			goto free;
 	}
diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c
index 845693f..6c6a23e 100644
--- a/drivers/net/wireless/orinoco/hermes.c
+++ b/drivers/net/wireless/orinoco/hermes.c
@@ -52,6 +52,26 @@
 #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
 
 /*
+ * AUX port access.  To unlock the AUX port write the access keys to the
+ * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
+ * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
+ */
+#define HERMES_AUX_ENABLE	0x8000	/* Enable auxiliary port access */
+#define HERMES_AUX_DISABLE	0x4000	/* Disable to auxiliary port access */
+#define HERMES_AUX_ENABLED	0xC000	/* Auxiliary port is open */
+#define HERMES_AUX_DISABLED	0x0000	/* Auxiliary port is closed */
+
+#define HERMES_AUX_PW0	0xFE01
+#define HERMES_AUX_PW1	0xDC23
+#define HERMES_AUX_PW2	0xBA45
+
+/* HERMES_CMD_DOWNLD */
+#define HERMES_PROGRAM_DISABLE             (0x0000 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_ENABLE_VOLATILE     (0x0100 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_NON_VOLATILE        (0x0300 | HERMES_CMD_DOWNLD)
+
+/*
  * Debugging helpers
  */
 
@@ -170,6 +190,7 @@ void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
 	hw->iobase = address;
 	hw->reg_spacing = reg_spacing;
 	hw->inten = 0x0;
+	hw->eeprom_pda = false;
 	hw->ops = &hermes_ops_local;
 }
 EXPORT_SYMBOL(hermes_struct_init);
@@ -529,6 +550,189 @@ static int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
 	return err;
 }
 
+/*** Hermes AUX control ***/
+
+static inline void
+hermes_aux_setaddr(hermes_t *hw, u32 addr)
+{
+	hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
+	hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
+}
+
+static inline int
+hermes_aux_control(hermes_t *hw, int enabled)
+{
+	int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
+	int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
+	int i;
+
+	/* Already open? */
+	if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
+		return 0;
+
+	hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
+	hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
+	hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
+	hermes_write_reg(hw, HERMES_CONTROL, action);
+
+	for (i = 0; i < 20; i++) {
+		udelay(10);
+		if (hermes_read_reg(hw, HERMES_CONTROL) ==
+		    desired_state)
+			return 0;
+	}
+
+	return -EBUSY;
+}
+
+/*** Hermes programming ***/
+
+/* About to start programming data (Hermes I)
+ * offset is the entry point
+ *
+ * Spectrum_cs' Symbol fw does not require this
+ * wl_lkm Agere fw does
+ * Don't know about intersil
+ */
+static int hermesi_program_init(hermes_t *hw, u32 offset)
+{
+	int err;
+
+	/* Disable interrupts?*/
+	/*hw->inten = 0x0;*/
+	/*hermes_write_regn(hw, INTEN, 0);*/
+	/*hermes_set_irqmask(hw, 0);*/
+
+	/* Acknowledge any outstanding command */
+	hermes_write_regn(hw, EVACK, 0xFFFF);
+
+	/* Using init_cmd_wait rather than cmd_wait */
+	err = hw->ops->init_cmd_wait(hw,
+				     0x0100 | HERMES_CMD_INIT,
+				     0, 0, 0, NULL);
+	if (err)
+		return err;
+
+	err = hw->ops->init_cmd_wait(hw,
+				     0x0000 | HERMES_CMD_INIT,
+				     0, 0, 0, NULL);
+	if (err)
+		return err;
+
+	err = hermes_aux_control(hw, 1);
+	pr_debug("AUX enable returned %d\n", err);
+
+	if (err)
+		return err;
+
+	pr_debug("Enabling volatile, EP 0x%08x\n", offset);
+	err = hw->ops->init_cmd_wait(hw,
+				     HERMES_PROGRAM_ENABLE_VOLATILE,
+				     offset & 0xFFFFu,
+				     offset >> 16,
+				     0,
+				     NULL);
+	pr_debug("PROGRAM_ENABLE returned %d\n", err);
+
+	return err;
+}
+
+/* Done programming data (Hermes I)
+ *
+ * Spectrum_cs' Symbol fw does not require this
+ * wl_lkm Agere fw does
+ * Don't know about intersil
+ */
+static int hermesi_program_end(hermes_t *hw)
+{
+	struct hermes_response resp;
+	int rc = 0;
+	int err;
+
+	rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
+
+	pr_debug("PROGRAM_DISABLE returned %d, "
+		 "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
+		 rc, resp.resp0, resp.resp1, resp.resp2);
+
+	if ((rc == 0) &&
+	    ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
+		rc = -EIO;
+
+	err = hermes_aux_control(hw, 0);
+	pr_debug("AUX disable returned %d\n", err);
+
+	/* Acknowledge any outstanding command */
+	hermes_write_regn(hw, EVACK, 0xFFFF);
+
+	/* Reinitialise, ignoring return */
+	(void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
+				      0, 0, 0, NULL);
+
+	return rc ? rc : err;
+}
+
+static int hermes_program_bytes(struct hermes *hw, const char *data,
+				u32 addr, u32 len)
+{
+	/* wl lkm splits the programming into chunks of 2000 bytes.
+	 * This restriction appears to come from USB. The PCMCIA
+	 * adapters can program the whole lot in one go */
+	hermes_aux_setaddr(hw, addr);
+	hermes_write_bytes(hw, HERMES_AUXDATA, data, len);
+	return 0;
+}
+
+/* Read PDA from the adapter */
+static int hermes_read_pda(hermes_t *hw, __le16 *pda, u32 pda_addr, u16 pda_len)
+{
+	int ret;
+	u16 pda_size;
+	u16 data_len = pda_len;
+	__le16 *data = pda;
+
+	if (hw->eeprom_pda) {
+		/* PDA of spectrum symbol is in eeprom */
+
+		/* Issue command to read EEPROM */
+		ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
+		if (ret)
+			return ret;
+	} else {
+		/* wl_lkm does not include PDA size in the PDA area.
+		 * We will pad the information into pda, so other routines
+		 * don't have to be modified */
+		pda[0] = cpu_to_le16(pda_len - 2);
+			/* Includes CFG_PROD_DATA but not itself */
+		pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
+		data_len = pda_len - 4;
+		data = pda + 2;
+	}
+
+	/* Open auxiliary port */
+	ret = hermes_aux_control(hw, 1);
+	pr_debug("AUX enable returned %d\n", ret);
+	if (ret)
+		return ret;
+
+	/* Read PDA */
+	hermes_aux_setaddr(hw, pda_addr);
+	hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
+
+	/* Close aux port */
+	ret = hermes_aux_control(hw, 0);
+	pr_debug("AUX disable returned %d\n", ret);
+
+	/* Check PDA length */
+	pda_size = le16_to_cpu(pda[0]);
+	pr_debug("Actual PDA length %d, Max allowed %d\n",
+		 pda_size, pda_len);
+	if (pda_size > pda_len)
+		return -EINVAL;
+
+	return 0;
+}
+
 static void hermes_lock_irqsave(spinlock_t *lock,
 				unsigned long *flags) __acquires(lock)
 {
@@ -561,6 +765,10 @@ static const struct hermes_ops hermes_ops_local = {
 	.write_ltv = hermes_write_ltv,
 	.bap_pread = hermes_bap_pread,
 	.bap_pwrite = hermes_bap_pwrite,
+	.read_pda = hermes_read_pda,
+	.program_init = hermesi_program_init,
+	.program_end = hermesi_program_end,
+	.program = hermes_program_bytes,
 	.lock_irqsave = hermes_lock_irqsave,
 	.unlock_irqrestore = hermes_unlock_irqrestore,
 	.lock_irq = hermes_lock_irq,
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index aed14ff..9ca34e7 100644
--- a/drivers/net/wireless/orinoco/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
@@ -393,6 +393,12 @@ struct hermes_ops {
 			 u16 id, u16 offset);
 	int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf,
 			  int len, u16 id, u16 offset);
+	int (*read_pda)(struct hermes *hw, __le16 *pda,
+			u32 pda_addr, u16 pda_len);
+	int (*program_init)(struct hermes *hw, u32 entry_point);
+	int (*program_end)(struct hermes *hw);
+	int (*program)(struct hermes *hw, const char *buf,
+		       u32 addr, u32 len);
 	void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags);
 	void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags);
 	void (*lock_irq)(spinlock_t *lock);
@@ -406,6 +412,7 @@ typedef struct hermes {
 #define HERMES_16BIT_REGSPACING	0
 #define HERMES_32BIT_REGSPACING	1
 	u16 inten; /* Which interrupts should be enabled? */
+	bool eeprom_pda;
 	const struct hermes_ops *ops;
 	void *priv;
 } hermes_t;
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index 8f22e20..6da85e7 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -46,37 +46,11 @@
 
 #define PFX "hermes_dld: "
 
-/*
- * AUX port access.  To unlock the AUX port write the access keys to the
- * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
- * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
- */
-#define HERMES_AUX_ENABLE	0x8000	/* Enable auxiliary port access */
-#define HERMES_AUX_DISABLE	0x4000	/* Disable to auxiliary port access */
-#define HERMES_AUX_ENABLED	0xC000	/* Auxiliary port is open */
-#define HERMES_AUX_DISABLED	0x0000	/* Auxiliary port is closed */
-
-#define HERMES_AUX_PW0	0xFE01
-#define HERMES_AUX_PW1	0xDC23
-#define HERMES_AUX_PW2	0xBA45
-
-/* HERMES_CMD_DOWNLD */
-#define HERMES_PROGRAM_DISABLE             (0x0000 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_VOLATILE     (0x0100 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_NON_VOLATILE        (0x0300 | HERMES_CMD_DOWNLD)
-
 /* End markers used in dblocks */
 #define PDI_END		0x00000000	/* End of PDA */
 #define BLOCK_END	0xFFFFFFFF	/* Last image block */
 #define TEXT_END	0x1A		/* End of text header */
 
-/* Limit the amout we try to download in a single shot.
- * Size is in bytes.
- */
-#define MAX_DL_SIZE 1024
-#define LIMIT_PROGRAM_SIZE 0
-
 /*
  * The following structures have little-endian fields denoted by
  * the leading underscore.  Don't access them directly - use inline
@@ -165,41 +139,6 @@ pdi_len(const struct pdi *pdi)
 	return 2 * (le16_to_cpu(pdi->len) - 1);
 }
 
-/*** Hermes AUX control ***/
-
-static inline void
-hermes_aux_setaddr(hermes_t *hw, u32 addr)
-{
-	hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
-	hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
-}
-
-static inline int
-hermes_aux_control(hermes_t *hw, int enabled)
-{
-	int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
-	int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
-	int i;
-
-	/* Already open? */
-	if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
-		return 0;
-
-	hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
-	hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
-	hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
-	hermes_write_reg(hw, HERMES_CONTROL, action);
-
-	for (i = 0; i < 20; i++) {
-		udelay(10);
-		if (hermes_read_reg(hw, HERMES_CONTROL) ==
-		    desired_state)
-			return 0;
-	}
-
-	return -EBUSY;
-}
-
 /*** Plug Data Functions ***/
 
 /*
@@ -271,62 +210,7 @@ hermes_plug_pdi(hermes_t *hw, const struct pdr *first_pdr,
 		return -EINVAL;
 
 	/* do the actual plugging */
-	hermes_aux_setaddr(hw, pdr_addr(pdr));
-	hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
-
-	return 0;
-}
-
-/* Read PDA from the adapter */
-int hermes_read_pda(hermes_t *hw,
-		    __le16 *pda,
-		    u32 pda_addr,
-		    u16 pda_len,
-		    int use_eeprom) /* can we get this into hw? */
-{
-	int ret;
-	u16 pda_size;
-	u16 data_len = pda_len;
-	__le16 *data = pda;
-
-	if (use_eeprom) {
-		/* PDA of spectrum symbol is in eeprom */
-
-		/* Issue command to read EEPROM */
-		ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
-		if (ret)
-			return ret;
-	} else {
-		/* wl_lkm does not include PDA size in the PDA area.
-		 * We will pad the information into pda, so other routines
-		 * don't have to be modified */
-		pda[0] = cpu_to_le16(pda_len - 2);
-			/* Includes CFG_PROD_DATA but not itself */
-		pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
-		data_len = pda_len - 4;
-		data = pda + 2;
-	}
-
-	/* Open auxiliary port */
-	ret = hermes_aux_control(hw, 1);
-	pr_debug(PFX "AUX enable returned %d\n", ret);
-	if (ret)
-		return ret;
-
-	/* read PDA from EEPROM */
-	hermes_aux_setaddr(hw, pda_addr);
-	hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
-
-	/* Close aux port */
-	ret = hermes_aux_control(hw, 0);
-	pr_debug(PFX "AUX disable returned %d\n", ret);
-
-	/* Check PDA length */
-	pda_size = le16_to_cpu(pda[0]);
-	pr_debug(PFX "Actual PDA length %d, Max allowed %d\n",
-		 pda_size, pda_len);
-	if (pda_size > pda_len)
-		return -EINVAL;
+	hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi));
 
 	return 0;
 }
@@ -389,101 +273,13 @@ hermes_blocks_length(const char *first_block, const void *end)
 
 /*** Hermes programming ***/
 
-/* About to start programming data (Hermes I)
- * offset is the entry point
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-int hermesi_program_init(hermes_t *hw, u32 offset)
-{
-	int err;
-
-	/* Disable interrupts?*/
-	/*hw->inten = 0x0;*/
-	/*hermes_write_regn(hw, INTEN, 0);*/
-	/*hermes_set_irqmask(hw, 0);*/
-
-	/* Acknowledge any outstanding command */
-	hermes_write_regn(hw, EVACK, 0xFFFF);
-
-	/* Using init_cmd_wait rather than cmd_wait */
-	err = hw->ops->init_cmd_wait(hw,
-				     0x0100 | HERMES_CMD_INIT,
-				     0, 0, 0, NULL);
-	if (err)
-		return err;
-
-	err = hw->ops->init_cmd_wait(hw,
-				     0x0000 | HERMES_CMD_INIT,
-				     0, 0, 0, NULL);
-	if (err)
-		return err;
-
-	err = hermes_aux_control(hw, 1);
-	pr_debug(PFX "AUX enable returned %d\n", err);
-
-	if (err)
-		return err;
-
-	pr_debug(PFX "Enabling volatile, EP 0x%08x\n", offset);
-	err = hw->ops->init_cmd_wait(hw,
-				     HERMES_PROGRAM_ENABLE_VOLATILE,
-				     offset & 0xFFFFu,
-				     offset >> 16,
-				     0,
-				     NULL);
-	pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err);
-
-	return err;
-}
-
-/* Done programming data (Hermes I)
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-int hermesi_program_end(hermes_t *hw)
-{
-	struct hermes_response resp;
-	int rc = 0;
-	int err;
-
-	rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
-
-	pr_debug(PFX "PROGRAM_DISABLE returned %d, "
-		 "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
-		 rc, resp.resp0, resp.resp1, resp.resp2);
-
-	if ((rc == 0) &&
-	    ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
-		rc = -EIO;
-
-	err = hermes_aux_control(hw, 0);
-	pr_debug(PFX "AUX disable returned %d\n", err);
-
-	/* Acknowledge any outstanding command */
-	hermes_write_regn(hw, EVACK, 0xFFFF);
-
-	/* Reinitialise, ignoring return */
-	(void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
-				      0, 0, 0, NULL);
-
-	return rc ? rc : err;
-}
-
 /* Program the data blocks */
 int hermes_program(hermes_t *hw, const char *first_block, const void *end)
 {
 	const struct dblock *blk;
 	u32 blkaddr;
 	u32 blklen;
-#if LIMIT_PROGRAM_SIZE
-	u32 addr;
-	u32 len;
-#endif
+	int err = 0;
 
 	blk = (const struct dblock *) first_block;
 
@@ -498,30 +294,10 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
 		pr_debug(PFX "Programming block of length %d "
 			 "to address 0x%08x\n", blklen, blkaddr);
 
-#if !LIMIT_PROGRAM_SIZE
-		/* wl_lkm driver splits this into writes of 2000 bytes */
-		hermes_aux_setaddr(hw, blkaddr);
-		hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
-				   blklen);
-#else
-		len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE;
-		addr = blkaddr;
-
-		while (addr < (blkaddr + blklen)) {
-			pr_debug(PFX "Programming subblock of length %d "
-				 "to address 0x%08x. Data @ %p\n",
-				 len, addr, &blk->data[addr - blkaddr]);
-
-			hermes_aux_setaddr(hw, addr);
-			hermes_write_bytes(hw, HERMES_AUXDATA,
-					   &blk->data[addr - blkaddr],
-					   len);
-
-			addr += len;
-			len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ?
-				(blkaddr + blklen - addr) : MAX_DL_SIZE;
-		}
-#endif
+		err = hw->ops->program(hw, blk->data, blkaddr, blklen);
+		if (err)
+			break;
+
 		blk = (const struct dblock *) &blk->data[blklen];
 
 		if ((void *) blk > (end - sizeof(*blk)))
@@ -530,7 +306,7 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
 		blkaddr = dblock_addr(blk);
 		blklen = dblock_len(blk);
 	}
-	return 0;
+	return err;
 }
 
 /*** Default plugging data for Hermes I ***/
@@ -690,9 +466,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
 			if ((pdi_len(pdi) == pdr_len(pdr)) &&
 			    ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
 				/* do the actual plugging */
-				hermes_aux_setaddr(hw, pdr_addr(pdr));
-				hermes_write_bytes(hw, HERMES_AUXDATA,
-						   pdi->data, pdi_len(pdi));
+				hw->ops->program(hw, pdi->data, pdr_addr(pdr),
+						 pdi_len(pdi));
 			}
 		}
 
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index 8e1b31c..e220933 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -184,6 +184,11 @@ MODULE_FIRMWARE("orinoco_ezusb_fw");
 #define EZUSB_RID_RX			0x0701
 #define EZUSB_RID_INIT1			0x0702
 #define EZUSB_RID_ACK			0x0710
+#define EZUSB_RID_READ_PDA		0x0800
+#define EZUSB_RID_PROG_INIT		0x0852
+#define EZUSB_RID_PROG_SET_ADDR		0x0853
+#define EZUSB_RID_PROG_BYTES		0x0854
+#define EZUSB_RID_PROG_END		0x0855
 #define EZUSB_RID_DOCMD			0x0860
 
 /* Recognize info frames */
@@ -198,6 +203,8 @@ MODULE_FIRMWARE("orinoco_ezusb_fw");
 
 #define BULK_BUF_SIZE			2048
 
+#define MAX_DL_SIZE (BULK_BUF_SIZE - sizeof(struct ezusb_packet))
+
 #define FW_BUF_SIZE			64
 #define FW_VAR_OFFSET_PTR		0x359
 #define FW_VAR_VALUE			0
@@ -1077,6 +1084,115 @@ static int ezusb_bap_pread(struct hermes *hw, int bap,
 	return 0;
 }
 
+static int ezusb_read_pda(struct hermes *hw, __le16 *pda,
+			  u32 pda_addr, u16 pda_len)
+{
+	struct ezusb_priv *upriv = hw->priv;
+	struct request_context *ctx;
+	__le16 data[] = {
+		cpu_to_le16(pda_addr & 0xffff),
+		cpu_to_le16(pda_len - 4)
+	};
+	ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_READ_PDA, EZUSB_RID_READ_PDA);
+	if (!ctx)
+		return -ENOMEM;
+
+	/* wl_lkm does not include PDA size in the PDA area.
+	 * We will pad the information into pda, so other routines
+	 * don't have to be modified */
+	pda[0] = cpu_to_le16(pda_len - 2);
+	/* Includes CFG_PROD_DATA but not itself */
+	pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
+
+	return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+				EZUSB_FRAME_CONTROL, &pda[2], pda_len - 4,
+				NULL);
+}
+
+static int ezusb_program_init(struct hermes *hw, u32 entry_point)
+{
+	struct ezusb_priv *upriv = hw->priv;
+	struct request_context *ctx;
+	__le32 data = cpu_to_le32(entry_point);
+
+	ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_INIT, EZUSB_RID_ACK);
+	if (!ctx)
+		return -ENOMEM;
+
+	return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+				EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_program_end(struct hermes *hw)
+{
+	struct ezusb_priv *upriv = hw->priv;
+	struct request_context *ctx;
+
+	ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_END, EZUSB_RID_ACK);
+	if (!ctx)
+		return -ENOMEM;
+
+	return ezusb_access_ltv(upriv, ctx, 0, NULL,
+				EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_program_bytes(struct hermes *hw, const char *buf,
+			       u32 addr, u32 len)
+{
+	struct ezusb_priv *upriv = hw->priv;
+	struct request_context *ctx;
+	__le32 data = cpu_to_le32(addr);
+	int err;
+
+	ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_SET_ADDR, EZUSB_RID_ACK);
+	if (!ctx)
+		return -ENOMEM;
+
+	err = ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+			       EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+	if (err)
+		return err;
+
+	ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_BYTES, EZUSB_RID_ACK);
+	if (!ctx)
+		return -ENOMEM;
+
+	return ezusb_access_ltv(upriv, ctx, len, buf,
+				EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_program(struct hermes *hw, const char *buf,
+			 u32 addr, u32 len)
+{
+	u32 ch_addr;
+	u32 ch_len;
+	int err = 0;
+
+	/* We can only send 2048 bytes out of the bulk xmit at a time,
+	 * so we have to split any programming into chunks of <2048
+	 * bytes. */
+
+	ch_len = (len < MAX_DL_SIZE) ? len : MAX_DL_SIZE;
+	ch_addr = addr;
+
+	while (ch_addr < (addr + len)) {
+		pr_debug("Programming subblock of length %d "
+			 "to address 0x%08x. Data @ %p\n",
+			 ch_len, ch_addr, &buf[ch_addr - addr]);
+
+		err = ezusb_program_bytes(hw, &buf[ch_addr - addr],
+					  ch_addr, ch_len);
+		if (err)
+			break;
+
+		ch_addr += ch_len;
+		ch_len = ((addr + len - ch_addr) < MAX_DL_SIZE) ?
+			(addr + len - ch_addr) : MAX_DL_SIZE;
+	}
+
+	return err;
+}
+
 static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct orinoco_private *priv = ndev_priv(dev);
@@ -1440,6 +1556,10 @@ static const struct hermes_ops ezusb_ops = {
 	.read_ltv = ezusb_read_ltv,
 	.write_ltv = ezusb_write_ltv,
 	.bap_pread = ezusb_bap_pread,
+	.read_pda = ezusb_read_pda,
+	.program_init = ezusb_program_init,
+	.program_end = ezusb_program_end,
+	.program = ezusb_program,
 	.lock_irqsave = ezusb_lock_irqsave,
 	.unlock_irqrestore = ezusb_unlock_irqrestore,
 	.lock_irq = ezusb_lock_irq,
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index b4f68ef..9b1af49 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -349,6 +349,7 @@ spectrum_cs_config(struct pcmcia_device *link)
 		goto failed;
 
 	hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
+	hw->eeprom_pda = true;
 
 	/*
 	 * This actually configures the PCMCIA socket -- setting up
-- 
1.6.4.4


^ permalink raw reply related

* Re: BCM4312 802.11b/g LP-PHY (rev 01) dma & led problems
From: Gábor Stefanik @ 2010-05-01 16:04 UTC (permalink / raw)
  To: Philippe De Muyter
  Cc: Larry Finger, Matthew Garrett, Dan Williams, linux-wireless
In-Reply-To: <20100501121706.GA32719@frolo.macqel>

On Sat, May 1, 2010 at 2:17 PM, Philippe De Muyter <phdm@macqel.be> wrote:
> This is a followup on my attempt to use b43 (now from 2.6.34-rc6) on
> a HP Pavilion dv6-1300sb.
>
> With 2.6.34-rc6, I have not had any boot problem (blocking around ssb/b43)
> so far.
>
> But, dma mode gives an error (like before) and driver now switches
> automatically to PIO mode (new).
>
>        [   89.830222] device mon0 entered promiscuous mode
>        [  101.965896] NOHZ: local_softirq_pending 08
>        [  101.969431] NOHZ: local_softirq_pending 08
>        [  101.972230] NOHZ: local_softirq_pending 08
>        [  101.975041] NOHZ: local_softirq_pending 08
>        [  101.977771] NOHZ: local_softirq_pending 08
>        [  101.984651] NOHZ: local_softirq_pending 08
>        [  101.988808] NOHZ: local_softirq_pending 08
>        [  101.991562] NOHZ: local_softirq_pending 08
>        [  101.994363] NOHZ: local_softirq_pending 08
>        [  101.997116] NOHZ: local_softirq_pending 08
>        [  111.816257] hpet1: lost 1 rtc interrupts
>        [  112.131040] hpet1: lost 1 rtc interrupts
>        [  112.133343] hpet1: lost 1 rtc interrupts
>        [  112.135528] hpet1: lost 1 rtc interrupts
>        [  112.137722] hpet1: lost 1 rtc interrupts
>        [  112.139911] hpet1: lost 1 rtc interrupts
>        [  112.142089] hpet1: lost 1 rtc interrupts
>        [  112.146370] hpet1: lost 1 rtc interrupts
>        [  112.150637] hpet1: lost 1 rtc interrupts
>        [  112.152849] hpet1: lost 1 rtc interrupts
>        [  113.100932] b43-phy0 ERROR: Fatal DMA error: 0x00000000, 0x00000800, 0x00000000, 0x00000000, 0x00000000, 0x00000000
>        [  113.100949] b43-phy0 ERROR: This device does not support DMA on your system. Please use PIO instead.
>        [  113.100957] b43-phy0: Controller RESET (DMA error) ...
>        [  113.336119] b43-phy0: Loading firmware version 478.104 (2008-07-01 00:50:23)
>        [  118.853353] b43-phy0: Controller restarted
>
> During the switch, the led switches from blue to red and returns to blue
> after some seconds.  Touching the led switches the hardware blocking on
> and off, but the led color does not change.
>
> I then tried with the broadcom supplied hybrid driver, and there the
> touch/led functionality works as expected : led is red whenever
> I touch the button (enabling hardware blocking) or when I issue
> a rfkill block 0 (enabling software blocking).  Led is blue only when
> both blocking are disabled.  But, hybrid driver does not give monitor
> functionality :( (and of course, also no injection).
>        [10703.172776] wl: module license 'unspecified' taints kernel.
>        [10703.172791] Disabling lock debugging due to kernel taint
>        [10703.174286] wl: Unknown symbol lib80211_get_crypto_ops
>        [10778.692746] lib80211: common routines for IEEE802.11 drivers
>        [10778.692759] lib80211_crypt: registered algorithm 'NULL'
>        [10783.823152] wl 0000:02:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
>        [10783.823188] wl 0000:02:00.0: setting latency timer to 64
>        [10783.921236] lib80211_crypt: registered algorithm 'TKIP'
>        [10783.921623] eth1: Broadcom BCM4315 802.11 Hybrid Wireless Controller 5.60.48.36
>
> Any idea on what I could do to debug more / fix the dma and led problems ?

Nothing, unfortunately. We are working on this issue; apparently some
workarounds are missing from our PCI-E init implementation.

>
> Philippe
>
> Here the output of lspci -nvv for that chip :
>
> linux-m1ew:~ # lspci -nvv -s 02:00.0
> 02:00.0 0280: 14e4:4315 (rev 01)
>        Subsystem: 103c:1508
>        Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
>        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
>        Latency: 0, Cache Line Size: 64 bytes
>        Interrupt: pin A routed to IRQ 16
>        Region 0: Memory at d9000000 (64-bit, non-prefetchable) [size=16K]
>        Capabilities: [40] Power Management version 3
>                Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
>                Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=2 PME-
>        Capabilities: [58] Vendor Specific Information: Len=78 <?>
>        Capabilities: [e8] MSI: Enable- Count=1/1 Maskable- 64bit+
>                Address: 0000000000000000  Data: 0000
>        Capabilities: [d0] Express (v1) Endpoint, MSI 00
>                DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <4us, L1 unlimited
>                        ExtTag+ AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
>                DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
>                        RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
>                        MaxPayload 128 bytes, MaxReadReq 128 bytes
>                DevSta: CorrErr+ UncorrErr- FatalErr- UnsuppReq+ AuxPwr- TransPend-
>                LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1, Latency L0 <4us, L1 <64us
>                        ClockPM+ Surprise- LLActRep- BwNot-
>                LnkCtl: ASPM L0s L1 Enabled; RCB 64 bytes Disabled- Retrain- CommClk+
>                        ExtSynch- ClockPM+ AutWidDis- BWInt- AutBWInt-
>                LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
>        Capabilities: [100 v1] Advanced Error Reporting
>                UESta:  DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
>                UEMsk:  DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
>                UESvrt: DLP+ SDES- TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
>                CESta:  RxErr+ BadTLP- BadDLLP- Rollover- Timeout+ NonFatalErr+
>                CEMsk:  RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
>                AERCap: First Error Pointer: 14, GenCap+ CGenEn- ChkCap+ ChkEn-
>        Capabilities: [13c v1] Virtual Channel
>                Caps:   LPEVC=0 RefClk=100ns PATEntryBits=1
>                Arb:    Fixed- WRR32- WRR64- WRR128-
>                Ctrl:   ArbSelect=Fixed
>                Status: InProgress-
>                VC0:    Caps:   PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
>                        Arb:    Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
>                        Ctrl:   Enable+ ID=0 ArbSelect=Fixed TC/VC=01
>                        Status: NegoPending- InProgress-
>        Capabilities: [160 v1] Device Serial Number 00-00-00-ff-ff-00-ff-ff
>        Capabilities: [16c v1] Power Budgeting <?>
>        Kernel driver in use: b43-pci-bridge
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)

^ permalink raw reply

* [PATCH] ar9170usb: remove deprecated aggregation code
From: Christian Lamparter @ 2010-05-01 16:18 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville

This patch removes the incomplete AMPDU implementation in ar9170usb.

The code in question is:
 * too big and complex (more than 550 SLOC.)
   This is enough to qualify for a new separate code file!

 * unbalanced quantity & quality
	over-engineered areas like:
		* xmit scheduling and queuing frames for multiple HT peers
		* redundant frame sorting
	are confronted by gaping holes:
		* accurate transmission feedback
		* firmware error-handling and device reset
		* HT rate control algorithm
		  
 * error-prone
	Since its inclusion, hardly anything was done to fix 
	any of the outlined flaws from the initial commit message.

   => This also indicates poor maintainability.

 * relies heavily on several spinlocks.

As a result of this shortcomings, the code is slow and does not
even support the most basic 11n requirement: HT station mode.

Therefore, I request to purge my heap of **** from the kernel:
"ar9170: implement transmit aggregation".

The next item on the agenda is: (re-)start from scratch with
an adequate design to accommodate the special requirements
and features of the available frameworks and tools.

Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
---
Note:

While this 'generic' ampdu implementation has failed to deliver
for ar9170usb, it is performing rather well in a different project
called" carl9170". Don't confuse these two.
---
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index dc662b7..4f845f8 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -109,41 +109,6 @@ struct ar9170_rxstream_mpdu_merge {
 	bool has_plcp;
 };
 
-#define AR9170_NUM_TID	16
-#define WME_BA_BMP_SIZE         64
-#define AR9170_NUM_MAX_AGG_LEN	(2 * WME_BA_BMP_SIZE)
-
-#define WME_AC_BE   2
-#define WME_AC_BK   3
-#define WME_AC_VI   1
-#define WME_AC_VO   0
-
-#define TID_TO_WME_AC(_tid)				\
-	((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE :	\
-	 (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK :	\
-	 (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI :	\
-	 WME_AC_VO)
-
-#define BAW_WITHIN(_start, _bawsz, _seqno) \
-	((((_seqno) - (_start)) & 0xfff) < (_bawsz))
-
-enum ar9170_tid_state {
-	AR9170_TID_STATE_INVALID,
-	AR9170_TID_STATE_SHUTDOWN,
-	AR9170_TID_STATE_PROGRESS,
-	AR9170_TID_STATE_COMPLETE,
-};
-
-struct ar9170_sta_tid {
-	struct list_head list;
-	struct sk_buff_head queue;
-	u8 addr[ETH_ALEN];
-	u16 ssn;
-	u16 tid;
-	enum ar9170_tid_state state;
-	bool active;
-};
-
 struct ar9170_tx_queue_stats {
 	unsigned int len;
 	unsigned int limit;
@@ -152,14 +117,11 @@ struct ar9170_tx_queue_stats {
 
 #define AR9170_QUEUE_TIMEOUT		64
 #define AR9170_TX_TIMEOUT		8
-#define AR9170_BA_TIMEOUT		4
 #define AR9170_JANITOR_DELAY		128
 #define AR9170_TX_INVALID_RATE		0xffffffff
 
-#define AR9170_NUM_TX_STATUS		128
-#define AR9170_NUM_TX_AGG_MAX		30
-#define AR9170_NUM_TX_LIMIT_HARD       AR9170_TXQ_DEPTH
-#define AR9170_NUM_TX_LIMIT_SOFT       (AR9170_TXQ_DEPTH - 10)
+#define AR9170_NUM_TX_LIMIT_HARD	AR9170_TXQ_DEPTH
+#define AR9170_NUM_TX_LIMIT_SOFT	(AR9170_TXQ_DEPTH - 10)
 
 struct ar9170 {
 	struct ieee80211_hw *hw;
@@ -234,11 +196,6 @@ struct ar9170 {
 	struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
 	struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
 	struct delayed_work tx_janitor;
-	/* tx ampdu */
-	struct sk_buff_head tx_status_ampdu;
-	spinlock_t tx_ampdu_list_lock;
-	struct list_head tx_ampdu_list;
-	atomic_t tx_ampdu_pending;
 
 	/* rxstream mpdu merge */
 	struct ar9170_rxstream_mpdu_merge rx_mpdu;
@@ -250,11 +207,6 @@ struct ar9170 {
 	u8 global_ampdu_factor;
 };
 
-struct ar9170_sta_info {
-	struct ar9170_sta_tid agg[AR9170_NUM_TID];
-	unsigned int ampdu_max_len;
-};
-
 struct ar9170_tx_info {
 	unsigned long timeout;
 };
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index f57e7c6..b68f317 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -50,10 +50,6 @@ static int modparam_nohwcrypt;
 module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 
-static int modparam_ht;
-module_param_named(ht, modparam_ht, bool, S_IRUGO);
-MODULE_PARM_DESC(ht, "enable MPDU aggregation.");
-
 #define RATE(_bitrate, _hw_rate, _txpidx, _flags) {	\
 	.bitrate	= (_bitrate),			\
 	.flags		= (_flags),			\
@@ -182,7 +178,6 @@ static struct ieee80211_supported_band ar9170_band_5GHz = {
 };
 
 static void ar9170_tx(struct ar9170 *ar);
-static bool ar9170_tx_ampdu(struct ar9170 *ar);
 
 static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
 {
@@ -195,21 +190,7 @@ static inline u16 ar9170_get_seq(struct sk_buff *skb)
 	return ar9170_get_seq_h((void *) txc->frame_data);
 }
 
-static inline u16 ar9170_get_tid_h(struct ieee80211_hdr *hdr)
-{
-	return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
-}
-
-static inline u16 ar9170_get_tid(struct sk_buff *skb)
-{
-	struct ar9170_tx_control *txc = (void *) skb->data;
-	return ar9170_get_tid_h((struct ieee80211_hdr *) txc->frame_data);
-}
-
-#define GET_NEXT_SEQ(seq)	((seq + 1) & 0x0fff)
-#define GET_NEXT_SEQ_FROM_SKB(skb)	(GET_NEXT_SEQ(ar9170_get_seq(skb)))
-
-#if (defined AR9170_QUEUE_DEBUG) || (defined AR9170_TXAGG_DEBUG)
+#ifdef AR9170_QUEUE_DEBUG
 static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
 {
 	struct ar9170_tx_control *txc = (void *) skb->data;
@@ -244,7 +225,7 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar,
 		       "mismatch %d != %d\n", skb_queue_len(queue), i);
 	printk(KERN_DEBUG "---[ end ]---\n");
 }
-#endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */
+#endif /* AR9170_QUEUE_DEBUG */
 
 #ifdef AR9170_QUEUE_DEBUG
 static void ar9170_dump_txqueue(struct ar9170 *ar,
@@ -275,20 +256,6 @@ static void __ar9170_dump_txstats(struct ar9170 *ar)
 }
 #endif /* AR9170_QUEUE_STOP_DEBUG */
 
-#ifdef AR9170_TXAGG_DEBUG
-static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags);
-	printk(KERN_DEBUG "%s: A-MPDU tx_status queue =>\n",
-	       wiphy_name(ar->hw->wiphy));
-	__ar9170_dump_txqueue(ar, &ar->tx_status_ampdu);
-	spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags);
-}
-
-#endif /* AR9170_TXAGG_DEBUG */
-
 /* caller must guarantee exclusive access for _bin_ queue. */
 static void ar9170_recycle_expired(struct ar9170 *ar,
 				   struct sk_buff_head *queue,
@@ -360,70 +327,6 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
 	ieee80211_tx_status_irqsafe(ar->hw, skb);
 }
 
-static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar)
-{
-	struct sk_buff_head success;
-	struct sk_buff *skb;
-	unsigned int i;
-	unsigned long queue_bitmap = 0;
-
-	skb_queue_head_init(&success);
-
-	while (skb_queue_len(&ar->tx_status_ampdu) > AR9170_NUM_TX_STATUS)
-		__skb_queue_tail(&success, skb_dequeue(&ar->tx_status_ampdu));
-
-	ar9170_recycle_expired(ar, &ar->tx_status_ampdu, &success);
-
-#ifdef AR9170_TXAGG_DEBUG
-	printk(KERN_DEBUG "%s: collected %d A-MPDU frames.\n",
-	       wiphy_name(ar->hw->wiphy), skb_queue_len(&success));
-	__ar9170_dump_txqueue(ar, &success);
-#endif /* AR9170_TXAGG_DEBUG */
-
-	while ((skb = __skb_dequeue(&success))) {
-		struct ieee80211_tx_info *txinfo;
-
-		queue_bitmap |= BIT(skb_get_queue_mapping(skb));
-
-		txinfo = IEEE80211_SKB_CB(skb);
-		ieee80211_tx_info_clear_status(txinfo);
-
-		txinfo->flags |= IEEE80211_TX_STAT_ACK;
-		txinfo->status.rates[0].count = 1;
-
-		skb_pull(skb, sizeof(struct ar9170_tx_control));
-		ieee80211_tx_status_irqsafe(ar->hw, skb);
-	}
-
-	for_each_set_bit(i, &queue_bitmap, BITS_PER_BYTE) {
-#ifdef AR9170_QUEUE_STOP_DEBUG
-		printk(KERN_DEBUG "%s: wake queue %d\n",
-		       wiphy_name(ar->hw->wiphy), i);
-		__ar9170_dump_txstats(ar);
-#endif /* AR9170_QUEUE_STOP_DEBUG */
-		ieee80211_wake_queue(ar->hw, i);
-	}
-
-	if (queue_bitmap)
-		ar9170_tx(ar);
-}
-
-static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
-{
-	struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
-	struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
-
-	arinfo->timeout = jiffies +
-			  msecs_to_jiffies(AR9170_BA_TIMEOUT);
-
-	skb_queue_tail(&ar->tx_status_ampdu, skb);
-	ar9170_tx_fake_ampdu_status(ar);
-
-	if (atomic_dec_and_test(&ar->tx_ampdu_pending) &&
-	    !list_empty(&ar->tx_ampdu_list))
-		ar9170_tx_ampdu(ar);
-}
-
 void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -447,14 +350,10 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
 	if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
 		ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);
 	} else {
-		if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-			ar9170_tx_ampdu_callback(ar, skb);
-		} else {
-			arinfo->timeout = jiffies +
-				  msecs_to_jiffies(AR9170_TX_TIMEOUT);
+		arinfo->timeout = jiffies +
+			  msecs_to_jiffies(AR9170_TX_TIMEOUT);
 
-			skb_queue_tail(&ar->tx_status[queue], skb);
-		}
+		skb_queue_tail(&ar->tx_status[queue], skb);
 	}
 
 	if (!ar->tx_stats[queue].len &&
@@ -524,38 +423,6 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
 	return NULL;
 }
 
-static void ar9170_handle_block_ack(struct ar9170 *ar, u16 count, u16 r)
-{
-	struct sk_buff *skb;
-	struct ieee80211_tx_info *txinfo;
-
-	while (count) {
-		skb = ar9170_get_queued_skb(ar, NULL, &ar->tx_status_ampdu, r);
-		if (!skb)
-			break;
-
-		txinfo = IEEE80211_SKB_CB(skb);
-		ieee80211_tx_info_clear_status(txinfo);
-
-		/* FIXME: maybe more ? */
-		txinfo->status.rates[0].count = 1;
-
-		skb_pull(skb, sizeof(struct ar9170_tx_control));
-		ieee80211_tx_status_irqsafe(ar->hw, skb);
-		count--;
-	}
-
-#ifdef AR9170_TXAGG_DEBUG
-	if (count) {
-		printk(KERN_DEBUG "%s: got %d more failed mpdus, but no more "
-		       "suitable frames left in tx_status queue.\n",
-		       wiphy_name(ar->hw->wiphy), count);
-
-		ar9170_dump_tx_status_ampdu(ar);
-	}
-#endif /* AR9170_TXAGG_DEBUG */
-}
-
 /*
  * This worker tries to keeps an maintain tx_status queues.
  * So we can guarantee that incoming tx_status reports are
@@ -592,8 +459,6 @@ static void ar9170_tx_janitor(struct work_struct *work)
 			resched = true;
 	}
 
-	ar9170_tx_fake_ampdu_status(ar);
-
 	if (!resched)
 		return;
 
@@ -673,10 +538,6 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
 
 	case 0xc5:
 		/* BlockACK events */
-		ar9170_handle_block_ack(ar,
-					le16_to_cpu(cmd->ba_fail_cnt.failed),
-					le16_to_cpu(cmd->ba_fail_cnt.rate));
-		ar9170_tx_fake_ampdu_status(ar);
 		break;
 
 	case 0xc6:
@@ -1247,7 +1108,6 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
 	ar->global_ampdu_density = 6;
 	ar->global_ampdu_factor = 3;
 
-	atomic_set(&ar->tx_ampdu_pending, 0);
 	ar->bad_hw_nagger = jiffies;
 
 	err = ar->open(ar);
@@ -1310,40 +1170,10 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
 		skb_queue_purge(&ar->tx_pending[i]);
 		skb_queue_purge(&ar->tx_status[i]);
 	}
-	skb_queue_purge(&ar->tx_status_ampdu);
 
 	mutex_unlock(&ar->mutex);
 }
 
-static void ar9170_tx_indicate_immba(struct ar9170 *ar, struct sk_buff *skb)
-{
-	struct ar9170_tx_control *txc = (void *) skb->data;
-
-	txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_AMPDU);
-}
-
-static void ar9170_tx_copy_phy(struct ar9170 *ar, struct sk_buff *dst,
-			       struct sk_buff *src)
-{
-	struct ar9170_tx_control *dst_txc, *src_txc;
-	struct ieee80211_tx_info *dst_info, *src_info;
-	struct ar9170_tx_info *dst_arinfo, *src_arinfo;
-
-	src_txc = (void *) src->data;
-	src_info = IEEE80211_SKB_CB(src);
-	src_arinfo = (void *) src_info->rate_driver_data;
-
-	dst_txc = (void *) dst->data;
-	dst_info = IEEE80211_SKB_CB(dst);
-	dst_arinfo = (void *) dst_info->rate_driver_data;
-
-	dst_txc->phy_control = src_txc->phy_control;
-
-	/* same MCS for the whole aggregate */
-	memcpy(dst_info->driver_rates, src_info->driver_rates,
-	       sizeof(dst_info->driver_rates));
-}
-
 static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
 {
 	struct ieee80211_hdr *hdr;
@@ -1420,14 +1250,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
 		txc->phy_control |=
 			cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT);
 
-		if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-			if (unlikely(!info->control.sta))
-				goto err_out;
-
-			txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
-		} else {
-			txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
-		}
+		txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
 	}
 
 	return 0;
@@ -1537,158 +1360,6 @@ static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb)
 	txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT);
 }
 
-static bool ar9170_tx_ampdu(struct ar9170 *ar)
-{
-	struct sk_buff_head agg;
-	struct ar9170_sta_tid *tid_info = NULL, *tmp;
-	struct sk_buff *skb, *first = NULL;
-	unsigned long flags, f2;
-	unsigned int i = 0;
-	u16 seq, queue, tmpssn;
-	bool run = false;
-
-	skb_queue_head_init(&agg);
-
-	spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-	if (list_empty(&ar->tx_ampdu_list)) {
-#ifdef AR9170_TXAGG_DEBUG
-		printk(KERN_DEBUG "%s: aggregation list is empty.\n",
-		       wiphy_name(ar->hw->wiphy));
-#endif /* AR9170_TXAGG_DEBUG */
-		goto out_unlock;
-	}
-
-	list_for_each_entry_safe(tid_info, tmp, &ar->tx_ampdu_list, list) {
-		if (tid_info->state != AR9170_TID_STATE_COMPLETE) {
-#ifdef AR9170_TXAGG_DEBUG
-			printk(KERN_DEBUG "%s: dangling aggregation entry!\n",
-			       wiphy_name(ar->hw->wiphy));
-#endif /* AR9170_TXAGG_DEBUG */
-			continue;
-		}
-
-		if (++i > 64) {
-#ifdef AR9170_TXAGG_DEBUG
-			printk(KERN_DEBUG "%s: enough frames aggregated.\n",
-			       wiphy_name(ar->hw->wiphy));
-#endif /* AR9170_TXAGG_DEBUG */
-			break;
-		}
-
-		queue = TID_TO_WME_AC(tid_info->tid);
-
-		if (skb_queue_len(&ar->tx_pending[queue]) >=
-		    AR9170_NUM_TX_AGG_MAX) {
-#ifdef AR9170_TXAGG_DEBUG
-			printk(KERN_DEBUG "%s: queue %d full.\n",
-			       wiphy_name(ar->hw->wiphy), queue);
-#endif /* AR9170_TXAGG_DEBUG */
-			continue;
-		}
-
-		list_del_init(&tid_info->list);
-
-		spin_lock_irqsave(&tid_info->queue.lock, f2);
-		tmpssn = seq = tid_info->ssn;
-		first = skb_peek(&tid_info->queue);
-
-		if (likely(first))
-			tmpssn = ar9170_get_seq(first);
-
-		if (unlikely(tmpssn != seq)) {
-#ifdef AR9170_TXAGG_DEBUG
-			printk(KERN_DEBUG "%s: ssn mismatch [%d != %d]\n.",
-			       wiphy_name(ar->hw->wiphy), seq, tmpssn);
-#endif /* AR9170_TXAGG_DEBUG */
-			tid_info->ssn = tmpssn;
-		}
-
-#ifdef AR9170_TXAGG_DEBUG
-		printk(KERN_DEBUG "%s: generate A-MPDU for tid:%d ssn:%d with "
-		       "%d queued frames.\n", wiphy_name(ar->hw->wiphy),
-		       tid_info->tid, tid_info->ssn,
-		       skb_queue_len(&tid_info->queue));
-		__ar9170_dump_txqueue(ar, &tid_info->queue);
-#endif /* AR9170_TXAGG_DEBUG */
-
-		while ((skb = skb_peek(&tid_info->queue))) {
-			if (unlikely(ar9170_get_seq(skb) != seq))
-				break;
-
-			__skb_unlink(skb, &tid_info->queue);
-			tid_info->ssn = seq = GET_NEXT_SEQ(seq);
-
-			if (unlikely(skb_get_queue_mapping(skb) != queue)) {
-#ifdef AR9170_TXAGG_DEBUG
-				printk(KERN_DEBUG "%s: tid:%d(q:%d) queue:%d "
-				       "!match.\n", wiphy_name(ar->hw->wiphy),
-				       tid_info->tid,
-				       TID_TO_WME_AC(tid_info->tid),
-				       skb_get_queue_mapping(skb));
-#endif /* AR9170_TXAGG_DEBUG */
-					dev_kfree_skb_any(skb);
-					continue;
-			}
-
-			if (unlikely(first == skb)) {
-				ar9170_tx_prepare_phy(ar, skb);
-				__skb_queue_tail(&agg, skb);
-				first = skb;
-			} else {
-				ar9170_tx_copy_phy(ar, skb, first);
-				__skb_queue_tail(&agg, skb);
-			}
-
-			if (unlikely(skb_queue_len(&agg) ==
-			    AR9170_NUM_TX_AGG_MAX))
-				break;
-		}
-
-		if (skb_queue_empty(&tid_info->queue))
-			tid_info->active = false;
-		else
-			list_add_tail(&tid_info->list,
-				      &ar->tx_ampdu_list);
-
-		spin_unlock_irqrestore(&tid_info->queue.lock, f2);
-
-		if (unlikely(skb_queue_empty(&agg))) {
-#ifdef AR9170_TXAGG_DEBUG
-			printk(KERN_DEBUG "%s: queued empty list!\n",
-			       wiphy_name(ar->hw->wiphy));
-#endif /* AR9170_TXAGG_DEBUG */
-			continue;
-		}
-
-		/*
-		 * tell the FW/HW that this is the last frame,
-		 * that way it will wait for the immediate block ack.
-		 */
-		ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
-
-#ifdef AR9170_TXAGG_DEBUG
-		printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
-		       wiphy_name(ar->hw->wiphy));
-		__ar9170_dump_txqueue(ar, &agg);
-#endif /* AR9170_TXAGG_DEBUG */
-
-		spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-
-		spin_lock_irqsave(&ar->tx_pending[queue].lock, flags);
-		skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]);
-		spin_unlock_irqrestore(&ar->tx_pending[queue].lock, flags);
-		run = true;
-
-		spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-	}
-
-out_unlock:
-	spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-	__skb_queue_purge(&agg);
-
-	return run;
-}
-
 static void ar9170_tx(struct ar9170 *ar)
 {
 	struct sk_buff *skb;
@@ -1763,9 +1434,6 @@ static void ar9170_tx(struct ar9170 *ar)
 			arinfo->timeout = jiffies +
 					  msecs_to_jiffies(AR9170_TX_TIMEOUT);
 
-			if (info->flags & IEEE80211_TX_CTL_AMPDU)
-				atomic_inc(&ar->tx_ampdu_pending);
-
 #ifdef AR9170_QUEUE_DEBUG
 			printk(KERN_DEBUG "%s: send frame q:%d =>\n",
 			       wiphy_name(ar->hw->wiphy), i);
@@ -1774,9 +1442,6 @@ static void ar9170_tx(struct ar9170 *ar)
 
 			err = ar->tx(ar, skb);
 			if (unlikely(err)) {
-				if (info->flags & IEEE80211_TX_CTL_AMPDU)
-					atomic_dec(&ar->tx_ampdu_pending);
-
 				frames_failed++;
 				dev_kfree_skb_any(skb);
 			} else {
@@ -1823,94 +1488,11 @@ static void ar9170_tx(struct ar9170 *ar)
 				     msecs_to_jiffies(AR9170_JANITOR_DELAY));
 }
 
-static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb)
-{
-	struct ieee80211_tx_info *txinfo;
-	struct ar9170_sta_info *sta_info;
-	struct ar9170_sta_tid *agg;
-	struct sk_buff *iter;
-	unsigned long flags, f2;
-	unsigned int max;
-	u16 tid, seq, qseq;
-	bool run = false, queue = false;
-
-	tid = ar9170_get_tid(skb);
-	seq = ar9170_get_seq(skb);
-	txinfo = IEEE80211_SKB_CB(skb);
-	sta_info = (void *) txinfo->control.sta->drv_priv;
-	agg = &sta_info->agg[tid];
-	max = sta_info->ampdu_max_len;
-
-	spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-
-	if (unlikely(agg->state != AR9170_TID_STATE_COMPLETE)) {
-#ifdef AR9170_TXAGG_DEBUG
-		printk(KERN_DEBUG "%s: BlockACK session not fully initialized "
-		       "for ESS:%pM tid:%d state:%d.\n",
-		       wiphy_name(ar->hw->wiphy), agg->addr, agg->tid,
-		       agg->state);
-#endif /* AR9170_TXAGG_DEBUG */
-		goto err_unlock;
-	}
-
-	if (!agg->active) {
-		agg->active = true;
-		agg->ssn = seq;
-		queue = true;
-	}
-
-	/* check if seq is within the BA window */
-	if (unlikely(!BAW_WITHIN(agg->ssn, max, seq))) {
-#ifdef AR9170_TXAGG_DEBUG
-		printk(KERN_DEBUG "%s: frame with tid:%d seq:%d does not "
-		       "fit into BA window (%d - %d)\n",
-		       wiphy_name(ar->hw->wiphy), tid, seq, agg->ssn,
-		       (agg->ssn + max) & 0xfff);
-#endif /* AR9170_TXAGG_DEBUG */
-		goto err_unlock;
-	}
-
-	spin_lock_irqsave(&agg->queue.lock, f2);
-
-	skb_queue_reverse_walk(&agg->queue, iter) {
-		qseq = ar9170_get_seq(iter);
-
-		if (GET_NEXT_SEQ(qseq) == seq) {
-			__skb_queue_after(&agg->queue, iter, skb);
-			goto queued;
-		}
-	}
-
-	__skb_queue_head(&agg->queue, skb);
-
-queued:
-	spin_unlock_irqrestore(&agg->queue.lock, f2);
-
-#ifdef AR9170_TXAGG_DEBUG
-	printk(KERN_DEBUG "%s: new aggregate %p queued.\n",
-	       wiphy_name(ar->hw->wiphy), skb);
-	__ar9170_dump_txqueue(ar, &agg->queue);
-#endif /* AR9170_TXAGG_DEBUG */
-
-	if (skb_queue_len(&agg->queue) >= AR9170_NUM_TX_AGG_MAX)
-		run = true;
-
-	if (queue)
-		list_add_tail(&agg->list, &ar->tx_ampdu_list);
-
-	spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-	return run;
-
-err_unlock:
-	spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-	dev_kfree_skb_irq(skb);
-	return false;
-}
-
 int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
 	struct ar9170 *ar = hw->priv;
 	struct ieee80211_tx_info *info;
+	unsigned int queue;
 
 	if (unlikely(!IS_STARTED(ar)))
 		goto err_free;
@@ -1918,18 +1500,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	if (unlikely(ar9170_tx_prepare(ar, skb)))
 		goto err_free;
 
+	queue = skb_get_queue_mapping(skb);
 	info = IEEE80211_SKB_CB(skb);
-	if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-		bool run = ar9170_tx_ampdu_queue(ar, skb);
-
-		if (run || !atomic_read(&ar->tx_ampdu_pending))
-			ar9170_tx_ampdu(ar);
-	} else {
-		unsigned int queue = skb_get_queue_mapping(skb);
-
-		ar9170_tx_prepare_phy(ar, skb);
-		skb_queue_tail(&ar->tx_pending[queue], skb);
-	}
+	ar9170_tx_prepare_phy(ar, skb);
+	skb_queue_tail(&ar->tx_pending[queue], skb);
 
 	ar9170_tx(ar);
 	return NETDEV_TX_OK;
@@ -2330,57 +1904,6 @@ out:
 	return err;
 }
 
-static int ar9170_sta_add(struct ieee80211_hw *hw,
-			  struct ieee80211_vif *vif,
-			  struct ieee80211_sta *sta)
-{
-	struct ar9170 *ar = hw->priv;
-	struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
-	unsigned int i;
-
-	memset(sta_info, 0, sizeof(*sta_info));
-
-	if (!sta->ht_cap.ht_supported)
-		return 0;
-
-	if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
-		ar->global_ampdu_density = sta->ht_cap.ampdu_density;
-
-	if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
-		ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
-
-	for (i = 0; i < AR9170_NUM_TID; i++) {
-		sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
-		sta_info->agg[i].active = false;
-		sta_info->agg[i].ssn = 0;
-		sta_info->agg[i].tid = i;
-		INIT_LIST_HEAD(&sta_info->agg[i].list);
-		skb_queue_head_init(&sta_info->agg[i].queue);
-	}
-
-	sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
-
-	return 0;
-}
-
-static int ar9170_sta_remove(struct ieee80211_hw *hw,
-			     struct ieee80211_vif *vif,
-			     struct ieee80211_sta *sta)
-{
-	struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
-	unsigned int i;
-
-	if (!sta->ht_cap.ht_supported)
-		return 0;
-
-	for (i = 0; i < AR9170_NUM_TID; i++) {
-		sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
-		skb_queue_purge(&sta_info->agg[i].queue);
-	}
-
-	return 0;
-}
-
 static int ar9170_get_stats(struct ieee80211_hw *hw,
 			    struct ieee80211_low_level_stats *stats)
 {
@@ -2423,55 +1946,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
 			       enum ieee80211_ampdu_mlme_action action,
 			       struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
-	struct ar9170 *ar = hw->priv;
-	struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
-	struct ar9170_sta_tid *tid_info = &sta_info->agg[tid];
-	unsigned long flags;
-
-	if (!modparam_ht)
-		return -EOPNOTSUPP;
-
 	switch (action) {
-	case IEEE80211_AMPDU_TX_START:
-		spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-		if (tid_info->state != AR9170_TID_STATE_SHUTDOWN ||
-		    !list_empty(&tid_info->list)) {
-			spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-#ifdef AR9170_TXAGG_DEBUG
-			printk(KERN_INFO "%s: A-MPDU [ESS:[%pM] tid:[%d]] "
-			       "is in a very bad state!\n",
-			       wiphy_name(hw->wiphy), sta->addr, tid);
-#endif /* AR9170_TXAGG_DEBUG */
-			return -EBUSY;
-		}
-
-		*ssn = tid_info->ssn;
-		tid_info->state = AR9170_TID_STATE_PROGRESS;
-		tid_info->active = false;
-		spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-		break;
-
-	case IEEE80211_AMPDU_TX_STOP:
-		spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-		tid_info->state = AR9170_TID_STATE_SHUTDOWN;
-		list_del_init(&tid_info->list);
-		tid_info->active = false;
-		skb_queue_purge(&tid_info->queue);
-		spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-		break;
-
-	case IEEE80211_AMPDU_TX_OPERATIONAL:
-#ifdef AR9170_TXAGG_DEBUG
-		printk(KERN_INFO "%s: A-MPDU for %pM [tid:%d] Operational.\n",
-		       wiphy_name(hw->wiphy), sta->addr, tid);
-#endif /* AR9170_TXAGG_DEBUG */
-		spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-		sta_info->agg[tid].state = AR9170_TID_STATE_COMPLETE;
-		spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-		break;
-
 	case IEEE80211_AMPDU_RX_START:
 	case IEEE80211_AMPDU_RX_STOP:
 		/* Handled by firmware */
@@ -2497,8 +1972,6 @@ static const struct ieee80211_ops ar9170_ops = {
 	.bss_info_changed	= ar9170_op_bss_info_changed,
 	.get_tsf		= ar9170_op_get_tsf,
 	.set_key		= ar9170_set_key,
-	.sta_add		= ar9170_sta_add,
-	.sta_remove		= ar9170_sta_remove,
 	.get_stats		= ar9170_get_stats,
 	.ampdu_action		= ar9170_ampdu_action,
 };
@@ -2531,8 +2004,6 @@ void *ar9170_alloc(size_t priv_size)
 	mutex_init(&ar->mutex);
 	spin_lock_init(&ar->cmdlock);
 	spin_lock_init(&ar->tx_stats_lock);
-	spin_lock_init(&ar->tx_ampdu_list_lock);
-	skb_queue_head_init(&ar->tx_status_ampdu);
 	for (i = 0; i < __AR9170_NUM_TXQ; i++) {
 		skb_queue_head_init(&ar->tx_status[i]);
 		skb_queue_head_init(&ar->tx_pending[i]);
@@ -2540,7 +2011,6 @@ void *ar9170_alloc(size_t priv_size)
 	ar9170_rx_reset_rx_mpdu(ar);
 	INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
 	INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
-	INIT_LIST_HEAD(&ar->tx_ampdu_list);
 
 	/* all hw supports 2.4 GHz, so set channel to 1 by default */
 	ar->channel = &ar9170_2ghz_chantable[0];
@@ -2554,16 +2024,8 @@ void *ar9170_alloc(size_t priv_size)
 			 IEEE80211_HW_SIGNAL_DBM |
 			 IEEE80211_HW_NOISE_DBM;
 
-	if (modparam_ht) {
-		ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
-	} else {
-		ar9170_band_2GHz.ht_cap.ht_supported = false;
-		ar9170_band_5GHz.ht_cap.ht_supported = false;
-	}
-
 	ar->hw->queues = __AR9170_NUM_TXQ;
 	ar->hw->extra_tx_headroom = 8;
-	ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
 
 	ar->hw->max_rates = 1;
 	ar->hw->max_rate_tries = 3;

^ permalink raw reply related

* [PATCH] ssb: Implement fast powerup delay calculation
From: Gábor Stefanik @ 2010-05-01 16:29 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, b43-dev, Michael Buesch, Larry Finger

Implement fast powerup delay calculation, as described
in the recently updated specs. The 4325 part is coming soon.

Signed-off-by: Gábor Stefanik<netrolller.3d@gmail.com>
---

To people experiencing DMA errors: please test this patch, it touches
the PMU code, one of the suspected problem areas.

I'm submitting this patch using Thunderbird 3; so I cannot be held liable
if it gets damaged in transit. Blame Mozilla. :-)

Index: wireless-testing/drivers/ssb/driver_chipcommon.c
===================================================================
--- wireless-testing.orig/drivers/ssb/driver_chipcommon.c
+++ wireless-testing/drivers/ssb/driver_chipcommon.c
@@ -209,7 +209,24 @@ static void chipco_powercontrol_init(str
  	}
  }

-static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
+static u16 pmu_fast_powerup_delay(struct ssb_chipcommon *cc)
+{
+	struct ssb_bus *bus = cc->dev->bus;
+
+	switch (bus->chip_id) {
+	case 0x4312:
+	case 0x4322:
+	case 0x4328:
+		return 7000;
+	case 0x4325:
+		/* TODO: */
+	default:
+		break;
+	}
+	return 15000;
+}
+
+static u16 calc_fast_powerup_delay(struct ssb_chipcommon *cc)
  {
  	struct ssb_bus *bus = cc->dev->bus;
  	int minfreq;
@@ -217,26 +234,33 @@ static void calc_fast_powerup_delay(stru
  	u32 pll_on_delay;

  	if (bus->bustype != SSB_BUSTYPE_PCI)
-		return;
+		return 0;
+	if (cc->capabilities&  SSB_CHIPCO_CAP_PMU)
+		return pmu_fast_powerup_delay(cc);
  	if (!(cc->capabilities&  SSB_CHIPCO_CAP_PCTL))
-		return;
+		return 0;

  	minfreq = chipco_pctl_clockfreqlimit(cc, 0);
  	pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY);
  	tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
  	SSB_WARN_ON(tmp&  ~0xFFFF);

-	cc->fast_pwrup_delay = tmp;
+	return tmp;
  }

  void ssb_chipcommon_init(struct ssb_chipcommon *cc)
  {
+	u16 delay;
+
  	if (!cc->dev)
  		return; /* We don't have a ChipCommon */
  	ssb_pmu_init(cc);
  	chipco_powercontrol_init(cc);
  	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
-	calc_fast_powerup_delay(cc);
+	delay = calc_fast_powerup_delay(cc);
+	ssb_printk(KERN_INFO PFX "fast_pwrup_delay is %d\n", delay);
+	cc->fast_pwrup_delay = delay;
+	ssb_write16(cc->dev, SSB_MMIO_POWERUP_DELAY, delay);
  }

  void ssb_chipco_suspend(struct ssb_chipcommon *cc)
Index: wireless-testing/include/linux/ssb/ssb_regs.h
===================================================================
--- wireless-testing.orig/include/linux/ssb/ssb_regs.h
+++ wireless-testing/include/linux/ssb/ssb_regs.h
@@ -26,6 +26,7 @@
  #define	SSB_EUART		(SSB_EXTIF_BASE + 0x00800000)
  #define	SSB_LED			(SSB_EXTIF_BASE + 0x00900000)

+#define SSB_MMIO_POWERUP_DELAY	0x06A8

  /* Enumeration space constants */
  #define SSB_CORE_SIZE		0x1000	/* Size of a core MMIO area */



^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox